diff options
23 files changed, 342 insertions, 47 deletions
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 01984eb9cba..e848ef0a11b 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -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) */ diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index bbaf42a91b1..26f129ae2a5 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -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); diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 17910c01fa3..9f42e682e82 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -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 { diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 9462c508084..251a14fd4b3 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -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 */ diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index afe40b20893..726ce3eeba6 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -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) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 3a01daeca1a..0685bc268d4 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -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; } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index ddbacb1ef23..fd80536dea1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -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); diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index e92101e10e7..5577c7aa8a6 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -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); } diff --git a/source/blender/include/BDR_editobject.h b/source/blender/include/BDR_editobject.h index b86209f46f6..4a175728d99 100644 --- a/source/blender/include/BDR_editobject.h +++ b/source/blender/include/BDR_editobject.h @@ -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) diff --git a/source/blender/include/BIF_interface.h b/source/blender/include/BIF_interface.h index 41a5bc5e5a1..0f263096792 100644 --- a/source/blender/include/BIF_interface.h +++ b/source/blender/include/BIF_interface.h @@ -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) diff --git a/source/blender/include/BIF_outliner.h b/source/blender/include/BIF_outliner.h index 4d281e08c14..dc71d02970c 100644 --- a/source/blender/include/BIF_outliner.h +++ b/source/blender/include/BIF_outliner.h @@ -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 diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 2c6122198b8..d27dc391f24 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -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; diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index 0b59173afa7..cfcdd4ec959 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -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 */ diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index ef43ab72dfc..8a4ef6cda37 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -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; diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 48c73d2eaf0..07c02e279d2 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -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)); } diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index f2ed963dfb5..57802d3eb3e 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -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 */ diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index a7032aefea6..c3d57d7e2d7 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -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, ""); diff --git a/source/blender/src/interface.c b/source/blender/src/interface.c index 10c97f1f894..7e94ede8fd4 100644 --- a/source/blender/src/interface.c +++ b/source/blender/src/interface.c @@ -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: diff --git a/source/blender/src/interface_draw.c b/source/blender/src/interface_draw.c index 58ca38ec30c..b91a8f83b64 100644 --- a/source/blender/src/interface_draw.c +++ b/source/blender/src/interface_draw.c @@ -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; diff --git a/source/blender/src/outliner.c b/source/blender/src/outliner.c index 1f15bb62205..01eb93c9f60 100644 --- a/source/blender/src/outliner.c +++ b/source/blender/src/outliner.c @@ -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: diff --git a/source/blender/src/poseobject.c b/source/blender/src/poseobject.c index cce2e3705a3..f1d7761fa6c 100644 --- a/source/blender/src/poseobject.c +++ b/source/blender/src/poseobject.c @@ -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) diff --git a/source/blender/src/space.c b/source/blender/src/space.c index 059f4959f76..26720f825b3 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -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)) { diff --git a/source/blender/src/transform_generics.c b/source/blender/src/transform_generics.c index 8b75586442b..f9e75d2336a 100755 --- a/source/blender/src/transform_generics.c +++ b/source/blender/src/transform_generics.c @@ -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; } } |