== PoseLib - Overhauled Implementation ==

Based on feedback from Ton, I've recoded the way "PoseLibs" are implemented/exposed. Therefore, quite a bit of code has been changed to fit this in better.

Now, ANY ACTION can be a "PoseLib". A set of Markers which belong to the Action (it's taken a year, but they're finally back), are used to tag "poses" in the Action. These markers are shown using diamond-shaped blue icons (designed by Matt Ebb) in three shades - unselected/normal, selected, active. 

Notes:
* Each Armature Object has an Action which acts as a PoseLib.
* Improved UI presented in buttons panel for this
-- added proper buttons for action assigning
-- renamed "Validate PoseLib" to "Auto-Sync PoseLib" (this option auto-tags poses based on keyframes found) 

Like in the 3d-view, use the hotkeys:
* Shift-L to add a local marker 
* Ctrl-Shift-L to rename a local marker
* Alt-L to delete selected local markers

Note: transforms, etc. are not currently available with these markers 

== PoseLib Preview ==
Added a few features here:
* Left/Right-Arrow keys now change the poses too (previous and next respectively)
* Up/Down-Arrow keys also change the poses, but "jump" to a pose 5 steps away in their respective directions
This commit is contained in:
Joshua Leung 2007-12-30 12:08:28 +00:00
parent 96935a6c5d
commit 5be2e5aa98
29 changed files with 2693 additions and 2400 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -163,15 +163,6 @@ 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)
{
@ -187,8 +178,9 @@ void free_action (bAction *act)
if (act->chanbase.first)
BLI_freelistN(&act->chanbase);
/* Free PoseLib */
free_act_poselib(act);
/* Free pose-references */
if (act->markers.first)
BLI_freelistN(&act->markers);
}
bAction *copy_action (bAction *src)
@ -200,6 +192,7 @@ bAction *copy_action (bAction *src)
dst= copy_libblock(src);
duplicatelist(&(dst->chanbase), &(src->chanbase));
duplicatelist(&(dst->markers), &(src->markers));
for (dchan=dst->chanbase.first, schan=src->chanbase.first; dchan; dchan=dchan->next, schan=schan->next){
dchan->ipo = copy_ipo(dchan->ipo);

View File

@ -225,12 +225,12 @@ void free_object(Object *ob)
ob->path= 0;
if(ob->ipo) ob->ipo->id.us--;
if(ob->action) ob->action->id.us--;
if(ob->poselib) ob->poselib->id.us--;
if(ob->dup_group) ob->dup_group->id.us--;
if(ob->defbase.first)
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);

View File

@ -1802,9 +1802,6 @@ 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;
@ -1864,13 +1861,10 @@ static void direct_link_action(FileData *fd, bAction *act)
bActionChannel *achan;
link_list(fd, &act->chanbase);
link_list(fd, &act->markers);
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)
@ -2790,6 +2784,7 @@ static void lib_link_object(FileData *fd, Main *main)
ob->track= newlibadr(fd, ob->id.lib, ob->track);
ob->ipo= newlibadr_us(fd, ob->id.lib, ob->ipo);
ob->action = newlibadr_us(fd, ob->id.lib, ob->action);
ob->poselib= newlibadr_us(fd, ob->id.lib, ob->poselib);
ob->dup_group= newlibadr_us(fd, ob->id.lib, ob->dup_group);
ob->proxy= newlibadr_us(fd, ob->id.lib, ob->proxy);
@ -7821,8 +7816,6 @@ 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)
@ -7900,6 +7893,7 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
expand_doit(fd, mainvar, ob->data);
expand_doit(fd, mainvar, ob->ipo);
expand_doit(fd, mainvar, ob->action);
expand_doit(fd, mainvar, ob->poselib);
for (md=ob->modifiers.first; md; md=md->next) {
expand_modifier(fd, mainvar, md);

View File

@ -1738,6 +1738,7 @@ static void write_actions(WriteData *wd, ListBase *idbase)
{
bAction *act;
bActionChannel *chan;
TimeMarker *marker;
for(act=idbase->first; act; act= act->id.next) {
if (act->id.us>0 || wd->current) {
@ -1749,14 +1750,8 @@ static void write_actions(WriteData *wd, ListBase *idbase)
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);
for (marker=act->markers.first; marker; marker=marker->next) {
writestruct(wd, DATA, "TimeMarker", 1, marker);
}
}
}

View File

@ -100,6 +100,7 @@ struct Ipo;
struct BWinEvent;
struct Key;
struct ListBase;
struct TimeMarker;
/* Key operations */
void transform_action_keys(int mode, int dummy);
@ -122,7 +123,7 @@ void free_actcopybuf(void);
void copy_actdata(void);
void paste_actdata(void);
/* channel/strip operations */
/* Channel/strip operations */
void up_sel_action(void);
void down_sel_action(void);
void top_sel_action(void);
@ -141,6 +142,12 @@ int select_channel(struct bAction *act, struct bActionChannel *achan, int select
void select_actionchannel_by_name(struct bAction *act, char *name, int select);
void selectkeys_leftright (short leftright, short select_mode);
/* Action Markers */
void action_set_activemarker(struct bAction *act, struct TimeMarker *active, short deselect);
void action_add_localmarker(struct bAction *act, int frame);
void action_rename_localmarker(struct bAction *act);
void action_remove_localmarkers(struct bAction *act);
/* ShapeKey stuff */
struct Key *get_action_mesh_key(void);
int get_nearest_key_num(struct Key *key, short *mval, float *x);

View File

@ -35,19 +35,18 @@
struct Object;
struct bAction;
struct bPoseLib;
struct bPoseLibRef;
struct TimeMarker;
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);
char *poselib_build_poses_menu(struct bAction *act, char title[]);
int poselib_get_free_index(struct bAction *act);
struct TimeMarker *poselib_get_active_pose(struct bAction *act);
struct bPoseLib *poselib_init_new(struct Object *ob);
struct bPoseLib *poselib_validate(struct Object *ob);
struct bAction *poselib_init_new(struct Object *ob);
struct bAction *poselib_validate(struct Object *ob);
void poselib_validate_act(struct bAction *act);
void poselib_remove_pose(struct Object *ob, struct bPoseLibRef *plr);
void poselib_remove_pose(struct Object *ob, struct TimeMarker *marker);
void poselib_rename_pose(struct Object *ob);
void poselib_add_current_pose(struct Object *ob, int mode);

View File

@ -73,9 +73,9 @@ typedef enum {
ICON_SMOOTH,
ICON_POTATO,
ICON_MARKER_HLT,
ICON_NORMALVIEW,
ICON_LOCALVIEW,
ICON_UNUSEDVIEW,
ICON_PMARKER_ACT,
ICON_PMARKER_SEL,
ICON_PMARKER,
ICON_VIEWZOOM,
ICON_SORTALPHA,
ICON_SORTTIME,

View File

@ -35,8 +35,14 @@
struct ListBase;
struct View2D;
struct TimeMarker;
/* ******** Markers - General Api ********* */
/* ****** Marker Macros - General API ****** */
/* macro for getting the scene's set of markers */
#define SCE_MARKERS (&(G.scene->markers))
/* ******** Markers - General API ********* */
void add_marker(int frame);
void duplicate_marker(void);
void remove_marker(void);
@ -45,17 +51,25 @@ void transform_markers(int mode, int smode);
void borderselect_markers(void);
void deselect_markers(short test, short sel);
struct TimeMarker *find_nearest_marker(int clip_y);
struct TimeMarker *find_nearest_marker(struct ListBase *markers, int clip_y);
void nextprev_marker(short dir);
void get_minmax_markers(short sel, float *first, float *last);
int find_nearest_marker_time(float dx);
struct TimeMarker *get_frame_marker(int frame);
void add_marker_to_cfra_elem(struct ListBase *lb, struct TimeMarker *marker, short only_sel);
void make_marker_cfra_list(struct ListBase *lb, short only_sel);
void draw_markers_timespace(int lines);
TimeMarker *get_frame_marker(int frame);
/* ********* Markers - Drawing API ********* */
/* flags for drawing markers */
enum {
DRAW_MARKERS_LINES = (1<<0),
DRAW_MARKERS_LOCAL = (1<<1)
};
void draw_markers_timespace(struct ListBase *markers, int flag);
/* ******** Animation - Preview Range ************* */
void anim_previewrange_set(void);

View File

@ -511,13 +511,16 @@ 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_VALIDATE 2311
#define B_POSELIB_ADDPOSE 2312
#define B_POSELIB_REPLACEP 2313
#define B_POSELIB_REMOVEP 2314
#define B_POSELIB_APPLYP 2315
#define B_POSELIB_VALIDATE 2310
#define B_POSELIB_ADDPOSE 2311
#define B_POSELIB_REPLACEP 2312
#define B_POSELIB_REMOVEP 2313
#define B_POSELIB_APPLYP 2314
/* these shouldn't be here... */
#define B_POSELIB_BROWSE 2320
#define B_POSELIB_ALONE 2321
#define B_POSELIB_DELETE 2322
/* *********************** */
#define B_CAMBUTS 2500

View File

@ -99,26 +99,6 @@ typedef struct bPose {
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 flag; /* temporary settings for this pose */
} 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.
*/
@ -137,8 +117,12 @@ 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) */
ListBase markers; /* TimeMarkers local to this Action for labelling 'poses' */
int active_marker; /* Index of active-marker (first marker = 1) */
int pad;
} bAction;
/* Action Editor Space. This is defined here instead of in DNA_space_types.h */

