This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/src/editconstraint.c
Kent Mein d0e346d544 updated .c files to include:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Just need to finish cpp files now :)

Kent
--
mein@cs.umn.edu
2002-11-25 12:02:15 +00:00

758 lines
16 KiB
C

/**
* $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"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
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;
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;
}