Experimental feature, especially for the animation department:

THE OBJECT PROXY

Or simple said; local control of referenced data from libraries.
Having library files with references is a very common studio setup, and
Blender did do quite well in that area. Were it not that for character
setups it was impossible to use still.

This commit will enable a full rig+character to remain in the library,
and still have - under strict control - local access for animation edits.

Full log:
http://www.blender3d.org/cms/Proxy_Objects.824.0.html
This commit is contained in:
2006-11-11 16:45:17 +00:00
parent 97f892b86b
commit feb210f08e
23 changed files with 342 additions and 47 deletions

View File

@@ -139,6 +139,11 @@ struct bAction *bake_obIPO_to_action(struct Object *ob);
void blend_poses(struct bPose *dst, struct bPose *src, float srcweight, short mode);
void extract_pose_from_pose(struct bPose *pose, const struct bPose *src);
/* for proxy */
void copy_pose_result(struct bPose *to, struct bPose *from);
/* clear all transforms */
void rest_pose(struct bPose *pose);
/* map global time (frame nr) to strip converted time, doesn't clip */
float get_action_frame(struct Object *ob, float cframe);
/* map strip time to global time (frame nr) */

View File

@@ -55,6 +55,8 @@ void free_object(struct Object *ob);
void object_free_display(struct Object *ob);
void object_free_modifiers(struct Object *ob);
void object_make_proxy(struct Object *ob, struct Object *target);
void unlink_object(struct Object *ob);
int exist_object(struct Object *obtest);
void *add_camera(void);

View File

@@ -696,8 +696,8 @@ void extract_pose_from_action(bPose *pose, bAction *act, float ctime)
pose->ctime= ctime; /* used for cyclic offset matching */
}
/* for do_all_pose_actions, clears the pose */
static void rest_pose(bPose *pose)
/* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */
void rest_pose(bPose *pose)
{
bPoseChannel *pchan;
int i;
@@ -720,6 +720,27 @@ static void rest_pose(bPose *pose)
}
}
/* both poses should be in sync */
void copy_pose_result(bPose *to, bPose *from)
{
bPoseChannel *pchanto, *pchanfrom;
if(to==NULL || from==NULL) {
printf("pose result copy error\n"); // debug temp
return;
}
pchanto= to->chanbase.first;
pchanfrom= from->chanbase.first;
for(; pchanto && pchanfrom; pchanto= pchanto->next, pchanfrom= pchanfrom->next) {
Mat4CpyMat4(pchanto->pose_mat, pchanfrom->pose_mat);
Mat4CpyMat4(pchanto->chan_mat, pchanfrom->chan_mat);
VECCOPY(pchanto->pose_head, pchanfrom->pose_head);
VECCOPY(pchanto->pose_tail, pchanfrom->pose_tail);
pchanto->flag= pchanfrom->flag;
}
}
/* ********** NLA with non-poses works with ipo channels ********** */
typedef struct NlaIpoChannel {

View File

@@ -964,6 +964,50 @@ void where_is_armature (bArmature *arm)
}
}
/* if bone layer is protected, copy the data from proxy->pose */
static void pose_proxy_synchronize(Object *ob, Object *proxy, int layer_protected)
{
bPose *pose= ob->pose, *proxypose= proxy->pose;
bPoseChannel *pchan, *pchanp, pchanw;
bConstraint *con;
char *str;
if(proxypose==NULL) return;
/* clear all transformation values from library */
rest_pose(proxypose);
pchan= pose->chanbase.first;
pchanp= proxypose->chanbase.first;
for(; pchan && pchanp; pchan= pchan->next, pchanp= pchanp->next) {
if(pchan->bone->layer & layer_protected) {
/* copy posechannel to temp, but restore important pointers */
pchanw= *pchanp;
pchanw.prev= pchan->prev;
pchanw.next= pchan->next;
pchanw.parent= pchan->parent;
pchanw.child= pchan->child;
pchanw.path= NULL;
/* constraints, set target ob pointer to own object */
copy_constraints(&pchanw.constraints, &pchanp->constraints);
for(con= pchanw.constraints.first; con; con= con->next) {
if(proxy==get_constraint_target(con, &str))
set_constraint_target(con, ob, NULL);
}
/* free stuff from current channel */
if(pchan->path) MEM_freeN(pchan->path);
free_constraints(&pchan->constraints);
/* the final copy */
*pchan= pchanw;
}
}
}
static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int counter)
{
bPoseChannel *pchan = verify_pose_channel (pose, bone->name); // verify checks and/or adds
@@ -983,7 +1027,7 @@ static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int
return counter;
}
/* only after leave editmode, duplicating, but also for validating older files */
/* only after leave editmode, duplicating, validating older files, library syncing */
/* NOTE: pose->flag is set for it */
void armature_rebuild_pose(Object *ob, bArmature *arm)
{
@@ -1019,6 +1063,10 @@ void armature_rebuild_pose(Object *ob, bArmature *arm)
}
// printf("rebuild pose %s, %d bones\n", ob->id.name, counter);
/* synchronize protected layers with proxy */
if(ob->id.lib==NULL && ob->proxy)
pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected);
update_pose_constraint_flags(ob->pose); // for IK detection for example
/* the sorting */