View File

@ -84,6 +84,7 @@ typedef struct Object {
struct Path *path;
struct BoundBox *bb;
struct bAction *action;
struct bAction *poselib;
struct bPose *pose;
void *data;

File diff suppressed because it is too large Load Diff

View File

@ -103,6 +103,7 @@
#include "BSE_filesel.h"
#include "BIF_gl.h"
#include "BIF_editaction.h"
#include "BIF_editarmature.h"
#include "BIF_editconstraint.h"
#include "BIF_editdeform.h"
@ -3694,6 +3695,7 @@ static void editing_panel_lattice_type(Object *ob, Lattice *lt)
void do_armbuts(unsigned short event)
{
Object *ob= OBACT;
bAction *act;
switch(event) {
case B_ARM_RECALCDATA:
@ -3731,45 +3733,125 @@ 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);
allqueue(REDRAWACTION, 0);
break;
case B_POSELIB_REPLACEP:
if (ob && ob->pose)
poselib_add_current_pose(ob, 2);
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWACTION, 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);
bAction *act= ob->poselib;
TimeMarker *marker= poselib_get_active_pose(act);
poselib_remove_pose(ob, plr);
poselib_remove_pose(ob, marker);
}
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWACTION, 0);
break;
case B_POSELIB_VALIDATE:
if (ob && ob->pose) {
bAction *act= ob->pose->poselib;
poselib_validate_act(act);
}
if (ob && ob->pose)
poselib_validate_act(ob->poselib);
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWACTION, 0);
break;
case B_POSELIB_APPLYP:
if (ob && ob->pose)
poselib_preview_poses(ob, 1);
allqueue(REDRAWBUTSEDIT, 0);
break;
/* note: copied from headerbuttons.c */
case B_POSELIB_ALONE: //B_ACTALONE
if (ob && ob->id.lib==0) {
act= ob->poselib;
if (act->id.us > 1) {
if (okee("Single user")) {
ob->poselib= copy_action(act);
act->id.us--;
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWACTION, 0);
}
}
}
break;
case B_POSELIB_DELETE: //B_ACTIONDELETE
act= ob->poselib;
if (act)
act->id.us--;
ob->poselib=NULL;
BIF_undo_push("Unlink PoseLib");
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWACTION, 0);
break;
case B_POSELIB_BROWSE: //B_ACTIONBROWSE:
{
ID *id, *idtest;
int nr= 1;
if (ob == NULL)
break;
act= ob->poselib;
id= (ID *)act;
if (G.buts->menunr == -2) {
activate_databrowse((ID *)ob->poselib, ID_AC, 0, B_POSELIB_BROWSE, &G.buts->menunr, do_armbuts);
return;
}
if (G.buts->menunr < 0) break;
/* See if we have selected a valid action */
for (idtest= G.main->action.first; idtest; idtest= idtest->next) {
if (nr == G.buts->menunr) {
break;
}
nr++;
}
/* Store current action */
if (!idtest) {
/* 'Add New' option:
* - make a copy of an exisiting action
* - or make a new empty action if no existing action
*/
if (act) {
idtest= (ID *)copy_action(act);
}
else {
/* a plain action */
idtest=(ID *)add_empty_action("PoseLib");
}
idtest->us--;
}
if ((idtest != id) && (ob)) {
act= (bAction *)idtest;
ob->poselib= act;
id_us_plus(idtest);
if (id) id->us--;
/* Update everything */
BIF_undo_push("Browse PoseLibs");
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWHEADERS, 0);
}
}
break;
}
}
@ -4982,50 +5064,38 @@ static void editing_panel_links(Object *ob)
/* 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;
bAction *act= ob->poselib;
xco= 143;
uiDefBut(block, LABEL,0,"PoseLib:", xco, 154, 130,20, 0, 0, 0, 0, 0, "");
uiDefBut(block, LABEL,0, "Action (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,70,20, 0, 0, 0, 0, 0, "Creates a new PoseLib");
uiDefBut(block, BUT, B_POSELIB_VALIDATE, "Validate PoseLib", xco+70,110,70,20, 0, 0, 0, 0, 0, "Validates active PoseLib");
uiBlockSetCol(block, TH_BUT_SETTING2);
std_libbuttons(block, 143, 130, 0, NULL, B_POSELIB_BROWSE, ID_AC, 0, (ID *)act, (ID *)ob, &(G.buts->menunr), B_POSELIB_ALONE, 0, B_POSELIB_DELETE, 0, 0);
uiBlockSetCol(block, TH_AUTO);
uiDefBut(block, BUT, B_POSELIB_VALIDATE, "Auto-Sync PoseLib", xco,110,160,20, 0, 0, 0, 0, 0, "Syncs the current PoseLib with the poses available");
/* 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");
if ((act) && (act->markers.first)) {
TimeMarker *marker= poselib_get_active_pose(act);
int count= BLI_countlist(&act->markers);
char *menustr= poselib_build_poses_menu(act, "PoseLib Poses");
uiBlockBeginAlign(block);
/* currently 'active' pose */
uiDefButI(block, MENU, B_POSELIB_APPLYP, menustr, xco, 85,18,20, &pl->active_nr, 1, plr_count, 0, 0, "Browses Poses in PoseLib. Applies chosen pose.");
uiDefButI(block, MENU, B_POSELIB_APPLYP, menustr, xco, 85,18,20, &act->active_marker, 1, count, 0, 0, "Browses Poses in PoseLib. Applies chosen pose.");
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");
if (act->active_marker) {
uiDefBut(block, TEX, REDRAWBUTSEDIT,"", xco+18,85,160-18-20,20, marker->name, 0, 63, 0, 0, "Displays current PoseLib Pose name. Click to change.");
uiDefIconBut(block, BUT, B_POSELIB_REMOVEP, VICON_X, xco+160-20, 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");
uiDefBut(block, BUT, B_POSELIB_ADDPOSE, "Add Pose", xco,65,80,20, 0, 0, 0, 0, 0, "Add current pose to PoseLib");
uiDefBut(block, BUT, B_POSELIB_REPLACEP, "Replace Pose", xco+80,65,80,20, 0, 0, 0, 0, 0, "Replace existing PoseLib Pose with current pose");
uiBlockEndAlign(block);
}
}

