#ifdef HAVE_CONFIG_H #include <config.h> #endif Just need to finish cpp files now :) Kent -- mein@cs.umn.edu
882 lines
19 KiB
C
882 lines
19 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 *****
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <stdlib.h> /* for NULL */
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
#include "BLI_arithb.h"
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BKE_action.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_ipo_types.h"
|
|
#include "DNA_curve_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_action_types.h"
|
|
#include "DNA_nla_types.h"
|
|
|
|
#include "BKE_blender.h"
|
|
#include "BKE_ipo.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_library.h"
|
|
#include "BKE_anim.h"
|
|
#include "BKE_armature.h"
|
|
|
|
#include "nla.h"
|
|
|
|
#include "BKE_constraint.h"
|
|
#include "DNA_constraint_types.h"
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
/* Local function prototypes */
|
|
static
|
|
void
|
|
do_pose_constraint_channels(
|
|
bPose *pose,
|
|
bAction *act,
|
|
float ctime
|
|
);
|
|
|
|
static
|
|
void
|
|
get_constraint_influence_from_pose (
|
|
bPose *dst,
|
|
bPose *src
|
|
);
|
|
|
|
static
|
|
void
|
|
blend_constraints(
|
|
ListBase *dst,
|
|
const ListBase *src,
|
|
float srcweight,
|
|
short mode
|
|
);
|
|
|
|
static
|
|
void
|
|
rest_pose (
|
|
bPose *pose,
|
|
int clearflag
|
|
);
|
|
|
|
/* Implementation */
|
|
|
|
bPoseChannel *
|
|
get_pose_channel (
|
|
const bPose *pose,
|
|
const char *name
|
|
){
|
|
bPoseChannel *chan;
|
|
|
|
for (chan=pose->chanbase.first; chan; chan=chan->next){
|
|
if (!strcmp (chan->name, name))
|
|
return chan;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static
|
|
void
|
|
rest_pose (
|
|
bPose *pose,
|
|
int clearflag
|
|
){
|
|
bPoseChannel *chan;
|
|
int i;
|
|
|
|
if (!pose)
|
|
return;
|
|
|
|
for (chan=pose->chanbase.first; chan; chan=chan->next){
|
|
for (i=0; i<3; i++){
|
|
chan->loc[i]=0.0;
|
|
chan->quat[i+1]=0.0;
|
|
chan->size[i]=1.0;
|
|
}
|
|
chan->quat[0]=1.0;
|
|
if (clearflag)
|
|
chan->flag =0;
|
|
}
|
|
}
|
|
|
|
static
|
|
void
|
|
blend_constraints(
|
|
ListBase *dst,
|
|
const ListBase *src,
|
|
float srcweight,
|
|
short mode
|
|
){
|
|
bConstraint *dcon;
|
|
const bConstraint *scon;
|
|
float dstweight;
|
|
|
|
switch (mode){
|
|
case POSE_BLEND:
|
|
dstweight = 1.0F - srcweight;
|
|
break;
|
|
case POSE_ADD:
|
|
dstweight = 1.0F;
|
|
break;
|
|
}
|
|
|
|
/* Blend constraints */
|
|
for (dcon=dst->first; dcon; dcon=dcon->next){
|
|
for (scon = src->first; scon; scon=scon->next){
|
|
if (!strcmp(scon->name, dcon->name))
|
|
break;
|
|
}
|
|
|
|
if (scon){
|
|
dcon->enforce = (dcon->enforce*dstweight) + (scon->enforce*srcweight);
|
|
if (mode == POSE_BLEND)
|
|
dcon->enforce/=2.0;
|
|
|
|
if (dcon->enforce>1.0)
|
|
dcon->enforce=1.0;
|
|
if (dcon->enforce<0.0)
|
|
dcon->enforce=0.0;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
blend_poses (
|
|
bPose *dst,
|
|
const bPose *src,
|
|
float srcweight,
|
|
short mode
|
|
){
|
|
bPoseChannel *dchan;
|
|
const bPoseChannel *schan;
|
|
float dquat[4], squat[4], mat[3][3];
|
|
float dstweight;
|
|
int i;
|
|
|
|
switch (mode){
|
|
case POSE_BLEND:
|
|
dstweight = 1.0F - srcweight;
|
|
break;
|
|
case POSE_ADD:
|
|
dstweight = 1.0F;
|
|
break;
|
|
default :
|
|
dstweight = 1.0F;
|
|
}
|
|
|
|
for (dchan = dst->chanbase.first; dchan; dchan=dchan->next){
|
|
schan = get_pose_channel(src, dchan->name);
|
|
if (schan){
|
|
if (schan->flag & (POSE_ROT|POSE_LOC|POSE_SIZE)){
|
|
|
|
/* Convert both quats to matrices and then back again.
|
|
* This prevents interpolation problems
|
|
* This sucks because it is slow and stupid
|
|
*/
|
|
|
|
QuatToMat3(dchan->quat, mat);
|
|
Mat3ToQuat(mat, dquat);
|
|
QuatToMat3(schan->quat, mat);
|
|
Mat3ToQuat(mat, squat);
|
|
|
|
/* Do the transformation blend */
|
|
for (i=0; i<3; i++){
|
|
if (schan->flag & POSE_LOC)
|
|
dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight);
|
|
if (schan->flag & POSE_SIZE)
|
|
dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight);
|
|
if (schan->flag & POSE_ROT)
|
|
dchan->quat[i+1] = (dquat[i+1]*dstweight) + (squat[i+1]*srcweight);
|
|
}
|
|
|
|
/* Do one more iteration for the quaternions only and normalize the quaternion if needed */
|
|
if (schan->flag & POSE_ROT)
|
|
dchan->quat[0] = 1.0f + ((dquat[0]-1.0f)*dstweight) + ((squat[0]-1.0f)*srcweight);
|
|
if (mode==POSE_BLEND)
|
|
NormalQuat (dchan->quat);
|
|
dchan->flag |= schan->flag;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
clear_pose_constraint_status (
|
|
Object *ob
|
|
){
|
|
bPoseChannel *chan;
|
|
|
|
if (!ob)
|
|
return;
|
|
if (!ob->pose)
|
|
return;
|
|
|
|
for (chan = ob->pose->chanbase.first; chan; chan=chan->next){
|
|
chan->flag &= ~PCHAN_DONE;
|
|
}
|
|
}
|
|
|
|
float
|
|
calc_action_start (
|
|
const bAction *act
|
|
){
|
|
const bActionChannel *chan;
|
|
const IpoCurve *icu;
|
|
float size=999999999.0f;
|
|
int i;
|
|
int foundvert=0;
|
|
const bConstraintChannel *conchan;
|
|
|
|
|
|
if (!act)
|
|
return 0;
|
|
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
for (icu=chan->ipo->curve.first; icu; icu=icu->next)
|
|
for (i=0; i<icu->totvert; i++){
|
|
size = MIN2 (size, icu->bezt[i].vec[1][0]);
|
|
foundvert=1;
|
|
|
|
}
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
|
|
for (icu=conchan->ipo->curve.first; icu; icu=icu->next)
|
|
for (i=0; i<icu->totvert; i++){
|
|
size = MIN2 (size, icu->bezt[i].vec[1][0]);
|
|
foundvert=1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!foundvert)
|
|
return 0;
|
|
else
|
|
return size;
|
|
}
|
|
|
|
float
|
|
calc_action_end (
|
|
const bAction *act
|
|
){
|
|
const bActionChannel *chan;
|
|
const bConstraintChannel *conchan;
|
|
const IpoCurve *icu;
|
|
float size=0;
|
|
int i;
|
|
|
|
if (!act)
|
|
return 0;
|
|
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
for (icu=chan->ipo->curve.first; icu; icu=icu->next)
|
|
for (i=0; i<icu->totvert; i++)
|
|
size = MAX2 (size, icu->bezt[i].vec[1][0]);
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
|
|
for (icu=conchan->ipo->curve.first; icu; icu=icu->next)
|
|
for (i=0; i<icu->totvert; i++)
|
|
size = MAX2 (size, icu->bezt[i].vec[1][0]);
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
void
|
|
verify_pose_channel (
|
|
bPose* pose,
|
|
const char* name
|
|
) {
|
|
bPoseChannel *chan;
|
|
|
|
if (!pose){
|
|
return;
|
|
}
|
|
|
|
/* See if this channel exists */
|
|
for (chan=pose->chanbase.first; chan; chan=chan->next){
|
|
if (!strcmp (name, chan->name))
|
|
return;
|
|
}
|
|
|
|
/* If not, create it and add it */
|
|
chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel");
|
|
|
|
strcpy (chan->name, name);
|
|
chan->loc[0] = chan->loc[1] = chan->loc[2] = 0.0F;
|
|
chan->quat[1] = chan->quat[2] = chan->quat[3] = 0.0F; chan->quat[0] = 1.0F;
|
|
chan->size[0] = chan->size[1] = chan->size[2] = 1.0F;
|
|
|
|
chan->flag |= POSE_ROT|POSE_SIZE|POSE_LOC;
|
|
|
|
BLI_addtail (&pose->chanbase, chan);
|
|
}
|
|
|
|
void
|
|
get_pose_from_pose (
|
|
bPose **pose,
|
|
const bPose *src
|
|
){
|
|
const bPoseChannel *pchan;
|
|
bPoseChannel *newchan;
|
|
|
|
if (!src)
|
|
return;
|
|
if (!pose)
|
|
return;
|
|
|
|
/* If there is no pose, create one */
|
|
if (!*pose){
|
|
*pose=MEM_callocN (sizeof(bPose), "pose");
|
|
}
|
|
|
|
/* Copy the data from the action into the pose */
|
|
for (pchan=src->chanbase.first; pchan; pchan=pchan->next){
|
|
newchan = copy_pose_channel(pchan);
|
|
verify_pose_channel(*pose, pchan->name);
|
|
set_pose_channel(*pose, newchan);
|
|
}
|
|
}
|
|
|
|
static void get_constraint_influence_from_pose (bPose *dst, bPose *src)
|
|
{
|
|
bConstraint *dcon, *scon;
|
|
|
|
if (!src || !dst)
|
|
return;
|
|
|
|
for (dcon = dst->chanbase.first; dcon; dcon=dcon->next){
|
|
for (scon=src->chanbase.first; scon; scon=scon->next){
|
|
if (!strcmp(scon->name, dcon->name))
|
|
break;
|
|
}
|
|
if (scon){
|
|
dcon->enforce = scon->enforce;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If the pose does not exist, a new one is created */
|
|
|
|
void
|
|
get_pose_from_action (
|
|
bPose **pose,
|
|
bAction *act,
|
|
float ctime
|
|
) {
|
|
bActionChannel *achan;
|
|
bPoseChannel *pchan;
|
|
Ipo *ipo;
|
|
IpoCurve *curve;
|
|
|
|
|
|
if (!act)
|
|
return;
|
|
if (!pose)
|
|
return;
|
|
|
|
/* If there is no pose, create one */
|
|
if (!*pose){
|
|
*pose=MEM_callocN (sizeof(bPose), "pose");
|
|
}
|
|
|
|
/* Copy the data from the action into the pose */
|
|
for (achan=act->chanbase.first; achan; achan=achan->next){
|
|
act->achan= achan;
|
|
|
|
ipo = achan->ipo;
|
|
if (ipo){
|
|
pchan=MEM_callocN (sizeof(bPoseChannel), "gpfa_poseChannel");
|
|
strcpy (pchan->name, achan->name);
|
|
|
|
act->pchan=pchan;
|
|
/* Evaluates and sets the internal ipo value */
|
|
calc_ipo(ipo, ctime);
|
|
|
|
/* Set the pchan flags */
|
|
for (curve = achan->ipo->curve.first; curve; curve=curve->next){
|
|
/* Skip empty curves */
|
|
if (!curve->totvert)
|
|
continue;
|
|
|
|
switch (curve->adrcode){
|
|
case AC_QUAT_X:
|
|
case AC_QUAT_Y:
|
|
case AC_QUAT_Z:
|
|
case AC_QUAT_W:
|
|
pchan->flag |= POSE_ROT;
|
|
break;
|
|
case AC_LOC_X:
|
|
case AC_LOC_Y:
|
|
case AC_LOC_Z:
|
|
pchan->flag |= POSE_LOC;
|
|
break;
|
|
case AC_SIZE_X:
|
|
case AC_SIZE_Y:
|
|
case AC_SIZE_Z:
|
|
pchan->flag |= POSE_SIZE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
execute_ipo((ID*)act, achan->ipo);
|
|
|
|
set_pose_channel(*pose, pchan);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
do_all_actions(
|
|
){
|
|
Base *base;
|
|
bPose *apose=NULL;
|
|
bPose *tpose=NULL;
|
|
Object *ob;
|
|
bActionStrip *strip;
|
|
int doit;
|
|
float striptime, frametime, length, actlength;
|
|
float blendfac, stripframe;
|
|
|
|
int set;
|
|
|
|
/* NEW: current scene ob ipo's */
|
|
base= G.scene->base.first;
|
|
set= 0;
|
|
|
|
while(base) {
|
|
|
|
ob = base->object;
|
|
|
|
/* Retrieve data from the NLA */
|
|
if(ob->type==OB_ARMATURE){
|
|
|
|
doit=0;
|
|
|
|
/* Clear pose */
|
|
if (apose){
|
|
clear_pose(apose);
|
|
MEM_freeN(apose);
|
|
}
|
|
/* Clear pose */
|
|
if (tpose){
|
|
clear_pose(tpose);
|
|
MEM_freeN(tpose);
|
|
}
|
|
|
|
copy_pose(&apose, ob->pose, 1);
|
|
copy_pose(&tpose, ob->pose, 1);
|
|
rest_pose(apose, 1);
|
|
|
|
if (base->object->nlastrips.first){
|
|
rest_pose(base->object->pose, 0);
|
|
}
|
|
|
|
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
|
|
doit = 0;
|
|
if (strip->act){
|
|
|
|
/* Determine if the current frame is within the strip's range */
|
|
length = strip->end-strip->start;
|
|
actlength = strip->actend-strip->actstart;
|
|
striptime = (G.scene->r.cfra-(strip->start)) / length;
|
|
stripframe = (G.scene->r.cfra-(strip->start)) ;
|
|
|
|
|
|
if (striptime>=0.0){
|
|
|
|
rest_pose(tpose, 1);
|
|
|
|
/* Handle path */
|
|
if (strip->flag & ACTSTRIP_USESTRIDE){
|
|
if (ob->parent && ob->parent->type==OB_CURVE){
|
|
Curve *cu = ob->parent->data;
|
|
float ctime, pdist;
|
|
|
|
if (cu->flag & CU_PATH){
|
|
/* Ensure we have a valid path */
|
|
if(cu->path==0 || cu->path->data==0) calc_curvepath(ob->parent);
|
|
|
|
/* Find the position on the path */
|
|
ctime= bsystem_time(ob, ob->parent, (float)G.scene->r.cfra, 0.0);
|
|
|
|
if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) {
|
|
ctime /= cu->pathlen;
|
|
CLAMP(ctime, 0.0, 1.0);
|
|
}
|
|
pdist = ctime*cu->path->totdist;
|
|
|
|
if (strip->stridelen)
|
|
striptime = pdist / strip->stridelen;
|
|
else
|
|
striptime = 0;
|
|
|
|
striptime = (float)fmod (striptime, 1.0);
|
|
|
|
frametime = (striptime * actlength) + strip->actstart;
|
|
get_pose_from_action (&tpose, strip->act, bsystem_time(ob, 0, frametime, 0.0));
|
|
#ifdef __NLA_BLENDCON
|
|
do_pose_constraint_channels(tpose, strip->act, bsystem_time(ob, 0, frametime, 0.0));
|
|
#endif
|
|
doit=1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Handle repeat */
|
|
|
|
else if (striptime < 1.0){
|
|
/* Mod to repeat */
|
|
striptime*=strip->repeat;
|
|
striptime = (float)fmod (striptime, 1.0);
|
|
|
|
frametime = (striptime * actlength) + strip->actstart;
|
|
get_pose_from_action (&tpose, strip->act, bsystem_time(ob, 0, frametime, 0.0));
|
|
#ifdef __NLA_BLENDCON
|
|
do_pose_constraint_channels(tpose, strip->act, bsystem_time(ob, 0, frametime, 0.0));
|
|
#endif
|
|
doit=1;
|
|
}
|
|
/* Handle extend */
|
|
else{
|
|
if (strip->flag & ACTSTRIP_HOLDLASTFRAME){
|
|
striptime = 1.0;
|
|
frametime = (striptime * actlength) + strip->actstart;
|
|
get_pose_from_action (&tpose, strip->act, bsystem_time(ob, 0, frametime, 0.0));
|
|
#ifdef __NLA_BLENDCON
|
|
do_pose_constraint_channels(tpose, strip->act, bsystem_time(ob, 0, frametime, 0.0));
|
|
#endif
|
|
doit=1;
|
|
}
|
|
}
|
|
|
|
/* Handle blendin & blendout */
|
|
if (doit){
|
|
/* Handle blendin */
|
|
|
|
if (strip->blendin>0.0 && stripframe<=strip->blendin && G.scene->r.cfra>=strip->start){
|
|
blendfac = stripframe/strip->blendin;
|
|
}
|
|
else if (strip->blendout>0.0 && stripframe>=(length-strip->blendout) && G.scene->r.cfra<=strip->end){
|
|
blendfac = (length-stripframe)/(strip->blendout);
|
|
}
|
|
else
|
|
blendfac = 1;
|
|
|
|
/* Blend this pose with the accumulated pose */
|
|
blend_poses (apose, tpose, blendfac, strip->mode);
|
|
#ifdef __NLA_BLENDCON
|
|
blend_constraints(&apose->chanbase, &tpose->chanbase, blendfac, strip->mode);
|
|
#endif
|
|
}
|
|
}
|
|
if (apose){
|
|
get_pose_from_pose(&ob->pose, apose);
|
|
#ifdef __NLA_BLENDCON
|
|
get_constraint_influence_from_pose(ob->pose, apose);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* Do local action (always overrides the nla actions) */
|
|
/* At the moment, only constraint ipos on the local action have any effect */
|
|
if(base->object->action) {
|
|
get_pose_from_action (&ob->pose, ob->action, bsystem_time(ob, 0, (float) G.scene->r.cfra, 0.0));
|
|
do_pose_constraint_channels(ob->pose, ob->action, bsystem_time(ob, 0, (float) G.scene->r.cfra, 0.0));
|
|
doit = 1;
|
|
}
|
|
|
|
if (doit)
|
|
apply_pose_armature(get_armature(ob), ob->pose, 1);
|
|
|
|
}
|
|
base= base->next;
|
|
if(base==0 && set==0 && G.scene->set) {
|
|
set= 1;
|
|
base= G.scene->set->base.first;
|
|
}
|
|
|
|
}
|
|
|
|
if (apose){
|
|
clear_pose(apose);
|
|
MEM_freeN(apose);
|
|
apose = NULL;
|
|
}
|
|
if (tpose){
|
|
clear_pose(tpose);
|
|
MEM_freeN(tpose);
|
|
apose = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
static void do_pose_constraint_channels(bPose *pose, bAction *act, float ctime)
|
|
{
|
|
bPoseChannel *pchan;
|
|
bActionChannel *achan;
|
|
|
|
if (!pose || !act)
|
|
return;
|
|
|
|
for (pchan=pose->chanbase.first; pchan; pchan=pchan->next){
|
|
achan=get_named_actionchannel(act, pchan->name);
|
|
if (achan)
|
|
do_constraint_channels(&pchan->constraints, &achan->constraintChannels, ctime);
|
|
}
|
|
}
|
|
|
|
bActionChannel *
|
|
get_named_actionchannel (
|
|
bAction *act,
|
|
const char *name
|
|
){
|
|
bActionChannel *chan;
|
|
|
|
if (!act)
|
|
return NULL;
|
|
|
|
for (chan = act->chanbase.first; chan; chan=chan->next){
|
|
if (!strcmp (chan->name, name))
|
|
return chan;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
clear_pose (
|
|
bPose *pose
|
|
) {
|
|
bPoseChannel *chan;
|
|
|
|
if (pose->chanbase.first){
|
|
for (chan = pose->chanbase.first; chan; chan=chan->next){
|
|
free_constraints(&chan->constraints);
|
|
}
|
|
BLI_freelistN (&pose->chanbase);
|
|
}
|
|
}
|
|
|
|
void
|
|
make_local_action(
|
|
bAction *act
|
|
){
|
|
Object *ob;
|
|
bAction *actn;
|
|
int local=0, lib=0;
|
|
|
|
if(act->id.lib==0) return;
|
|
if(act->id.us==1) {
|
|
act->id.lib= 0;
|
|
act->id.flag= LIB_LOCAL;
|
|
new_id(0, (ID *)act, 0);
|
|
return;
|
|
}
|
|
|
|
ob= G.main->object.first;
|
|
while(ob) {
|
|
if(ob->action==act) {
|
|
if(ob->id.lib) lib= 1;
|
|
else local= 1;
|
|
}
|
|
ob= ob->id.next;
|
|
}
|
|
|
|
if(local && lib==0) {
|
|
act->id.lib= 0;
|
|
act->id.flag= LIB_LOCAL;
|
|
new_id(0, (ID *)act, 0);
|
|
}
|
|
else if(local && lib) {
|
|
actn= copy_action(act);
|
|
actn->id.us= 0;
|
|
|
|
ob= G.main->object.first;
|
|
while(ob) {
|
|
if(ob->action==act) {
|
|
|
|
if(ob->id.lib==0) {
|
|
ob->action = actn;
|
|
ob->activecon = NULL;
|
|
actn->id.us++;
|
|
act->id.us--;
|
|
}
|
|
}
|
|
ob= ob->id.next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
free_action(
|
|
bAction *act
|
|
){
|
|
bActionChannel *chan;
|
|
|
|
/* Free channels */
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
if (chan->ipo)
|
|
chan->ipo->id.us--;
|
|
free_constraint_channels(&chan->constraintChannels);
|
|
}
|
|
|
|
if (act->chanbase.first)
|
|
BLI_freelistN (&act->chanbase);
|
|
}
|
|
|
|
bAction*
|
|
copy_action (
|
|
const bAction *src
|
|
){
|
|
bAction *dst = NULL;
|
|
bActionChannel *dchan, *schan;
|
|
|
|
if(!src) return NULL;
|
|
|
|
dst= copy_libblock(src);
|
|
duplicatelist(&(dst->chanbase), &(src->chanbase));
|
|
|
|
for (dchan=dst->chanbase.first, schan=src->chanbase.first; dchan; dchan=dchan->next, schan=schan->next){
|
|
dchan->ipo = copy_ipo(dchan->ipo);
|
|
copy_constraint_channels(&dchan->constraintChannels, &schan->constraintChannels);
|
|
}
|
|
dst->id.flag |= LIB_FAKEUSER;
|
|
dst->id.us++;
|
|
return dst;
|
|
}
|
|
|
|
bPoseChannel *
|
|
copy_pose_channel (
|
|
const bPoseChannel* src
|
|
){
|
|
bPoseChannel *dst;
|
|
|
|
if (!src)
|
|
return NULL;
|
|
|
|
dst = MEM_callocN (sizeof(bPoseChannel), "copyPoseChannel");
|
|
memcpy (dst, src, sizeof(bPoseChannel));
|
|
dst->prev=dst->next=NULL;
|
|
|
|
return dst;
|
|
}
|
|
|
|
void
|
|
copy_pose(
|
|
bPose **dst,
|
|
const bPose *src,
|
|
int copycon
|
|
){
|
|
bPose *outPose;
|
|
const bPose * inPose;
|
|
bPoseChannel *newChan;
|
|
const bPoseChannel *curChan;
|
|
|
|
inPose = src;
|
|
|
|
if (!inPose){
|
|
*dst=NULL;
|
|
return;
|
|
}
|
|
|
|
outPose=MEM_callocN(sizeof(bPose), "pose");
|
|
|
|
for (curChan=inPose->chanbase.first; curChan; curChan=curChan->next){
|
|
newChan=MEM_callocN(sizeof(bPoseChannel), "copyposePoseChannel");
|
|
|
|
strcpy (newChan->name, curChan->name);
|
|
newChan->flag=curChan->flag;
|
|
|
|
memcpy (newChan->loc, curChan->loc, sizeof (curChan->loc));
|
|
memcpy (newChan->size, curChan->size, sizeof (curChan->size));
|
|
memcpy (newChan->quat, curChan->quat, sizeof (curChan->quat));
|
|
Mat4CpyMat4 (newChan->obmat, curChan->obmat);
|
|
|
|
BLI_addtail (&outPose->chanbase, newChan);
|
|
if (copycon){
|
|
copy_constraints(&newChan->constraints, &curChan->constraints);
|
|
}
|
|
}
|
|
|
|
*dst=outPose;
|
|
}
|
|
|
|
bPoseChannel *set_pose_channel (bPose *pose, bPoseChannel *chan){
|
|
/* chan is no longer valid for the calling function.
|
|
and should not be used by that function after calling
|
|
this one
|
|
*/
|
|
bPoseChannel *curChan;
|
|
|
|
/* Determine if an equivalent channel exists already */
|
|
for (curChan=pose->chanbase.first; curChan; curChan=curChan->next){
|
|
if (!strcmp (curChan->name, chan->name)){
|
|
if (chan->flag & POSE_ROT)
|
|
memcpy (curChan->quat, chan->quat, sizeof(chan->quat));
|
|
if (chan->flag & POSE_SIZE)
|
|
memcpy (curChan->size, chan->size, sizeof(chan->size));
|
|
if (chan->flag & POSE_LOC)
|
|
memcpy (curChan->loc, chan->loc, sizeof(chan->loc));
|
|
if (chan->flag & PCHAN_DONE)
|
|
Mat4CpyMat4 (curChan->obmat, chan->obmat);
|
|
|
|
curChan->flag |= chan->flag;
|
|
MEM_freeN (chan);
|
|
return curChan;
|
|
}
|
|
}
|
|
|
|
MEM_freeN (chan);
|
|
return NULL;
|
|
/* If an equivalent channel doesn't exist, then don't bother setting it. */
|
|
}
|
|
|
|
|