== PoseLib - Pose-Library Tool for Blender ==
"A slightly late Christmas present for the Animators out there :-)" This tool allows animators to store frequently used poses in an action, and be able to label those poses to help them retrieve them later. In a way, it acts as a glorified clipboard for poses. One of the cool features with this is the ability to select which stored pose to use interactively in the 3d-view. Once a few poses have been stored in the PoseLib, simply use the "Ctrl L" hotkey to start previewing. Use the Mousewheel or the Page Up/Down keys to change poses, and confirm/cancel the preview in the same way as you do for transforms. Usage Notes: * Each Armature may get its own PoseLib. PoseLibs are simply actions with extra data, so they can get relinked. * Manually editing actions used as PoseLibs is not a good idea, as some data may not be able to be found. Tools to automagically find poses in an action could be investigated... * PoseLib will only apply/retrieve poses to/from selected bones * A basic UI for this can be found in the "Links and Materials" panel. Most of the PoseLib tools are presented there. Useful Hotkeys (also found in Pose->PoseLib menu): * Ctrl L - interactively preview poses * Shift L - add a new pose or replace an existing pose in the PoseLib with the current pose * Ctrl Shift L - rename an existing pose in the PoseLib * Alt L - remove a pose from the poselib.c
This commit is contained in:
@@ -163,6 +163,15 @@ void make_local_action(bAction *act)
|
||||
}
|
||||
}
|
||||
|
||||
static void free_act_poselib (bAction *act)
|
||||
{
|
||||
if (act->poselib) {
|
||||
bPoseLib *pl= act->poselib;
|
||||
|
||||
BLI_freelistN(&pl->poses);
|
||||
MEM_freeN(pl);
|
||||
}
|
||||
}
|
||||
|
||||
void free_action (bAction *act)
|
||||
{
|
||||
@@ -177,6 +186,9 @@ void free_action (bAction *act)
|
||||
|
||||
if (act->chanbase.first)
|
||||
BLI_freelistN(&act->chanbase);
|
||||
|
||||
/* Free PoseLib */
|
||||
free_act_poselib(act);
|
||||
}
|
||||
|
||||
bAction *copy_action (bAction *src)
|
||||
|
||||
@@ -230,6 +230,7 @@ void free_object(Object *ob)
|
||||
BLI_freelistN(&ob->defbase);
|
||||
if(ob->pose) {
|
||||
free_pose_channels(ob->pose);
|
||||
if (ob->pose->poselib) ob->pose->poselib->id.us--;
|
||||
MEM_freeN(ob->pose);
|
||||
}
|
||||
free_effects(&ob->effect);
|
||||
|
||||
@@ -1785,6 +1785,9 @@ static void lib_link_pose(FileData *fd, Object *ob, bPose *pose)
|
||||
}
|
||||
}
|
||||
|
||||
// ob->id.lib???
|
||||
pose->poselib = newlibadr_us(fd, ob->id.lib, pose->poselib);
|
||||
|
||||
if(rebuild) {
|
||||
ob->recalc= OB_RECALC;
|
||||
pose->flag |= POSE_RECALC;
|
||||
@@ -1814,12 +1817,12 @@ static void lib_link_action(FileData *fd, Main *main)
|
||||
while(act) {
|
||||
if(act->id.flag & LIB_NEEDLINK) {
|
||||
act->id.flag -= LIB_NEEDLINK;
|
||||
|
||||
|
||||
for (chan=act->chanbase.first; chan; chan=chan->next) {
|
||||
chan->ipo= newlibadr_us(fd, act->id.lib, chan->ipo);
|
||||
lib_link_constraint_channels(fd, &act->id, &chan->constraintChannels);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
act= act->id.next;
|
||||
}
|
||||
@@ -1847,7 +1850,10 @@ static void direct_link_action(FileData *fd, bAction *act)
|
||||
|
||||
for (achan = act->chanbase.first; achan; achan=achan->next)
|
||||
link_list(fd, &achan->constraintChannels);
|
||||
|
||||
|
||||
act->poselib= newdataadr(fd, act->poselib);
|
||||
if (act->poselib)
|
||||
link_list(fd, &act->poselib->poses);
|
||||
}
|
||||
|
||||
static void direct_link_armature(FileData *fd, bArmature *arm)
|
||||
@@ -2942,7 +2948,6 @@ static void direct_link_pose(FileData *fd, bPose *pose) {
|
||||
pchan->iktree.first= pchan->iktree.last= NULL;
|
||||
pchan->path= NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void direct_link_modifiers(FileData *fd, ListBase *lb)
|
||||
@@ -7799,6 +7804,8 @@ static void expand_pose(FileData *fd, Main *mainvar, bPose *pose)
|
||||
expand_constraints(fd, mainvar, &chan->constraints);
|
||||
expand_doit(fd, mainvar, chan->custom);
|
||||
}
|
||||
|
||||
expand_doit(fd, mainvar, pose->poselib);
|
||||
}
|
||||
|
||||
static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm)
|
||||
|
||||
@@ -1743,11 +1743,21 @@ static void write_actions(WriteData *wd, ListBase *idbase)
|
||||
if (act->id.us>0 || wd->current) {
|
||||
writestruct(wd, ID_AC, "bAction", 1, act);
|
||||
if (act->id.properties) IDP_WriteProperty(act->id.properties, wd);
|
||||
|
||||
|
||||
for (chan=act->chanbase.first; chan; chan=chan->next) {
|
||||
writestruct(wd, DATA, "bActionChannel", 1, chan);
|
||||
write_constraint_channels(wd, &chan->constraintChannels);
|
||||
}
|
||||
|
||||
if (act->poselib) {
|
||||
bPoseLib *pl= act->poselib;
|
||||
bPoseLibRef *plr;
|
||||
|
||||
writestruct(wd, DATA, "bPoseLib", 1, pl);
|
||||
|
||||
for (plr= pl->poses.first; plr; plr= plr->next)
|
||||
writestruct(wd, DATA, "bPoseLibRef", 1, plr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
52
source/blender/include/BIF_poselib.h
Normal file
52
source/blender/include/BIF_poselib.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* $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) 2007 Blender Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: this is a new part of Blender
|
||||
*
|
||||
* Contributor(s): Joshua Leung
|
||||
*
|
||||
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef BIF_POSELIB_H
|
||||
#define BIF_POSELIB_H
|
||||
|
||||
struct Object;
|
||||
struct bPoseLib;
|
||||
struct bPoseLibRef;
|
||||
|
||||
char *poselib_build_poses_menu(struct bPoseLib *pl, char title[]);
|
||||
void poselib_unique_pose_name(struct bPoseLib *pl, char name[]);
|
||||
int poselib_get_free_index(struct bPoseLib *pl);
|
||||
|
||||
struct bPoseLib *poselib_init_new(struct Object *ob);
|
||||
|
||||
void poselib_remove_pose(struct Object *ob, struct bPoseLibRef *plr);
|
||||
void poselib_rename_pose(struct Object *ob);
|
||||
void poselib_add_current_pose(struct Object *ob, int mode);
|
||||
|
||||
void poselib_preview_poses(struct Object *ob);
|
||||
|
||||
#endif
|
||||
@@ -501,6 +501,11 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
|
||||
#define B_ARM_CALCPATHS 2303
|
||||
#define B_ARM_CLEARPATHS 2304
|
||||
|
||||
#define B_POSELIB_NEW 2310
|
||||
#define B_POSELIB_ADDPOSE 2311
|
||||
#define B_POSELIB_REPLACEP 2312
|
||||
#define B_POSELIB_REMOVEP 2313
|
||||
|
||||
/* *********************** */
|
||||
#define B_CAMBUTS 2500
|
||||
|
||||
|
||||
@@ -90,12 +90,35 @@ typedef struct bPoseChannel {
|
||||
*/
|
||||
typedef struct bPose {
|
||||
ListBase chanbase; /* list of pose channels */
|
||||
struct bAction *poselib; /* poselib-action for this pose */
|
||||
|
||||
short flag, proxy_layer; /* proxy layer: copy from armature, gets synced */
|
||||
|
||||
float ctime; /* local action time of this pose */
|
||||
float stride_offset[3]; /* applied to object */
|
||||
float cyclic_offset[3]; /* result of match and cycles, applied in where_is_pose() */
|
||||
} bPose;
|
||||
|
||||
|
||||
/* "Pose" reference for PoseLib */
|
||||
typedef struct bPoseLibRef {
|
||||
struct bPoseLibRef *next, *prev;
|
||||
int frame; /* frame in the action to look for this pose */
|
||||
char name[32]; /* name of the pose */
|
||||
int pad;
|
||||
} bPoseLibRef;
|
||||
|
||||
/* PoseLib data for Action
|
||||
* PoseLib data is stored in actions so that poselibs can easily be assigned/removed from
|
||||
* a pose. Currently the only data that is stored for a poselib is a set of references to which
|
||||
* frame a named pose occurs in the action.
|
||||
*/
|
||||
typedef struct bPoseLib {
|
||||
ListBase poses; /* List of poses for an action (arranged in chronological order) */
|
||||
int flag; /* Settings (not used yet) */
|
||||
int active_nr; /* Index of the poselib's active pose (for UI) */
|
||||
} bPoseLib;
|
||||
|
||||
/* Action Channels belong to Actions. They are linked with an IPO block, and can also own
|
||||
* Constraint Channels in certain situations.
|
||||
*/
|
||||
@@ -115,6 +138,7 @@ typedef struct bActionChannel {
|
||||
typedef struct bAction {
|
||||
ID id;
|
||||
ListBase chanbase; /* Action Channels in this Action */
|
||||
bPoseLib *poselib; /* PoseLib data of this Action (only if the action is used as poselib) */
|
||||
} bAction;
|
||||
|
||||
/* Action Editor Space. This is defined here instead of in DNA_space_types.h */
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
#include "BIF_interface.h"
|
||||
#include "BIF_meshtools.h"
|
||||
#include "BIF_mywindow.h"
|
||||
#include "BIF_poselib.h"
|
||||
#include "BIF_poseobject.h"
|
||||
#include "BIF_renderwin.h"
|
||||
#include "BIF_resources.h"
|
||||
@@ -3729,6 +3730,32 @@ void do_armbuts(unsigned short event)
|
||||
if (ob && ob->pose)
|
||||
pose_clear_paths(ob);
|
||||
break;
|
||||
|
||||
case B_POSELIB_NEW:
|
||||
if (ob && ob->pose)
|
||||
poselib_init_new(ob);
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
break;
|
||||
case B_POSELIB_ADDPOSE:
|
||||
if (ob && ob->pose)
|
||||
poselib_add_current_pose(ob, 1);
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
break;
|
||||
case B_POSELIB_REPLACEP:
|
||||
if (ob && ob->pose)
|
||||
poselib_add_current_pose(ob, 2);
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
break;
|
||||
case B_POSELIB_REMOVEP:
|
||||
if (ob && ob->pose) {
|
||||
bAction *act= ob->pose->poselib;
|
||||
bPoseLib *pl= act->poselib;
|
||||
bPoseLibRef *plr= BLI_findlink(&pl->poses, pl->active_nr-1);
|
||||
|
||||
poselib_remove_pose(ob, plr);
|
||||
}
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4937,6 +4964,59 @@ static void editing_panel_links(Object *ob)
|
||||
return;
|
||||
}
|
||||
|
||||
/* poselib for armatures */
|
||||
if (ob->type==OB_ARMATURE) {
|
||||
if ((ob->pose) && (ob->flag & OB_POSEMODE) && (G.obedit != ob)) {
|
||||
bPose *pose= ob->pose;
|
||||
bAction *act= pose->poselib;
|
||||
|
||||
xco= 143;
|
||||
|
||||
uiDefBut(block, LABEL,0,"PoseLib:", xco, 154, 130,20, 0, 0, 0, 0, 0, "");
|
||||
|
||||
/* PoseLib Action */
|
||||
if (act) {
|
||||
if (act->poselib==NULL) {
|
||||
uiBlockSetCol(block, TH_REDALERT);
|
||||
uiDefIDPoinBut(block, test_actionpoin_but, ID_AC, REDRAWBUTSEDIT, "AC:", xco, 130, 140, 20, &pose->poselib, "Action to use as PoseLib - (Warning: this Action doesn't have a PoseLib)");
|
||||
uiBlockSetCol(block, TH_AUTO);
|
||||
}
|
||||
else {
|
||||
uiDefIDPoinBut(block, test_actionpoin_but, ID_AC, REDRAWBUTSEDIT, "AC:", xco, 130, 140, 20, &pose->poselib, "Action to use as PoseLib");
|
||||
}
|
||||
}
|
||||
uiDefBut(block, BUT, B_POSELIB_NEW, "New PoseLib", xco,110,140,20, 0, 0, 0, 0, 0, "Creates a new PoseLib");
|
||||
|
||||
|
||||
/* poselib pose editing controls */
|
||||
if ((act) && (act->poselib)) {
|
||||
bPoseLib *pl= act->poselib;
|
||||
bPoseLibRef *plr= BLI_findlink(&pl->poses, pl->active_nr-1);
|
||||
int plr_count= BLI_countlist(&pl->poses);
|
||||
char *menustr= poselib_build_poses_menu(pl, "PoseLib Poses");
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
/* currently 'active' pose */
|
||||
uiDefButI(block, MENU, REDRAWBUTSEDIT, menustr, xco, 85,18,20, &pl->active_nr, 1, plr_count, 0, 0, "Browses Poses in PoseLib");
|
||||
MEM_freeN(menustr);
|
||||
|
||||
if (pl->active_nr) {
|
||||
but= uiDefBut(block, TEX, REDRAWBUTSEDIT,"", 161,85,140-18-20,20, plr->name, 0, 31, 0, 0, "Displays current PoseLib Pose name. Click to change.");
|
||||
//uiButSetFunc(but, verify_vertexgroup_name_func, defGroup, NULL);
|
||||
//uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob);
|
||||
|
||||
but = uiDefIconBut(block, BUT, B_POSELIB_REMOVEP, VICON_X, 263, 85, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Remove this PoseLib Pose from PoseLib");
|
||||
}
|
||||
|
||||
/* add new poses */
|
||||
uiDefBut(block, BUT, B_POSELIB_ADDPOSE, "Add Pose", xco,65,70,20, 0, 0, 0, 0, 0, "Add current pose to PoseLib");
|
||||
uiDefBut(block, BUT, B_POSELIB_REPLACEP, "Replace Pose", xco+70,65,70,20, 0, 0, 0, 0, 0, "Replace existing PoseLib Pose with current pose");
|
||||
uiBlockEndAlign(block);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* vertex group... partially editmode... */
|
||||
if(ob->type==OB_MESH || ob->type==OB_LATTICE) {
|
||||
bDeformGroup *defGroup;
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
#include "BIF_interface.h"
|
||||
#include "BIF_mainqueue.h"
|
||||
#include "BIF_meshtools.h"
|
||||
#include "BIF_poselib.h"
|
||||
#include "BIF_poseobject.h"
|
||||
#include "BIF_renderwin.h"
|
||||
#include "BIF_resources.h"
|
||||
@@ -4048,6 +4049,49 @@ static uiBlock *view3d_pose_armature_motionpathsmenu(void *arg_unused)
|
||||
return block;
|
||||
}
|
||||
|
||||
static void do_view3d_pose_armature_poselibmenu(void *arg, int event)
|
||||
{
|
||||
Object *ob= OBACT;
|
||||
|
||||
switch(event) {
|
||||
case 1:
|
||||
poselib_preview_poses(ob);
|
||||
break;
|
||||
case 2:
|
||||
poselib_add_current_pose(ob, 0);
|
||||
break;
|
||||
case 3:
|
||||
poselib_rename_pose(ob);
|
||||
break;
|
||||
case 4:
|
||||
poselib_remove_pose(ob, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
|
||||
static uiBlock *view3d_pose_armature_poselibmenu(void *arg_unused)
|
||||
{
|
||||
uiBlock *block;
|
||||
short yco = 20, menuwidth = 120;
|
||||
|
||||
block= uiNewBlock(&curarea->uiblocks, "view3d_pose_armature_poselibmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
|
||||
uiBlockSetButmFunc(block, do_view3d_pose_armature_poselibmenu, NULL);
|
||||
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Apply Pose|Ctrl L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
|
||||
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add/Replace Pose|Shift L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rename Pose|Ctrl Shift L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Remove Pose|Alt L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
|
||||
|
||||
uiBlockSetDirection(block, UI_RIGHT);
|
||||
uiTextBoundsBlock(block, 60);
|
||||
return block;
|
||||
}
|
||||
|
||||
static void do_view3d_pose_armaturemenu(void *arg, int event)
|
||||
{
|
||||
Object *ob;
|
||||
@@ -4126,6 +4170,7 @@ static uiBlock *view3d_pose_armaturemenu(void *arg_unused)
|
||||
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
uiDefIconTextBlockBut(block, view3d_pose_armature_poselibmenu, NULL, ICON_RIGHTARROW_THIN, "PoseLib", 0, yco-=20, 120, 19, "");
|
||||
uiDefIconTextBlockBut(block, view3d_pose_armature_motionpathsmenu, NULL, ICON_RIGHTARROW_THIN, "Motion Paths", 0, yco-=20, 120, 19, "");
|
||||
uiDefIconTextBlockBut(block, view3d_pose_armature_ikmenu, NULL, ICON_RIGHTARROW_THIN, "Inverse Kinematics", 0, yco-=20, 120, 19, "");
|
||||
uiDefIconTextBlockBut(block, view3d_pose_armature_constraintsmenu, NULL, ICON_RIGHTARROW_THIN, "Constraints", 0, yco-=20, 120, 19, "");
|
||||
|
||||
770
source/blender/src/poselib.c
Normal file
770
source/blender/src/poselib.c
Normal file
@@ -0,0 +1,770 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_dynstr.h"
|
||||
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_ipo_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_object_force.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_ipo.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_utildefines.h"
|
||||
|
||||
//#include "BIF_keyframing.h"
|
||||
#include "BSE_editipo.h"
|
||||
|
||||
#include "BIF_poselib.h"
|
||||
#include "BIF_interface.h"
|
||||
#include "BIF_editaction.h"
|
||||
#include "BIF_space.h"
|
||||
#include "BIF_screen.h"
|
||||
#include "BIF_toolbox.h"
|
||||
|
||||
#include "blendef.h"
|
||||
|
||||
#include "PIL_time.h" /* sleep */
|
||||
#include "mydevice.h"
|
||||
|
||||
/* ************************************************************* */
|
||||
/* == POSE-LIBRARY TOOL FOR BLENDER ==
|
||||
*
|
||||
* Overview:
|
||||
* This tool allows animators to store a set of frequently used poses to dump into
|
||||
* the active action to help in "budget" productions to quickly block out new actions.
|
||||
* It acts as a kind of "glorified clipboard for poses", allowing for naming of poses.
|
||||
*
|
||||
* Features:
|
||||
* - PoseLibs are simply normal Actions, but with a poselib
|
||||
* - Each "pose" is simply a set of keyframes that occur on a particular frame
|
||||
* -> a bPoseLibRef struct is used to identify and label poses in the Action
|
||||
* -> all bPoseLibRefs are stored in the order they were added
|
||||
* -> keys for poses should occur on each positively numbered frame (starting from frame 1)
|
||||
* - The Scrollwheel or PageUp/Down buttons when used in a special mode or after pressing/holding
|
||||
* [a modifier] key, cycles through the poses available for the active pose's poselib, allowing the
|
||||
* animator to preview what action best suits that pose
|
||||
*/
|
||||
/* ************************************************************* */
|
||||
|
||||
/* gets list of poses in poselib as a string */
|
||||
char *poselib_build_poses_menu (bPoseLib *pl, char title[])
|
||||
{
|
||||
DynStr *pupds= BLI_dynstr_new();
|
||||
bPoseLibRef *plr;
|
||||
char *str;
|
||||
char buf[64];
|
||||
int i;
|
||||
|
||||
/* add title first */
|
||||
sprintf(buf, "%s%%t|", title);
|
||||
BLI_dynstr_append(pupds, buf);
|
||||
|
||||
/* loop through keyingsets, adding them */
|
||||
for (plr=pl->poses.first, i=1; plr; plr=plr->next, i++) {
|
||||
BLI_dynstr_append(pupds, plr->name);
|
||||
|
||||
sprintf(buf, "%%x%d", i);
|
||||
BLI_dynstr_append(pupds, buf);
|
||||
|
||||
if (plr->next)
|
||||
BLI_dynstr_append(pupds, "|");
|
||||
}
|
||||
|
||||
/* convert to normal MEM_malloc'd string */
|
||||
str= BLI_dynstr_get_cstring(pupds);
|
||||
BLI_dynstr_free(pupds);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* finds an unique name for pose to be added to poselib */
|
||||
void poselib_unique_pose_name (bPoseLib *pl, char name[])
|
||||
{
|
||||
bPoseLibRef *plr;
|
||||
char tempname[32];
|
||||
int number = 1, exists = 0;
|
||||
char *dot;
|
||||
|
||||
/* See if we are given an empty string */
|
||||
if (name[0] == '\0') {
|
||||
/* give it default name first */
|
||||
strcpy(name, "Pose");
|
||||
}
|
||||
|
||||
/* See if we even need to do this */
|
||||
for (plr= pl->poses.first; plr; plr= plr->next) {
|
||||
if (!strcmp(name, plr->name)) {
|
||||
exists = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (exists == 0)
|
||||
return;
|
||||
|
||||
/* Strip off the suffix */
|
||||
dot = strchr(name, '.');
|
||||
if (dot)
|
||||
*dot=0;
|
||||
|
||||
for (number = 1; number <= 999; number++) {
|
||||
sprintf(tempname, "%s.%03d", name, number);
|
||||
|
||||
exists = 0;
|
||||
for (plr= pl->poses.first; plr; plr= plr->next) {
|
||||
if (strcmp(name, tempname)==0) {
|
||||
exists = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists == 0) {
|
||||
BLI_strncpy(name, tempname, 32);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* gets the first available frame in poselib to store a pose on
|
||||
* - frames start from 1, and a pose should occur on every frame... 0 is error!
|
||||
*/
|
||||
int poselib_get_free_index (bPoseLib *pl)
|
||||
{
|
||||
bPoseLibRef *plr;
|
||||
int low=0, high=0;
|
||||
|
||||
/* sanity checks */
|
||||
if (ELEM(NULL, pl, pl->poses.first)) return 1;
|
||||
|
||||
/* loop over poses finding various values (poses are not stored in chronological order) */
|
||||
for (plr= pl->poses.first; plr; plr= plr->next) {
|
||||
/* only increase low if value is 1 greater than low, to find "gaps" where
|
||||
* poses were removed from the poselib
|
||||
*/
|
||||
if (plr->frame == (low + 1))
|
||||
low++;
|
||||
|
||||
/* value replaces high if it is the highest value encountered yet */
|
||||
if (plr->frame > high)
|
||||
high= plr->frame;
|
||||
}
|
||||
|
||||
/* - if low is not equal to high, then low+1 is a gap
|
||||
* - if low is equal to high, then high+1 is the next index (add at end)
|
||||
*/
|
||||
if (low < high)
|
||||
return (low + 1);
|
||||
else
|
||||
return (high + 1);
|
||||
}
|
||||
|
||||
/* ************************************************************* */
|
||||
|
||||
/* Initialise a new poselib */
|
||||
bPoseLib *poselib_init_new (Object *ob)
|
||||
{
|
||||
bPose *pose= (ob) ? ob->pose : NULL;
|
||||
bAction *act;
|
||||
bPoseLib *pl;
|
||||
|
||||
if (ELEM(NULL, ob, pose))
|
||||
return NULL;
|
||||
|
||||
/* init pose's poselib action */
|
||||
if (pose->poselib == NULL)
|
||||
pose->poselib= add_empty_action("PoseLib");
|
||||
act= pose->poselib;
|
||||
|
||||
/* init actions's poselib data */
|
||||
if (act->poselib == NULL)
|
||||
act->poselib= MEM_callocN(sizeof(bPoseLib), "bPoseLib");
|
||||
pl= act->poselib;
|
||||
|
||||
return pl;
|
||||
}
|
||||
|
||||
|
||||
/* This function adds an ipo-curve of the right type where it's needed */
|
||||
static IpoCurve *poselib_verify_icu (Ipo *ipo, int adrcode)
|
||||
{
|
||||
IpoCurve *icu;
|
||||
|
||||
for (icu= ipo->curve.first; icu; icu= icu->next) {
|
||||
if (icu->adrcode==adrcode) break;
|
||||
}
|
||||
if (icu==NULL) {
|
||||
icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
|
||||
|
||||
icu->flag |= IPO_VISIBLE|IPO_AUTO_HORIZ;
|
||||
if (ipo->curve.first==NULL) icu->flag |= IPO_ACTIVE; /* first one added active */
|
||||
|
||||
icu->blocktype= ID_PO;
|
||||
icu->adrcode= adrcode;
|
||||
|
||||
set_icu_vars(icu);
|
||||
|
||||
BLI_addtail(&ipo->curve, icu);
|
||||
}
|
||||
|
||||
return icu;
|
||||
}
|
||||
|
||||
/* This tool adds the current pose to the poselib
|
||||
* Note: Standard insertkey cannot be used for this due to its limitations
|
||||
*/
|
||||
void poselib_add_current_pose (Object *ob, int val)
|
||||
{
|
||||
bArmature *arm= (ob) ? ob->data : NULL;
|
||||
bPose *pose= (ob) ? ob->pose : NULL;
|
||||
bPoseChannel *pchan;
|
||||
bPoseLib *pl;
|
||||
bPoseLibRef *plr;
|
||||
bAction *act;
|
||||
bActionChannel *achan;
|
||||
IpoCurve *icu;
|
||||
int frame;
|
||||
char name[32];
|
||||
|
||||
/* sanity check */
|
||||
if (ELEM3(NULL, ob, arm, pose))
|
||||
return;
|
||||
|
||||
/* mode - add new or replace existing */
|
||||
if (val == 0) {
|
||||
if (pose->poselib && pose->poselib->poselib->poses.first) {
|
||||
val= pupmenu("PoseLib Add Current Pose%t|Add New%x1|Replace Existing%x2");
|
||||
if (val <= 0) return;
|
||||
}
|
||||
else
|
||||
val= 1;
|
||||
}
|
||||
|
||||
if ((pose->poselib) && (val == 2)) {
|
||||
char *menustr;
|
||||
|
||||
/* get poselib */
|
||||
act= pose->poselib;
|
||||
pl= act->poselib;
|
||||
|
||||
/* get the pose to replace */
|
||||
menustr= poselib_build_poses_menu(pl, "Replace PoseLib Pose");
|
||||
val= pupmenu(menustr);
|
||||
if (menustr) MEM_freeN(menustr);
|
||||
|
||||
if (val <= 0) return;
|
||||
plr= BLI_findlink(&pl->poses, val-1);
|
||||
if (plr == NULL) return;
|
||||
|
||||
/* get the frame from the poselib */
|
||||
frame= plr->frame;
|
||||
}
|
||||
else {
|
||||
/* get name of pose */
|
||||
sprintf(name, "Pose");
|
||||
if (sbutton(name, 0, sizeof(name)-1, "Name: ") == 0)
|
||||
return;
|
||||
|
||||
/* get/initialise poselib */
|
||||
pl= poselib_init_new(ob);
|
||||
act= pose->poselib;
|
||||
|
||||
/* validate name and get frame */
|
||||
poselib_unique_pose_name(pl, name);
|
||||
frame= poselib_get_free_index(pl);
|
||||
|
||||
/* add pose to poselib */
|
||||
plr= MEM_callocN(sizeof(bPoseLibRef), "bPoseLibRef");
|
||||
BLI_strncpy(plr->name, name, sizeof(plr->name));
|
||||
plr->frame= frame;
|
||||
BLI_addtail(&pl->poses, plr);
|
||||
}
|
||||
|
||||
/* loop through selected posechannels, keying their pose to the action */
|
||||
for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
|
||||
/* check if available */
|
||||
if ((pchan->bone) && (arm->layer & pchan->bone->layer)) {
|
||||
if (pchan->bone->flag & (BONE_SELECTED|BONE_ACTIVE)) {
|
||||
/* make action-channel if needed */
|
||||
achan= verify_action_channel(act, pchan->name);
|
||||
|
||||
/* make ipo if needed... */
|
||||
if (achan->ipo == NULL)
|
||||
achan->ipo= add_ipo(achan->name, ID_PO);
|
||||
|
||||
/* add missing ipo-curves and insert keys */
|
||||
#define INSERT_KEY_ICU(adrcode, data) {\
|
||||
icu= poselib_verify_icu(achan->ipo, adrcode); \
|
||||
insert_vert_icu(icu, frame, data, 1); \
|
||||
}
|
||||
|
||||
INSERT_KEY_ICU(AC_LOC_X, pchan->loc[0])
|
||||
INSERT_KEY_ICU(AC_LOC_Y, pchan->loc[1])
|
||||
INSERT_KEY_ICU(AC_LOC_Z, pchan->loc[2])
|
||||
INSERT_KEY_ICU(AC_SIZE_X, pchan->size[0])
|
||||
INSERT_KEY_ICU(AC_SIZE_Y, pchan->size[1])
|
||||
INSERT_KEY_ICU(AC_SIZE_Z, pchan->size[2])
|
||||
INSERT_KEY_ICU(AC_QUAT_W, pchan->quat[0])
|
||||
INSERT_KEY_ICU(AC_QUAT_X, pchan->quat[1])
|
||||
INSERT_KEY_ICU(AC_QUAT_Y, pchan->quat[2])
|
||||
INSERT_KEY_ICU(AC_QUAT_Z, pchan->quat[3])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* store new 'active' pose number */
|
||||
pl->active_nr= BLI_countlist(&pl->poses);
|
||||
|
||||
BIF_undo_push("PoseLib Add Pose");
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
}
|
||||
|
||||
|
||||
/* This tool removes the pose that the user selected from the poselib (or the provided pose) */
|
||||
void poselib_remove_pose (Object *ob, bPoseLibRef *plr)
|
||||
{
|
||||
bPose *pose= (ob) ? ob->pose : NULL;
|
||||
bAction *act= (pose) ? pose->poselib : NULL;
|
||||
bActionChannel *achan;
|
||||
bPoseLib *pl= (act) ? act->poselib : NULL;
|
||||
char *menustr;
|
||||
int val;
|
||||
|
||||
/* check if valid poselib */
|
||||
if (ELEM(NULL, ob, pose)) {
|
||||
error("PoseLib is only for Armatures in PoseMode");
|
||||
return;
|
||||
}
|
||||
if (ELEM(NULL, act, pl)) {
|
||||
error("Pose doesn't have a valid PoseLib");
|
||||
return;
|
||||
}
|
||||
|
||||
/* get index (and pointer) of pose to remove */
|
||||
if (plr == NULL) {
|
||||
menustr= poselib_build_poses_menu(pl, "Remove PoseLib Pose");
|
||||
val= pupmenu(menustr);
|
||||
if (menustr) MEM_freeN(menustr);
|
||||
|
||||
if (val <= 0) return;
|
||||
plr= BLI_findlink(&pl->poses, val-1);
|
||||
if (plr == NULL) return;
|
||||
}
|
||||
else {
|
||||
// TODO: we should really check if pose occurs in this poselib
|
||||
}
|
||||
|
||||
/* remove relevant keyframes */
|
||||
for (achan= act->chanbase.first; achan; achan= achan->next) {
|
||||
Ipo *ipo= achan->ipo;
|
||||
IpoCurve *icu;
|
||||
BezTriple *bezt;
|
||||
int i;
|
||||
|
||||
for (icu= ipo->curve.first; icu; icu= icu->next) {
|
||||
for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
|
||||
/* check if remove... */
|
||||
if (IS_EQ(bezt->vec[1][0], plr->frame)) {
|
||||
delete_icu_key(icu, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* remove poselib from list */
|
||||
BLI_freelinkN(&pl->poses, plr);
|
||||
|
||||
/* fix active pose number */
|
||||
pl->active_nr= 0;
|
||||
|
||||
/* undo + redraw */
|
||||
BIF_undo_push("PoseLib Remove Pose");
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
}
|
||||
|
||||
|
||||
/* This tool renames the pose that the user selected from the poselib */
|
||||
void poselib_rename_pose (Object *ob)
|
||||
{
|
||||
bPose *pose= (ob) ? ob->pose : NULL;
|
||||
bAction *act= (pose) ? pose->poselib : NULL;
|
||||
bPoseLib *pl= (act) ? act->poselib : NULL;
|
||||
bPoseLibRef *plr;
|
||||
char *menustr, name[32];
|
||||
int val;
|
||||
|
||||
/* check if valid poselib */
|
||||
if (ELEM(NULL, ob, pose)) {
|
||||
error("PoseLib is only for Armatures in PoseMode");
|
||||
return;
|
||||
}
|
||||
if (ELEM(NULL, act, pl)) {
|
||||
error("Pose doesn't have a valid PoseLib");
|
||||
return;
|
||||
}
|
||||
|
||||
/* get index of pose to remove */
|
||||
menustr= poselib_build_poses_menu(pl, "Rename PoseLib Pose");
|
||||
val= pupmenu(menustr);
|
||||
if (menustr) MEM_freeN(menustr);
|
||||
|
||||
if (val <= 0) return;
|
||||
plr= BLI_findlink(&pl->poses, val-1);
|
||||
if (plr == NULL) return;
|
||||
|
||||
/* get name of pose */
|
||||
sprintf(name, plr->name);
|
||||
if (sbutton(name, 0, sizeof(name)-1, "Name: ") == 0)
|
||||
return;
|
||||
|
||||
/* validate name */
|
||||
poselib_unique_pose_name(pl, name); // hmm what happens with the old pose's name...
|
||||
|
||||
/* copy name */
|
||||
BLI_strncpy(plr->name, name, sizeof(plr->name));
|
||||
|
||||
/* undo and update */
|
||||
BIF_undo_push("PoseLib Rename Pose");
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************* */
|
||||
|
||||
/* simple struct for storing backup info */
|
||||
typedef struct tPoseLib_Backup {
|
||||
struct tPoseLib_Backup *next, *prev;
|
||||
|
||||
float oldloc[3];
|
||||
float oldsize[3];
|
||||
float oldquat[4];
|
||||
|
||||
float *loc, *size, *quat;
|
||||
} tPoseLib_Backup;
|
||||
|
||||
/* Makes a copy of the current pose for restoration purposes - doesn't do constraints currently */
|
||||
static void poselib_backup_posecopy (ListBase *backups, bPose *pose)
|
||||
{
|
||||
bAction *poselib= pose->poselib;
|
||||
bActionChannel *achan;
|
||||
bPoseChannel *pchan;
|
||||
|
||||
/* for each posechannel that has an actionchannel in */
|
||||
for (achan= poselib->chanbase.first; achan; achan= achan->next) {
|
||||
/* try to find posechannel */
|
||||
pchan= get_pose_channel(pose, achan->name);
|
||||
|
||||
/* backup data if available */
|
||||
if (pchan) {
|
||||
tPoseLib_Backup *plb;
|
||||
|
||||
plb= MEM_callocN(sizeof(tPoseLib_Backup), "tPoseLib_Backup");
|
||||
|
||||
VECCOPY(plb->oldloc, pchan->loc);
|
||||
VECCOPY(plb->oldsize, pchan->size);
|
||||
QUATCOPY(plb->oldquat, pchan->quat);
|
||||
|
||||
plb->loc= pchan->loc;
|
||||
plb->size= pchan->size;
|
||||
plb->quat= pchan->quat;
|
||||
|
||||
BLI_addtail(backups, plb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restores original pose - doesn't do constraints currently */
|
||||
static void poselib_backup_restore (ListBase *backups)
|
||||
{
|
||||
tPoseLib_Backup *plb;
|
||||
|
||||
for (plb= backups->first; plb; plb= plb->next) {
|
||||
VECCOPY(plb->loc, plb->oldloc);
|
||||
VECCOPY(plb->size, plb->oldsize);
|
||||
VECCOPY(plb->quat, plb->oldquat);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------- */
|
||||
|
||||
/* Applies the appropriate stored pose from the pose-library to the current pose
|
||||
* - assumes that a valid object, with a poselib has been supplied
|
||||
* - gets the string to print in the header
|
||||
* - this code is based on the code for extract_pose_from_action in blenkernel/action.c
|
||||
*/
|
||||
static void poselib_apply_pose (Object *ob, bPoseLibRef *plr, char headerstr[])
|
||||
{
|
||||
bPose *pose= ob->pose;
|
||||
bPoseChannel *pchan;
|
||||
bAction *act= pose->poselib;
|
||||
bActionChannel *achan;
|
||||
IpoCurve *icu;
|
||||
int frame= plr->frame;
|
||||
|
||||
/* start applying - only those channels which have a key at this point in time! */
|
||||
for (achan= act->chanbase.first; achan; achan= achan->next) {
|
||||
short found= 0;
|
||||
|
||||
/* apply this achan? */
|
||||
if (achan->ipo) {
|
||||
/* find a keyframe at this frame */
|
||||
for (icu= achan->ipo->curve.first; icu; icu= icu->next) {
|
||||
BezTriple *bezt;
|
||||
int i;
|
||||
|
||||
for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
|
||||
if (IN_RANGE(bezt->vec[1][0], (frame-0.5f), (frame+0.5f))) {
|
||||
found= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) break;
|
||||
}
|
||||
|
||||
/* apply pose */
|
||||
if (found) {
|
||||
pchan= get_pose_channel(pose, achan->name);
|
||||
|
||||
if (pchan) {
|
||||
/* Evaluates and sets the internal ipo values */
|
||||
calc_ipo(achan->ipo, frame);
|
||||
/* This call also sets the pchan flags */
|
||||
execute_action_ipo(achan, pchan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* tag achan as having been used or not... */
|
||||
if (found)
|
||||
achan->flag |= ACHAN_SELECTED;
|
||||
else
|
||||
achan->flag &= ~ACHAN_SELECTED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Auto-keys/tags bones affected by the pose used from the poselib */
|
||||
static void poselib_keytag_pose (Object *ob)
|
||||
{
|
||||
bPose *pose= ob->pose;
|
||||
bPoseChannel *pchan;
|
||||
bAction *act= pose->poselib;
|
||||
bActionChannel *achan;
|
||||
|
||||
/* start tagging/keying */
|
||||
for (achan= act->chanbase.first; achan; achan= achan->next) {
|
||||
/* only for selected action channels */
|
||||
if (achan->flag & ACHAN_SELECTED) {
|
||||
pchan= get_pose_channel(ob->pose, achan->name);
|
||||
|
||||
if (pchan) {
|
||||
if (G.flags & G_RECORDKEYS) {
|
||||
ID *id= &ob->id;
|
||||
|
||||
/* Set keys on pose */
|
||||
if (pchan->flag & POSE_ROT) {
|
||||
insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X, 0);
|
||||
insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y, 0);
|
||||
insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z, 0);
|
||||
insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W, 0);
|
||||
}
|
||||
if (pchan->flag & POSE_SIZE) {
|
||||
insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X, 0);
|
||||
insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y, 0);
|
||||
insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z, 0);
|
||||
}
|
||||
if (pchan->flag & POSE_LOC) {
|
||||
insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X, 0);
|
||||
insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y, 0);
|
||||
insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z, 0);
|
||||
}
|
||||
|
||||
/* clear any unkeyed tags */
|
||||
if (pchan->bone)
|
||||
pchan->bone->flag &= ~BONE_UNKEYED;
|
||||
}
|
||||
else {
|
||||
/* add unkeyed tags */
|
||||
if (pchan->bone)
|
||||
pchan->bone->flag |= BONE_UNKEYED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------- */
|
||||
|
||||
/* defines for psoelib_preview_poses --> ret_val values */
|
||||
enum {
|
||||
PL_PREVIEW_RUNNING = 0,
|
||||
PL_PREVIEW_CONFIRM,
|
||||
PL_PREVIEW_CANCEL
|
||||
};
|
||||
|
||||
/* This tool allows users to preview the pose from the pose-lib using the mouse-scrollwheel/pageupdown */
|
||||
void poselib_preview_poses (Object *ob)
|
||||
{
|
||||
ListBase backups = {NULL, NULL};
|
||||
|
||||
bPose *pose= (ob) ? (ob->pose) : NULL;
|
||||
bArmature *arm= (ob) ? (ob->data) : NULL;
|
||||
bAction *act= (pose) ? (pose->poselib) : NULL;
|
||||
bPoseLib *pl= (act) ? (act->poselib) : NULL;
|
||||
bPoseLibRef *plr= (pl->active_nr) ? BLI_findlink(&pl->poses, pl->active_nr-1) : pl->poses.first;
|
||||
|
||||
short ret_val=PL_PREVIEW_RUNNING, val=0, redraw=1, firsttime=1;
|
||||
unsigned short event;
|
||||
char headerstr[200];
|
||||
|
||||
/* check if valid poselib */
|
||||
if (ELEM(NULL, ob, pose)) {
|
||||
error("PoseLib is only for Armatures in PoseMode");
|
||||
return;
|
||||
}
|
||||
if (ELEM(NULL, act, pl)) {
|
||||
error("Pose doesn't have a valid PoseLib");
|
||||
return;
|
||||
}
|
||||
if (plr == NULL) {
|
||||
error("PoseLib has no poses to preview");
|
||||
return;
|
||||
}
|
||||
|
||||
/* make backup of current pose for restoring pose */
|
||||
poselib_backup_posecopy(&backups, pose);
|
||||
|
||||
/* set depsgraph flags */
|
||||
/* make sure the lock is set OK, unlock can be accidentally saved? */
|
||||
pose->flag |= POSE_LOCKED;
|
||||
pose->flag &= ~POSE_DO_UNLOCK;
|
||||
|
||||
|
||||
/* start preview loop */
|
||||
while (ret_val == PL_PREVIEW_RUNNING) {
|
||||
/* preview a pose */
|
||||
if (redraw) {
|
||||
/* don't clear pose if firsttime */
|
||||
if (firsttime == 0)
|
||||
poselib_backup_restore(&backups);
|
||||
else
|
||||
firsttime = 0;
|
||||
|
||||
/* pose should be the right one to draw */
|
||||
poselib_apply_pose(ob, plr, headerstr);
|
||||
|
||||
/* old optimize trick... this enforces to bypass the depgraph
|
||||
* - note: code copied from transform_generics.c -> recalcData()
|
||||
*/
|
||||
if ((arm->flag & ARM_DELAYDEFORM)==0) {
|
||||
Base *base;
|
||||
|
||||
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); /* sets recalc flags */
|
||||
|
||||
/* bah, softbody exception... recalcdata doesnt reset */
|
||||
for (base= FIRSTBASE; base; base= base->next) {
|
||||
if (base->object->recalc & OB_RECALC_DATA)
|
||||
if (modifiers_isSoftbodyEnabled(base->object)) {
|
||||
base->object->softflag |= OB_SB_REDO;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
where_is_pose(ob);
|
||||
|
||||
/* do header print */
|
||||
sprintf(headerstr, "PoseLib Previewing Pose: \"%s\" | Use ScrollWheel or PageUp/Down to change", plr->name);
|
||||
headerprint(headerstr);
|
||||
|
||||
/* redraw... */
|
||||
force_draw(0);
|
||||
redraw= 0;
|
||||
}
|
||||
|
||||
/* essential for idling subloop */
|
||||
if( qtest()==0) PIL_sleep_ms(2);
|
||||
|
||||
/* emptying queue and reading events */
|
||||
while ( qtest() ) {
|
||||
event= extern_qread(&val);
|
||||
|
||||
/* event processing */
|
||||
if (val) {
|
||||
/* exit */
|
||||
if (ELEM(event, ESCKEY, RIGHTMOUSE))
|
||||
ret_val= PL_PREVIEW_CANCEL;
|
||||
else if (ELEM3(event, LEFTMOUSE, RETKEY, SPACEKEY))
|
||||
ret_val= PL_PREVIEW_CONFIRM;
|
||||
|
||||
/* change pose */
|
||||
else if (ELEM(event, PAGEUPKEY, WHEELUPMOUSE)) {
|
||||
/* find previous pose - go back to end of list if no previous (cyclic) */
|
||||
plr= (plr->prev) ? plr->prev : pl->poses.last;
|
||||
redraw= 1;
|
||||
}
|
||||
else if (ELEM(event, PAGEDOWNKEY, WHEELDOWNMOUSE)) {
|
||||
/* find next pose - go back to start of list if no next (cyclic) */
|
||||
plr= (plr->next) ? plr->next : pl->poses.first;
|
||||
redraw= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* clear pose if cancelled */
|
||||
if (ret_val == PL_PREVIEW_CANCEL) {
|
||||
poselib_backup_restore(&backups);
|
||||
where_is_pose(ob);
|
||||
}
|
||||
BLI_freelistN(&backups);
|
||||
|
||||
/* auto-keying if not cancelled */
|
||||
if (ret_val == PL_PREVIEW_CONFIRM)
|
||||
poselib_keytag_pose(ob);
|
||||
|
||||
/* this signal does one recalc on pose, then unlocks, so ESC or edit will work */
|
||||
pose->flag |= POSE_DO_UNLOCK;
|
||||
|
||||
/* Update event for pose and deformation children */
|
||||
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
|
||||
|
||||
/* updates */
|
||||
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;
|
||||
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
|
||||
BIF_undo_push("PoseLib Apply Pose");
|
||||
}
|
||||
@@ -125,6 +125,7 @@
|
||||
#include "BIF_meshtools.h"
|
||||
#include "BIF_mywindow.h"
|
||||
#include "BIF_oops.h"
|
||||
#include "BIF_poselib.h"
|
||||
#include "BIF_poseobject.h"
|
||||
#include "BIF_outliner.h"
|
||||
#include "BIF_resources.h"
|
||||
@@ -2132,7 +2133,16 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
selectconnected_nurb();
|
||||
}
|
||||
else if(ob && (ob->flag & OB_POSEMODE)) {
|
||||
selectconnected_posearmature();
|
||||
if (G.qual == LR_CTRLKEY)
|
||||
poselib_preview_poses(ob);
|
||||
else if (G.qual == LR_SHIFTKEY)
|
||||
poselib_add_current_pose(ob, 0);
|
||||
else if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY))
|
||||
poselib_rename_pose(ob);
|
||||
else if (G.qual == LR_ALTKEY)
|
||||
poselib_remove_pose(ob, NULL);
|
||||
else
|
||||
selectconnected_posearmature();
|
||||
}
|
||||
else {
|
||||
if(FACESEL_PAINT_TEST) {
|
||||
|
||||
Reference in New Issue
Block a user