This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/src/poseobject.c
Johnny Matthews 2da63a1ad7 Added Name flip for
_L
_l
_R
_r

Also added if suffix == 001, do not re-add suffix. So allows the following procedure

 bone named Bone_R is copied, becomes Bone_R.001
Bone_R.001 is Flipped, becomes Bone_L

Currently only works for 001, could be extended later
2005-07-27 18:48:08 +00:00

714 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.
*
* 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.
*
* Contributor(s): Ton Roosendaal, Blender Foundation '05, full recode.
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
* support for animation modes - Reevan McKay
*/
#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_object.h"
#include "BKE_utildefines.h"
#include "BIF_editarmature.h"
#include "BIF_editaction.h"
#include "BIF_editconstraint.h"
#include "BIF_gl.h"
#include "BIF_graphics.h"
#include "BIF_interface.h"
#include "BIF_poseobject.h"
#include "BIF_space.h"
#include "BIF_toolbox.h"
#include "BIF_screen.h"
#include "BDR_editobject.h"
#include "BSE_edit.h"
#include "mydevice.h"
#include "blendef.h"
void enter_posemode(void)
{
Base *base;
Object *ob;
bArmature *arm;
if(G.scene->id.lib) return;
base= BASACT;
if(base==NULL) return;
ob= base->object;
if (ob->id.lib){
error ("Can't pose libdata");
return;
}
switch (ob->type){
case OB_ARMATURE:
arm= get_armature(ob);
if( arm==NULL ) return;
ob->flag |= OB_POSEMODE;
base->flag= ob->flag;
allqueue(REDRAWHEADERS, 0);
allqueue(REDRAWBUTSALL, 0);
allqueue(REDRAWOOPS, 0);
allqueue(REDRAWVIEW3D, 0);
break;
default:
return;
}
if (G.obedit) exit_editmode(1);
G.f &= ~(G_VERTEXPAINT | G_FACESELECT | G_TEXTUREPAINT | G_WEIGHTPAINT);
}
void set_pose_keys (Object *ob)
{
bPoseChannel *chan;
if (ob->pose){
for (chan=ob->pose->chanbase.first; chan; chan=chan->next){
Bone *bone= chan->bone;
if(bone && (bone->flag & BONE_SELECTED)) {
chan->flag |= POSE_KEY;
}
else {
chan->flag &= ~POSE_KEY;
}
}
}
}
void exit_posemode(void)
{
Object *ob= OBACT;
Base *base= BASACT;
if(ob==NULL) return;
ob->flag &= ~OB_POSEMODE;
base->flag= ob->flag;
countall();
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWOOPS, 0);
allqueue(REDRAWHEADERS, 0);
allqueue(REDRAWBUTSALL, 0);
scrarea_queue_headredraw(curarea);
}
void pose_select_constraint_target(void)
{
Object *ob= OBACT;
bPoseChannel *pchan;
bConstraint *con;
/* paranoia checks */
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
for(con= pchan->constraints.first; con; con= con->next) {
char *subtarget;
Object *target= get_constraint_target(con, &subtarget);
if(ob==target) {
if(subtarget) {
bPoseChannel *pchanc= get_pose_channel(ob->pose, subtarget);
pchanc->bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
}
}
}
}
}
allqueue (REDRAWVIEW3D, 0);
allqueue (REDRAWBUTSOBJECT, 0);
allqueue (REDRAWOOPS, 0);
BIF_undo_push("Select constraint target");
}
/* context: active channel */
void pose_special_editmenu(void)
{
Object *ob= OBACT;
short nr;
/* paranoia checks */
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
nr= pupmenu("Specials%t|Select Constraint Target%x1|Flip Left-Right Names");
if(nr==1) {
pose_select_constraint_target();
}
else if(nr==2) {
pose_flip_names();
}
}
/* context: active object, active channel, optional selected channel */
void pose_add_IK(void)
{
Object *ob= OBACT;
bPoseChannel *pchanact, *pchansel;
bConstraint *con;
short nr;
/* paranoia checks */
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
/* find active */
for(pchanact= ob->pose->chanbase.first; pchanact; pchanact= pchanact->next)
if(pchanact->bone->flag & BONE_ACTIVE) break;
if(pchanact==NULL) return;
/* find selected */
for(pchansel= ob->pose->chanbase.first; pchansel; pchansel= pchansel->next) {
if(pchansel!=pchanact)
if(pchansel->bone->flag & BONE_SELECTED) break;
}
for(con= pchanact->constraints.first; con; con= con->next) {
if(con->type==CONSTRAINT_TYPE_KINEMATIC) break;
}
if(con) {
error("Pose Channel already has IK");
return;
}
if(pchansel)
nr= pupmenu("Add IK Constraint%t|To new Empty Object%x1|To selected Bone%x2");
else
nr= pupmenu("Add IK Constraint%t|To new Empty Object%x1");
if(nr<1) return;
/* prevent weird chains... */
if(nr==2) {
bPoseChannel *pchan= pchanact;
while(pchan) {
if(pchan==pchansel) break;
if(pchan->bone->flag & BONE_IK_TOPARENT)
pchan= pchan->parent;
else pchan= NULL;
}
if(pchan) {
error("IK target should not be in the IK chain itself");
return;
}
}
con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC);
BLI_addtail(&pchanact->constraints, con);
pchanact->constflag |= PCHAN_HAS_IK; // for draw, but also for detecting while pose solving
/* add new empty as target */
if(nr==1) {
Base *base= BASACT, *newbase;
Object *obt;
obt= add_object(OB_EMPTY);
/* set layers OK */
newbase= BASACT;
newbase->lay= base->lay;
obt->lay= newbase->lay;
/* transform cent to global coords for loc */
VecMat4MulVecfl(obt->loc, ob->obmat, pchanact->pose_tail);
set_constraint_target(con, obt, NULL);
/* restore, add_object sets active */
BASACT= base;
base->flag |= SELECT;
}
else if(nr==2) {
set_constraint_target(con, ob, pchansel->name);
}
ob->pose->flag |= POSE_RECALC; // sort pose channels
DAG_scene_sort(G.scene); // sort order of objects
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations
allqueue (REDRAWVIEW3D, 0);
allqueue (REDRAWBUTSOBJECT, 0);
allqueue (REDRAWOOPS, 0);
BIF_undo_push("Add IK constraint");
}
/* context: all selected channels */
void pose_clear_IK(void)
{
Object *ob= OBACT;
bPoseChannel *pchan;
bConstraint *con;
bConstraint *next;
/* paranoia checks */
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
if(okee("Remove IK constraint(s)")==0) return;
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
for(con= pchan->constraints.first; con; con= next) {
next= con->next;
if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
BLI_remlink(&pchan->constraints, con);
free_constraint_data(con);
MEM_freeN(con);
}
}
pchan->constflag &= ~PCHAN_HAS_IK;
}
}
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations
allqueue (REDRAWVIEW3D, 0);
allqueue (REDRAWBUTSOBJECT, 0);
allqueue (REDRAWOOPS, 0);
BIF_undo_push("Remove IK constraint(s)");
}
void pose_clear_constraints(void)
{
Object *ob= OBACT;
bPoseChannel *pchan;
/* paranoia checks */
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
if(okee("Remove Constraints")==0) return;
/* find active */
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
free_constraints(&pchan->constraints);
pchan->constflag= 0;
}
}
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations
allqueue (REDRAWVIEW3D, 0);
allqueue (REDRAWBUTSOBJECT, 0);
allqueue (REDRAWOOPS, 0);
BIF_undo_push("Remove Constraint(s)");
}
void pose_copy_menu(void)
{
Object *ob= OBACT;
bPoseChannel *pchan, *pchanact;
short nr;
/* paranoia checks */
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
/* find active */
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
if(pchan->bone->flag & BONE_ACTIVE) break;
}
if(pchan==NULL) return;
pchanact= pchan;
nr= pupmenu("Copy Pose Attributes %t|Location%x1|Rotation%x2|Size%x3|Constraints");
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
if(pchan->bone->flag & BONE_SELECTED) {
if(pchan!=pchanact) {
if(nr==1) {
VECCOPY(pchan->loc, pchanact->loc);
}
else if(nr==2) {
QUATCOPY(pchan->quat, pchanact->quat);
}
else if(nr==3) {
VECCOPY(pchan->size, pchanact->size);
}
else if(nr==4) {
free_constraints(&pchan->constraints);
copy_constraints(&pchan->constraints, &pchanact->constraints);
pchan->constflag = pchanact->constflag;
}
}
}
}
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations
allqueue (REDRAWVIEW3D, 0);
allqueue (REDRAWBUTSOBJECT, 0);
allqueue (REDRAWOOPS, 0);
BIF_undo_push("Copy Pose Attributes");
}
/* ******************** copy/paste pose ********************** */
static bPose *g_posebuf=NULL;
void free_posebuf(void)
{
if (g_posebuf) {
// was copied without constraints
BLI_freelistN (&g_posebuf->chanbase);
MEM_freeN (g_posebuf);
}
g_posebuf=NULL;
}
void copy_posebuf (void)
{
Object *ob= OBACT;
if (!ob || !ob->pose){
error ("No Pose");
return;
}
free_posebuf();
set_pose_keys(ob); // sets chan->flag to POSE_KEY if bone selected
copy_pose(&g_posebuf, ob->pose, 0);
}
static void flip_name (char *name)
{
char prefix[128]={""}; /* The part before the facing */
char suffix[128]={""}; /* The part after the facing */
char replace[128]={""}; /* The replacement string */
char *index=NULL;
/* Find the last period */
strcpy (prefix, name);
/* Check for an instance of .Right */
if (!index){
index = strstr (prefix, "Right");
if (index){
*index=0;
strcpy (replace, "Left");
strcpy (suffix, index+6);
}
}
/* Che ck for an instance of .RIGHT */
if (!index){
index = strstr (prefix, "RIGHT");
if (index){
*index=0;
strcpy (replace, "LEFT");
strcpy (suffix, index+6);
}
}
/* Check for an instance of .right */
if (!index){
index = strstr (prefix, "right");
if (index){
*index=0;
strcpy (replace, "left");
strcpy (suffix, index+6);
}
}
/* Check for an instance of .left */
if (!index){
index = strstr (prefix, "left");
if (index){
*index=0;
strcpy (replace, "right");
strcpy (suffix, index+5);
}
}
/* Check for an instance of .LEFT */
if (!index){
index = strstr (prefix, "LEFT");
if (index){
*index=0;
strcpy (replace, "RIGHT");
strcpy (suffix, index+5);
}
}
/* Check for an instance of .Left */
if (!index){
index = strstr (prefix, "Left");
if (index){
*index=0;
strcpy (replace, "Right");
strcpy (suffix, index+5);
}
}
/* check for an instance of .L */
if (!index){
index = strstr (prefix, ".L");
if (index){
*index=0;
strcpy (replace, ".R");
strcpy (suffix, index+2);
}
}
/* check for an instance of .l */
if (!index){
index = strstr (prefix, ".l");
if (index){
*index=0;
strcpy (replace, ".r");
strcpy (suffix, index+2);
}
}
/* check for an instance of _l */
if (!index){
index = strstr (prefix, "_l");
if (index){
*index=0;
strcpy (replace, "_r");
strcpy (suffix, index+2);
}
}
/* check for an instance of _L */
if (!index){
index = strstr (prefix, "_L");
if (index){
*index=0;
strcpy (replace, "_R");
strcpy (suffix, index+2);
}
}
/* Checl for an instance of .R */
if (!index){
index = strstr (prefix, ".R");
if (index){
*index=0;
strcpy (replace, ".L");
strcpy (suffix, index+2);
}
}
/* Checl for an instance of .r */
if (!index){
index = strstr (prefix, ".r");
if (index){
*index=0;
strcpy (replace, ".l");
strcpy (suffix, index+2);
}
}
/* Checl for an instance of _r */
if (!index){
index = strstr (prefix, "_r");
if (index){
*index=0;
strcpy (replace, "_l");
strcpy (suffix, index+2);
}
}
/* Check for an instance of _R */
if (!index){
index = strstr (prefix, "_R");
if (index){
*index=0;
strcpy (replace, "_L");
strcpy (suffix, index+2);
}
}
if(strstr (suffix, "001")){
sprintf (name, "%s%s", prefix, replace);
} else {
sprintf (name, "%s%s%s", prefix, replace, suffix);
}
}
void paste_posebuf (int flip)
{
Object *ob= OBACT;
bPoseChannel *chan, *pchan;
float eul[4];
int newchan = 0;
char name[32];
if (!ob || !ob->pose)
return;
if (!g_posebuf){
error ("Copy buffer is empty");
return;
}
/* Safely merge all of the channels in this pose into
any existing pose */
for (chan=g_posebuf->chanbase.first; chan; chan=chan->next){
if (chan->flag & POSE_KEY) {
BLI_strncpy(name, chan->name, sizeof(name));
if (flip)
flip_name (name);
/* only copy when channel exists, poses are not meant to add random channels to anymore */
pchan= get_pose_channel(ob->pose, name);
if(pchan) {
/* only loc rot size */
/* only copies transform info for the pose */
VECCOPY(pchan->loc, chan->loc);
VECCOPY(pchan->size, chan->size);
QUATCOPY(pchan->quat, chan->quat);
pchan->flag= chan->flag;
if (flip){
pchan->loc[0]*= -1;
QuatToEul(pchan->quat, eul);
eul[1]*= -1;
eul[2]*= -1;
EulToQuat(eul, pchan->quat);
}
if (G.flags & G_RECORDKEYS){
/* Set keys on pose */
if (chan->flag & POSE_ROT){
set_action_key(ob->action, pchan, AC_QUAT_X, newchan);
set_action_key(ob->action, pchan, AC_QUAT_Y, newchan);
set_action_key(ob->action, pchan, AC_QUAT_Z, newchan);
set_action_key(ob->action, pchan, AC_QUAT_W, newchan);
}
if (chan->flag & POSE_SIZE){
set_action_key(ob->action, pchan, AC_SIZE_X, newchan);
set_action_key(ob->action, pchan, AC_SIZE_Y, newchan);
set_action_key(ob->action, pchan, AC_SIZE_Z, newchan);
}
if (chan->flag & POSE_LOC){
set_action_key(ob->action, pchan, AC_LOC_X, newchan);
set_action_key(ob->action, pchan, AC_LOC_Y, newchan);
set_action_key(ob->action, pchan, AC_LOC_Z, newchan);
}
}
}
}
}
/* Update event for pose and deformation children */
ob->pose->ctime= -123456.0f;
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
if (G.flags & G_RECORDKEYS) {
remake_action_ipos(ob->action);
allqueue (REDRAWIPO, 0);
allqueue (REDRAWVIEW3D, 0);
allqueue (REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
}
else {
/* need to trick depgraph, action is not allowed to execute on pose */
where_is_pose(ob);
ob->recalc= 0;
}
BIF_undo_push("Paste Action Pose");
}
/* ********************************************** */
/* context active object */
void pose_flip_names(void)
{
Object *ob= OBACT;
bPoseChannel *pchan;
char newname[32];
/* paranoia checks */
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
BLI_strncpy(newname, pchan->name, sizeof(newname));
flip_name(newname);
armature_bone_rename(ob->data, pchan->name, newname);
}
}
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWBUTSOBJECT, 0);
allqueue (REDRAWACTION, 0);
allqueue(REDRAWOOPS, 0);
BIF_undo_push("Flip names");
}