Blender V2.61 - r43446

object_relations.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Blender Foundation, 2002-2008 full recode
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 
00035 #include "MEM_guardedalloc.h"
00036 
00037 #include "DNA_anim_types.h"
00038 #include "DNA_constraint_types.h"
00039 #include "DNA_group_types.h"
00040 #include "DNA_lamp_types.h"
00041 #include "DNA_lattice_types.h"
00042 #include "DNA_material_types.h"
00043 #include "DNA_meta_types.h"
00044 #include "DNA_particle_types.h"
00045 #include "DNA_scene_types.h"
00046 #include "DNA_speaker_types.h"
00047 #include "DNA_world_types.h"
00048 #include "DNA_object_types.h"
00049 
00050 #include "BLI_math.h"
00051 #include "BLI_editVert.h"
00052 #include "BLI_listbase.h"
00053 #include "BLI_string.h"
00054 #include "BLI_utildefines.h"
00055 
00056 #include "BKE_action.h"
00057 #include "BKE_animsys.h"
00058 #include "BKE_armature.h"
00059 #include "BKE_camera.h"
00060 #include "BKE_context.h"
00061 #include "BKE_constraint.h"
00062 #include "BKE_curve.h"
00063 #include "BKE_depsgraph.h"
00064 #include "BKE_DerivedMesh.h"
00065 #include "BKE_displist.h"
00066 #include "BKE_global.h"
00067 #include "BKE_fcurve.h"
00068 #include "BKE_lamp.h"
00069 #include "BKE_lattice.h"
00070 #include "BKE_library.h"
00071 #include "BKE_main.h"
00072 #include "BKE_material.h"
00073 #include "BKE_mball.h"
00074 #include "BKE_mesh.h"
00075 #include "BKE_modifier.h"
00076 #include "BKE_object.h"
00077 #include "BKE_report.h"
00078 #include "BKE_sca.h"
00079 #include "BKE_scene.h"
00080 #include "BKE_speaker.h"
00081 #include "BKE_texture.h"
00082 
00083 #include "WM_api.h"
00084 #include "WM_types.h"
00085 
00086 #include "UI_interface.h"
00087 #include "UI_resources.h"
00088 
00089 #include "RNA_access.h"
00090 #include "RNA_define.h"
00091 #include "RNA_enum_types.h"
00092 
00093 #include "ED_armature.h"
00094 #include "ED_curve.h"
00095 #include "ED_keyframing.h"
00096 #include "ED_object.h"
00097 #include "ED_screen.h"
00098 #include "ED_view3d.h"
00099 #include "ED_mesh.h"
00100 
00101 #include "object_intern.h"
00102 
00103 /*********************** Make Vertex Parent Operator ************************/
00104 
00105 static int vertex_parent_set_poll(bContext *C)
00106 {
00107     return ED_operator_editmesh(C) || ED_operator_editsurfcurve(C) || ED_operator_editlattice(C);
00108 }
00109 
00110 static int vertex_parent_set_exec(bContext *C, wmOperator *op)
00111 {
00112     Main *bmain= CTX_data_main(C);
00113     Scene *scene= CTX_data_scene(C);
00114     Object *obedit= CTX_data_edit_object(C);
00115     EditVert *eve;
00116     Curve *cu;
00117     Nurb *nu;
00118     BezTriple *bezt;
00119     BPoint *bp;
00120     Object *par;
00121     int a, v1=0, v2=0, v3=0, v4=0, nr=1;
00122     
00123     /* we need 1 to 3 selected vertices */
00124     
00125     if(obedit->type==OB_MESH) {
00126         Mesh *me= obedit->data;
00127         EditMesh *em;
00128 
00129         load_editMesh(scene, obedit);
00130         make_editMesh(scene, obedit);
00131 
00132         em= BKE_mesh_get_editmesh(me);
00133 
00134         /* derivedMesh might be needed for solving parenting,
00135            so re-create it here */
00136         makeDerivedMesh(scene, obedit, em, CD_MASK_BAREMESH);
00137 
00138         eve= em->verts.first;
00139         while(eve) {
00140             if(eve->f & 1) {
00141                 if(v1==0) v1= nr;
00142                 else if(v2==0) v2= nr;
00143                 else if(v3==0) v3= nr;
00144                 else if(v4==0) v4= nr;
00145                 else break;
00146             }
00147             nr++;
00148             eve= eve->next;
00149         }
00150 
00151         BKE_mesh_end_editmesh(me, em);
00152     }
00153     else if(ELEM(obedit->type, OB_SURF, OB_CURVE)) {
00154         ListBase *editnurb= object_editcurve_get(obedit);
00155         
00156         cu= obedit->data;
00157 
00158         nu= editnurb->first;
00159         while(nu) {
00160             if(nu->type == CU_BEZIER) {
00161                 bezt= nu->bezt;
00162                 a= nu->pntsu;
00163                 while(a--) {
00164                     if(BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
00165                         if(v1==0) v1= nr;
00166                         else if(v2==0) v2= nr;
00167                         else if(v3==0) v3= nr;
00168                         else if(v4==0) v4= nr;
00169                         else break;
00170                     }
00171                     nr++;
00172                     bezt++;
00173                 }
00174             }
00175             else {
00176                 bp= nu->bp;
00177                 a= nu->pntsu*nu->pntsv;
00178                 while(a--) {
00179                     if(bp->f1 & SELECT) {
00180                         if(v1==0) v1= nr;
00181                         else if(v2==0) v2= nr;
00182                         else if(v3==0) v3= nr;
00183                         else if(v4==0) v4= nr;
00184                         else break;
00185                     }
00186                     nr++;
00187                     bp++;
00188                 }
00189             }
00190             nu= nu->next;
00191         }
00192     }
00193     else if(obedit->type==OB_LATTICE) {
00194         Lattice *lt= obedit->data;
00195         
00196         a= lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw;
00197         bp= lt->editlatt->latt->def;
00198         while(a--) {
00199             if(bp->f1 & SELECT) {
00200                 if(v1==0) v1= nr;
00201                 else if(v2==0) v2= nr;
00202                 else if(v3==0) v3= nr;
00203                 else if(v4==0) v4= nr;
00204                 else break;
00205             }
00206             nr++;
00207             bp++;
00208         }
00209     }
00210     
00211     if(v4 || !((v1 && v2==0 && v3==0) || (v1 && v2 && v3)) ) {
00212         BKE_report(op->reports, RPT_ERROR, "Select either 1 or 3 vertices to parent to");
00213         return OPERATOR_CANCELLED;
00214     }
00215     
00216     CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00217         if(ob != obedit) {
00218             ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
00219             par= obedit->parent;
00220             
00221             while(par) {
00222                 if(par==ob) break;
00223                 par= par->parent;
00224             }
00225             if(par) {
00226                 BKE_report(op->reports, RPT_ERROR, "Loop in parents");
00227             }
00228             else {
00229                 Object workob;
00230                 
00231                 ob->parent= BASACT->object;
00232                 if(v3) {
00233                     ob->partype= PARVERT3;
00234                     ob->par1= v1-1;
00235                     ob->par2= v2-1;
00236                     ob->par3= v3-1;
00237 
00238                     /* inverse parent matrix */
00239                     what_does_parent(scene, ob, &workob);
00240                     invert_m4_m4(ob->parentinv, workob.obmat);
00241                 }
00242                 else {
00243                     ob->partype= PARVERT1;
00244                     ob->par1= v1-1;
00245 
00246                     /* inverse parent matrix */
00247                     what_does_parent(scene, ob, &workob);
00248                     invert_m4_m4(ob->parentinv, workob.obmat);
00249                 }
00250             }
00251         }
00252     }
00253     CTX_DATA_END;
00254     
00255     DAG_scene_sort(bmain, scene);
00256 
00257     WM_event_add_notifier(C, NC_OBJECT, NULL);
00258 
00259     return OPERATOR_FINISHED;
00260 }
00261 
00262 void OBJECT_OT_vertex_parent_set(wmOperatorType *ot)
00263 {
00264     /* identifiers */
00265     ot->name= "Make Vertex Parent";
00266     ot->description = "Parent selected objects to the selected vertices";
00267     ot->idname= "OBJECT_OT_vertex_parent_set";
00268     
00269     /* api callbacks */
00270     ot->invoke= WM_operator_confirm;
00271     ot->poll= vertex_parent_set_poll;
00272     ot->exec= vertex_parent_set_exec;
00273     
00274     /* flags */
00275     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00276 }
00277 
00278 /********************** Make Proxy Operator *************************/
00279 
00280 /* set the object to proxify */
00281 static int make_proxy_invoke (bContext *C, wmOperator *op, wmEvent *evt)
00282 {
00283     Scene *scene= CTX_data_scene(C);
00284     Object *ob= ED_object_active_context(C);
00285     
00286     /* sanity checks */
00287     if (!scene || scene->id.lib || !ob)
00288         return OPERATOR_CANCELLED;
00289         
00290     /* Get object to work on - use a menu if we need to... */
00291     if (ob->dup_group && ob->dup_group->id.lib) {
00292         /* gives menu with list of objects in group */
00293         //proxy_group_objects_menu(C, op, ob, ob->dup_group);
00294         WM_enum_search_invoke(C, op, evt);
00295         return OPERATOR_CANCELLED;
00296 
00297     }
00298     else if (ob->id.lib) {
00299         uiPopupMenu *pup= uiPupMenuBegin(C, "OK?", ICON_QUESTION);
00300         uiLayout *layout= uiPupMenuLayout(pup);
00301         
00302         /* create operator menu item with relevant properties filled in */
00303         uiItemFullO(layout, op->idname, op->type->name, ICON_NONE, NULL, WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS);
00304         
00305         /* present the menu and be done... */
00306         uiPupMenuEnd(C, pup);
00307     }
00308     else {
00309         /* error.. cannot continue */
00310         BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or group");
00311     }
00312     
00313     /* this invoke just calls another instance of this operator... */
00314     return OPERATOR_CANCELLED;
00315 }
00316 
00317 static int make_proxy_exec (bContext *C, wmOperator *op)
00318 {
00319     Main *bmain= CTX_data_main(C);
00320     Object *ob, *gob= ED_object_active_context(C);
00321     GroupObject *go;
00322     Scene *scene= CTX_data_scene(C);
00323 
00324     if (gob->dup_group != NULL)
00325     {
00326         go= BLI_findlink(&gob->dup_group->gobject, RNA_enum_get(op->ptr, "type"));
00327         ob= go->ob;
00328     }
00329     else
00330     {
00331         ob= gob;
00332         gob = NULL;
00333     }
00334     
00335     if (ob) {
00336         Object *newob;
00337         Base *newbase, *oldbase= BASACT;
00338         char name[MAX_ID_NAME+4];
00339         
00340         /* Add new object for the proxy */
00341         newob= add_object(scene, OB_EMPTY);
00342 
00343         BLI_snprintf(name, sizeof(name), "%s_proxy", ((ID *)(gob ? gob : ob))->name+2);
00344 
00345         rename_id(&newob->id, name);
00346         
00347         /* set layers OK */
00348         newbase= BASACT;    /* add_object sets active... */
00349         newbase->lay= oldbase->lay;
00350         newob->lay= newbase->lay;
00351         
00352         /* remove base, leave user count of object, it gets linked in object_make_proxy */
00353         if (gob==NULL) {
00354             BLI_remlink(&scene->base, oldbase);
00355             MEM_freeN(oldbase);
00356         }
00357         
00358         object_make_proxy(newob, ob, gob);
00359         
00360         /* depsgraph flushes are needed for the new data */
00361         DAG_scene_sort(bmain, scene);
00362         DAG_id_tag_update(&newob->id, OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME);
00363         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, newob);
00364     }
00365     else {
00366         BKE_report(op->reports, RPT_ERROR, "No object to make proxy for");
00367         return OPERATOR_CANCELLED;
00368     }
00369     
00370     return OPERATOR_FINISHED;
00371 }
00372 
00373 /* Generic itemf's for operators that take library args */
00374 static EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
00375 {
00376     EnumPropertyItem item_tmp= {0}, *item= NULL;
00377     int totitem= 0;
00378     int i= 0;
00379     Object *ob= ED_object_active_context(C);
00380     GroupObject *go;
00381 
00382     if(!ob || !ob->dup_group)
00383         return DummyRNA_DEFAULT_items;
00384 
00385     /* find the object to affect */
00386     for (go= ob->dup_group->gobject.first; go; go= go->next) {
00387         item_tmp.identifier= item_tmp.name= go->ob->id.name+2;
00388         item_tmp.value= i++;
00389         RNA_enum_item_add(&item, &totitem, &item_tmp);
00390     }
00391 
00392     RNA_enum_item_end(&item, &totitem);
00393     *free= 1;
00394 
00395     return item;
00396 }
00397 
00398 void OBJECT_OT_proxy_make (wmOperatorType *ot)
00399 {
00400     PropertyRNA *prop;
00401 
00402     /* identifiers */
00403     ot->name= "Make Proxy";
00404     ot->idname= "OBJECT_OT_proxy_make";
00405     ot->description= "Add empty object to become local replacement data of a library-linked object";
00406     
00407     /* callbacks */
00408     ot->invoke= make_proxy_invoke;
00409     ot->exec= make_proxy_exec;
00410     ot->poll= ED_operator_object_active;
00411     
00412     /* flags */
00413     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00414     
00415     /* properties */
00416     RNA_def_string(ot->srna, "object", "", MAX_ID_NAME-2, "Proxy Object", "Name of lib-linked/grouped object to make a proxy for");
00417     prop= RNA_def_enum(ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Type", "Group object"); /* XXX, relies on hard coded ID at the moment */
00418     RNA_def_enum_funcs(prop, proxy_group_object_itemf);
00419     ot->prop= prop;
00420 }
00421 
00422 /********************** Clear Parent Operator ******************* */
00423 
00424 static EnumPropertyItem prop_clear_parent_types[] = {
00425     {0, "CLEAR", 0, "Clear Parent", ""},
00426     {1, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation", ""},
00427     {2, "CLEAR_INVERSE", 0, "Clear Parent Inverse", ""},
00428     {0, NULL, 0, NULL, NULL}
00429 };
00430 
00431 /* note, poll should check for editable scene */
00432 static int parent_clear_exec(bContext *C, wmOperator *op)
00433 {
00434     Main *bmain= CTX_data_main(C);
00435     Scene *scene= CTX_data_scene(C);
00436     int type= RNA_enum_get(op->ptr, "type");
00437     
00438     CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00439 
00440         if(ob->parent == NULL)
00441             continue;
00442         
00443         if(type == 0) {
00444             ob->parent= NULL;
00445         }           
00446         else if(type == 1) {
00447             ob->parent= NULL;
00448             object_apply_mat4(ob, ob->obmat, TRUE, FALSE);
00449         }
00450         else if(type == 2)
00451             unit_m4(ob->parentinv);
00452 
00453         ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
00454     }
00455     CTX_DATA_END;
00456     
00457     DAG_scene_sort(bmain, scene);
00458     DAG_ids_flush_update(bmain, 0);
00459     WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00460     WM_event_add_notifier(C, NC_OBJECT|ND_PARENT, NULL);
00461 
00462     return OPERATOR_FINISHED;
00463 }
00464 
00465 void OBJECT_OT_parent_clear(wmOperatorType *ot)
00466 {
00467     /* identifiers */
00468     ot->name= "Clear Parent";
00469     ot->description = "Clear the object's parenting";
00470     ot->idname= "OBJECT_OT_parent_clear";
00471     
00472     /* api callbacks */
00473     ot->invoke= WM_menu_invoke;
00474     ot->exec= parent_clear_exec;
00475     
00476     ot->poll= ED_operator_object_active_editable;
00477     
00478     /* flags */
00479     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00480     
00481     ot->prop= RNA_def_enum(ot->srna, "type", prop_clear_parent_types, 0, "Type", "");
00482 }
00483 
00484 /* ******************** Make Parent Operator *********************** */
00485 
00486 #define PAR_OBJECT              0
00487 #define PAR_ARMATURE            1
00488 #define PAR_ARMATURE_NAME       2
00489 #define PAR_ARMATURE_ENVELOPE   3
00490 #define PAR_ARMATURE_AUTO       4
00491 #define PAR_BONE                5
00492 #define PAR_CURVE               6
00493 #define PAR_FOLLOW              7
00494 #define PAR_PATH_CONST          8
00495 #define PAR_LATTICE             9
00496 #define PAR_VERTEX              10
00497 #define PAR_TRIA                11
00498 
00499 static EnumPropertyItem prop_make_parent_types[] = {
00500     {PAR_OBJECT, "OBJECT", 0, "Object", ""},
00501     {PAR_ARMATURE, "ARMATURE", 0, "Armature Deform", ""},
00502     {PAR_ARMATURE_NAME, "ARMATURE_NAME", 0, "   With Empty Groups", ""},
00503     {PAR_ARMATURE_AUTO, "ARMATURE_AUTO", 0, "   With Automatic Weights", ""},
00504     {PAR_ARMATURE_ENVELOPE, "ARMATURE_ENVELOPE", 0, "   With Envelope Weights", ""},
00505     {PAR_BONE, "BONE", 0, "Bone", ""},
00506     {PAR_CURVE, "CURVE", 0, "Curve Deform", ""},
00507     {PAR_FOLLOW, "FOLLOW", 0, "Follow Path", ""},
00508     {PAR_PATH_CONST, "PATH_CONST", 0, "Path Constraint", ""},
00509     {PAR_LATTICE, "LATTICE", 0, "Lattice Deform", ""},
00510     {PAR_VERTEX, "VERTEX", 0, "Vertex", ""},
00511     {PAR_TRIA, "TRIA", 0, "Triangle", ""},
00512     {0, NULL, 0, NULL, NULL}
00513 };
00514 
00515 void ED_object_parent(Object *ob, Object *par, int type, const char *substr)
00516 {
00517     if (!par || BKE_object_parent_loop_check(par, ob)) {
00518         ob->parent= NULL;
00519         ob->partype= PAROBJECT;
00520         ob->parsubstr[0]= 0;
00521         return;
00522     }
00523 
00524     /* this could use some more checks */
00525 
00526     ob->parent= par;
00527     ob->partype &= ~PARTYPE;
00528     ob->partype |= type;
00529     BLI_strncpy(ob->parsubstr, substr, sizeof(ob->parsubstr));
00530 }
00531 
00532 static int parent_set_exec(bContext *C, wmOperator *op)
00533 {
00534     Main *bmain= CTX_data_main(C);
00535     Scene *scene= CTX_data_scene(C);
00536     Object *par= ED_object_active_context(C);
00537     bPoseChannel *pchan= NULL;
00538     int partype= RNA_enum_get(op->ptr, "type");
00539     int pararm= ELEM4(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
00540     
00541     par->recalc |= OB_RECALC_OB;
00542     
00543     /* preconditions */
00544     if(partype==PAR_FOLLOW || partype==PAR_PATH_CONST) {
00545         if(par->type!=OB_CURVE)
00546             return OPERATOR_CANCELLED;
00547         else {
00548             Curve *cu= par->data;
00549             
00550             if((cu->flag & CU_PATH)==0) {
00551                 cu->flag |= CU_PATH|CU_FOLLOW;
00552                 makeDispListCurveTypes(scene, par, 0);  /* force creation of path data */
00553             }
00554             else cu->flag |= CU_FOLLOW;
00555             
00556             /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */
00557             if(partype == PAR_FOLLOW) {
00558                 /* get or create F-Curve */
00559                 bAction *act = verify_adt_action(&cu->id, 1);
00560                 FCurve *fcu = verify_fcurve(act, NULL, "eval_time", 0, 1);
00561                 
00562                 /* setup dummy 'generator' modifier here to get 1-1 correspondance still working */
00563                 if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first)
00564                     add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
00565             }
00566             
00567             /* fall back on regular parenting now (for follow only) */
00568             if(partype == PAR_FOLLOW)
00569                 partype= PAR_OBJECT;
00570         }       
00571     }
00572     else if(partype==PAR_BONE) {
00573         pchan= get_active_posechannel(par);
00574         
00575         if(pchan==NULL) {
00576             BKE_report(op->reports, RPT_ERROR, "No active Bone");
00577             return OPERATOR_CANCELLED;
00578         }
00579     }
00580     
00581     /* context iterator */
00582     CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00583         
00584         if(ob!=par) {
00585             
00586             if (BKE_object_parent_loop_check(par, ob)) {
00587                 BKE_report(op->reports, RPT_ERROR, "Loop in parents");
00588             }
00589             else {
00590                 Object workob;
00591                 
00592                 /* apply transformation of previous parenting */
00593                 /* object_apply_mat4(ob, ob->obmat); */ /* removed because of bug [#23577] */
00594 
00595                 /* set the parent (except for follow-path constraint option) */
00596                 if(partype != PAR_PATH_CONST)
00597                     ob->parent= par;
00598                 
00599                 /* handle types */
00600                 if (pchan)
00601                     BLI_strncpy(ob->parsubstr, pchan->name, sizeof(ob->parsubstr));
00602                 else
00603                     ob->parsubstr[0]= 0;
00604                     
00605                 if(partype == PAR_PATH_CONST)
00606                     ; /* don't do anything here, since this is not technically "parenting" */
00607                 else if( ELEM(partype, PAR_CURVE, PAR_LATTICE) || pararm )
00608                 {
00609                     /* partype is now set to PAROBJECT so that invisible 'virtual' modifiers don't need to be created
00610                      * NOTE: the old (2.4x) method was to set ob->partype = PARSKEL, creating the virtual modifiers
00611                      */
00612                     ob->partype= PAROBJECT; /* note, dna define, not operator property */
00613                     //ob->partype= PARSKEL; /* note, dna define, not operator property */
00614                     
00615                     /* BUT, to keep the deforms, we need a modifier, and then we need to set the object that it uses */
00616                     // XXX currently this should only happen for meshes, curves, surfaces, and lattices - this stuff isn't available for metas yet
00617                     if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) 
00618                     {
00619                         ModifierData *md;
00620 
00621                         switch (partype) {
00622                         case PAR_CURVE: /* curve deform */
00623                             md= ED_object_modifier_add(op->reports, bmain, scene, ob, NULL, eModifierType_Curve);
00624                             ((CurveModifierData *)md)->object= par;
00625                             break;
00626                         case PAR_LATTICE: /* lattice deform */
00627                             md= ED_object_modifier_add(op->reports, bmain, scene, ob, NULL, eModifierType_Lattice);
00628                             ((LatticeModifierData *)md)->object= par;
00629                             break;
00630                         default: /* armature deform */
00631                             md= ED_object_modifier_add(op->reports, bmain, scene, ob, NULL, eModifierType_Armature);
00632                             ((ArmatureModifierData *)md)->object= par;
00633                             break;
00634                         }
00635                     }
00636                 }
00637                 else if (partype == PAR_BONE)
00638                     ob->partype= PARBONE; /* note, dna define, not operator property */
00639                 else
00640                     ob->partype= PAROBJECT; /* note, dna define, not operator property */
00641                 
00642                 /* constraint */
00643                 if(partype == PAR_PATH_CONST) {
00644                     bConstraint *con;
00645                     bFollowPathConstraint *data;
00646                     float cmat[4][4], vec[3];
00647                     
00648                     con = add_ob_constraint(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH);
00649                     
00650                     data = con->data;
00651                     data->tar = par;
00652                     
00653                     get_constraint_target_matrix(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra);
00654                     sub_v3_v3v3(vec, ob->obmat[3], cmat[3]);
00655                     
00656                     ob->loc[0] = vec[0];
00657                     ob->loc[1] = vec[1];
00658                     ob->loc[2] = vec[2];
00659                 }
00660                 else if(pararm && ob->type==OB_MESH && par->type == OB_ARMATURE) {
00661                     if(partype == PAR_ARMATURE_NAME)
00662                         create_vgroups_from_armature(op->reports, scene, ob, par, ARM_GROUPS_NAME, 0);
00663                     else if(partype == PAR_ARMATURE_ENVELOPE)
00664                         create_vgroups_from_armature(op->reports, scene, ob, par, ARM_GROUPS_ENVELOPE, 0);
00665                     else if(partype == PAR_ARMATURE_AUTO) {
00666                         WM_cursor_wait(1);
00667                         create_vgroups_from_armature(op->reports, scene, ob, par, ARM_GROUPS_AUTO, 0);
00668                         WM_cursor_wait(0);
00669                     }
00670                     /* get corrected inverse */
00671                     ob->partype= PAROBJECT;
00672                     what_does_parent(scene, ob, &workob);
00673                     
00674                     invert_m4_m4(ob->parentinv, workob.obmat);
00675                 }
00676                 else {
00677                     /* calculate inverse parent matrix */
00678                     what_does_parent(scene, ob, &workob);
00679                     invert_m4_m4(ob->parentinv, workob.obmat);
00680                 }
00681                 
00682                 ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
00683             }
00684         }
00685     }
00686     CTX_DATA_END;
00687     
00688     DAG_scene_sort(bmain, scene);
00689     DAG_ids_flush_update(bmain, 0);
00690     WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00691     WM_event_add_notifier(C, NC_OBJECT|ND_PARENT, NULL);
00692     
00693     return OPERATOR_FINISHED;
00694 }
00695 
00696 static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
00697 {
00698     Object *ob= ED_object_active_context(C);
00699     uiPopupMenu *pup= uiPupMenuBegin(C, "Set Parent To", ICON_NONE);
00700     uiLayout *layout= uiPupMenuLayout(pup);
00701     
00702     uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
00703     uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_OBJECT);
00704     
00705     /* ob becomes parent, make the associated menus */
00706     if(ob->type==OB_ARMATURE) {
00707         uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_ARMATURE);
00708         uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_ARMATURE_NAME);
00709         uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_ARMATURE_ENVELOPE);
00710         uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_ARMATURE_AUTO);
00711         uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_BONE);
00712     }
00713     else if(ob->type==OB_CURVE) {
00714         uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_CURVE);
00715         uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_FOLLOW);
00716         uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_PATH_CONST);
00717     }
00718     else if(ob->type == OB_LATTICE) {
00719         uiItemEnumO(layout, "OBJECT_OT_parent_set", NULL, 0, "type", PAR_LATTICE);
00720     }
00721     
00722     uiPupMenuEnd(C, pup);
00723     
00724     return OPERATOR_CANCELLED;
00725 }
00726 
00727 
00728 void OBJECT_OT_parent_set(wmOperatorType *ot)
00729 {
00730     /* identifiers */
00731     ot->name= "Make Parent";
00732     ot->description = "Set the object's parenting";
00733     ot->idname= "OBJECT_OT_parent_set";
00734     
00735     /* api callbacks */
00736     ot->invoke= parent_set_invoke;
00737     ot->exec= parent_set_exec;
00738     
00739     ot->poll= ED_operator_object_active;
00740     
00741     /* flags */
00742     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00743     
00744     RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
00745 }
00746 
00747 /* ************ Make Parent Without Inverse Operator ******************* */
00748 
00749 static int parent_noinv_set_exec(bContext *C, wmOperator *op)
00750 {
00751     Main *bmain= CTX_data_main(C);
00752     Object *par= ED_object_active_context(C);
00753     
00754     par->recalc |= OB_RECALC_OB;
00755     
00756     /* context iterator */
00757     CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00758         if (ob != par) {
00759             if (BKE_object_parent_loop_check(par, ob)) {
00760                 BKE_report(op->reports, RPT_ERROR, "Loop in parents");
00761             }
00762             else {
00763                 /* clear inverse matrix and also the object location */
00764                 unit_m4(ob->parentinv);
00765                 memset(ob->loc, 0, 3*sizeof(float));
00766                 
00767                 /* set recalc flags */
00768                 ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
00769                 
00770                 /* set parenting type for object - object only... */
00771                 ob->parent= par;
00772                 ob->partype= PAROBJECT; /* note, dna define, not operator property */
00773             }
00774         }
00775     }
00776     CTX_DATA_END;
00777     
00778     DAG_scene_sort(bmain, CTX_data_scene(C));
00779     DAG_ids_flush_update(bmain, 0);
00780     WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00781     
00782     return OPERATOR_FINISHED;
00783 }
00784 
00785 void OBJECT_OT_parent_no_inverse_set(wmOperatorType *ot)
00786 {
00787     /* identifiers */
00788     ot->name= "Make Parent without Inverse";
00789     ot->description = "Set the object's parenting without setting the inverse parent correction";
00790     ot->idname= "OBJECT_OT_parent_no_inverse_set";
00791     
00792     /* api callbacks */
00793     ot->invoke= WM_operator_confirm;
00794     ot->exec= parent_noinv_set_exec;
00795     ot->poll= ED_operator_object_active_editable;
00796     
00797     /* flags */
00798     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00799 }
00800 
00801 /************************ Clear Slow Parent Operator *********************/
00802 
00803 static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
00804 {
00805     Main *bmain= CTX_data_main(C);
00806     Scene *scene= CTX_data_scene(C);
00807 
00808     CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00809         if(ob->parent) {
00810             if(ob->partype & PARSLOW) {
00811                 ob->partype -= PARSLOW;
00812                 where_is_object(scene, ob);
00813                 ob->partype |= PARSLOW;
00814                 ob->recalc |= OB_RECALC_OB;
00815             }
00816         }
00817     }
00818     CTX_DATA_END;
00819 
00820     DAG_ids_flush_update(bmain, 0);
00821     WM_event_add_notifier(C, NC_SCENE, scene);
00822     
00823     return OPERATOR_FINISHED;
00824 }
00825 
00826 void OBJECT_OT_slow_parent_clear(wmOperatorType *ot)
00827 {
00828     
00829     /* identifiers */
00830     ot->name= "Clear Slow Parent";
00831     ot->description = "Clear the object's slow parent";
00832     ot->idname= "OBJECT_OT_slow_parent_clear";
00833     
00834     /* api callbacks */
00835     ot->invoke= WM_operator_confirm;
00836     ot->exec= object_slow_parent_clear_exec;
00837     ot->poll= ED_operator_view3d_active;
00838     
00839     /* flags */
00840     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00841 }
00842 
00843 /********************** Make Slow Parent Operator *********************/
00844 
00845 static int object_slow_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
00846 {
00847     Main *bmain= CTX_data_main(C);
00848     Scene *scene= CTX_data_scene(C);
00849 
00850     CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00851         if(ob->parent)
00852             ob->partype |= PARSLOW;
00853 
00854         ob->recalc |= OB_RECALC_OB;
00855         
00856     }
00857     CTX_DATA_END;
00858 
00859     DAG_ids_flush_update(bmain, 0);
00860     WM_event_add_notifier(C, NC_SCENE, scene);
00861     
00862     return OPERATOR_FINISHED;
00863 }
00864 
00865 void OBJECT_OT_slow_parent_set(wmOperatorType *ot)
00866 {
00867     
00868     /* identifiers */
00869     ot->name= "Set Slow Parent";
00870     ot->description = "Set the object's slow parent";
00871     ot->idname= "OBJECT_OT_slow_parent_set";
00872     
00873     /* api callbacks */
00874     ot->invoke= WM_operator_confirm;
00875     ot->exec= object_slow_parent_set_exec;
00876     ot->poll= ED_operator_view3d_active;
00877     
00878     /* flags */
00879     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00880 }
00881 
00882 /* ******************** Clear Track Operator ******************* */
00883 
00884 static EnumPropertyItem prop_clear_track_types[] = {
00885     {0, "CLEAR", 0, "Clear Track", ""},
00886     {1, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation (Clear Track)", ""},
00887     {0, NULL, 0, NULL, NULL}
00888 };
00889 
00890 /* note, poll should check for editable scene */
00891 static int object_track_clear_exec(bContext *C, wmOperator *op)
00892 {
00893     Main *bmain= CTX_data_main(C);
00894     Scene *scene= CTX_data_scene(C);
00895     int type= RNA_enum_get(op->ptr, "type");
00896 
00897     if(CTX_data_edit_object(C)) {
00898         BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in EditMode");
00899         return OPERATOR_CANCELLED;
00900     }
00901     CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00902         bConstraint *con, *pcon;
00903         
00904         /* remove track-object for old track */
00905         ob->track= NULL;
00906         ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
00907         
00908         /* also remove all tracking constraints */
00909         for (con= ob->constraints.last; con; con= pcon) {
00910             pcon= con->prev;
00911             if (ELEM3(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK))
00912                 remove_constraint(&ob->constraints, con);
00913         }
00914         
00915         if(type == 1)
00916             object_apply_mat4(ob, ob->obmat, TRUE, TRUE);
00917     }
00918     CTX_DATA_END;
00919 
00920     DAG_ids_flush_update(bmain, 0);
00921     DAG_scene_sort(bmain, scene);
00922     WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00923 
00924     return OPERATOR_FINISHED;
00925 }
00926 
00927 void OBJECT_OT_track_clear(wmOperatorType *ot)
00928 {
00929     /* identifiers */
00930     ot->name= "Clear track";
00931     ot->description = "Clear tracking constraint or flag from object";
00932     ot->idname= "OBJECT_OT_track_clear";
00933     
00934     /* api callbacks */
00935     ot->invoke= WM_menu_invoke;
00936     ot->exec= object_track_clear_exec;
00937     
00938     ot->poll= ED_operator_objectmode;
00939     
00940     /* flags */
00941     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00942     
00943     ot->prop= RNA_def_enum(ot->srna, "type", prop_clear_track_types, 0, "Type", "");
00944 }
00945 
00946 /************************** Make Track Operator *****************************/
00947 
00948 static EnumPropertyItem prop_make_track_types[] = {
00949     {1, "DAMPTRACK", 0, "Damped Track Constraint", ""},
00950     {2, "TRACKTO", 0, "Track To Constraint", ""},
00951     {3, "LOCKTRACK", 0, "Lock Track Constraint", ""},
00952     {0, NULL, 0, NULL, NULL}
00953 };
00954 
00955 static int track_set_exec(bContext *C, wmOperator *op)
00956 {
00957     Main *bmain= CTX_data_main(C);
00958     Scene *scene= CTX_data_scene(C);
00959     Object *obact= ED_object_active_context(C); 
00960     
00961     int type= RNA_enum_get(op->ptr, "type");
00962     
00963     if(type == 1) {
00964         bConstraint *con;
00965         bDampTrackConstraint *data;
00966 
00967         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00968             if(ob!=obact) {
00969                 con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK);
00970 
00971                 data = con->data;
00972                 data->tar = obact;
00973                 ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
00974                 
00975                 /* Lamp, Camera and Speaker track differently by default */
00976                 if (ob->type == OB_LAMP || ob->type == OB_CAMERA || ob->type == OB_SPEAKER)
00977                     data->trackflag = TRACK_nZ;
00978             }
00979         }
00980         CTX_DATA_END;
00981     }
00982     else if(type == 2) {
00983         bConstraint *con;
00984         bTrackToConstraint *data;
00985 
00986         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00987             if(ob!=obact) {
00988                 con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO);
00989 
00990                 data = con->data;
00991                 data->tar = obact;
00992                 ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
00993                 
00994                 /* Lamp, Camera and Speaker track differently by default */
00995                 if (ob->type == OB_LAMP || ob->type == OB_CAMERA || ob->type == OB_SPEAKER) {
00996                     data->reserved1 = TRACK_nZ;
00997                     data->reserved2 = UP_Y;
00998                 }
00999             }
01000         }
01001         CTX_DATA_END;
01002     }
01003     else if(type == 3) {
01004         bConstraint *con;
01005         bLockTrackConstraint *data;
01006 
01007         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
01008             if(ob!=obact) {
01009                 con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK);
01010 
01011                 data = con->data;
01012                 data->tar = obact;
01013                 ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
01014                 
01015                 /* Lamp, Camera and Speaker track differently by default */
01016                 if (ob->type == OB_LAMP || ob->type == OB_CAMERA || ob->type == OB_SPEAKER) {
01017                     data->trackflag = TRACK_nZ;
01018                     data->lockflag = LOCK_Y;
01019                 }
01020             }
01021         }
01022         CTX_DATA_END;
01023     }
01024     
01025     DAG_scene_sort(bmain, scene);
01026     DAG_ids_flush_update(bmain, 0);
01027     WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
01028     
01029     return OPERATOR_FINISHED;
01030 }
01031 
01032 void OBJECT_OT_track_set(wmOperatorType *ot)
01033 {
01034     /* identifiers */
01035     ot->name= "Make Track";
01036     ot->description = "Make the object track another object, either by constraint or old way or locked track";
01037     ot->idname= "OBJECT_OT_track_set";
01038     
01039     /* api callbacks */
01040     ot->invoke= WM_menu_invoke;
01041     ot->exec= track_set_exec;
01042     
01043     ot->poll= ED_operator_objectmode;
01044     
01045     /* flags */
01046     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01047     
01048     /* properties */
01049     ot->prop= RNA_def_enum(ot->srna, "type", prop_make_track_types, 0, "Type", "");
01050 }
01051 
01052 /************************** Move to Layer Operator *****************************/
01053 
01054 static unsigned int move_to_layer_init(bContext *C, wmOperator *op)
01055 {
01056     int values[20], a;
01057     unsigned int lay= 0;
01058 
01059     if(!RNA_struct_property_is_set(op->ptr, "layers")) {
01060         /* note: layers are set in bases, library objects work for this */
01061         CTX_DATA_BEGIN(C, Base*, base, selected_bases) {
01062             lay |= base->lay;
01063         }
01064         CTX_DATA_END;
01065 
01066         for(a=0; a<20; a++)
01067             values[a]= (lay & (1<<a));
01068         
01069         RNA_boolean_set_array(op->ptr, "layers", values);
01070     }
01071     else {
01072         RNA_boolean_get_array(op->ptr, "layers", values);
01073 
01074         for(a=0; a<20; a++)
01075             if(values[a])
01076                 lay |= (1 << a);
01077     }
01078 
01079     return lay;
01080 }
01081 
01082 static int move_to_layer_invoke(bContext *C, wmOperator *op, wmEvent *event)
01083 {
01084     View3D *v3d= CTX_wm_view3d(C);
01085     if(v3d && v3d->localvd) {
01086         return WM_operator_confirm_message(C, op, "Move from localview");
01087     }
01088     else {
01089         move_to_layer_init(C, op);
01090         return WM_operator_props_popup(C, op, event);
01091     }
01092 }
01093 
01094 static int move_to_layer_exec(bContext *C, wmOperator *op)
01095 {
01096     Main *bmain= CTX_data_main(C);
01097     Scene *scene= CTX_data_scene(C);
01098     View3D *v3d= CTX_wm_view3d(C);
01099     unsigned int lay, local;
01100     /* int islamp= 0; */ /* UNUSED */
01101     
01102     lay= move_to_layer_init(C, op);
01103     lay &= 0xFFFFFF;
01104 
01105     if(lay==0) return OPERATOR_CANCELLED;
01106     
01107     if(v3d && v3d->localvd) {
01108         /* now we can move out of localview. */
01109         /* note: layers are set in bases, library objects work for this */
01110         CTX_DATA_BEGIN(C, Base*, base, selected_bases) {
01111             lay= base->lay & ~v3d->lay;
01112             base->lay= lay;
01113             base->object->lay= lay;
01114             base->object->flag &= ~SELECT;
01115             base->flag &= ~SELECT;
01116             /* if(base->object->type==OB_LAMP) islamp= 1; */
01117         }
01118         CTX_DATA_END;
01119     }
01120     else {
01121         /* normal non localview operation */
01122         /* note: layers are set in bases, library objects work for this */
01123         CTX_DATA_BEGIN(C, Base*, base, selected_bases) {
01124             /* upper byte is used for local view */
01125             local= base->lay & 0xFF000000;  
01126             base->lay= lay + local;
01127             base->object->lay= lay;
01128             /* if(base->object->type==OB_LAMP) islamp= 1; */
01129         }
01130         CTX_DATA_END;
01131     }
01132     
01133     /* warning, active object may be hidden now */
01134     
01135     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, scene);
01136     WM_event_add_notifier(C, NC_SCENE|ND_LAYER_CONTENT, scene);
01137 
01138     DAG_scene_sort(bmain, scene);
01139 
01140     return OPERATOR_FINISHED;
01141 }
01142 
01143 void OBJECT_OT_move_to_layer(wmOperatorType *ot)
01144 {
01145     /* identifiers */
01146     ot->name= "Move to Layer";
01147     ot->description = "Move the object to different layers";
01148     ot->idname= "OBJECT_OT_move_to_layer";
01149     
01150     /* api callbacks */
01151     ot->invoke= move_to_layer_invoke;
01152     ot->exec= move_to_layer_exec;
01153     ot->poll= ED_operator_objectmode;
01154     
01155     /* flags */
01156     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01157     
01158     /* properties */
01159     RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", "");
01160 }
01161 
01162 /************************** Link to Scene Operator *****************************/
01163 
01164 #if 0
01165 static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr))
01166 {
01167     Scene *sce= (Scene*) BLI_findlink(&bmain->scene, G.curscreen->scenenr-1);
01168     Base *base, *nbase;
01169     
01170     if(sce==0) return;
01171     if(sce->id.lib) return;
01172     
01173     for(base= FIRSTBASE; base; base= base->next) {
01174         if(TESTBASE(v3d, base)) {
01175             
01176             nbase= MEM_mallocN( sizeof(Base), "newbase");
01177             *nbase= *base;
01178             BLI_addhead( &(sce->base), nbase);
01179             id_us_plus((ID *)base->object);
01180         }
01181     }
01182 }
01183 #endif
01184 
01185 static int make_links_scene_exec(bContext *C, wmOperator *op)
01186 {
01187     Main *bmain= CTX_data_main(C);
01188     Scene *scene_to= BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene"));
01189 
01190     if(scene_to==NULL) {
01191         BKE_report(op->reports, RPT_ERROR, "Scene not found");
01192         return OPERATOR_CANCELLED;
01193     }
01194 
01195     if(scene_to == CTX_data_scene(C)) {
01196         BKE_report(op->reports, RPT_ERROR, "Can't link objects into the same scene");
01197         return OPERATOR_CANCELLED;
01198     }
01199 
01200     if(scene_to->id.lib) {
01201         BKE_report(op->reports, RPT_ERROR, "Can't link objects into a linked scene");
01202         return OPERATOR_CANCELLED;
01203     }
01204 
01205     CTX_DATA_BEGIN(C, Base*, base, selected_bases)
01206     {
01207         if(!object_in_scene(base->object, scene_to)) {
01208             Base *nbase= MEM_mallocN( sizeof(Base), "newbase");
01209             *nbase= *base;
01210             BLI_addhead( &(scene_to->base), nbase);
01211             id_us_plus((ID *)base->object);
01212         }
01213     }
01214     CTX_DATA_END;
01215 
01216     DAG_ids_flush_update(bmain, 0);
01217 
01218     /* one day multiple scenes will be visible, then we should have some update function for them */
01219     return OPERATOR_FINISHED;
01220 }
01221 
01222 enum {
01223     MAKE_LINKS_OBDATA = 1,
01224     MAKE_LINKS_MATERIALS,
01225     MAKE_LINKS_ANIMDATA,
01226     MAKE_LINKS_DUPLIGROUP,
01227     MAKE_LINKS_MODIFIERS
01228 };
01229 
01230 /* Return 1 if make link data is allow, zero otherwise */
01231 static int allow_make_links_data(int ev, Object *ob, Object *obt)
01232 {
01233     switch(ev) {
01234         case MAKE_LINKS_OBDATA:
01235             if (ob->type == obt->type && ob->type != OB_EMPTY)
01236                 return 1;
01237             break;
01238         case MAKE_LINKS_MATERIALS:
01239             if (OB_TYPE_SUPPORT_MATERIAL(ob->type) &&
01240                 OB_TYPE_SUPPORT_MATERIAL(obt->type))
01241             {
01242                 return 1;
01243             }
01244             break;
01245         case MAKE_LINKS_ANIMDATA:
01246         case MAKE_LINKS_DUPLIGROUP:
01247             return 1;
01248         case MAKE_LINKS_MODIFIERS:
01249             if (ob->type != OB_EMPTY && obt->type != OB_EMPTY)
01250                 return 1;
01251             break;
01252     }
01253     return 0;
01254 }
01255 
01256 static int make_links_data_exec(bContext *C, wmOperator *op)
01257 {
01258     Main *bmain= CTX_data_main(C);
01259     int event = RNA_enum_get(op->ptr, "type");
01260     Object *ob;
01261     ID *id;
01262     int a;
01263 
01264     ob= ED_object_active_context(C);
01265 
01266     CTX_DATA_BEGIN(C, Object*, obt, selected_editable_objects) {
01267         if(ob != obt) {
01268             if (allow_make_links_data(event, ob, obt)) {
01269                 switch(event) {
01270                 case MAKE_LINKS_OBDATA: /* obdata */
01271                     id= obt->data;
01272                     id->us--;
01273 
01274                     id= ob->data;
01275                     id_us_plus(id);
01276                     obt->data= id;
01277 
01278                     /* if amount of material indices changed: */
01279                     test_object_materials(obt->data);
01280 
01281                     obt->recalc |= OB_RECALC_DATA;
01282                     break;
01283                 case MAKE_LINKS_MATERIALS:
01284                     /* new approach, using functions from kernel */
01285                     for(a=0; a<ob->totcol; a++) {
01286                         Material *ma= give_current_material(ob, a+1);
01287                         assign_material(obt, ma, a+1);  /* also works with ma==NULL */
01288                     }
01289                     break;
01290                 case MAKE_LINKS_ANIMDATA:
01291                     BKE_copy_animdata_id((ID *)obt, (ID *)ob, FALSE);
01292                     BKE_copy_animdata_id((ID *)obt->data, (ID *)ob->data, FALSE);
01293                     break;
01294                 case MAKE_LINKS_DUPLIGROUP:
01295                     obt->dup_group= ob->dup_group;
01296                     if(obt->dup_group) {
01297                         id_lib_extern(&obt->dup_group->id);
01298                         obt->transflag |= OB_DUPLIGROUP;
01299                     }
01300                     break;
01301                 case MAKE_LINKS_MODIFIERS:
01302                     object_link_modifiers(obt, ob);
01303                     obt->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
01304                     break;
01305                 }
01306             }
01307         }
01308     }
01309     CTX_DATA_END;
01310 
01311     DAG_scene_sort(bmain, CTX_data_scene(C));
01312     
01313     DAG_ids_flush_update(bmain, 0);
01314     WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, CTX_wm_view3d(C));
01315     return OPERATOR_FINISHED;
01316 }
01317 
01318 
01319 void OBJECT_OT_make_links_scene(wmOperatorType *ot)
01320 {
01321     PropertyRNA *prop;
01322 
01323     /* identifiers */
01324     ot->name= "Link Objects to Scene";
01325     ot->description = "Link selection to another scene";
01326     ot->idname= "OBJECT_OT_make_links_scene";
01327 
01328     /* api callbacks */
01329     ot->invoke= WM_enum_search_invoke;
01330     ot->exec= make_links_scene_exec;
01331     /* better not run the poll check */
01332 
01333     /* flags */
01334     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01335 
01336     /* properties */
01337     prop= RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", "");
01338     RNA_def_enum_funcs(prop, RNA_scene_local_itemf);
01339     ot->prop= prop;
01340 }
01341 
01342 void OBJECT_OT_make_links_data(wmOperatorType *ot)
01343 {
01344     static EnumPropertyItem make_links_items[]= {
01345         {MAKE_LINKS_OBDATA,     "OBDATA", 0, "Object Data", ""},
01346         {MAKE_LINKS_MATERIALS,  "MATERIAL", 0, "Materials", ""},
01347         {MAKE_LINKS_ANIMDATA,   "ANIMATION", 0, "Animation Data", ""},
01348         {MAKE_LINKS_DUPLIGROUP, "DUPLIGROUP", 0, "DupliGroup", ""},
01349         {MAKE_LINKS_MODIFIERS,  "MODIFIERS", 0, "Modifiers", ""},
01350         {0, NULL, 0, NULL, NULL}};
01351 
01352     /* identifiers */
01353     ot->name= "Link Data";
01354     ot->description = "Make links from the active object to other selected objects";
01355     ot->idname= "OBJECT_OT_make_links_data";
01356 
01357     /* api callbacks */
01358     ot->exec= make_links_data_exec;
01359     ot->poll= ED_operator_object_active;
01360 
01361     /* flags */
01362     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01363 
01364     /* properties */
01365     ot->prop= RNA_def_enum(ot->srna, "type", make_links_items, 0, "Type", "");
01366 }
01367 
01368 
01369 /**************************** Make Single User ********************************/
01370 
01371 static void single_object_users(Scene *scene, View3D *v3d, int flag)    
01372 {
01373     Base *base;
01374     Object *ob, *obn;
01375     
01376     clear_sca_new_poins();  /* sensor/contr/act */
01377 
01378     /* duplicate (must set newid) */
01379     for(base= FIRSTBASE; base; base= base->next) {
01380         ob= base->object;
01381         
01382         /* newid may still have some trash from Outliner tree building,
01383          * so clear that first to avoid errors [#26002]
01384          */
01385         ob->id.newid = NULL;
01386         
01387         if( (base->flag & flag)==flag ) {
01388             if(ob->id.lib==NULL && ob->id.us>1) {
01389                 /* base gets copy of object */
01390                 obn= copy_object(ob);
01391                 base->object= obn;
01392                 ob->id.us--;
01393             }
01394         }
01395     }
01396     
01397     ID_NEW(scene->camera);
01398     if(v3d) ID_NEW(v3d->camera);
01399     
01400     /* object pointers */
01401     for(base= FIRSTBASE; base; base= base->next) {
01402         object_relink(base->object);
01403     }
01404 
01405     set_sca_new_poins();
01406 }
01407 
01408 /* not an especially efficient function, only added so the single user
01409  * button can be functional.*/
01410 void ED_object_single_user(Scene *scene, Object *ob)
01411 {
01412     Base *base;
01413 
01414     for(base= FIRSTBASE; base; base= base->next) {
01415         if(base->object == ob)  base->flag |=  OB_DONE;
01416         else                    base->flag &= ~OB_DONE;
01417     }
01418 
01419     single_object_users(scene, NULL, OB_DONE);
01420 }
01421 
01422 static void new_id_matar(Material **matar, int totcol)
01423 {
01424     ID *id;
01425     int a;
01426     
01427     for(a=0; a<totcol; a++) {
01428         id= (ID *)matar[a];
01429         if(id && id->lib == NULL) {
01430             if(id->newid) {
01431                 matar[a]= (Material *)id->newid;
01432                 id_us_plus(id->newid);
01433                 id->us--;
01434             }
01435             else if(id->us>1) {
01436                 matar[a]= copy_material(matar[a]);
01437                 id->us--;
01438                 id->newid= (ID *)matar[a];
01439             }
01440         }
01441     }
01442 }
01443 
01444 static void single_obdata_users(Main *bmain, Scene *scene, int flag)
01445 {
01446     Object *ob;
01447     Lamp *la;
01448     Curve *cu;
01449     //Camera *cam;
01450     Base *base;
01451     Mesh *me;
01452     ID *id;
01453     int a;
01454 
01455     for(base= FIRSTBASE; base; base= base->next) {
01456         ob= base->object;
01457         if(ob->id.lib==NULL && (base->flag & flag)==flag ) {
01458             id= ob->data;
01459             
01460             if(id && id->us>1 && id->lib==NULL) {
01461                 ob->recalc= OB_RECALC_DATA;
01462                 
01463                 BKE_copy_animdata_id_action(id);
01464                 
01465                 switch(ob->type) {
01466                 case OB_LAMP:
01467                     ob->data= la= copy_lamp(ob->data);
01468                     for(a=0; a<MAX_MTEX; a++) {
01469                         if(la->mtex[a]) {
01470                             ID_NEW(la->mtex[a]->object);
01471                         }
01472                     }
01473                     break;
01474                 case OB_CAMERA:
01475                     ob->data= copy_camera(ob->data);
01476                     break;
01477                 case OB_MESH:
01478                     ob->data= copy_mesh(ob->data);
01479                     //me= ob->data;
01480                     //if(me && me->key)
01481                     //  ipo_idnew(me->key->ipo);    /* drivers */
01482                     break;
01483                 case OB_MBALL:
01484                     ob->data= copy_mball(ob->data);
01485                     break;
01486                 case OB_CURVE:
01487                 case OB_SURF:
01488                 case OB_FONT:
01489                     ob->data= cu= copy_curve(ob->data);
01490                     ID_NEW(cu->bevobj);
01491                     ID_NEW(cu->taperobj);
01492                     break;
01493                 case OB_LATTICE:
01494                     ob->data= copy_lattice(ob->data);
01495                     break;
01496                 case OB_ARMATURE:
01497                     ob->recalc |= OB_RECALC_DATA;
01498                     ob->data= copy_armature(ob->data);
01499                     armature_rebuild_pose(ob, ob->data);
01500                     break;
01501                 case OB_SPEAKER:
01502                     ob->data= copy_speaker(ob->data);
01503                     break;
01504                 default:
01505                     if (G.f & G_DEBUG)
01506                         printf("ERROR single_obdata_users: can't copy %s\n", id->name);
01507                     return;
01508                 }
01509                 
01510                 id->us--;
01511                 id->newid= ob->data;
01512                 
01513             }
01514             
01515         }
01516     }
01517     
01518     me= bmain->mesh.first;
01519     while(me) {
01520         ID_NEW(me->texcomesh);
01521         me= me->id.next;
01522     }
01523 }
01524 
01525 static void single_object_action_users(Scene *scene, int flag)
01526 {
01527     Object *ob;
01528     Base *base;
01529     
01530     for(base= FIRSTBASE; base; base= base->next) {
01531         ob= base->object;
01532         if(ob->id.lib==NULL && (flag==0 || (base->flag & SELECT)) ) {
01533             ob->recalc= OB_RECALC_DATA;
01534             BKE_copy_animdata_id_action(&ob->id);
01535         }
01536     }
01537 }
01538 
01539 static void single_mat_users(Scene *scene, int flag, int do_textures)
01540 {
01541     Object *ob;
01542     Base *base;
01543     Material *ma, *man;
01544     Tex *tex;
01545     int a, b;
01546     
01547     for(base= FIRSTBASE; base; base= base->next) {
01548         ob= base->object;
01549         if(ob->id.lib==NULL && (flag==0 || (base->flag & SELECT)) ) {
01550     
01551             for(a=1; a<=ob->totcol; a++) {
01552                 ma= give_current_material(ob, a);
01553                 if(ma) {
01554                     /* do not test for LIB_NEW: this functions guaranteed delivers single_users! */
01555                     
01556                     if(ma->id.us>1) {
01557                         man= copy_material(ma);
01558                         BKE_copy_animdata_id_action(&man->id);
01559                         
01560                         man->id.us= 0;
01561                         assign_material(ob, man, a);
01562 
01563                         if(do_textures) {
01564                             for(b=0; b<MAX_MTEX; b++) {
01565                                 if(ma->mtex[b] && (tex= ma->mtex[b]->tex)) {
01566                                     if(tex->id.us>1) {
01567                                         tex->id.us--;
01568                                         tex= copy_texture(tex);
01569                                         BKE_copy_animdata_id_action(&tex->id);
01570                                         ma->mtex[b]->tex= tex;
01571                                     }
01572                                 }
01573                             }
01574                         }
01575                     }
01576                 }
01577             }
01578         }
01579     }
01580 }
01581 
01582 static void do_single_tex_user(Tex **from)
01583 {
01584     Tex *tex, *texn;
01585     
01586     tex= *from;
01587     if(tex==NULL) return;
01588     
01589     if(tex->id.newid) {
01590         *from= (Tex *)tex->id.newid;
01591         id_us_plus(tex->id.newid);
01592         tex->id.us--;
01593     }
01594     else if(tex->id.us>1) {
01595         texn= copy_texture(tex);
01596         BKE_copy_animdata_id_action(&texn->id);
01597         tex->id.newid= (ID *)texn;
01598         tex->id.us--;
01599         *from= texn;
01600     }
01601 }
01602 
01603 static void single_tex_users_expand(Main *bmain)
01604 {
01605     /* only when 'parent' blocks are LIB_NEW */
01606     Material *ma;
01607     Lamp *la;
01608     World *wo;
01609     int b;
01610         
01611     for(ma= bmain->mat.first; ma; ma=ma->id.next) {
01612         if(ma->id.flag & LIB_NEW) {
01613             for(b=0; b<MAX_MTEX; b++) {
01614                 if(ma->mtex[b] && ma->mtex[b]->tex) {
01615                     do_single_tex_user( &(ma->mtex[b]->tex) );
01616                 }
01617             }
01618         }
01619     }
01620 
01621     for(la= bmain->lamp.first; la; la=la->id.next) {
01622         if(la->id.flag & LIB_NEW) {
01623             for(b=0; b<MAX_MTEX; b++) {
01624                 if(la->mtex[b] && la->mtex[b]->tex) {
01625                     do_single_tex_user( &(la->mtex[b]->tex) );
01626                 }
01627             }
01628         }
01629     }
01630 
01631     for(wo= bmain->world.first; wo; wo=wo->id.next) {
01632         if(wo->id.flag & LIB_NEW) {
01633             for(b=0; b<MAX_MTEX; b++) {
01634                 if(wo->mtex[b] && wo->mtex[b]->tex) {
01635                     do_single_tex_user( &(wo->mtex[b]->tex) );
01636                 }
01637             }
01638         }
01639     }
01640 }
01641 
01642 static void single_mat_users_expand(Main *bmain)
01643 {
01644     /* only when 'parent' blocks are LIB_NEW */
01645     Object *ob;
01646     Mesh *me;
01647     Curve *cu;
01648     MetaBall *mb;
01649     Material *ma;
01650     int a;
01651     
01652     for(ob=bmain->object.first; ob; ob=ob->id.next)
01653         if(ob->id.flag & LIB_NEW)
01654             new_id_matar(ob->mat, ob->totcol);
01655 
01656     for(me=bmain->mesh.first; me; me=me->id.next)
01657         if(me->id.flag & LIB_NEW)
01658             new_id_matar(me->mat, me->totcol);
01659 
01660     for(cu=bmain->curve.first; cu; cu=cu->id.next)
01661         if(cu->id.flag & LIB_NEW)
01662             new_id_matar(cu->mat, cu->totcol);
01663 
01664     for(mb=bmain->mball.first; mb; mb=mb->id.next)
01665         if(mb->id.flag & LIB_NEW)
01666             new_id_matar(mb->mat, mb->totcol);
01667 
01668     /* material imats  */
01669     for(ma=bmain->mat.first; ma; ma=ma->id.next)
01670         if(ma->id.flag & LIB_NEW)
01671             for(a=0; a<MAX_MTEX; a++)
01672                 if(ma->mtex[a])
01673                     ID_NEW(ma->mtex[a]->object);
01674 }
01675 
01676 /* used for copying scenes */
01677 void ED_object_single_users(Main *bmain, Scene *scene, int full)
01678 {
01679     single_object_users(scene, NULL, 0);
01680 
01681     if(full) {
01682         single_obdata_users(bmain, scene, 0);
01683         single_object_action_users(scene, 0);
01684         single_mat_users_expand(bmain);
01685         single_tex_users_expand(bmain);
01686     }
01687 
01688     clear_id_newpoins();
01689 }
01690 
01691 /******************************* Make Local ***********************************/
01692 
01693 /* helper for below, ma was checked to be not NULL */
01694 static void make_local_makelocalmaterial(Material *ma)
01695 {
01696     AnimData *adt;
01697     int b;
01698     
01699     id_make_local(&ma->id, 0);
01700     
01701     for(b=0; b<MAX_MTEX; b++)
01702         if(ma->mtex[b] && ma->mtex[b]->tex)
01703             id_make_local(&ma->mtex[b]->tex->id, 0);
01704     
01705     adt= BKE_animdata_from_id(&ma->id);
01706     if(adt) BKE_animdata_make_local(adt);
01707 
01708     /* nodetree? XXX */
01709 }
01710 
01711 static int make_local_exec(bContext *C, wmOperator *op)
01712 {
01713     Main *bmain= CTX_data_main(C);
01714     AnimData *adt;
01715     ParticleSystem *psys;
01716     Material *ma, ***matarar;
01717     Lamp *la;
01718     ID *id;
01719     int a, b, mode= RNA_enum_get(op->ptr, "type");
01720     
01721     if(mode==3) {
01722         BKE_library_make_local(bmain, NULL, 0); /* NULL is all libs */
01723         WM_event_add_notifier(C, NC_WINDOW, NULL);
01724         return OPERATOR_FINISHED;
01725     }
01726 
01727     clear_id_newpoins();
01728     
01729     CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
01730         if(ob->id.lib)
01731             id_make_local(&ob->id, 0);
01732     }
01733     CTX_DATA_END;
01734     
01735     /* maybe object pointers */
01736     CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
01737         if(ob->id.lib==NULL) {
01738             ID_NEW(ob->parent);
01739         }
01740     }
01741     CTX_DATA_END;
01742 
01743     CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
01744         id= ob->data;
01745             
01746         if(id && mode>1) {
01747             id_make_local(id, 0);
01748             adt= BKE_animdata_from_id(id);
01749             if(adt) BKE_animdata_make_local(adt);
01750             
01751             /* tag indirect data direct */
01752             matarar= (Material ***)give_matarar(ob);
01753             if(matarar) {
01754                 for(a=0; a<ob->totcol; a++) {
01755                     ma= (*matarar)[a];
01756                     if(ma)
01757                         id_lib_extern(&ma->id);
01758                 }
01759             }
01760         }
01761 
01762         for(psys=ob->particlesystem.first; psys; psys=psys->next)
01763             id_make_local(&psys->part->id, 0);
01764 
01765         adt= BKE_animdata_from_id(&ob->id);
01766         if(adt) BKE_animdata_make_local(adt);
01767     }
01768     CTX_DATA_END;
01769 
01770     if(mode>1) {
01771         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
01772             if(ob->type==OB_LAMP) {
01773                 la= ob->data;
01774 
01775                 for(b=0; b<MAX_MTEX; b++)
01776                     if(la->mtex[b] && la->mtex[b]->tex)
01777                         id_make_local(&la->mtex[b]->tex->id, 0);
01778             }
01779             else {
01780                 for(a=0; a<ob->totcol; a++) {
01781                     ma= ob->mat[a];
01782                     if(ma)
01783                         make_local_makelocalmaterial(ma);
01784                 }
01785                 
01786                 matarar= (Material ***)give_matarar(ob);
01787                 if(matarar) {
01788                     for(a=0; a<ob->totcol; a++) {
01789                         ma= (*matarar)[a];
01790                         if(ma)
01791                             make_local_makelocalmaterial(ma);
01792                     }
01793                 }
01794             }
01795         }
01796         CTX_DATA_END;
01797     }
01798 
01799     WM_event_add_notifier(C, NC_WINDOW, NULL);
01800 
01801     return OPERATOR_FINISHED;
01802 }
01803 
01804 void OBJECT_OT_make_local(wmOperatorType *ot)
01805 {
01806     static EnumPropertyItem type_items[]= {
01807         {1, "SELECTED_OBJECTS", 0, "Selected Objects", ""},
01808         {2, "SELECTED_OBJECTS_DATA", 0, "Selected Objects and Data", ""},
01809         {3, "ALL", 0, "All", ""},
01810         {0, NULL, 0, NULL, NULL}};
01811 
01812     /* identifiers */
01813     ot->name= "Make Local";
01814     ot->description = "Make library linked datablocks local to this file";
01815     ot->idname= "OBJECT_OT_make_local";
01816     
01817     /* api callbacks */
01818     ot->invoke= WM_menu_invoke;
01819     ot->exec= make_local_exec;
01820     ot->poll= ED_operator_objectmode;
01821     
01822     /* flags */
01823     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01824     
01825     /* properties */
01826     ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
01827 }
01828 
01829 static int make_single_user_exec(bContext *C, wmOperator *op)
01830 {
01831     Main *bmain= CTX_data_main(C);
01832     Scene *scene= CTX_data_scene(C);
01833     View3D *v3d= CTX_wm_view3d(C); /* ok if this is NULL */
01834     int flag= RNA_enum_get(op->ptr, "type"); /* 0==ALL, SELECTED==selected objecs */
01835 
01836     if(RNA_boolean_get(op->ptr, "object"))
01837         single_object_users(scene, v3d, flag);
01838 
01839     if(RNA_boolean_get(op->ptr, "obdata"))
01840         single_obdata_users(bmain, scene, flag);
01841 
01842     if(RNA_boolean_get(op->ptr, "material"))
01843         single_mat_users(scene, flag, RNA_boolean_get(op->ptr, "texture"));
01844 
01845 #if 0 /* can't do this separate from materials */
01846     if(RNA_boolean_get(op->ptr, "texture"))
01847         single_mat_users(scene, flag, TRUE);
01848 #endif
01849     if(RNA_boolean_get(op->ptr, "animation"))
01850         single_object_action_users(scene, flag);
01851 
01852     clear_id_newpoins();
01853 
01854     WM_event_add_notifier(C, NC_WINDOW, NULL);
01855     return OPERATOR_FINISHED;
01856 }
01857 
01858 void OBJECT_OT_make_single_user(wmOperatorType *ot)
01859 {
01860     static EnumPropertyItem type_items[]= {
01861         {SELECT, "SELECTED_OBJECTS", 0, "Selected Objects", ""},
01862         {0, "ALL", 0, "All", ""},
01863         {0, NULL, 0, NULL, NULL}};
01864 
01865     /* identifiers */
01866     ot->name= "Make Single User";
01867     ot->description = "Make linked data local to each object";
01868     ot->idname= "OBJECT_OT_make_single_user";
01869 
01870     /* api callbacks */
01871     ot->invoke= WM_menu_invoke;
01872     ot->exec= make_single_user_exec;
01873     ot->poll= ED_operator_objectmode;
01874 
01875     /* flags */
01876     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01877 
01878     /* properties */
01879     ot->prop= RNA_def_enum(ot->srna, "type", type_items, SELECT, "Type", "");
01880 
01881     RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects");
01882     RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data");
01883     RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each datablock");
01884     RNA_def_boolean(ot->srna, "texture", 0, "Textures", "Make textures local to each material");
01885     RNA_def_boolean(ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object");
01886 }
01887 
01888 static int drop_named_material_invoke(bContext *C, wmOperator *op, wmEvent *event)
01889 {
01890     Main *bmain= CTX_data_main(C);
01891     Base *base= ED_view3d_give_base_under_cursor(C, event->mval);
01892     Material *ma;
01893     char name[MAX_ID_NAME-2];
01894     
01895     RNA_string_get(op->ptr, "name", name);
01896     ma= (Material *)find_id("MA", name);
01897     if(base==NULL || ma==NULL) 
01898         return OPERATOR_CANCELLED;
01899     
01900     assign_material(base->object, ma, 1);
01901     
01902     DAG_ids_flush_update(bmain, 0);
01903     WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, CTX_wm_view3d(C));
01904     
01905     return OPERATOR_FINISHED;
01906 }
01907 
01908 /* used for dropbox */
01909 /* assigns to object under cursor, only first material slot */
01910 void OBJECT_OT_drop_named_material(wmOperatorType *ot)
01911 {
01912 
01913     /* identifiers */
01914     ot->name= "Drop Named Material on Object";
01915     ot->description = "";
01916     ot->idname= "OBJECT_OT_drop_named_material";
01917     
01918     /* api callbacks */
01919     ot->invoke= drop_named_material_invoke;
01920     ot->poll= ED_operator_objectmode;
01921     
01922     /* flags */
01923     ot->flag= OPTYPE_UNDO;
01924     
01925     /* properties */
01926     RNA_def_string(ot->srna, "name", "Material", MAX_ID_NAME-2, "Name", "Material name to assign");
01927 }