View File

@@ -466,6 +466,11 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int
dag_add_relation(dag,node2,node,DAG_RL_OB_OB);
addtoroot = 0;
}
if (ob->id.lib==NULL && ob->proxy) {
node2 = dag_get_node(dag, ob->proxy);
dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA|DAG_RL_OB_OB);
/* inverted relation, so addtoroot shouldn't be set to zero */
}
if (ob->transflag & OB_DUPLI) {
if((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
@@ -588,6 +593,8 @@ struct DagForest *build_dag(struct Scene *sce, short mask)
ob= base->object;
build_dag_object(dag, scenenode, ob, mask);
if(ob->proxy)
build_dag_object(dag, scenenode, ob->proxy, mask);
/* handled in next loop */
if(ob->dup_group)

View File

@@ -111,7 +111,7 @@
#include "BPY_extern.h"
/* Local function protos */
static void solve_parenting (Object *ob, Object *par, float slowmat[][4], int simul);
static void solve_parenting (Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul);
float originmat[3][3]; /* after where_is_object(), can be used in other functions (bad!) */
Object workob;
@@ -269,7 +269,11 @@ void unlink_object(Object *ob)
/* check all objects: parents en bevels and fields */
obt= G.main->object.first;
while(obt) {
if(obt->id.lib==NULL) {
if(obt->id.lib) {
if(obt->proxy==ob)
obt->proxy= NULL;
}
else {
if(obt->parent==ob) {
obt->parent= NULL;
@@ -859,6 +863,23 @@ SoftBody *copy_softbody(SoftBody *sb)
return sbn;
}
static void copy_object_pose(Object *obn, Object *ob)
{
bPoseChannel *chan;
copy_pose(&obn->pose, ob->pose, 1);
for (chan = obn->pose->chanbase.first; chan; chan=chan->next){
bConstraint *con;
char *str;
chan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
for(con= chan->constraints.first; con; con= con->next) {
if(ob==get_constraint_target(con, &str))
set_constraint_target(con, obn, NULL);
}
}
}
Object *copy_object(Object *ob)
{
Object *obn;
@@ -872,7 +893,8 @@ Object *copy_object(Object *ob)
}
if(ob->bb) obn->bb= MEM_dupallocN(ob->bb);
obn->path= 0;
obn->path= NULL;
obn->proxy= NULL;
obn->flag &= ~OB_FROMGROUP;
copy_effects(&obn->effect, &ob->effect);
@@ -894,7 +916,7 @@ Object *copy_object(Object *ob)
copy_actuators(&obn->actuators, &ob->actuators);
if(ob->pose) {
copy_pose(&obn->pose, ob->pose, 1);
copy_object_pose(obn, ob);
/* backwards compat... non-armatures can get poses in older files? */
if(ob->type==OB_ARMATURE)
armature_rebuild_pose(obn, obn->data);
@@ -968,9 +990,11 @@ void make_local_object(Object *ob)
* - mixed: make copy
*/
if(ob->id.lib==0) return;
if(ob->id.lib==NULL) return;
if(ob->proxy) return;
if(ob->id.us==1) {
ob->id.lib= 0;
ob->id.lib= NULL;
ob->id.flag= LIB_LOCAL;
new_id(0, (ID *)ob, 0);
@@ -1020,6 +1044,48 @@ void make_local_object(Object *ob)
expand_local_object(ob);
}
/* *************** PROXY **************** */
/* proxy rule: lib_object->proxy == the one we borrow from, set temporally while object_update */
/* local_object->proxy == pointer to library object, saved in files and read */
void object_make_proxy(Object *ob, Object *target)
{
/* paranoia checks */
if(ob->id.lib || target->id.lib==NULL) {
printf("cannot make proxy\n");
return;
}
ob->proxy= target;
target->proxy= ob;
ob->recalc= target->recalc= OB_RECALC;
/* copy transform */
VECCOPY(ob->loc, target->loc);
VECCOPY(ob->rot, target->rot);
VECCOPY(ob->size, target->size);
ob->parent= target->parent; /* libdata */
Mat4CpyMat4(ob->parentinv, target->parentinv);
ob->ipo= target->ipo; /* libdata */
/* skip constraints, constraintchannels, nla? */
ob->type= target->type;
ob->data= target->data;
id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_EXTERN */
/* type conversions */
if(target->type == OB_ARMATURE) {
copy_object_pose(ob, target); /* data copy, object pointers in constraints */
rest_pose(ob->pose); /* clear all transforms in channels */
armature_rebuild_pose(ob, ob->data); /* set all internal links */
}
}
/* *************** CALC ****************** */
/* there is also a timing calculation in drawobject() */
@@ -1380,7 +1446,6 @@ int during_scriptlink(void) {
void where_is_object_time(Object *ob, float ctime)
{
Object *par;
float *fp1, *fp2, slowmat[4][4] = MAT4_UNITY;
float stime, fac1, fac2, vec[3];
int a;
@@ -1395,6 +1460,7 @@ void where_is_object_time(Object *ob, float ctime)
/* this is needed to be able to grab objects with ipos, otherwise it always freezes them */
stime= bsystem_time(ob, 0, ctime, 0.0);
if(stime != ob->ctime) {
ob->ctime= stime;
if(ob->ipo) {
@@ -1413,8 +1479,8 @@ void where_is_object_time(Object *ob, float ctime)
}
if(ob->parent) {
par= ob->parent;
Object *par= ob->parent;
if(ob->ipoflag & OB_OFFS_PARENT) ctime-= ob->sf;
/* hurms, code below conflicts with depgraph... (ton) */
@@ -1426,10 +1492,11 @@ void where_is_object_time(Object *ob, float ctime)
pushdata(par, sizeof(Object));
pop= 1;
where_is_object_time(par, ctime);
if(par->id.lib && par->proxy); // was a copied matrix, no where_is! bad...
else where_is_object_time(par, ctime);
}
solve_parenting(ob, par, slowmat, 0);
solve_parenting(ob, par, ob->obmat, slowmat, 0);
if(pop) {
poplast(par);
@@ -1474,17 +1541,17 @@ void where_is_object_time(Object *ob, float ctime)
else ob->transflag &= ~OB_NEG_SCALE;
}
static void solve_parenting (Object *ob, Object *par, float slowmat[][4], int simul)
static void solve_parenting (Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul)
{
float totmat[4][4];
float tmat[4][4];
float obmat[4][4];
float locmat[4][4];
float vec[3];
int ok;
object_to_mat4(ob, obmat);
object_to_mat4(ob, locmat);
if(ob->partype & PARSLOW) Mat4CpyMat4(slowmat, ob->obmat);
if(ob->partype & PARSLOW) Mat4CpyMat4(slowmat, obmat);
switch(ob->partype & PARTYPE) {
@@ -1533,10 +1600,10 @@ static void solve_parenting (Object *ob, Object *par, float slowmat[][4], int si
// total
Mat4MulSerie(tmat, totmat, ob->parentinv,
NULL, NULL, NULL, NULL, NULL, NULL);
Mat4MulSerie(ob->obmat, tmat, obmat,
Mat4MulSerie(obmat, tmat, locmat,
NULL, NULL, NULL, NULL, NULL, NULL);
if (simul){
if (simul) {
}
else{
@@ -1609,7 +1676,7 @@ for a lamp that is the child of another object */
if(ob->parent) {
par= ob->parent;
solve_parenting(ob, par, slowmat, 1);
solve_parenting(ob, par, ob->obmat, slowmat, 1);
if(ob->partype & PARSLOW) {
@@ -1883,17 +1950,26 @@ void minmax_object(Object *ob, float *min, float *max)
}
}
/* proxy rule: lib_object->proxy == the one we borrow from, set on read */
/* local_object->proxy == pointer to library object, saved in files and read */
/* the main object update call, for object matrix, constraints, keys and displist (modifiers) */
/* requires flags to be set! */
void object_handle_update(Object *ob)
{
if(ob->recalc & OB_RECALC) {
if(ob->recalc & OB_RECALC_OB) where_is_object(ob);
if(ob->recalc & OB_RECALC_OB) {
if(ob->id.lib && ob->proxy)
Mat4CpyMat4(ob->obmat, ob->proxy->obmat);
else
where_is_object(ob);
}
if(ob->recalc & OB_RECALC_DATA) {
// printf("recalcdata %s\n", ob->id.name+2);
// printf("recalcdata %s\n", ob->id.name+2);
/* includes all keys and modifiers */
if(ob->type==OB_MESH) {
@@ -1909,14 +1985,22 @@ void object_handle_update(Object *ob)
lattice_calc_modifiers(ob);
}
else if(ob->type==OB_ARMATURE) {
/* this actually only happens for reading old files... */
/* this happens for reading old files and to match library armatures with poses */
if(ob->pose==NULL || (ob->pose->flag & POSE_RECALC))
armature_rebuild_pose(ob, ob->data);
do_all_pose_actions(ob);
where_is_pose(ob);
if(ob->id.lib && ob->proxy)
copy_pose_result(ob->pose, ob->proxy->pose);
else {
do_all_pose_actions(ob);
where_is_pose(ob);
}
}
}
if(ob->id.lib==NULL && ob->proxy)
object_handle_update(ob->proxy);
ob->recalc &= ~OB_RECALC;
}
}

View File

@@ -1589,18 +1589,29 @@ static void lib_link_pose(FileData *fd, Object *ob, bPose *pose)
{
bPoseChannel *pchan;
bArmature *arm= ob->data;
int rebuild= 0;
int rebuild;
if (!pose || !arm)
return;
/* always rebuild to match lib changes */
rebuild= (ob->id.lib==NULL && arm->id.lib);
for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
lib_link_constraints(fd, (ID *)ob, &pchan->constraints);
// hurms... loop in a loop, but yah... later... (ton)
/* hurms... loop in a loop, but yah... later... (ton) */
pchan->bone= get_named_bone(arm, pchan->name);
pchan->custom= newlibadr(fd, arm->id.lib, pchan->custom);
if(pchan->bone==NULL)
rebuild= 1;
else if(ob->id.lib==NULL && arm->id.lib) {
/* local pose selection copied to armature, bit hackish */
pchan->bone->flag &= ~(BONE_SELECTED|BONE_ACTIVE);
pchan->bone->flag |= pchan->selectflag;
}
}
if(rebuild) {
ob->recalc= OB_RECALC;
pose->flag |= POSE_RECALC;
@@ -2407,7 +2418,19 @@ static void lib_link_object(FileData *fd, Main *main)
ob->ipo= newlibadr_us(fd, ob->id.lib, ob->ipo);
ob->action = newlibadr_us(fd, ob->id.lib, ob->action);
ob->dup_group= newlibadr_us(fd, ob->id.lib, ob->dup_group);
if(ob->id.lib) {
/* no proxy in library data, is default local data */
ob->proxy= NULL; ob->proxy_group= NULL;
}
else {
ob->proxy= newlibadr_us(fd, ob->id.lib, ob->proxy);
if(ob->proxy) {
ob->proxy->proxy= ob;
/* force proxy updates after load/undo, a bit weak */
ob->recalc= ob->proxy->recalc= OB_RECALC;
}
ob->proxy_group= newlibadr_us(fd, ob->id.lib, ob->proxy_group);
}
poin= ob->data;
ob->data= newlibadr_us(fd, ob->id.lib, ob->data);

View File

@@ -710,6 +710,7 @@ static void write_pose(WriteData *wd, bPose *pose)
// Write channels
for (chan=pose->chanbase.first; chan; chan=chan->next) {
write_constraints(wd, &chan->constraints);
chan->selectflag= chan->bone->flag & (BONE_SELECTED|BONE_ACTIVE); // gets restored on read, for library armatures
writestruct(wd, DATA, "bPoseChannel", 1, chan);
}

View File

@@ -55,6 +55,7 @@ void set_slowparent(void);
void make_vertex_parent(void);
int test_parent_loop(struct Object *par, struct Object *ob);
void make_parent(void);
void make_proxy(void);
#define EM_WAITCURSOR (1 << 0)
#define EM_FREEDATA (1 << 1)

View File

@@ -163,6 +163,7 @@ struct ScrArea;
#define BUT_COLORBAND (30<<9)
#define BUT_NORMAL (31<<9)
#define BUT_CURVE (32<<9)
#define BUT_TOGDUAL (33<<9)
#define BUTTYPE (63<<9)

View File

@@ -71,6 +71,7 @@ typedef struct TreeElement {
#define TSE_VERSE_OBJ_NODE 16
#define TSE_VERSE_GEOM_NODE 17
/*#endif*/
#define TSE_PROXY 18
/* outliner search flags */
#define OL_FIND 0

View File

@@ -49,8 +49,8 @@ typedef struct bPoseChannel {
short flag; /* dynamic, for detecting transform changes */
short constflag; /* for quick detecting which constraints affect this channel */
short ikflag; /* settings for IK bones */
short pad1;
int pathlen; /* for drawing paths, the amount of frames */
short selectflag; /* copy of bone flag, so you can work with library armatures */
int pathlen; /* for drawing paths, the amount of frames */
short protectflag;/* protect channels from being transformed */
short pad2;

View File

@@ -76,8 +76,10 @@ typedef struct bArmature {
ListBase chainbase;
int flag;
int drawtype;
short deformflag, layer;
short deformflag, pad1;
short layer, layer_protected; /* for buttons to work, both variables in this order together */
short ghostep, ghostsize;
int pad2;
}bArmature;
/* armature->flag */

View File

@@ -86,7 +86,8 @@ typedef struct Object {
int par1, par2, par3; /* can be vertexnrs */
char parsubstr[32]; /* String describing subobject info */
void *pardata;
struct Object *parent, *track;
struct Object *parent, *track, *proxy;
struct Group *proxy_group;
struct Ipo *ipo;
struct Path *path;
struct BoundBox *bb;

View File

@@ -3146,13 +3146,13 @@ static void editing_panel_armature_type(Object *ob, bArmature *arm)
uiBlockBeginAlign(block);
for(a=0; a<8; a++) {
short dx= 18;
but= uiDefButBitS(block, TOG, 1<<a, REDRAWVIEW3D, "", 10+a*dx, 123, dx, 15, &arm->layer, 0, 0, 0, 0, "");
but= uiDefButBitS(block, BUT_TOGDUAL, 1<<a, REDRAWVIEW3D, "", 10+a*dx, 123, dx, 15, &arm->layer, 0, 0, 0, 0, "");
uiButSetFunc(but, armature_layer_cb, &arm->layer, (void *)(1<<a));
}
uiBlockBeginAlign(block);
for(a=8; a<16; a++) {
short dx= 18;
but= uiDefButBitS(block, TOG, 1<<a, REDRAWVIEW3D, "", 18+a*dx, 123, dx, 15, &arm->layer, 0, 0, 0, 0, "");
but= uiDefButBitS(block, BUT_TOGDUAL, 1<<a, REDRAWVIEW3D, "", 18+a*dx, 123, dx, 15, &arm->layer, 0, 0, 0, 0, "");
uiButSetFunc(but, armature_layer_cb, &arm->layer, (void *)(1<<a));
}

View File

@@ -1239,6 +1239,44 @@ void make_vertex_parent(void)
/* BIF_undo_push(str); not, conflicts with editmode undo... */
}
/* adds empty object to become local replacement data of a library-linked object */
void make_proxy(void)
{
Object *ob= OBACT;
if(G.scene->id.lib) return;
if(ob==NULL) return;
if(ob->id.lib==NULL) {
error("Can not make proxy for non-linked object");
}
else if(okee("Make Proxy Object")) {
Object *newob;
Base *newbase, *oldbase= BASACT;
char name[32];
newob= add_object(OB_EMPTY);
strcpy(name, ob->id.name+2);
strcat(name, "_proxy");
rename_id(&newob->id, name);
/* set layers OK */
newbase= BASACT; /* add_object sets active... */
newbase->lay= oldbase->lay;
newob->lay= newbase->lay;
/* remove base, leave user count of object, it gets linked in object_make_proxy */
BLI_remlink(&G.scene->base, oldbase);
MEM_freeN(oldbase);
object_make_proxy(newob, ob);
DAG_scene_sort(G.scene);
allqueue(REDRAWALL, 0);
BIF_undo_push("Make Proxy Object");
}
}
int test_parent_loop(Object *par, Object *ob)
{
/* test if 'ob' is a parent somewhere in par's parents */

View File

@@ -59,6 +59,7 @@
#include "DNA_text_types.h" /* for space handlers */
#include "DNA_texture_types.h"
#include "BKE_action.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_displist.h"
@@ -3521,6 +3522,8 @@ static uiBlock *view3d_edit_armaturemenu(void *arg_unused)
static void do_view3d_pose_armature_transformmenu(void *arg, int event)
{
Object *ob= OBACT;
switch(event) {
case 0: /* clear origin */
clear_object('o');
@@ -3534,6 +3537,11 @@ static void do_view3d_pose_armature_transformmenu(void *arg, int event)
case 3: /* clear location */
clear_object('g');
break;
case 4: /* clear pose */
rest_pose(ob->pose);
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
BIF_undo_push("Clear Pose");
break;
}
allqueue(REDRAWVIEW3D, 0);
}
@@ -3546,6 +3554,8 @@ static uiBlock *view3d_pose_armature_transformmenu(void *arg_unused)
block= uiNewBlock(&curarea->uiblocks, "view3d_pose_armature_transformmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
uiBlockSetButmFunc(block, do_view3d_pose_armature_transformmenu, NULL);
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Pose|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Location|Alt G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Rotation|Alt R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Scale|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");

View File

@@ -1419,6 +1419,7 @@ static void ui_is_but_sel(uiBut *but)
case TOG:
case TOGR:
case TOG3:
case BUT_TOGDUAL:
case ICONTOG:
if(value!=but->min) push= 1;
break;
@@ -1501,12 +1502,20 @@ static int ui_do_but_KEYEVT(uiBut *but)
return (event!=0);
}
static int ui_do_but_TOG(uiBlock *block, uiBut *but)
static int ui_do_but_TOG(uiBlock *block, uiBut *but, int qual)
{
uiBut *bt;
double value;
int w, lvalue, push;
/* local hack... */
if(but->type==BUT_TOGDUAL && qual) {
if(but->pointype==SHO)
but->poin += 2;
else if(but->pointype==INT)
but->poin += 4;
}
value= ui_get_but_val(but);
lvalue= (int)value;
@@ -1534,6 +1543,7 @@ static int ui_do_but_TOG(uiBlock *block, uiBut *but)
if(lvalue==0) lvalue= 1<<(but->bitnr);
}
}
ui_set_but_val(but, (double)lvalue);
if(but->type==ICONTOG) ui_check_but(but);
// no frontbuffer draw for this one
@@ -1551,6 +1561,14 @@ static int ui_do_but_TOG(uiBlock *block, uiBut *but)
if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
}
/* end local hack... */
if(but->type==BUT_TOGDUAL && qual) {
if(but->pointype==SHO)
but->poin -= 2;
else if(but->pointype==INT)
but->poin -= 2;
}
/* no while loop...this button is used for viewmove */
uibut_do_func(but);
@@ -3817,8 +3835,9 @@ static int ui_do_button(uiBlock *block, uiBut *but, uiEvent *uevent)
case TOGR:
case ICONTOG:
case TOGN:
case BUT_TOGDUAL:
if(uevent->val) {
retval= ui_do_but_TOG(block, but);
retval= ui_do_but_TOG(block, but, uevent->qual);
}
break;
@@ -5483,6 +5502,7 @@ static int ui_auto_themecol(uiBut *but)
case TOG3:
case TOGR:
case TOGN:
case BUT_TOGDUAL:
return TH_BUT_SETTING;
case SLI:
case NUM:

View File

@@ -1507,6 +1507,18 @@ static void ui_draw_text_icon(uiBut *but)
}
}
}
if(but->type==BUT_TOGDUAL) {
int dualset= 0;
if(but->pointype==SHO)
dualset= BTST( *(((short *)but->poin)+1), but->bitnr);
else if(but->pointype==INT)
dualset= BTST( *(((int *)but->poin)+1), but->bitnr);
if(dualset) {
ui_draw_icon(but, ICON_DOT);
}
}
if(but->drawstr[0]!=0) {
int transopts;
int tog3= 0;

View File

@@ -432,6 +432,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
{
Object *ob= (Object *)id;
if(ob->proxy && ob->id.lib==NULL)
outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0);
if(ob->pose) {
@@ -566,7 +569,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
if(ob->dup_group)
outliner_add_element(soops, &te->subtree, ob->dup_group, te, 0, 0);
if(ob->nlastrips.first) {
bActionStrip *strip;
TreeElement *ten;
@@ -2628,6 +2631,8 @@ static void tselem_draw_icon(float x, float y, TreeStoreElem *tselem, TreeElemen
BIF_icon_draw(x, y, ICON_ARMATURE_DEHLT); break;
case TSE_POSE_CHANNEL:
BIF_icon_draw(x, y, ICON_WPAINT_DEHLT); break;
case TSE_PROXY:
BIF_icon_draw(x, y, ICON_GHOST); break;
#ifdef WITH_VERSE
case ID_VS:
case ID_MS:

View File

@@ -323,7 +323,7 @@ void pose_special_editmenu(void)
if(!ob && !ob->pose) return;
if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
nr= pupmenu("Specials%t|Select Constraint Target%x1|Flip Left-Right Names%x2|Calculate Paths%x3|Clear All Paths%x4");
nr= pupmenu("Specials%t|Select Constraint Target%x1|Flip Left-Right Names%x2|Calculate Paths%x3|Clear All Paths%x4|Clear Pose %x5");
if(nr==1) {
pose_select_constraint_target();
}
@@ -336,6 +336,11 @@ void pose_special_editmenu(void)
else if(nr==4) {
pose_clear_paths(ob);
}
else if(nr==5) {
rest_pose(ob->pose);
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
BIF_undo_push("Clear Pose");
}
}
void pose_add_IK(void)

View File

@@ -1783,6 +1783,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
}
else if(G.qual==LR_ALTKEY)
clear_parent();
else if(G.qual==(LR_ALTKEY|LR_CTRLKEY))
make_proxy();
else if((G.qual==0) && (OBACT) && (OBACT->type==OB_ARMATURE) && (OBACT->flag & OB_POSEMODE))
select_bone_parent();
else if((G.qual==0)) {

View File

@@ -322,21 +322,23 @@ void recalcData(TransInfo *t)
}
else {
for(base= FIRSTBASE; base; base= base->next) {
Object *ob= base->object;
/* this flag is from depgraph, was stored in nitialize phase, handled in drawview.c */
if(base->flag & BA_HAS_RECALC_OB)
base->object->recalc |= OB_RECALC_OB;
ob->recalc |= OB_RECALC_OB;
if(base->flag & BA_HAS_RECALC_DATA)
base->object->recalc |= OB_RECALC_DATA;
ob->recalc |= OB_RECALC_DATA;
/* thanks to ob->ctime usage, ipos are not called in where_is_object,
unless we edit ipokeys */
if(base->flag & BA_DO_IPO) {
if(base->object->ipo) {
if(ob->ipo) {
IpoCurve *icu;
base->object->ctime= -1234567.0;
ob->ctime= -1234567.0;
icu= base->object->ipo->curve.first;
icu= ob->ipo->curve.first;
while(icu) {
calchandles_ipocurve(icu);
icu= icu->next;
@@ -345,10 +347,14 @@ void recalcData(TransInfo *t)
}
/* softbody exception */
if(modifiers_isSoftbodyEnabled(base->object)) {
if(base->object->recalc & OB_RECALC_DATA)
base->object->softflag |= OB_SB_REDO;
if(modifiers_isSoftbodyEnabled(ob)) {
if(ob->recalc & OB_RECALC_DATA)
ob->softflag |= OB_SB_REDO;
}
/* proxy exception */
if(ob->proxy)
ob->proxy->recalc |= ob->recalc;
}
}