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:
Diffstat (limited to 'source/blender/src/editconstraint.c')
-rw-r--r--source/blender/src/editconstraint.c753
1 files changed, 753 insertions, 0 deletions
diff --git a/source/blender/src/editconstraint.c b/source/blender/src/editconstraint.c
new file mode 100644
index 00000000000..17d59a18192
--- /dev/null
+++ b/source/blender/src/editconstraint.c
@@ -0,0 +1,753 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_object.h"
+#include "BKE_global.h"
+#include "BKE_constraint.h"
+#include "BKE_ipo.h"
+
+#include "BIF_editarmature.h"
+#include "BIF_editconstraint.h"
+#include "BIF_interface.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_editaction.h"
+
+#include "interface.h"
+#include "blendef.h"
+#include "nla.h"
+
+static short add_constraint_element (Object *owner, const char *substring, Object *parent, const char *parentstring);
+static short detect_constraint_loop (Object *owner, const char* substring, int disable);
+static void test_bonelist_constraints (Object *owner, ListBase *list);
+static void clear_object_constraint_loop_flags(Object *ob);
+//static int is_child_of(struct Object *owner, struct Object *parent);
+//static int is_bonechild_of(struct Bone *bone, struct Bone *parent);
+static int is_child_of_ex(Object *owner, const char *ownersubstr, Object *parent, const char *parsubstr);
+
+ListBase g_conBase;
+const char *g_conString;
+Object *g_conObj;
+
+
+void unique_constraint_name (bConstraint *con, ListBase *list){
+ char tempname[64];
+ int number;
+ char *dot;
+ int exists = 0;
+ bConstraint *curcon;
+
+ /* See if we even need to do this */
+ for (curcon = list->first; curcon; curcon=curcon->next){
+ if (curcon!=con){
+ if (!strcmp(curcon->name, con->name)){
+ exists = 1;
+ break;
+ }
+ }
+ }
+
+ if (!exists)
+ return;
+
+ /* Strip off the suffix */
+ dot=strchr(con->name, '.');
+ if (dot)
+ *dot=0;
+
+ for (number = 1; number <=999; number++){
+ sprintf (tempname, "%s.%03d", con->name, number);
+
+ exists = 0;
+ for (curcon=list->first; curcon; curcon=curcon->next){
+ if (con!=curcon){
+ if (!strcmp (curcon->name, tempname)){
+ exists = 1;
+ break;
+ }
+ }
+ }
+ if (!exists){
+ strcpy (con->name, tempname);
+ return;
+ }
+ }
+}
+
+static int is_child_of_ex(Object *owner, const char *ownersubstr, Object *parent, const char *parsubstr)
+{
+ Object *curob;
+ int working = 1;
+ Bone *bone = NULL;
+ Bone *parbone= NULL;
+
+ curob=owner;
+
+ /* If this is a bone */
+ if (strlen(ownersubstr))
+ bone = get_named_bone(get_armature(owner->parent), ownersubstr);
+
+ if (strlen(parsubstr))
+ parbone = get_named_bone(get_armature(parent), parsubstr);
+
+
+ /* Traverse the scene graph */
+ while (curob && !bone){
+ switch (curob->partype){
+ case PARBONE:
+ if (strlen(parsubstr)){
+ bone = get_named_bone(get_armature(curob->parent), curob->parsubstr);
+ break;
+ }
+ /* The break is supposed to be missing */
+ default:
+ if (curob==parent){
+ if (parbone)
+ return 0;
+ else
+ return 1;
+ }
+ curob=curob->parent;
+ }
+ }
+
+
+ /* Descend into the armature scene graph */
+ while (bone){
+ if (bone==parbone)
+ return 1;
+ bone=bone->parent;
+ }
+
+ return 0;
+}
+/*
+static int is_child_of(Object *owner, Object *parent)
+{
+ Object *curpar;
+
+ for (curpar = owner->parent; curpar; curpar=curpar->parent){
+ if (curpar==parent)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int is_bonechild_of(Bone *bone, Bone *parent)
+{
+ Bone *curpar;
+
+ if (!bone)
+ return 0;
+
+ for (curpar = bone->parent; curpar; curpar=curpar->parent){
+ if (curpar==parent)
+ return 1;
+ }
+ return 0;
+}
+*/
+static short add_constraint_element (Object *owner, const char *substring, Object *parent, const char *parentstring)
+{
+
+ if (!owner)
+ return 0;
+
+ /* See if this is the original object */
+ if (parent == owner){
+ if (!strcmp (parentstring, substring))
+ return 1;
+ }
+
+ if (owner == g_conObj){
+ if (!strcmp (g_conString, substring))
+ return 1;
+ }
+
+ /* See if this is a child of the adding object */
+ if (parent){
+// if (is_child_of (owner, parent))
+ if (is_child_of_ex (owner, substring, parent, parentstring))
+ return 1;
+ /* Parent is a bone */
+/* if ((owner==parent) && (owner->type == OB_ARMATURE)){
+ if (strlen (substring) && strlen(parentstring)){
+ if (is_bonechild_of(get_named_bone(owner->data, substring), get_named_bone(parent->data, parentstring)))
+ return 1;
+ }
+ }
+ */
+ }
+ return 0;
+}
+
+static void test_bonelist_constraints (Object *owner, ListBase *list)
+{
+ Bone *bone;
+ Base *base1;
+
+
+ for (bone = list->first; bone; bone=bone->next){
+ for (base1 = G.scene->base.first; base1; base1=base1->next){
+ clear_object_constraint_loop_flags(base1->object);
+ }
+ test_constraints(owner, bone->name, 1);
+ test_bonelist_constraints (owner, &bone->childbase);
+ }
+}
+
+
+static void clear_object_constraint_loop_flags(Object *ob)
+{
+ bConstraint *con;
+
+ if (!ob)
+ return;
+
+ /* Test object constraints */
+ for (con = ob->constraints.first; con; con=con->next){
+ con->flag &= ~CONSTRAINT_LOOPTESTED;
+ }
+
+ switch (ob->type){
+ case OB_ARMATURE:
+ if (ob->pose){
+ bPoseChannel *pchan;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next){
+ for (con = pchan->constraints.first; con; con=con->next){
+ con->flag &= ~CONSTRAINT_LOOPTESTED;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+void test_scene_constraints (void)
+{
+ Base *base, *base1;
+
+/* Clear the "done" flags of all constraints */
+
+ for (base = G.scene->base.first; base; base=base->next){
+ clear_object_constraint_loop_flags(base->object);
+ }
+
+ /* Test all constraints */
+ for (base = G.scene->base.first; base; base=base->next){
+ /* Test the object */
+
+ for (base1 = G.scene->base.first; base1; base1=base1->next)
+ clear_object_constraint_loop_flags(base1->object);
+
+
+ test_constraints (base->object, "", 1);
+
+
+ /* Test the subobject constraints */
+ switch (base->object->type){
+ case OB_ARMATURE:
+ {
+ bArmature *arm;
+ arm = get_armature(base->object);
+ if (arm)
+ test_bonelist_constraints (base->object, &arm->bonebase);
+ }
+ break;
+ default:
+ break;
+ }
+
+
+ }
+}
+
+int test_constraints (Object *owner, const char *substring, int disable)
+{
+/* init_constraint_elements();*/
+ g_conObj = owner;
+ g_conString = substring;
+
+ if (detect_constraint_loop (owner, substring, disable))
+ return 1;
+ else
+ return 0;
+
+/* free_constraint_elements(); */
+}
+
+static short detect_constraint_loop (Object *owner, const char* substring, int disable)
+{
+
+ bConstraint *curcon;
+ ListBase *conlist;
+ int type;
+ int result = 0;
+
+ if (!owner)
+ return result;
+
+ /* Check parents */
+ /* Get the constraint list for this object */
+
+ if (strlen (substring)){
+ switch (owner->type){
+ case OB_ARMATURE:
+ type = TARGET_BONE;
+ break;
+ default:
+ type = TARGET_OBJECT;
+ break;
+ }
+ }
+ else
+ type = TARGET_OBJECT;
+
+
+ switch (type){
+ case TARGET_OBJECT:
+ conlist = &owner->constraints;
+ /* Check parents */
+#if 0
+ if (owner->parent && (ELEM (owner->partype, PAROBJECT, PARBONE))){
+ if (add_constraint_element (owner->parent, "", NULL, NULL)){
+ return 1;
+ }
+ /* if (detect_constraint_loop (owner->parent, "", disable)){
+ return 1;
+ }
+ */
+ }
+ /* Check tracking */
+ if (owner->track && (ELEM (owner->partype, PAROBJECT, PARBONE))){
+ if (add_constraint_element (owner->track, "", NULL, NULL)){
+ return 1;
+ }
+ /* if (detect_constraint_loop (owner->track, "", disable)){
+ return 1;
+ }
+ */
+ }
+#else
+ if (owner->parent && (owner->partype==PAROBJECT))
+ if (add_constraint_element (owner->parent, "", NULL, NULL))
+ return 1;
+
+ if (owner->parent && (owner->partype==PARBONE))
+ if (add_constraint_element (owner->parent, owner->parsubstr, NULL, NULL))
+ return 1;
+
+ /* Check tracking */
+ if (owner->track)
+ if (add_constraint_element (owner->track, "", NULL, NULL))
+ return 1;
+#endif
+
+ break;
+ case TARGET_BONE:
+ {
+ Bone *bone;
+ bPoseChannel *chan;
+
+ bone = get_named_bone(((bArmature*)owner->data), substring);
+ chan = get_pose_channel (owner->pose, substring);
+ if (bone){
+ conlist = &chan->constraints;
+ if (bone->parent){
+ if (add_constraint_element (owner, bone->parent->name, NULL, NULL))
+ return 1;
+ if (detect_constraint_loop (owner, bone->parent->name, disable))
+ return 1;
+ }
+ else{
+ if (add_constraint_element (owner, "", NULL, NULL))
+ return 1;
+ if (detect_constraint_loop (owner, "", disable))
+ return 1;
+ }
+ }
+ else
+ conlist = NULL;
+ }
+ break;
+ default:
+ conlist = NULL;
+ break;
+ }
+
+ /* Cycle constraints */
+ if (conlist){
+ for (curcon = conlist->first; curcon; curcon=curcon->next){
+
+ /* Clear the disable flag */
+
+ if (curcon->flag & CONSTRAINT_LOOPTESTED){
+ return 0;
+ }
+ else {
+ curcon->flag &= ~CONSTRAINT_DISABLE;
+ curcon->flag |= CONSTRAINT_LOOPTESTED;
+ switch (curcon->type){
+ case CONSTRAINT_TYPE_ACTION:
+ {
+ bActionConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)){
+ data->tar = NULL;
+ break;
+ }
+
+ if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
+ curcon->flag |= CONSTRAINT_DISABLE;
+ result = 1;
+ break;
+ // return 1;
+ }
+ if (detect_constraint_loop (data->tar, data->subtarget, disable)){
+ curcon->flag |= CONSTRAINT_DISABLE;
+ result = 1;
+ break;
+ // return 1;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCLIKE:
+ {
+ bLocateLikeConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)){
+ data->tar = NULL;
+ break;
+ }
+
+ if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
+ curcon->flag |= CONSTRAINT_DISABLE;
+ result = 1;
+ break;
+ // return 1;
+ }
+ if (detect_constraint_loop (data->tar, data->subtarget, disable)){
+ curcon->flag |= CONSTRAINT_DISABLE;
+ result = 1;
+ break;
+ // return 1;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)){
+ data->tar = NULL;
+ break;
+ }
+
+ if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
+ curcon->flag |= CONSTRAINT_DISABLE;
+ result = 1;
+ break;
+ // return 1;
+ }
+ if (detect_constraint_loop (data->tar, data->subtarget, disable)){
+ curcon->flag |= CONSTRAINT_DISABLE;
+ result = 1;
+ break;
+ // return 1;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ {
+ bKinematicConstraint *data = curcon->data;
+ if (!exist_object(data->tar)){
+ data->tar = NULL;
+ break;
+ }
+
+ if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
+ curcon->flag |= CONSTRAINT_DISABLE;
+ result = 1;
+ break;
+ // return 1;
+ }
+ if (detect_constraint_loop (data->tar, data->subtarget, disable)){
+ curcon->flag |= CONSTRAINT_DISABLE;
+ result = 1;
+ break;
+ // return 1;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_TRACKTO:
+ {
+ bTrackToConstraint *data = curcon->data;
+ if (!exist_object(data->tar)) data->tar = NULL;
+
+ if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
+ curcon->flag |= CONSTRAINT_DISABLE;
+ result = 1;
+ break;
+ // return 1;
+ }
+ if (detect_constraint_loop (data->tar, data->subtarget, disable)){
+ curcon->flag |= CONSTRAINT_DISABLE;
+ result = 1;
+ break;
+ // return 1;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+ListBase *get_constraint_client_channels (int forcevalid)
+{
+
+ Object *ob;
+ char ipstr[64];
+
+ ob=OBACT;
+
+ if (!ob)
+ return NULL;
+
+ /* See if we are a bone constraint */
+ if (G.obpose){
+ switch (G.obpose->type){
+ case OB_ARMATURE:
+ {
+ bActionChannel *achan;
+ Bone *bone;
+
+ bone = get_first_selected_bone();
+ if (!bone) break;
+
+ /* Make sure we have an action */
+ if (!G.obpose->action){
+ if (!forcevalid)
+ return NULL;
+
+ G.obpose->action=add_empty_action();
+ }
+
+ /* Make sure we have an actionchannel */
+ achan = get_named_actionchannel(G.obpose->action, bone->name);
+ if (!achan){
+ if (!forcevalid)
+ return NULL;
+
+ achan = MEM_callocN (sizeof(bActionChannel), "actionChannel");
+
+ strcpy (achan->name, bone->name);
+ sprintf (ipstr, "%s.%s", G.obpose->action->id.name+2, achan->name);
+ ipstr[23]=0;
+ achan->ipo= add_ipo(ipstr, ID_AC);
+
+ BLI_addtail (&G.obpose->action->chanbase, achan);
+ }
+
+ return &achan->constraintChannels;
+ }
+ }
+ }
+
+ return &ob->constraintChannels;
+}
+
+ListBase *get_constraint_client(char *name, short *clientType, void **clientdata)
+{
+ Object *ob;
+ ListBase *list;
+
+ ob=OBACT;
+ if (clientType)
+ *clientType = -1;
+
+ if (!ob)
+ return NULL;
+
+ list = &ob->constraints;
+
+ /* Prep the object's constraint channels */
+ if (clientType)
+ *clientType = TARGET_OBJECT;
+
+ if (name)
+ strcpy (name, ob->id.name+2);
+
+ if (G.obpose){
+ switch (G.obpose->type){
+ case OB_ARMATURE:
+ {
+ Bone *bone;
+
+ bone = get_first_selected_bone();
+ if (!bone) break;
+
+ {
+ bPoseChannel *chan;
+
+ /* Is the bone the client? */
+ if (clientType)
+ *clientType = TARGET_BONE;
+ if (clientdata)
+ *clientdata = bone;
+ if (name)
+ sprintf (name, "%s>>%s", name, bone->name);
+ verify_pose_channel(G.obpose->pose, bone->name);
+ chan = get_pose_channel (G.obpose->pose, bone->name);
+ list = &chan->constraints;
+
+ }
+ }
+ break;
+ }
+ }
+
+ return list;
+}
+
+void *new_constraint_data (short type)
+{
+ void *result;
+
+ switch (type){
+ case CONSTRAINT_TYPE_KINEMATIC:
+ {
+ bKinematicConstraint *data;
+ data = MEM_callocN(sizeof(bKinematicConstraint), "kinematicConstraint");
+
+ data->tolerance = 0.001;
+ data->iterations = 500;
+
+ result = data;
+ }
+ break;
+ case CONSTRAINT_TYPE_NULL:
+ {
+ result = NULL;
+ }
+ break;
+ case CONSTRAINT_TYPE_TRACKTO:
+ {
+ bTrackToConstraint *data;
+ data = MEM_callocN(sizeof(bTrackToConstraint), "tracktoConstraint");
+
+ result = data;
+
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data;
+ data = MEM_callocN(sizeof(bRotateLikeConstraint), "rotlikeConstraint");
+
+ result = data;
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCLIKE:
+ {
+ bLocateLikeConstraint *data;
+ data = MEM_callocN(sizeof(bLocateLikeConstraint), "loclikeConstraint");
+
+ data->flag |= LOCLIKE_X|LOCLIKE_Y|LOCLIKE_Z;
+ result = data;
+ }
+ break;
+ case CONSTRAINT_TYPE_ACTION:
+ {
+ bActionConstraint *data;
+ data = MEM_callocN(sizeof(bActionConstraint), "actionConstraint");
+
+ result = data;
+ }
+ break;
+ default:
+ result = NULL;
+ break;
+ }
+
+ return result;
+}
+
+bConstraint * add_new_constraint(void)
+{
+ bConstraint *con;
+
+ con = MEM_callocN(sizeof(bConstraint), "constraint");
+
+ /* Set up a generic constraint datablock */
+ con->type = CONSTRAINT_TYPE_TRACKTO;
+ con->flag |= CONSTRAINT_EXPAND;
+ con->enforce=1.0F;
+ /* Load the data for it */
+ con->data = new_constraint_data(con->type);
+ strcpy (con->name, "Const");
+ return con;
+}
+
+bConstraintChannel *add_new_constraint_channel(const char* name)
+{
+ bConstraintChannel *chan = NULL;
+
+ chan = MEM_callocN(sizeof(bConstraintChannel), "constraintChannel");
+ strcpy(chan->name, name);
+
+ return chan;
+} \ No newline at end of file