View File

@ -883,7 +883,7 @@ void drawactionspace(ScrArea *sa, void *spacedata)
glClearColor(col[0], col[1], col[2], 0.0);
glClear(GL_COLOR_BUFFER_BIT);
if(curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
if (curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
if(G.v2d->scroll) {
ofsx= curarea->winrct.xmin;
ofsy= curarea->winrct.ymin;
@ -927,8 +927,10 @@ void drawactionspace(ScrArea *sa, void *spacedata)
/* Draw current frame */
draw_cfra_action();
/* Draw markers */
draw_markers_timespace(0);
/* Draw markers (local behind scene ones, as local obscure scene markers) */
if (act)
draw_markers_timespace(&act->markers, DRAW_MARKERS_LOCAL);
draw_markers_timespace(SCE_MARKERS, 0);
/* Draw 'curtains' for preview */
draw_anim_preview_timespace();

View File

@ -2247,7 +2247,7 @@ void drawipospace(ScrArea *sa, void *spacedata)
draw_anim_preview_timespace();
/* draw markers */
draw_markers_timespace(0);
draw_markers_timespace(SCE_MARKERS, 0);
/* restore viewport */
mywinset(sa->win);

View File

@ -792,7 +792,7 @@ void drawnlaspace(ScrArea *sa, void *spacedata)
draw_cfra_action();
/* draw markers */
draw_markers_timespace(0);
draw_markers_timespace(SCE_MARKERS, 0);
/* Draw preview 'curtains' */
draw_anim_preview_timespace();

View File

@ -1064,7 +1064,7 @@ void drawseqspace(ScrArea *sa, void *spacedata)
}
/* Draw markers */
draw_markers_timespace(1);
draw_markers_timespace(SCE_MARKERS, DRAW_MARKERS_LINES);
/* restore viewport */
mywinset(sa->win);

View File

@ -220,7 +220,7 @@ void drawsoundspace(ScrArea *sa, void *spacedata)
}
draw_cfra_sound(spacedata);
draw_markers_timespace(0);
draw_markers_timespace(SCE_MARKERS, 0);
/* restore viewport */
mywinset(curarea->win);

View File

@ -64,6 +64,7 @@
#include "BIF_language.h"
#include "BSE_drawipo.h"
#include "BSE_time.h"
#include "BSE_view.h"
#include "blendef.h"
@ -84,7 +85,7 @@
/* ---- prototypes ------ */
void drawtimespace(ScrArea *, void *);
/* draws a current frame indicator for the TimeLine */
static void draw_cfra_time(SpaceTime *stime)
{
float vec[2];
@ -144,9 +145,13 @@ static void draw_cfra_time(SpaceTime *stime)
}
static void draw_marker(TimeMarker *marker, int lines)
/* ---------- */
/* function to draw markers */
static void draw_marker(TimeMarker *marker, int flag)
{
float xpos, ypixels, xscale, yscale;
int icon_id= 0;
xpos = marker->frame;
/* no time correction for framelen! space is drawn with old values */
@ -161,7 +166,7 @@ static void draw_marker(TimeMarker *marker, int lines)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* verticle line */
if (lines) {
if (flag & DRAW_MARKERS_LINES) {
setlinestyle(3);
if(marker->flag & SELECT)
glColor4ub(255,255,255, 96);
@ -176,14 +181,20 @@ static void draw_marker(TimeMarker *marker, int lines)
}
/* 5 px to offset icon to align properly, space / pixels corrects for zoom */
if(marker->flag & SELECT)
BIF_icon_draw(xpos*xscale-5.0, 12.0, ICON_MARKER_HLT);
else
BIF_icon_draw(xpos*xscale-5.0, 12.0, ICON_MARKER);
if (flag & DRAW_MARKERS_LOCAL) {
icon_id= (marker->flag & ACTIVE) ? ICON_PMARKER_ACT :
(marker->flag & SELECT) ? ICON_PMARKER_SEL :
ICON_PMARKER;
}
else {
icon_id= (marker->flag & SELECT) ? ICON_MARKER_HLT :
ICON_MARKER;
}
BIF_icon_draw(xpos*xscale-5.0, 12.0, icon_id);
glBlendFunc(GL_ONE, GL_ZERO);
glDisable(GL_BLEND);
/* and the marker name too, shifted slightly to the top-right */
if(marker->name && marker->name[0]) {
if(marker->flag & SELECT) {
@ -202,24 +213,27 @@ static void draw_marker(TimeMarker *marker, int lines)
glScalef(xscale, yscale, 1.0);
}
static void draw_markers_time(int lines)
/* Draw Scene-Markers for the TimeLine */
static void draw_markers_time(int flag)
{
TimeMarker *marker;
/* unselected markers are drawn at the first time */
for(marker= G.scene->markers.first; marker; marker= marker->next) {
if(!(marker->flag & SELECT)) draw_marker(marker, lines);
for (marker= G.scene->markers.first; marker; marker= marker->next) {
if (!(marker->flag & SELECT)) draw_marker(marker, flag);
}
/* selected markers are drawn later ... selected markers have to cover unselected
* markers laying at the same position as selected markers
* (jiri: it is hack, it could be solved better) */
for(marker= G.scene->markers.first; marker; marker= marker->next) {
if(marker->flag & SELECT) draw_marker(marker, lines);
* (jiri: it is hack, it could be solved better)
*/
for (marker= G.scene->markers.first; marker; marker= marker->next) {
if (marker->flag & SELECT) draw_marker(marker, flag);
}
}
void draw_markers_timespace(int lines)
/* Draw specified set of markers for Animation Editors */
void draw_markers_timespace(ListBase *markers, int flag)
{
TimeMarker *marker;
float yspace, ypixels;
@ -233,21 +247,21 @@ void draw_markers_timespace(int lines)
glTranslatef(0.0f, -11.0*yspace/ypixels, 0.0f);
/* unselected markers are drawn at the first time */
for(marker= G.scene->markers.first; marker; marker= marker->next) {
if(!(marker->flag & SELECT)) draw_marker(marker, lines);
for (marker= markers->first; marker; marker= marker->next) {
if (!(marker->flag & SELECT)) draw_marker(marker, flag);
}
/* selected markers are drawn later ... selected markers have to cover unselected
* markers laying at the same position as selected markers */
for(marker= G.scene->markers.first; marker; marker= marker->next) {
if(marker->flag & SELECT) draw_marker(marker, lines);
for (marker= markers->first; marker; marker= marker->next) {
if (marker->flag & SELECT) draw_marker(marker, flag);
}
glTranslatef(0.0f, -G.v2d->cur.ymin, 0.0f);
glTranslatef(0.0f, 11.0*yspace/ypixels, 0.0f);
}
void draw_anim_preview_timespace()
{
/* only draw this if preview range is set */

View File

@ -2227,9 +2227,11 @@ void column_select_action_keys(int mode)
}
/* some quick defines for borderselect modes */
#define ACTEDIT_BORDERSEL_ALL 0
#define ACTEDIT_BORDERSEL_FRA 1
#define ACTEDIT_BORDERSEL_CHA 2
enum {
ACTEDIT_BORDERSEL_ALL = 0,
ACTEDIT_BORDERSEL_FRA,
ACTEDIT_BORDERSEL_CHA
};
/* borderselect: for keyframes only */
void borderselect_action (void)
@ -2351,7 +2353,7 @@ static void mouse_action (int selectmode)
bActionChannel *achan= NULL;
bConstraintChannel *conchan= NULL;
IpoCurve *icu= NULL;
TimeMarker *marker;
TimeMarker *marker, *pmarker;
void *act_channel;
short sel, act_type;
@ -2363,9 +2365,63 @@ static void mouse_action (int selectmode)
if (datatype == ACTCONT_ACTION) act= (bAction *)data;
act_channel= get_nearest_action_key(&selx, &sel, &act_type, &achan);
marker=find_nearest_marker(1);
marker= find_nearest_marker(SCE_MARKERS, 1);
pmarker= (act) ? find_nearest_marker(&act->markers, 1) : NULL;
if (marker) {
/* what about scene's markers? */
if (selectmode == SELECT_REPLACE) {
deselect_markers(0, 0);
marker->flag |= SELECT;
}
else if (selectmode == SELECT_INVERT) {
if (marker->flag & SELECT)
marker->flag &= ~SELECT;
else
marker->flag |= SELECT;
}
else if (selectmode == SELECT_ADD)
marker->flag |= SELECT;
else if (selectmode == SELECT_SUBTRACT)
marker->flag &= ~SELECT;
if (act_channel) {
std_rmouse_transform(transform_markers);
allqueue(REDRAWMARKER, 0);
}
else if (pmarker) {
/* action's markers are drawn behind scene markers */
if (selectmode == SELECT_REPLACE) {
action_set_activemarker(act, pmarker, 1);
pmarker->flag |= SELECT;
}
else if (selectmode == SELECT_INVERT) {
if (pmarker->flag & SELECT) {
pmarker->flag &= ~SELECT;
action_set_activemarker(act, NULL, 0);
}
else {
pmarker->flag |= SELECT;
action_set_activemarker(act, pmarker, 0);
}
}
else if (selectmode == SELECT_ADD) {
pmarker->flag |= SELECT;
action_set_activemarker(act, pmarker, 0);
}
else if (selectmode == SELECT_SUBTRACT) {
pmarker->flag &= ~SELECT;
action_set_activemarker(act, NULL, 0);
}
// TODO: local-markers cannot be moved atm...
//std_rmouse_transform(transform_markers);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWBUTSEDIT, 0);
}
else if (act_channel) {
/* must have been a channel */
switch (act_type) {
case ACTTYPE_ICU:
icu= (IpoCurve *)act_channel;
@ -2410,27 +2466,6 @@ static void mouse_action (int selectmode)
allqueue(REDRAWOOPS, 0);
allqueue(REDRAWBUTSALL, 0);
}
else if (marker) {
/* not channel, so maybe marker */
if (selectmode == SELECT_REPLACE) {
deselect_markers(0, 0);
marker->flag |= SELECT;
}
else if (selectmode == SELECT_INVERT) {
if (marker->flag & SELECT)
marker->flag &= ~SELECT;
else
marker->flag |= SELECT;
}
else if (selectmode == SELECT_ADD)
marker->flag |= SELECT;
else if (selectmode == SELECT_SUBTRACT)
marker->flag &= ~SELECT;
std_rmouse_transform(transform_markers);
allqueue(REDRAWMARKER, 0);
}
}
/* lefthand side - mouse-click */
@ -2699,7 +2734,7 @@ void bottom_sel_action ()
if (VISIBLE_ACHAN(achan)) {
if (SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED)) {
/* take it out off the chain keep data */
BLI_remlink (&act->chanbase, achan);
BLI_remlink(&act->chanbase, achan);
/* add at end */
BLI_addtail(&act->chanbase, achan);
achan->flag |= ACHAN_MOVED;
@ -2720,6 +2755,141 @@ void bottom_sel_action ()
allqueue(REDRAWNLA, 0);
}
/* **************************************************** */
/* ACTION MARKERS (PoseLib features) */
/* NOTE: yes, these duplicate code from edittime.c a bit, but these do a bit more...
* These could get merged with those someday if need be... (Aligorith, 20071230)
*/
/* Makes the given marker the active one
* - deselect indicates whether unactive ones should be deselected too
*/
void action_set_activemarker (bAction *act, TimeMarker *active, short deselect)
{
TimeMarker *marker;
int index= 0;
/* sanity checks */
if (act == NULL)
return;
act->active_marker= 0;
/* set appropriate flags for all markers */
for (marker=act->markers.first; marker; marker=marker->next, index++) {
/* only active may be active */
if (marker == active) {
act->active_marker= index + 1;
marker->flag |= (SELECT|ACTIVE);
}
else {
if (deselect)
marker->flag &= ~(SELECT|ACTIVE);
else
marker->flag &= ~ACTIVE;
}
}
}
/* Adds a local marker to the active action */
void action_add_localmarker (bAction *act, int frame)
{
TimeMarker *marker;
char name[64];
/* sanity checks */
if (act == NULL)
return;
/* get name of marker */
sprintf(name, "Pose");
if (sbutton(name, 0, sizeof(name)-1, "Name: ") == 0)
return;
/* add marker to action - replaces any existing marker there */
for (marker= act->markers.first; marker; marker= marker->next) {
if (marker->frame == frame) {
BLI_strncpy(marker->name, name, sizeof(marker->name));
break;
}
}
if (marker == NULL) {
marker= MEM_callocN(sizeof(TimeMarker), "ActionMarker");
BLI_strncpy(marker->name, name, sizeof(marker->name));
marker->frame= frame;
BLI_addtail(&act->markers, marker);
}
/* sets the newly added marker as the active one */
action_set_activemarker(act, marker, 1);
BIF_undo_push("Action Add Marker");
allqueue(REDRAWACTION, 0);
allqueue(REDRAWBUTSEDIT, 0);
}
/* Renames the active local marker to the active action */
void action_rename_localmarker (bAction *act)
{
TimeMarker *marker;
char name[64];
int val;
/* sanity checks */
if (act == NULL)
return;
/* get active marker to rename */
if (act->active_marker == 0)
return;
else
val= act->active_marker;
if (val <= 0) return;
marker= BLI_findlink(&act->markers, val-1);
if (marker == NULL) return;
/* get name of marker */
sprintf(name, marker->name);
if (sbutton(name, 0, sizeof(name)-1, "Name: ") == 0)
return;
/* copy name */
BLI_strncpy(marker->name, name, sizeof(marker->name));
/* undo and update */
BIF_undo_push("Action Rename Marker");
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWACTION, 0);
}
/* Deletes all selected markers, and adjusts things as appropriate */
void action_remove_localmarkers (bAction *act)
{
TimeMarker *marker, *next;
/* sanity checks */
if (act == NULL)
return;
/* remove selected markers */
for (marker= act->markers.first; marker; marker= next) {
next= marker->next;
if (marker->flag & SELECT)
BLI_freelinkN(&act->markers, marker);
}
/* clear active just in case */
act->active_marker= 0;
/* undo and update */
BIF_undo_push("Action Remove Marker(s)");
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWACTION, 0);
}
/* **************************************************** */
/* EVENT HANDLING */
@ -2860,6 +3030,18 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
allqueue(REDRAWMARKER, 0);
break;
case LKEY:
/* poselib manipulation - only for actions */
if (datatype == ACTCONT_ACTION) {
if (G.qual == LR_SHIFTKEY)
action_add_localmarker(data, CFRA);
else if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY))
action_rename_localmarker(data);
else if (G.qual == LR_ALTKEY)
action_remove_localmarkers(data);
}
break;
case MKEY:
if (G.qual & LR_SHIFTKEY) {
/* mirror keyframes */

View File

@ -1465,7 +1465,7 @@ void mouse_select_ipo(void)
if(G.sipo->editipo==0) return;
get_status_editipo();
marker=find_nearest_marker(1);
marker=find_nearest_marker(SCE_MARKERS, 1);
/* map ipo-points for editing if scaled ipo */
if (NLA_IPO_SCALED) {

View File

@ -1257,7 +1257,7 @@ static void mouse_nla(int selectmode)
/* Try object ipo or ob-constraint ipo selection */
base= get_nearest_nlachannel_ob_key(&selx, &sel);
marker=find_nearest_marker(1);
marker=find_nearest_marker(SCE_MARKERS, 1);
if (base) {
isdone= 1;

View File

@ -791,7 +791,7 @@ void mouse_select_seq(void)
int hand,seldir;
TimeMarker *marker;
marker=find_nearest_marker(1);
marker=find_nearest_marker(0, 1);
if (marker) {
int oldflag;

View File

@ -173,7 +173,7 @@ void winqreadsoundspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
getmouseco_areawin(mval);
areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
marker = find_nearest_marker(0);
marker = find_nearest_marker(SCE_MARKERS, 0);
if (marker) {
if ((G.qual & LR_SHIFTKEY)==0)
deselect_markers(0, 0);

View File

@ -473,7 +473,7 @@ void get_minmax_markers(short sel, float *first, float *last)
*last= max;
}
TimeMarker *find_nearest_marker(int clip_y)
TimeMarker *find_nearest_marker(ListBase *markers, int clip_y)
{
TimeMarker *marker;
float xmin, xmax;
@ -483,7 +483,7 @@ TimeMarker *find_nearest_marker(int clip_y)
getmouseco_areawin (mval);
/* first clip selection in Y */
if((clip_y) && (mval[1] > 30))
if ((clip_y) && (mval[1] > 30))
return NULL;
mval[0]-=7;
@ -494,7 +494,7 @@ TimeMarker *find_nearest_marker(int clip_y)
xmin= rectf.xmin;
xmax= rectf.xmax;
for(marker= G.scene->markers.first; marker; marker= marker->next) {
for (marker= markers->first; marker; marker= marker->next) {
if ((marker->frame > xmin) && (marker->frame <= xmax)) {
return marker;
}
@ -877,9 +877,9 @@ void winqreadtimespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
case RIGHTMOUSE: /* select/deselect marker */
getmouseco_areawin(mval);
areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
cfra= find_nearest_marker_time(dx);
if (G.qual && LR_SHIFTKEY)
select_timeline_marker_frame(cfra, 1);
else

View File

@ -174,7 +174,10 @@ enum {
ACTMENU_MARKERS_DUPLICATE,
ACTMENU_MARKERS_DELETE,
ACTMENU_MARKERS_NAME,
ACTMENU_MARKERS_MOVE
ACTMENU_MARKERS_MOVE,
ACTMENU_MARKERS_LOCALADD,
ACTMENU_MARKERS_LOCALRENAME,
ACTMENU_MARKERS_LOCALDELETE
};
void do_action_buttons(unsigned short event)
@ -1103,6 +1106,16 @@ static void do_action_markermenu(void *arg, int event)
case ACTMENU_MARKERS_MOVE:
transform_markers('g', 0);
break;
case ACTMENU_MARKERS_LOCALADD:
action_add_localmarker(G.saction->action, CFRA);
break;
case ACTMENU_MARKERS_LOCALDELETE:
action_remove_localmarkers(G.saction->action);
break;
case ACTMENU_MARKERS_LOCALRENAME:
action_rename_localmarker(G.saction->action);
break;
}
allqueue(REDRAWMARKER, 0);
@ -1130,7 +1143,15 @@ static uiBlock *action_markermenu(void *arg_unused)
menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_NAME, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Marker|Ctrl G", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_MOVE, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Local Marker|Shift L", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALADD, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rename Local Marker|Ctrl Shift L", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALRENAME, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Local Marker|Alt L", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_LOCALDELETE, "");
if(curarea->headertype==HEADERTOP) {
uiBlockSetDirection(block, UI_DOWN);

View File

@ -325,6 +325,7 @@ int std_libbuttons(uiBlock *block, short xco, short yco,
}
if( GS(id->name)==ID_IP) len= 110;
else if((yco) && (GS(id->name)==ID_AC)) len= 100; // comes from button panel (poselib)
else if(yco) len= 140; // comes from button panel
else len= 120;
@ -932,6 +933,7 @@ void do_global_buttons(unsigned short event)
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWBUTSEDIT, 0);
break;
case B_ACTIONBROWSE:
if (!ob)
@ -1030,6 +1032,7 @@ void do_global_buttons(unsigned short event)
allqueue(REDRAWNLA, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWHEADERS, 0);
allqueue(REDRAWBUTSEDIT, 0);
}
}
@ -1703,7 +1706,8 @@ void do_global_buttons2(short event)
if(act->id.lib) {
if(okee("Make local")) {
make_local_action(act);
allqueue(REDRAWACTION,0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWBUTSEDIT, 0);
}
}
}
@ -1711,12 +1715,13 @@ void do_global_buttons2(short event)
case B_ACTALONE:
if(ob && ob->id.lib==0) {
act= ob->action;
if(act->id.us>1) {
if(okee("Single user")) {
ob->action=copy_action(act);
act->id.us--;
allqueue(REDRAWACTION, 0);
allqueue(REDRAWBUTSEDIT, 0);
}
}
}

View File

@ -63,6 +63,7 @@
#include "BSE_editipo.h"
#include "BDR_drawaction.h"
#include "BSE_time.h"
#include "BIF_poselib.h"
#include "BIF_interface.h"
@ -72,6 +73,7 @@
#include "BIF_toets.h"
#include "BIF_toolbox.h"
#include "blendef.h"
#include "PIL_time.h" /* sleep */
@ -86,22 +88,21 @@
* 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
* - PoseLibs are simply normal Actions
* - 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)
* -> a set of TimeMarkers that belong to each Action, help 'label' where a 'pose' can be
* found in the Action
* - 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[])
/* gets list of poses in poselib as a string usable for pupmenu() */
char *poselib_build_poses_menu (bAction *act, char title[])
{
DynStr *pupds= BLI_dynstr_new();
bPoseLibRef *plr;
TimeMarker *marker;
char *str;
char buf[64];
int i;
@ -110,14 +111,14 @@ char *poselib_build_poses_menu (bPoseLib *pl, char title[])
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);
/* loop through markers, adding them */
for (marker=act->markers.first, i=1; marker; marker=marker->next, i++) {
BLI_dynstr_append(pupds, marker->name);
sprintf(buf, "%%x%d", i);
BLI_dynstr_append(pupds, buf);
if (plr->next)
if (marker->next)
BLI_dynstr_append(pupds, "|");
}
@ -128,75 +129,28 @@ char *poselib_build_poses_menu (bPoseLib *pl, char title[])
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)
int poselib_get_free_index (bAction *act)
{
bPoseLibRef *plr;
TimeMarker *marker;
int low=0, high=0;
/* sanity checks */
if (ELEM(NULL, pl, pl->poses.first)) return 1;
if (ELEM(NULL, act, act->markers.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) {
for (marker= act->markers.first; marker; marker= marker->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))
if (marker->frame == (low + 1))
low++;
/* value replaces high if it is the highest value encountered yet */
if (plr->frame > high)
high= plr->frame;
if (marker->frame > high)
high= marker->frame;
}
/* - if low is not equal to high, then low+1 is a gap
@ -208,46 +162,41 @@ int poselib_get_free_index (bPoseLib *pl)
return (high + 1);
}
/* returns the active pose for a poselib */
TimeMarker *poselib_get_active_pose (bAction *act)
{
if ((act) && (act->active_marker))
return BLI_findlink(&act->markers, act->active_marker-1);
else
return NULL;
}
/* ************************************************************* */
/* Initialise a new poselib (whether it is needed or not) */
bPoseLib *poselib_init_new (Object *ob)
bAction *poselib_init_new (Object *ob)
{
bPose *pose= (ob) ? ob->pose : NULL;
bAction *act;
bPoseLib *pl;
if (ELEM(NULL, ob, pose))
/* sanity checks - only for armatures */
if (ELEM(NULL, ob, ob->pose))
return NULL;
/* init pose's poselib action (unlink old one if there) */
if (pose->poselib)
pose->poselib->id.us--;
pose->poselib= add_empty_action("PoseLib");
act= pose->poselib;
/* init object's poselib action (unlink old one if there) */
if (ob->poselib)
ob->poselib->id.us--;
ob->poselib= add_empty_action("PoseLib");
/* init actions's poselib data */
if (act->poselib == NULL)
act->poselib= MEM_callocN(sizeof(bPoseLib), "bPoseLib");
pl= act->poselib;
return pl;
return ob->poselib;
}
/* Initialise a new poselib (checks if that needs to happen) */
bPoseLib *poselib_validate (Object *ob)
bAction *poselib_validate (Object *ob)
{
bPose *pose= (ob) ? ob->pose : NULL;
bAction *act= (pose) ? pose->poselib : NULL;
bPoseLib *pl= (act) ? act->poselib : NULL;
if (ELEM(NULL, ob, pose))
if (ELEM(NULL, ob, ob->pose))
return NULL;
if (ELEM(NULL, act, pl))
else if (ob->poselib == NULL)
return poselib_init_new(ob);
else
return pl;
return ob->poselib;
}
@ -258,8 +207,7 @@ void poselib_validate_act (bAction *act)
{
ListBase keys = {NULL, NULL};
ActKeyColumn *ak;
bPoseLib *pl;
bPoseLibRef *plr, *plrn;
TimeMarker *marker, *markern;
/* validate action and poselib */
if (act == NULL) {
@ -267,49 +215,44 @@ void poselib_validate_act (bAction *act)
return;
}
if (act->poselib == NULL)
act->poselib= MEM_callocN(sizeof(bPoseLib), "bPoseLib");
pl= act->poselib;
/* determine which frames have keys */
action_to_keylist(act, &keys, NULL);
/* for each key, make sure there is a correspnding pose */
for (ak= keys.first; ak; ak= ak->next) {
/* check if any pose matches this */
for (plr= pl->poses.first; plr; plr= plr->next) {
if (IS_EQ(plr->frame, ak->cfra)) {
plr->flag = 1;
for (marker= act->markers.first; marker; marker= marker->next) {
if (IS_EQ(marker->frame, ak->cfra)) {
marker->flag = -1;
break;
}
}
/* add new if none found */
if (plr == NULL) {
char name[32];
if (marker == NULL) {
char name[64];
/* add pose to poselib */
plr= MEM_callocN(sizeof(bPoseLibRef), "bPoseLibRef");
marker= MEM_callocN(sizeof(TimeMarker), "ActionMarker");
strcpy(name, "Pose");
poselib_unique_pose_name(pl, name);
BLI_strncpy(plr->name, name, sizeof(plr->name));
BLI_strncpy(marker->name, name, sizeof(marker->name));
plr->frame= (int)ak->cfra;
plr->flag= 1;
marker->frame= (int)ak->cfra;
marker->flag= -1;
BLI_addtail(&pl->poses, plr);
BLI_addtail(&act->markers, marker);
}
}
/* remove all untagged poses (unused), and remove all tags */
for (plr= pl->poses.first; plr; plr= plrn) {
plrn= plr->next;
for (marker= act->markers.first; marker; marker= markern) {
markern= marker->next;
if (plr->flag == 0)
BLI_freelinkN(&pl->poses, plr);
if (marker->flag != -1)
BLI_freelinkN(&act->markers, marker);
else
plr->flag = 0;
marker->flag = 0;
}
/* free temp memory */
@ -353,13 +296,12 @@ 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;
TimeMarker *marker;
bAction *act;
bActionChannel *achan;
IpoCurve *icu;
int frame;
char name[32];
char name[64];
/* sanity check */
if (ELEM3(NULL, ob, arm, pose))
@ -367,7 +309,7 @@ void poselib_add_current_pose (Object *ob, int val)
/* mode - add new or replace existing */
if (val == 0) {
if (pose->poselib && pose->poselib->poselib->poses.first) {
if ((ob->poselib) && (ob->poselib->markers.first)) {
val= pupmenu("PoseLib Add Current Pose%t|Add New%x1|Replace Existing%x2");
if (val <= 0) return;
}
@ -375,24 +317,23 @@ void poselib_add_current_pose (Object *ob, int val)
val= 1;
}
if ((pose->poselib) && (val == 2)) {
if ((ob->poselib) && (val == 2)) {
char *menustr;
/* get poselib */
act= pose->poselib;
pl= act->poselib;
act= ob->poselib;
/* get the pose to replace */
menustr= poselib_build_poses_menu(pl, "Replace PoseLib Pose");
menustr= poselib_build_poses_menu(act, "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;
marker= BLI_findlink(&act->markers, val-1);
if (marker == NULL) return;
/* get the frame from the poselib */
frame= plr->frame;
frame= marker->frame;
}
else {
/* get name of pose */
@ -401,18 +342,26 @@ void poselib_add_current_pose (Object *ob, int val)
return;
/* get/initialise poselib */
pl= poselib_validate(ob);
act= pose->poselib;
act= poselib_validate(ob);
/* validate name and get frame */
poselib_unique_pose_name(pl, name);
frame= poselib_get_free_index(pl);
frame= poselib_get_free_index(act);
/* 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);
/* add pose to poselib - replaces any existing pose there */
for (marker= act->markers.first; marker; marker= marker->next) {
if (marker->frame == frame) {
BLI_strncpy(marker->name, name, sizeof(marker->name));
break;
}
}
if (marker == NULL) {
marker= MEM_callocN(sizeof(TimeMarker), "ActionMarker");
BLI_strncpy(marker->name, name, sizeof(marker->name));
marker->frame= frame;
BLI_addtail(&act->markers, marker);
}
}
/* loop through selected posechannels, keying their pose to the action */
@ -448,7 +397,7 @@ void poselib_add_current_pose (Object *ob, int val)
}
/* store new 'active' pose number */
pl->active_nr= BLI_countlist(&pl->poses);
act->active_marker= BLI_countlist(&act->markers);
BIF_undo_push("PoseLib Add Pose");
allqueue(REDRAWBUTSEDIT, 0);
@ -456,12 +405,11 @@ void poselib_add_current_pose (Object *ob, int val)
/* This tool removes the pose that the user selected from the poselib (or the provided pose) */
void poselib_remove_pose (Object *ob, bPoseLibRef *plr)
void poselib_remove_pose (Object *ob, TimeMarker *marker)
{
bPose *pose= (ob) ? ob->pose : NULL;
bAction *act= (pose) ? pose->poselib : NULL;
bAction *act= (ob) ? ob->poselib : NULL;
bActionChannel *achan;
bPoseLib *pl= (act) ? act->poselib : NULL;
char *menustr;
int val;
@ -470,24 +418,24 @@ void poselib_remove_pose (Object *ob, bPoseLibRef *plr)
error("PoseLib is only for Armatures in PoseMode");
return;
}
if (ELEM(NULL, act, pl)) {
error("Pose doesn't have a valid PoseLib");
if (act == NULL) {
error("Object doesn't have PoseLib data");
return;
}
/* get index (and pointer) of pose to remove */
if (plr == NULL) {
menustr= poselib_build_poses_menu(pl, "Remove PoseLib Pose");
if (marker == NULL) {
menustr= poselib_build_poses_menu(act, "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;
marker= BLI_findlink(&act->markers, val-1);
if (marker == NULL) return;
}
else {
/* only continue if pose belongs to poselib */
if (BLI_findindex(&pl->poses, plr) == -1)
if (BLI_findindex(&act->markers, marker) == -1)
return;
}
@ -501,7 +449,7 @@ void poselib_remove_pose (Object *ob, bPoseLibRef *plr)
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)) {
if (IS_EQ(bezt->vec[1][0], marker->frame)) {
delete_icu_key(icu, i);
break;
}
@ -510,14 +458,15 @@ void poselib_remove_pose (Object *ob, bPoseLibRef *plr)
}
/* remove poselib from list */
BLI_freelinkN(&pl->poses, plr);
BLI_freelinkN(&act->markers, marker);
/* fix active pose number */
pl->active_nr= 0;
act->active_marker= 0;
/* undo + redraw */
BIF_undo_push("PoseLib Remove Pose");
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWACTION, 0);
}
@ -525,10 +474,9 @@ void poselib_remove_pose (Object *ob, bPoseLibRef *plr)
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];
bAction *act= (ob) ? ob->poselib : NULL;
TimeMarker *marker;
char *menustr, name[64];
int val;
/* check if valid poselib */
@ -536,34 +484,32 @@ void poselib_rename_pose (Object *ob)
error("PoseLib is only for Armatures in PoseMode");
return;
}
if (ELEM(NULL, act, pl)) {
error("Pose doesn't have a valid PoseLib");
if (act == NULL) {
error("Object doesn't have a valid PoseLib");
return;
}
/* get index of pose to remove */
menustr= poselib_build_poses_menu(pl, "Rename PoseLib Pose");
menustr= poselib_build_poses_menu(act, "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;
marker= BLI_findlink(&act->markers, val-1);
if (marker == NULL) return;
/* get name of pose */
sprintf(name, plr->name);
sprintf(name, marker->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));
BLI_strncpy(marker->name, name, sizeof(marker->name));
/* undo and update */
BIF_undo_push("PoseLib Rename Pose");
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWACTION, 0);
}
@ -574,23 +520,17 @@ typedef struct tPoseLib_Backup {
struct tPoseLib_Backup *next, *prev;
bPoseChannel *pchan;
float oldloc[3];
float oldsize[3];
float oldquat[4];
int oldflag;
bPoseChannel olddata;
} 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)
static void poselib_backup_posecopy (ListBase *backups, bPose *pose, bAction *act)
{
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) {
for (achan= act->chanbase.first; achan; achan= achan->next) {
/* try to find posechannel */
pchan= get_pose_channel(pose, achan->name);
@ -600,11 +540,8 @@ static void poselib_backup_posecopy (ListBase *backups, bPose *pose)
plb= MEM_callocN(sizeof(tPoseLib_Backup), "tPoseLib_Backup");
VECCOPY(plb->oldloc, pchan->loc);
VECCOPY(plb->oldsize, pchan->size);
QUATCOPY(plb->oldquat, pchan->quat);
plb->pchan= pchan;
memcpy(&plb->olddata, plb->pchan, sizeof(bPoseChannel));
BLI_addtail(backups, plb);
}
@ -617,14 +554,11 @@ static void poselib_backup_restore (ListBase *backups)
tPoseLib_Backup *plb;
for (plb= backups->first; plb; plb= plb->next) {
VECCOPY(plb->pchan->loc, plb->oldloc);
VECCOPY(plb->pchan->size, plb->oldsize);
VECCOPY(plb->pchan->quat, plb->oldquat);
plb->pchan->flag = plb->oldflag;
memcpy(plb->pchan, &plb->olddata, sizeof(bPoseChannel));
}
}
/* ---------------------------- */
/* Applies the appropriate stored pose from the pose-library to the current pose
@ -632,14 +566,14 @@ static void poselib_backup_restore (ListBase *backups)
* - 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[])
static void poselib_apply_pose (Object *ob, TimeMarker *marker, char headerstr[])
{
bPose *pose= ob->pose;
bPoseChannel *pchan;
bAction *act= pose->poselib;
bAction *act= ob->poselib;
bActionChannel *achan;
IpoCurve *icu;
int frame= plr->frame;
int frame= marker->frame;
/* start applying - only those channels which have a key at this point in time! */
for (achan= act->chanbase.first; achan; achan= achan->next) {
@ -662,11 +596,13 @@ static void poselib_apply_pose (Object *ob, bPoseLibRef *plr, char headerstr[])
if (found) break;
}
/* apply pose */
/* apply pose - only if posechannel selected? */
if (found) {
pchan= get_pose_channel(pose, achan->name);
if (pchan) {
if ( (pchan) && (pchan->bone) &&
(pchan->bone->flag & (BONE_SELECTED|BONE_ACTIVE)) )
{
/* Evaluates and sets the internal ipo values */
calc_ipo(achan->ipo, frame);
/* This call also sets the pchan flags */
@ -686,9 +622,8 @@ static void poselib_apply_pose (Object *ob, bPoseLibRef *plr, char headerstr[])
/* 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;
bAction *act= ob->poselib;
bActionChannel *achan;
/* start tagging/keying */
@ -735,6 +670,35 @@ static void poselib_keytag_pose (Object *ob)
/* ---------------------------- */
/* This helper function is called during poselib_preview_poses to find the
* pose to preview next (after a change event)
*/
static TimeMarker *poselib_preview_get_next (bAction *act, TimeMarker *current, int step)
{
if (step) {
TimeMarker *marker, *next;
/* Loop through the markers in a cyclic fashion, incrementing/decrementing step as appropriate
* until step == 0. At this point, marker should be the correct marker.
*/
if (step > 0) {
for (marker=current; marker && step; marker=next, step--)
next= (marker->next) ? marker->next : act->markers.first;
}
else {
for (marker=current; marker && step; marker=next, step++)
next= (marker->prev) ? marker->prev : act->markers.last;
}
/* don't go anywhere if for some reason an error occurred */
return (marker) ? marker : current;
}
else
return current;
}
/* ---------------------------- */
/* defines for poselib_preview_poses --> ret_val values */
enum {
PL_PREVIEW_RUNNING = 0,
@ -759,9 +723,8 @@ void poselib_preview_poses (Object *ob, short apply_active)
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 == NULL) ? NULL : (pl->active_nr) ? BLI_findlink(&pl->poses, pl->active_nr-1) : pl->poses.first;
bAction *act= (ob) ? (ob->poselib) : NULL;
TimeMarker *marker= poselib_get_active_pose(act);
Base *base;
short ret_val= (apply_active) ? PL_PREVIEW_RUNONCE : PL_PREVIEW_RUNNING;
@ -770,21 +733,21 @@ void poselib_preview_poses (Object *ob, short apply_active)
char headerstr[200];
/* check if valid poselib */
if (ELEM(NULL, ob, pose)) {
if (ELEM3(NULL, ob, pose, arm)) {
error("PoseLib is only for Armatures in PoseMode");
return;
}
if (ELEM(NULL, act, pl)) {
error("Pose doesn't have a valid PoseLib");
if (act == NULL) {
error("Object doesn't have a valid PoseLib");
return;
}
if (plr == NULL) {
error("PoseLib has no poses to preview");
if (marker == NULL) {
error("PoseLib has no poses to preview/apply");
return;
}
/* make backup of current pose for restoring pose */
poselib_backup_posecopy(&backups, pose);
poselib_backup_posecopy(&backups, pose, act);
/* set depsgraph flags */
/* make sure the lock is set OK, unlock can be accidentally saved? */
@ -805,7 +768,7 @@ void poselib_preview_poses (Object *ob, short apply_active)
firsttime = 0;
/* pose should be the right one to draw */
poselib_apply_pose(ob, plr, headerstr);
poselib_apply_pose(ob, marker, headerstr);
/* old optimize trick... this enforces to bypass the depgraph
* - note: code copied from transform_generics.c -> recalcData()
@ -827,7 +790,7 @@ void poselib_preview_poses (Object *ob, short apply_active)
/* do header print - if interactively previewing */
if (ret_val == PL_PREVIEW_RUNNING) {
sprintf(headerstr, "PoseLib Previewing Pose: \"%s\" | Use ScrollWheel or PageUp/Down to change", plr->name);
sprintf(headerstr, "PoseLib Previewing Pose: \"%s\" | Use ScrollWheel or PageUp/Down to change", marker->name);
headerprint(headerstr);
}
@ -866,17 +829,31 @@ void poselib_preview_poses (Object *ob, short apply_active)
ret_val= PL_PREVIEW_CONFIRM;
break;
/* change to previous pose - go back to end of list if no previous (cyclic) */
/* change to previous pose (cyclic) */
case PAGEUPKEY:
case WHEELUPMOUSE:
plr= (plr->prev) ? plr->prev : pl->poses.last;
case RIGHTARROWKEY:
marker= poselib_preview_get_next(act, marker, -1);
redraw= PL_PREVIEW_REDRAWALL;
break;
/* change to next pose - go back to start of list if no next (cyclic) */
/* change to next pose (cyclic) */
case PAGEDOWNKEY:
case WHEELDOWNMOUSE:
plr= (plr->next) ? plr->next : pl->poses.first;
case LEFTARROWKEY:
marker= poselib_preview_get_next(act, marker, 1);
redraw= PL_PREVIEW_REDRAWALL;
break;
/* jump 5 poses (cyclic, back) */
case DOWNARROWKEY:
marker= poselib_preview_get_next(act, marker, -5);
redraw= PL_PREVIEW_REDRAWALL;
break;
/* jump 5 poses (cyclic, forward) */
case UPARROWKEY:
marker= poselib_preview_get_next(act, marker, 5);
redraw= PL_PREVIEW_REDRAWALL;
break;
@ -931,7 +908,7 @@ void poselib_preview_poses (Object *ob, short apply_active)
poselib_keytag_pose(ob);
/* change active pose setting */
pl->active_nr= BLI_findindex(&pl->poses, plr) + 1;
act->active_marker= BLI_findindex(&act->markers, marker) + 1;
/* Update event for pose and deformation children */
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);