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