2.5 Object mode:
[blender.git] / source / blender / editors / object / object_edit.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, 2002-2008 full recode
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 #include <time.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "IMB_imbuf_types.h"
35
36 #include "DNA_action_types.h"
37 #include "DNA_armature_types.h"
38 #include "DNA_camera_types.h"
39 #include "DNA_constraint_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_effect_types.h"
42 #include "DNA_group_types.h"
43 #include "DNA_image_types.h"
44 #include "DNA_key_types.h"
45 #include "DNA_lamp_types.h"
46 #include "DNA_lattice_types.h"
47 #include "DNA_material_types.h"
48 #include "DNA_mesh_types.h"
49 #include "DNA_meshdata_types.h"
50 #include "DNA_meta_types.h"
51 #include "DNA_nla_types.h"
52 #include "DNA_object_types.h"
53 #include "DNA_object_fluidsim.h"
54 #include "DNA_object_force.h"
55 #include "DNA_scene_types.h"
56 #include "DNA_space_types.h"
57 #include "DNA_screen_types.h"
58 #include "DNA_texture_types.h"
59 #include "DNA_particle_types.h"
60 #include "DNA_property_types.h"
61 #include "DNA_userdef_types.h"
62 #include "DNA_view3d_types.h"
63 #include "DNA_vfont_types.h"
64 #include "DNA_world_types.h"
65 #include "DNA_modifier_types.h"
66
67 #include "BLI_blenlib.h"
68 #include "BLI_arithb.h"
69 #include "BLI_editVert.h"
70 #include "BLI_ghash.h"
71 #include "BLI_rand.h"
72
73 #include "BKE_action.h"
74 #include "BKE_anim.h"
75 #include "BKE_armature.h"
76 #include "BKE_booleanops.h"
77 #include "BKE_constraint.h"
78 #include "BKE_context.h"
79 #include "BKE_customdata.h"
80 #include "BKE_blender.h"
81 #include "BKE_booleanops.h"
82 #include "BKE_cloth.h"
83 #include "BKE_curve.h"
84 #include "BKE_displist.h"
85 #include "BKE_depsgraph.h"
86 #include "BKE_DerivedMesh.h"
87 #include "BKE_effect.h"
88 #include "BKE_font.h"
89 #include "BKE_global.h"
90 #include "BKE_group.h"
91 #include "BKE_image.h"
92 #include "BKE_key.h"
93 #include "BKE_lattice.h"
94 #include "BKE_library.h"
95 #include "BKE_main.h"
96 #include "BKE_material.h"
97 #include "BKE_mball.h"
98 #include "BKE_mesh.h"
99 #include "BKE_nla.h"
100 #include "BKE_object.h"
101 #include "BKE_paint.h"
102 #include "BKE_particle.h"
103 #include "BKE_property.h"
104 #include "BKE_report.h"
105 #include "BKE_sca.h"
106 #include "BKE_scene.h"
107 #include "BKE_softbody.h"
108 #include "BKE_subsurf.h"
109 #include "BKE_texture.h"
110 #include "BKE_utildefines.h"
111 #include "BKE_modifier.h"
112
113 #include "ED_anim_api.h"
114 #include "ED_armature.h"
115 #include "ED_curve.h"
116 #include "ED_particle.h"
117 #include "ED_mesh.h"
118 #include "ED_mball.h"
119 #include "ED_object.h"
120 #include "ED_screen.h"
121 #include "ED_transform.h"
122 #include "ED_types.h"
123 #include "ED_util.h"
124 #include "ED_view3d.h"
125
126 #include "UI_interface.h"
127
128 #include "RNA_access.h"
129 #include "RNA_define.h"
130 #include "RNA_enum_types.h"
131
132 /* for menu/popup icons etc etc*/
133 #include "UI_interface.h"
134 #include "UI_resources.h"
135
136 #include "WM_api.h"
137 #include "WM_types.h"
138
139 #include "object_intern.h"      // own include
140
141 /* ************* XXX **************** */
142 static void error() {}
143 static void waitcursor(int val) {}
144 static int pupmenu(const char *msg) {return 0;}
145 static int pupmenu_col(const char *msg, int val) {return 0;}
146 static int okee(const char *msg) {return 0;}
147
148 /* port over here */
149 static bContext *C;
150 static void error_libdata() {}
151
152 /* ********************************** */
153
154 /* --------------------------------- */
155
156 /* simple API for object selection, rather than just using the flag
157  * this takes into account the 'restrict selection in 3d view' flag.
158  * deselect works always, the restriction just prevents selection */
159
160 /* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! */
161
162 void ED_base_object_select(Base *base, short mode)
163 {
164         if (base) {
165                 if (mode==BA_SELECT) {
166                         if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
167                                 if (mode==BA_SELECT) base->flag |= SELECT;
168                 }
169                 else if (mode==BA_DESELECT) {
170                         base->flag &= ~SELECT;
171                 }
172                 base->object->flag= base->flag;
173         }
174 }
175
176 /* also to set active NULL */
177 void ED_base_object_activate(bContext *C, Base *base)
178 {
179         Scene *scene= CTX_data_scene(C);
180         Base *tbase;
181         
182         /* sets scene->basact */
183         BASACT= base;
184         
185         if(base) {
186                 
187                 /* XXX old signals, remember to handle notifiers now! */
188                 //              select_actionchannel_by_name(base->object->action, "Object", 1);
189                 
190                 /* disable temporal locks */
191                 for(tbase=FIRSTBASE; tbase; tbase= tbase->next) {
192                         if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) {
193                                 tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK;
194                                 DAG_object_flush_update(scene, tbase->object, OB_RECALC_DATA);
195                         }
196                 }
197                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
198         }
199         else
200                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, NULL);
201 }
202
203
204 /* exported */
205 void ED_object_base_init_from_view(bContext *C, Base *base)
206 {
207         View3D *v3d= CTX_wm_view3d(C);
208         Scene *scene= CTX_data_scene(C);
209         Object *ob= base->object;
210         
211         if (scene==NULL)
212                 return;
213         
214         if (v3d==NULL) {
215                 base->lay = scene->lay;
216                 VECCOPY(ob->loc, scene->cursor);
217         } 
218         else {
219                 if (v3d->localview) {
220                         base->lay= ob->lay= v3d->layact | v3d->lay;
221                         VECCOPY(ob->loc, v3d->cursor);
222                 } 
223                 else {
224                         base->lay= ob->lay= v3d->layact;
225                         VECCOPY(ob->loc, scene->cursor);
226                 }
227                 
228                 if (U.flag & USER_ADD_VIEWALIGNED) {
229                         ARegion *ar= CTX_wm_region(C);
230                         if(ar) {
231                                 RegionView3D *rv3d= ar->regiondata;
232                                 
233                                 rv3d->viewquat[0]= -rv3d->viewquat[0];
234                                 QuatToEul(rv3d->viewquat, ob->rot);
235                                 rv3d->viewquat[0]= -rv3d->viewquat[0];
236                         }
237                 }
238         }
239         where_is_object(scene, ob);
240 }
241
242 /* ******************* add object operator ****************** */
243
244 static EnumPropertyItem prop_object_types[] = {
245         {OB_MESH, "MESH", 0, "Mesh", ""},
246         {OB_CURVE, "CURVE", 0, "Curve", ""},
247         {OB_SURF, "SURFACE", 0, "Surface", ""},
248         {OB_MBALL, "META", 0, "Meta", ""},
249         {OB_FONT, "TEXT", 0, "Text", ""},
250         {0, "", 0, NULL, NULL},
251         {OB_ARMATURE, "ARMATURE", 0, "Armature", ""},
252         {OB_LATTICE, "LATTICE", 0, "Lattice", ""},
253         {OB_EMPTY, "EMPTY", 0, "Empty", ""},
254         {0, "", 0, NULL, NULL},
255         {OB_CAMERA, "CAMERA", 0, "Camera", ""},
256         {OB_LAMP, "LAMP", 0, "Lamp", ""},
257         {0, NULL, 0, NULL, NULL}
258 };
259
260
261
262 void add_object_draw(Scene *scene, View3D *v3d, int type)       /* for toolbox or menus, only non-editmode stuff */
263 {
264         /* keep here to get things compile, remove later */
265 }
266
267 /* for object add primitive operators */
268 static Object *object_add_type(bContext *C, int type)
269 {
270         Scene *scene= CTX_data_scene(C);
271         Object *ob;
272         
273         /* for as long scene has editmode... */
274         if (CTX_data_edit_object(C)) 
275                 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* freedata, and undo */
276         
277         /* deselects all, sets scene->basact */
278         ob= add_object(scene, type);
279         /* editor level activate, notifiers */
280         ED_base_object_activate(C, BASACT);
281
282         /* more editor stuff */
283         ED_object_base_init_from_view(C, BASACT);
284
285         DAG_scene_sort(scene);
286
287         return ob;
288 }
289
290 /* for object add operator */
291 static int object_add_exec(bContext *C, wmOperator *op)
292 {
293         object_add_type(C, RNA_int_get(op->ptr, "type"));
294         
295         return OPERATOR_FINISHED;
296 }
297
298 void OBJECT_OT_object_add(wmOperatorType *ot)
299 {
300         /* identifiers */
301         ot->name= "Add Object";
302         ot->description = "Add an object to the scene.";
303         ot->idname= "OBJECT_OT_object_add";
304         
305         /* api callbacks */
306         ot->invoke= WM_menu_invoke;
307         ot->exec= object_add_exec;
308         
309         ot->poll= ED_operator_scene_editable;
310         
311         /* flags */
312         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
313         
314         RNA_def_enum(ot->srna, "type", prop_object_types, 0, "Type", "");
315 }
316
317 /* ***************** add primitives *************** */
318 /* ******  work both in and outside editmode ****** */
319
320 static EnumPropertyItem prop_mesh_types[] = {
321         {0, "PLANE", ICON_MESH_PLANE, "Plane", ""},
322         {1, "CUBE", ICON_MESH_CUBE, "Cube", ""},
323         {2, "CIRCLE", ICON_MESH_CIRCLE, "Circle", ""},
324         {3, "UVSPHERE", ICON_MESH_UVSPHERE, "UVsphere", ""},
325         {4, "ICOSPHERE", ICON_MESH_ICOSPHERE, "Icosphere", ""},
326         {5, "CYLINDER", ICON_MESH_TUBE, "Cylinder", ""},
327         {6, "CONE", ICON_MESH_CONE, "Cone", ""},
328         {0, "", 0, NULL, NULL},
329         {7, "GRID", ICON_MESH_GRID, "Grid", ""},
330         {8, "MONKEY", ICON_MESH_MONKEY, "Monkey", ""},
331         {0, NULL, 0, NULL, NULL}
332 };
333
334 static int object_add_mesh_exec(bContext *C, wmOperator *op)
335 {
336         Object *obedit= CTX_data_edit_object(C);
337         int newob= 0;
338         
339         if(obedit==NULL || obedit->type!=OB_MESH) {
340                 object_add_type(C, OB_MESH);
341                 ED_object_enter_editmode(C, EM_DO_UNDO);
342                 newob = 1;
343         }
344         else DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
345
346         switch(RNA_enum_get(op->ptr, "type")) {
347                 case 0:
348                         WM_operator_name_call(C, "MESH_OT_primitive_plane_add", WM_OP_INVOKE_REGION_WIN, NULL);
349                         break;
350                 case 1:
351                         WM_operator_name_call(C, "MESH_OT_primitive_cube_add", WM_OP_INVOKE_REGION_WIN, NULL);
352                         break;
353                 case 2:
354                         WM_operator_name_call(C, "MESH_OT_primitive_circle_add", WM_OP_INVOKE_REGION_WIN, NULL);
355                         break;
356                 case 3:
357                         WM_operator_name_call(C, "MESH_OT_primitive_uv_sphere_add", WM_OP_INVOKE_REGION_WIN, NULL);
358                         break;
359                 case 4:
360                         WM_operator_name_call(C, "MESH_OT_primitive_ico_sphere_add", WM_OP_INVOKE_REGION_WIN, NULL);
361                         break;
362                 case 5:
363                         WM_operator_name_call(C, "MESH_OT_primitive_cylinder_add", WM_OP_INVOKE_REGION_WIN, NULL);
364                         break;
365                 case 6:
366                         WM_operator_name_call(C, "MESH_OT_primitive_cone_add", WM_OP_INVOKE_REGION_WIN, NULL);
367                         break;
368                 case 7:
369                         WM_operator_name_call(C, "MESH_OT_primitive_grid_add", WM_OP_INVOKE_REGION_WIN, NULL);
370                         break;
371                 case 8:
372                         WM_operator_name_call(C, "MESH_OT_primitive_monkey_add", WM_OP_INVOKE_REGION_WIN, NULL);
373                         break;
374         }
375         /* userdef */
376         if (newob && (U.flag & USER_ADD_EDITMODE)==0) {
377                 ED_object_exit_editmode(C, EM_FREEDATA);
378         }
379         
380         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
381         
382         return OPERATOR_FINISHED;
383 }
384
385
386 void OBJECT_OT_mesh_add(wmOperatorType *ot)
387 {
388         /* identifiers */
389         ot->name= "Add Mesh";
390         ot->description = "Add a mesh object to the scene.";
391         ot->idname= "OBJECT_OT_mesh_add";
392         
393         /* api callbacks */
394         ot->invoke= WM_menu_invoke;
395         ot->exec= object_add_mesh_exec;
396         
397         ot->poll= ED_operator_scene_editable;
398         
399         /* flags: no register or undo, this operator calls operators */
400         ot->flag= 0; //OPTYPE_REGISTER|OPTYPE_UNDO;
401         
402         RNA_def_enum(ot->srna, "type", prop_mesh_types, 0, "Primitive", "");
403 }
404
405 static EnumPropertyItem prop_curve_types[] = {
406         {CU_BEZIER|CU_2D|CU_PRIM_CURVE, "BEZIER_CURVE", ICON_CURVE_BEZCURVE, "Bezier Curve", ""},
407         {CU_BEZIER|CU_2D|CU_PRIM_CIRCLE, "BEZIER_CIRCLE", ICON_CURVE_BEZCIRCLE, "Bezier Circle", ""},
408         {CU_NURBS|CU_2D|CU_PRIM_CURVE, "NURBS_CURVE", ICON_CURVE_NCURVE, "NURBS Curve", ""},
409         {CU_NURBS|CU_2D|CU_PRIM_CIRCLE, "NURBS_CIRCLE", ICON_CURVE_NCIRCLE, "NURBS Circle", ""},
410         {CU_NURBS|CU_2D|CU_PRIM_PATH, "PATH", ICON_CURVE_PATH, "Path", ""},
411         {0, NULL, 0, NULL, NULL}
412 };
413
414 static int object_add_curve_exec(bContext *C, wmOperator *op)
415 {
416         Object *obedit= CTX_data_edit_object(C);
417         ListBase *editnurb;
418         Nurb *nu;
419         int newob= 0;
420         
421         if(obedit==NULL || obedit->type!=OB_CURVE) {
422                 object_add_type(C, OB_CURVE);
423                 ED_object_enter_editmode(C, 0);
424                 newob = 1;
425         }
426         else DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
427         
428         obedit= CTX_data_edit_object(C);
429         nu= add_nurbs_primitive(C, RNA_enum_get(op->ptr, "type"), newob);
430         editnurb= curve_get_editcurve(obedit);
431         BLI_addtail(editnurb, nu);
432         
433         /* userdef */
434         if (newob && (U.flag & USER_ADD_EDITMODE)==0) {
435                 ED_object_exit_editmode(C, EM_FREEDATA);
436         }
437         
438         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
439         
440         return OPERATOR_FINISHED;
441 }
442
443 static int object_add_curve_invoke(bContext *C, wmOperator *op, wmEvent *event)
444 {
445         Object *obedit= CTX_data_edit_object(C);
446         uiPopupMenu *pup;
447         uiLayout *layout;
448
449         pup= uiPupMenuBegin(C, op->type->name, 0);
450         layout= uiPupMenuLayout(pup);
451         if(!obedit || obedit->type == OB_CURVE)
452                 uiItemsEnumO(layout, op->type->idname, "type");
453         else
454                 uiItemsEnumO(layout, "OBJECT_OT_surface_add", "type");
455         uiPupMenuEnd(C, pup);
456
457         return OPERATOR_CANCELLED;
458 }
459
460 void OBJECT_OT_curve_add(wmOperatorType *ot)
461 {
462         /* identifiers */
463         ot->name= "Add Curve";
464         ot->description = "Add a curve object to the scene.";
465         ot->idname= "OBJECT_OT_curve_add";
466         
467         /* api callbacks */
468         ot->invoke= object_add_curve_invoke;
469         ot->exec= object_add_curve_exec;
470         
471         ot->poll= ED_operator_scene_editable;
472         
473         /* flags */
474         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
475         
476         RNA_def_enum(ot->srna, "type", prop_curve_types, 0, "Primitive", "");
477 }
478
479 static EnumPropertyItem prop_surface_types[]= {
480         {CU_PRIM_CURVE|CU_NURBS, "NURBS_CURVE", ICON_SURFACE_NCURVE, "NURBS Curve", ""},
481         {CU_PRIM_CIRCLE|CU_NURBS, "NURBS_CIRCLE", ICON_SURFACE_NCIRCLE, "NURBS Circle", ""},
482         {CU_PRIM_PATCH|CU_NURBS, "NURBS_SURFACE", ICON_SURFACE_NSURFACE, "NURBS Surface", ""},
483         {CU_PRIM_TUBE|CU_NURBS, "NURBS_TUBE", ICON_SURFACE_NTUBE, "NURBS Tube", ""},
484         {CU_PRIM_SPHERE|CU_NURBS, "NURBS_SPHERE", ICON_SURFACE_NSPHERE, "NURBS Sphere", ""},
485         {CU_PRIM_DONUT|CU_NURBS, "NURBS_DONUT", ICON_SURFACE_NDONUT, "NURBS Donut", ""},
486         {0, NULL, 0, NULL, NULL}
487 };
488
489 static int object_add_surface_exec(bContext *C, wmOperator *op)
490 {
491         Object *obedit= CTX_data_edit_object(C);
492         ListBase *editnurb;
493         Nurb *nu;
494         int newob= 0;
495         
496         if(obedit==NULL || obedit->type!=OB_SURF) {
497                 object_add_type(C, OB_SURF);
498                 ED_object_enter_editmode(C, 0);
499                 newob = 1;
500         }
501         else DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
502         
503         obedit= CTX_data_edit_object(C);
504         nu= add_nurbs_primitive(C, RNA_enum_get(op->ptr, "type"), newob);
505         editnurb= curve_get_editcurve(obedit);
506         BLI_addtail(editnurb, nu);
507         
508         /* userdef */
509         if (newob && (U.flag & USER_ADD_EDITMODE)==0) {
510                 ED_object_exit_editmode(C, EM_FREEDATA);
511         }
512         
513         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
514         
515         return OPERATOR_FINISHED;
516 }
517
518 void OBJECT_OT_surface_add(wmOperatorType *ot)
519 {
520         /* identifiers */
521         ot->name= "Add Surface";
522         ot->description = "Add a surface object to the scene.";
523         ot->idname= "OBJECT_OT_surface_add";
524         
525         /* api callbacks */
526         ot->invoke= WM_menu_invoke;
527         ot->exec= object_add_surface_exec;
528         
529         ot->poll= ED_operator_scene_editable;
530         
531         /* flags */
532         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
533         
534         RNA_def_enum(ot->srna, "type", prop_surface_types, 0, "Primitive", "");
535 }
536
537 static EnumPropertyItem prop_metaball_types[]= {
538         {MB_BALL, "MBALL_BALL", ICON_META_BALL, "Meta Ball", ""},
539         {MB_TUBE, "MBALL_TUBE", ICON_META_TUBE, "Meta Tube", ""},
540         {MB_PLANE, "MBALL_PLANE", ICON_META_PLANE, "Meta Plane", ""},
541         {MB_CUBE, "MBALL_CUBE", ICON_META_CUBE, "Meta Cube", ""},
542         {MB_ELIPSOID, "MBALL_ELLIPSOID", ICON_META_ELLIPSOID, "Meta Ellipsoid", ""},
543         {0, NULL, 0, NULL, NULL}
544 };
545
546 static int object_metaball_add_exec(bContext *C, wmOperator *op)
547 {
548         Object *obedit= CTX_data_edit_object(C);
549         MetaBall *mball;
550         MetaElem *elem;
551         int newob= 0;
552         
553         if(obedit==NULL || obedit->type!=OB_MBALL) {
554                 object_add_type(C, OB_MBALL);
555                 ED_object_enter_editmode(C, 0);
556                 newob = 1;
557         }
558         else DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
559         
560         obedit= CTX_data_edit_object(C);
561         elem= (MetaElem*)add_metaball_primitive(C, RNA_enum_get(op->ptr, "type"), newob);
562         mball= (MetaBall*)obedit->data;
563         BLI_addtail(mball->editelems, elem);
564         
565         /* userdef */
566         if (newob && (U.flag & USER_ADD_EDITMODE)==0) {
567                 ED_object_exit_editmode(C, EM_FREEDATA);
568         }
569         
570         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
571         
572         return OPERATOR_FINISHED;
573 }
574
575 static int object_metaball_add_invoke(bContext *C, wmOperator *op, wmEvent *event)
576 {
577         Object *obedit= CTX_data_edit_object(C);
578         uiPopupMenu *pup;
579         uiLayout *layout;
580
581         pup= uiPupMenuBegin(C, op->type->name, 0);
582         layout= uiPupMenuLayout(pup);
583         if(!obedit || obedit->type == OB_MBALL)
584                 uiItemsEnumO(layout, op->type->idname, "type");
585         else
586                 uiItemsEnumO(layout, "OBJECT_OT_metaball_add", "type");
587         uiPupMenuEnd(C, pup);
588
589         return OPERATOR_CANCELLED;
590 }
591
592 void OBJECT_OT_metaball_add(wmOperatorType *ot)
593 {
594         /* identifiers */
595         ot->name= "Metaball";
596         ot->description= "Add an metaball object to the scene.";
597         ot->idname= "OBJECT_OT_metaball_add";
598
599         /* api callbacks */
600         ot->invoke= object_metaball_add_invoke;
601         ot->exec= object_metaball_add_exec;
602         ot->poll= ED_operator_scene_editable;
603
604         /* flags */
605         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
606         
607         RNA_def_enum(ot->srna, "type", prop_metaball_types, 0, "Primitive", "");
608 }
609 static int object_add_text_exec(bContext *C, wmOperator *op)
610 {
611         Object *obedit= CTX_data_edit_object(C);
612         
613         if(obedit && obedit->type==OB_FONT)
614                 return OPERATOR_CANCELLED;
615
616         object_add_type(C, OB_FONT);
617         obedit= CTX_data_active_object(C);
618
619         if(U.flag & USER_ADD_EDITMODE)
620                 ED_object_enter_editmode(C, 0);
621         
622         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
623         
624         return OPERATOR_FINISHED;
625 }
626
627 void OBJECT_OT_text_add(wmOperatorType *ot)
628 {
629         /* identifiers */
630         ot->name= "Add Text";
631         ot->description = "Add a text object to the scene";
632         ot->idname= "OBJECT_OT_text_add";
633         
634         /* api callbacks */
635         ot->exec= object_add_text_exec;
636         ot->poll= ED_operator_scene_editable;
637         
638         /* flags */
639         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
640 }
641
642 static int object_armature_add_exec(bContext *C, wmOperator *op)
643 {
644         Object *obedit= CTX_data_edit_object(C);
645         View3D *v3d= CTX_wm_view3d(C);
646         RegionView3D *rv3d= NULL;
647         int newob= 0;
648         
649         if ((obedit==NULL) || (obedit->type != OB_ARMATURE)) {
650                 object_add_type(C, OB_ARMATURE);
651                 ED_object_enter_editmode(C, 0);
652                 newob = 1;
653         }
654         else DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
655         
656         if(v3d) 
657                 rv3d= CTX_wm_region(C)->regiondata;
658         
659         /* v3d and rv3d are allowed to be NULL */
660         add_primitive_bone(CTX_data_scene(C), v3d, rv3d);
661
662         /* userdef */
663         if (newob && (U.flag & USER_ADD_EDITMODE)==0) {
664                 ED_object_exit_editmode(C, EM_FREEDATA);
665         }
666         
667         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
668         
669         return OPERATOR_FINISHED;
670 }
671
672 void OBJECT_OT_armature_add(wmOperatorType *ot)
673 {       
674         /* identifiers */
675         ot->name= "Add Armature";
676         ot->description = "Add an armature object to the scene.";
677         ot->idname= "OBJECT_OT_armature_add";
678         
679         /* api callbacks */
680         ot->exec= object_armature_add_exec;
681         ot->poll= ED_operator_scene_editable;
682         
683         /* flags */
684         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
685 }
686
687 static int object_primitive_add_invoke(bContext *C, wmOperator *op, wmEvent *event)
688 {
689         uiPopupMenu *pup= uiPupMenuBegin(C, "Add Object", 0);
690         uiLayout *layout= uiPupMenuLayout(pup);
691         
692         uiItemMenuEnumO(layout, "Mesh", ICON_OUTLINER_OB_MESH, "OBJECT_OT_mesh_add", "type");
693         uiItemMenuEnumO(layout, "Curve", ICON_OUTLINER_OB_CURVE, "OBJECT_OT_curve_add", "type");
694         uiItemMenuEnumO(layout, "Surface", ICON_OUTLINER_OB_SURFACE, "OBJECT_OT_surface_add", "type");
695         uiItemMenuEnumO(layout, NULL, ICON_OUTLINER_OB_META, "OBJECT_OT_metaball_add", "type");
696         uiItemO(layout, "Text", ICON_OUTLINER_OB_FONT, "OBJECT_OT_text_add");
697         uiItemS(layout);
698         uiItemO(layout, "Armature", ICON_OUTLINER_OB_ARMATURE, "OBJECT_OT_armature_add");
699         uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_LATTICE, "OBJECT_OT_object_add", "type", OB_LATTICE);
700         uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_EMPTY, "OBJECT_OT_object_add", "type", OB_EMPTY);
701         uiItemS(layout);
702         uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_CAMERA, "OBJECT_OT_object_add", "type", OB_CAMERA);
703         uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_LAMP, "OBJECT_OT_object_add", "type", OB_LAMP);
704         
705         uiPupMenuEnd(C, pup);
706         
707         /* this operator is only for a menu, not used further */
708         return OPERATOR_CANCELLED;
709 }
710
711 /* only used as menu */
712 void OBJECT_OT_primitive_add(wmOperatorType *ot)
713 {
714         /* identifiers */
715         ot->name= "Add Primitive";
716         ot->description = "Add a primitive object.";
717         ot->idname= "OBJECT_OT_primitive_add";
718         
719         /* api callbacks */
720         ot->invoke= object_primitive_add_invoke;
721         
722         ot->poll= ED_operator_scene_editable;
723         
724         /* flags */
725         ot->flag= 0;
726 }
727
728
729 /* ******************************* */
730
731 /* remove base from a specific scene */
732 /* note: now unlinks constraints as well */
733 void ED_base_object_free_and_unlink(Scene *scene, Base *base)
734 {
735         BLI_remlink(&scene->base, base);
736         free_libblock_us(&G.main->object, base->object);
737         if(scene->basact==base) scene->basact= NULL;
738         MEM_freeN(base);
739 }
740
741 static int object_delete_exec(bContext *C, wmOperator *op)
742 {
743         Scene *scene= CTX_data_scene(C);
744         int islamp= 0;
745         
746         if(CTX_data_edit_object(C)) 
747                 return OPERATOR_CANCELLED;
748         
749         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
750
751                 if(base->object->type==OB_LAMP) islamp= 1;
752                 
753                 /* remove from current scene only */
754                 ED_base_object_free_and_unlink(scene, base);
755         }
756         CTX_DATA_END;
757
758         if(islamp) reshadeall_displist(scene);  /* only frees displist */
759         
760         DAG_scene_sort(scene);
761         ED_anim_dag_flush_update(C);
762         
763         WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, CTX_data_scene(C));
764         
765         return OPERATOR_FINISHED;
766 }
767
768 void OBJECT_OT_delete(wmOperatorType *ot)
769 {
770         
771         /* identifiers */
772         ot->name= "Delete";
773         ot->description = "Delete selected objects.";
774         ot->idname= "OBJECT_OT_delete";
775         
776         /* api callbacks */
777         ot->invoke= WM_operator_confirm;
778         ot->exec= object_delete_exec;
779         ot->poll= ED_operator_scene_editable;
780         
781         /* flags */
782         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
783         
784 }
785
786
787 static void single_object_users__forwardModifierLinks(void *userData, Object *ob, Object **obpoin)
788 {
789         ID_NEW(*obpoin);
790 }
791
792 static void copy_object__forwardModifierLinks(void *userData, Object *ob,
793                                               ID **idpoin)
794 {
795         /* this is copied from ID_NEW; it might be better to have a macro */
796         if(*idpoin && (*idpoin)->newid) *idpoin = (*idpoin)->newid;
797 }
798
799
800 /* after copying objects, copied data should get new pointers */
801 static void copy_object_set_idnew(Scene *scene, View3D *v3d, int dupflag)
802 {
803         Base *base;
804         Object *ob;
805         Material *ma, *mao;
806         ID *id;
807 #if 0 // XXX old animation system
808         Ipo *ipo;
809         bActionStrip *strip;
810 #endif // XXX old animation system
811         int a;
812         
813         /* XXX check object pointers */
814         for(base= FIRSTBASE; base; base= base->next) {
815                 if(TESTBASELIB_BGMODE(v3d, base)) {
816                         ob= base->object;
817                         relink_constraints(&ob->constraints);
818                         if (ob->pose){
819                                 bPoseChannel *chan;
820                                 for (chan = ob->pose->chanbase.first; chan; chan=chan->next){
821                                         relink_constraints(&chan->constraints);
822                                 }
823                         }
824                         modifiers_foreachIDLink(ob, copy_object__forwardModifierLinks, NULL);
825                         ID_NEW(ob->parent);
826                         ID_NEW(ob->track);
827                         ID_NEW(ob->proxy);
828                         ID_NEW(ob->proxy_group);
829                         
830 #if 0 // XXX old animation system
831                         for(strip= ob->nlastrips.first; strip; strip= strip->next) {
832                                 bActionModifier *amod;
833                                 for(amod= strip->modifiers.first; amod; amod= amod->next)
834                                         ID_NEW(amod->ob);
835                         }
836 #endif // XXX old animation system
837                 }
838         }
839         
840         /* materials */
841         if( dupflag & USER_DUP_MAT) {
842                 mao= G.main->mat.first;
843                 while(mao) {
844                         if(mao->id.newid) {
845                                 
846                                 ma= (Material *)mao->id.newid;
847                                 
848                                 if(dupflag & USER_DUP_TEX) {
849                                         for(a=0; a<MAX_MTEX; a++) {
850                                                 if(ma->mtex[a]) {
851                                                         id= (ID *)ma->mtex[a]->tex;
852                                                         if(id) {
853                                                                 ID_NEW_US(ma->mtex[a]->tex)
854                                                                 else ma->mtex[a]->tex= copy_texture(ma->mtex[a]->tex);
855                                                                 id->us--;
856                                                         }
857                                                 }
858                                         }
859                                 }
860 #if 0 // XXX old animation system
861                                 id= (ID *)ma->ipo;
862                                 if(id) {
863                                         ID_NEW_US(ma->ipo)
864                                         else ma->ipo= copy_ipo(ma->ipo);
865                                         id->us--;
866                                 }
867 #endif // XXX old animation system
868                         }
869                         mao= mao->id.next;
870                 }
871         }
872         
873 #if 0 // XXX old animation system
874         /* lamps */
875         if( dupflag & USER_DUP_IPO) {
876                 Lamp *la= G.main->lamp.first;
877                 while(la) {
878                         if(la->id.newid) {
879                                 Lamp *lan= (Lamp *)la->id.newid;
880                                 id= (ID *)lan->ipo;
881                                 if(id) {
882                                         ID_NEW_US(lan->ipo)
883                                         else lan->ipo= copy_ipo(lan->ipo);
884                                         id->us--;
885                                 }
886                         }
887                         la= la->id.next;
888                 }
889         }
890         
891         /* ipos */
892         ipo= G.main->ipo.first;
893         while(ipo) {
894                 if(ipo->id.lib==NULL && ipo->id.newid) {
895                         Ipo *ipon= (Ipo *)ipo->id.newid;
896                         IpoCurve *icu;
897                         for(icu= ipon->curve.first; icu; icu= icu->next) {
898                                 if(icu->driver) {
899                                         ID_NEW(icu->driver->ob);
900                                 }
901                         }
902                 }
903                 ipo= ipo->id.next;
904         }
905 #endif // XXX old animation system
906         
907         set_sca_new_poins();
908         
909         clear_id_newpoins();
910         
911 }
912
913 static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float *cent)
914 {
915         EditVert *eve;
916         int *index, nr, totvert=0;
917         
918         for(eve= em->verts.first; eve; eve= eve->next) {
919                 if(eve->f & SELECT) totvert++;
920         }
921         if(totvert==0) return 0;
922         
923         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
924         *tot= totvert;
925         nr= 0;
926         cent[0]= cent[1]= cent[2]= 0.0;
927         
928         for(eve= em->verts.first; eve; eve= eve->next) {
929                 if(eve->f & SELECT) {
930                         *index= nr; index++;
931                         VecAddf(cent, cent, eve->co);
932                 }
933                 nr++;
934         }
935         
936         VecMulf(cent, 1.0f/(float)totvert);
937         
938         return totvert;
939 }
940
941 static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, float *cent)
942 {
943         MDeformVert *dvert;
944         EditVert *eve;
945         int i, totvert=0;
946         
947         cent[0]= cent[1]= cent[2]= 0.0;
948         
949         if(obedit->actdef) {
950                 
951                 /* find the vertices */
952                 for(eve= em->verts.first; eve; eve= eve->next) {
953                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
954
955                         if(dvert) {
956                                 for(i=0; i<dvert->totweight; i++){
957                                         if(dvert->dw[i].def_nr == (obedit->actdef-1)) {
958                                                 totvert++;
959                                                 VecAddf(cent, cent, eve->co);
960                                         }
961                                 }
962                         }
963                 }
964                 if(totvert) {
965                         bDeformGroup *defGroup = BLI_findlink(&obedit->defbase, obedit->actdef-1);
966                         strcpy(name, defGroup->name);
967                         VecMulf(cent, 1.0f/(float)totvert);
968                         return 1;
969                 }
970         }
971         
972         return 0;
973 }       
974
975 static void select_editmesh_hook(Object *ob, HookModifierData *hmd)
976 {
977         Mesh *me= ob->data;
978         EditMesh *em= BKE_mesh_get_editmesh(me);
979         EditVert *eve;
980         int index=0, nr=0;
981         
982         if (hmd->indexar == NULL)
983                 return;
984         
985         for(eve= em->verts.first; eve; eve= eve->next, nr++) {
986                 if(nr==hmd->indexar[index]) {
987                         eve->f |= SELECT;
988                         if(index < hmd->totindex-1) index++;
989                 }
990         }
991         EM_select_flush(em);
992
993         BKE_mesh_end_editmesh(me, em);
994 }
995
996 static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent)
997 {
998         BPoint *bp;
999         int *index, nr, totvert=0, a;
1000         
1001         /* count */
1002         a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
1003         bp= editlatt->def;
1004         while(a--) {
1005                 if(bp->f1 & SELECT) {
1006                         if(bp->hide==0) totvert++;
1007                 }
1008                 bp++;
1009         }
1010
1011         if(totvert==0) return 0;
1012         
1013         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
1014         *tot= totvert;
1015         nr= 0;
1016         cent[0]= cent[1]= cent[2]= 0.0;
1017         
1018         a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
1019         bp= editlatt->def;
1020         while(a--) {
1021                 if(bp->f1 & SELECT) {
1022                         if(bp->hide==0) {
1023                                 *index= nr; index++;
1024                                 VecAddf(cent, cent, bp->vec);
1025                         }
1026                 }
1027                 bp++;
1028                 nr++;
1029         }
1030         
1031         VecMulf(cent, 1.0f/(float)totvert);
1032         
1033         return totvert;
1034 }
1035
1036 static void select_editlattice_hook(Object *obedit, HookModifierData *hmd)
1037 {
1038         Lattice *lt= obedit->data;
1039         BPoint *bp;
1040         int index=0, nr=0, a;
1041         
1042         /* count */
1043         a= lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw;
1044         bp= lt->editlatt->def;
1045         while(a--) {
1046                 if(hmd->indexar[index]==nr) {
1047                         bp->f1 |= SELECT;
1048                         if(index < hmd->totindex-1) index++;
1049                 }
1050                 nr++;
1051                 bp++;
1052         }
1053 }
1054
1055 static int return_editcurve_indexar(Object *obedit, int *tot, int **indexar, float *cent)
1056 {
1057         ListBase *editnurb= curve_get_editcurve(obedit);
1058         Nurb *nu;
1059         BPoint *bp;
1060         BezTriple *bezt;
1061         int *index, a, nr, totvert=0;
1062         
1063         for(nu= editnurb->first; nu; nu= nu->next) {
1064                 if((nu->type & 7)==CU_BEZIER) {
1065                         bezt= nu->bezt;
1066                         a= nu->pntsu;
1067                         while(a--) {
1068                                 if(bezt->f1 & SELECT) totvert++;
1069                                 if(bezt->f2 & SELECT) totvert++;
1070                                 if(bezt->f3 & SELECT) totvert++;
1071                                 bezt++;
1072                         }
1073                 }
1074                 else {
1075                         bp= nu->bp;
1076                         a= nu->pntsu*nu->pntsv;
1077                         while(a--) {
1078                                 if(bp->f1 & SELECT) totvert++;
1079                                 bp++;
1080                         }
1081                 }
1082         }
1083         if(totvert==0) return 0;
1084         
1085         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
1086         *tot= totvert;
1087         nr= 0;
1088         cent[0]= cent[1]= cent[2]= 0.0;
1089         
1090         for(nu= editnurb->first; nu; nu= nu->next) {
1091                 if((nu->type & 7)==CU_BEZIER) {
1092                         bezt= nu->bezt;
1093                         a= nu->pntsu;
1094                         while(a--) {
1095                                 if(bezt->f1 & SELECT) {
1096                                         *index= nr; index++;
1097                                         VecAddf(cent, cent, bezt->vec[0]);
1098                                 }
1099                                 nr++;
1100                                 if(bezt->f2 & SELECT) {
1101                                         *index= nr; index++;
1102                                         VecAddf(cent, cent, bezt->vec[1]);
1103                                 }
1104                                 nr++;
1105                                 if(bezt->f3 & SELECT) {
1106                                         *index= nr; index++;
1107                                         VecAddf(cent, cent, bezt->vec[2]);
1108                                 }
1109                                 nr++;
1110                                 bezt++;
1111                         }
1112                 }
1113                 else {
1114                         bp= nu->bp;
1115                         a= nu->pntsu*nu->pntsv;
1116                         while(a--) {
1117                                 if(bp->f1 & SELECT) {
1118                                         *index= nr; index++;
1119                                         VecAddf(cent, cent, bp->vec);
1120                                 }
1121                                 nr++;
1122                                 bp++;
1123                         }
1124                 }
1125         }
1126         
1127         VecMulf(cent, 1.0f/(float)totvert);
1128         
1129         return totvert;
1130 }
1131
1132 void ED_object_apply_obmat(Object *ob)
1133 {
1134         float mat[3][3], imat[3][3], tmat[3][3];
1135         
1136         /* from obmat to loc rot size */
1137         
1138         if(ob==NULL) return;
1139         Mat3CpyMat4(mat, ob->obmat);
1140         
1141         VECCOPY(ob->loc, ob->obmat[3]);
1142
1143         Mat3ToEul(mat, ob->rot);
1144         EulToMat3(ob->rot, tmat);
1145
1146         Mat3Inv(imat, tmat);
1147         
1148         Mat3MulMat3(tmat, imat, mat);
1149         
1150         ob->size[0]= tmat[0][0];
1151         ob->size[1]= tmat[1][1];
1152         ob->size[2]= tmat[2][2];
1153         
1154 }
1155
1156 int object_hook_index_array(Object *obedit, int *tot, int **indexar, char *name, float *cent_r)
1157 {
1158         *indexar= NULL;
1159         *tot= 0;
1160         name[0]= 0;
1161         
1162         switch(obedit->type) {
1163                 case OB_MESH:
1164                 {
1165                         Mesh *me= obedit->data;
1166                         EditMesh *em = BKE_mesh_get_editmesh(me);
1167
1168                         /* check selected vertices first */
1169                         if( return_editmesh_indexar(em, tot, indexar, cent_r)) {
1170                                 BKE_mesh_end_editmesh(me, em);
1171                                 return 1;
1172                         } else {
1173                                 int ret = return_editmesh_vgroup(obedit, em, name, cent_r);
1174                                 BKE_mesh_end_editmesh(me, em);
1175                                 return ret;
1176                         }
1177                 }
1178                 case OB_CURVE:
1179                 case OB_SURF:
1180                         return return_editcurve_indexar(obedit, tot, indexar, cent_r);
1181                 case OB_LATTICE:
1182                 {
1183                         Lattice *lt= obedit->data;
1184                         return return_editlattice_indexar(lt->editlatt, tot, indexar, cent_r);
1185                 }
1186                 default:
1187                         return 0;
1188         }
1189 }
1190
1191 static void select_editcurve_hook(Object *obedit, HookModifierData *hmd)
1192 {
1193         ListBase *editnurb= curve_get_editcurve(obedit);
1194         Nurb *nu;
1195         BPoint *bp;
1196         BezTriple *bezt;
1197         int index=0, a, nr=0;
1198         
1199         for(nu= editnurb->first; nu; nu= nu->next) {
1200                 if((nu->type & 7)==CU_BEZIER) {
1201                         bezt= nu->bezt;
1202                         a= nu->pntsu;
1203                         while(a--) {
1204                                 if(nr == hmd->indexar[index]) {
1205                                         bezt->f1 |= SELECT;
1206                                         if(index<hmd->totindex-1) index++;
1207                                 }
1208                                 nr++;
1209                                 if(nr == hmd->indexar[index]) {
1210                                         bezt->f2 |= SELECT;
1211                                         if(index<hmd->totindex-1) index++;
1212                                 }
1213                                 nr++;
1214                                 if(nr == hmd->indexar[index]) {
1215                                         bezt->f3 |= SELECT;
1216                                         if(index<hmd->totindex-1) index++;
1217                                 }
1218                                 nr++;
1219                                 
1220                                 bezt++;
1221                         }
1222                 }
1223                 else {
1224                         bp= nu->bp;
1225                         a= nu->pntsu*nu->pntsv;
1226                         while(a--) {
1227                                 if(nr == hmd->indexar[index]) {
1228                                         bp->f1 |= SELECT;
1229                                         if(index<hmd->totindex-1) index++;
1230                                 }
1231                                 nr++;
1232                                 bp++;
1233                         }
1234                 }
1235         }
1236 }
1237
1238 void object_hook_select(Object *ob, HookModifierData *hmd) 
1239 {
1240         if(ob->type==OB_MESH) select_editmesh_hook(ob, hmd);
1241         else if(ob->type==OB_LATTICE) select_editlattice_hook(ob, hmd);
1242         else if(ob->type==OB_CURVE) select_editcurve_hook(ob, hmd);
1243         else if(ob->type==OB_SURF) select_editcurve_hook(ob, hmd);
1244 }
1245
1246
1247 void add_hook(Scene *scene, View3D *v3d, int mode)
1248 {
1249         ModifierData *md = NULL;
1250         HookModifierData *hmd = NULL;
1251         Object *ob=NULL;
1252         Object *obedit= scene->obedit;  // XXX get from context
1253         
1254         if(obedit==NULL) return;
1255         
1256         /* preconditions */
1257         if(mode==2) { /* selected object */
1258                 Base *base;
1259                 for(base= FIRSTBASE; base; base= base->next) {
1260                         if(TESTBASELIB(v3d, base)) {
1261                                 if(base!=BASACT) {
1262                                         ob= base->object;
1263                                         break;
1264                                 }
1265                         }
1266                 }
1267                 if(ob==NULL) {
1268                         error("Requires selected Object");
1269                         return;
1270                 }
1271         }
1272         else if(mode!=1) {
1273                 int maxlen=0, a, nr;
1274                 char *cp;
1275                 
1276                 /* make pupmenu with hooks */
1277                 for(md=obedit->modifiers.first; md; md= md->next) {
1278                         if (md->type==eModifierType_Hook) 
1279                                 maxlen+=32;
1280                 }
1281                 
1282                 if(maxlen==0) {
1283                         error("Object has no hooks yet");
1284                         return;
1285                 }
1286                 
1287                 cp= MEM_callocN(maxlen+32, "temp string");
1288                 if(mode==3) strcpy(cp, "Remove %t|");
1289                 else if(mode==4) strcpy(cp, "Reassign %t|");
1290                 else if(mode==5) strcpy(cp, "Select %t|");
1291                 else if(mode==6) strcpy(cp, "Clear Offset %t|");
1292                 
1293                 for(md=obedit->modifiers.first; md; md= md->next) {
1294                         if (md->type==eModifierType_Hook) {
1295                                 strcat(cp, md->name);
1296                                 strcat(cp, " |");
1297                         }
1298                 }
1299                 
1300                 nr= pupmenu(cp);
1301                 MEM_freeN(cp);
1302                 
1303                 if(nr<1) return;
1304                 
1305                 a= 1;
1306                 for(md=obedit->modifiers.first; md; md=md->next) {
1307                         if (md->type==eModifierType_Hook) {
1308                                 if(a==nr) break;
1309                                 a++;
1310                         }
1311                 }
1312                 
1313                 hmd = (HookModifierData*) md;
1314                 ob= hmd->object;
1315         }
1316
1317         /* do it, new hooks or reassign */
1318         if(mode==1 || mode==2 || mode==4) {
1319                 float cent[3];
1320                 int tot, ok, *indexar;
1321                 char name[32];
1322                 
1323                 ok = object_hook_index_array(obedit, &tot, &indexar, name, cent);
1324                 
1325                 if(ok==0) {
1326                         error("Requires selected vertices or active Vertex Group");
1327                 }
1328                 else {
1329                         
1330                         if(mode==1) {
1331                                 Base *base= BASACT, *newbase;
1332                                 
1333                                 ob= add_object(scene, OB_EMPTY);
1334                                 /* set layers OK */
1335                                 newbase= BASACT;
1336                                 newbase->lay= base->lay;
1337                                 ob->lay= newbase->lay;
1338                                 
1339                                 /* transform cent to global coords for loc */
1340                                 VecMat4MulVecfl(ob->loc, obedit->obmat, cent);
1341                                 
1342                                 /* restore, add_object sets active */
1343                                 BASACT= base;
1344                         }
1345                         /* if mode is 2 or 4, ob has been set */
1346                         
1347                         /* new hook */
1348                         if(mode==1 || mode==2) {
1349                                 ModifierData *md = obedit->modifiers.first;
1350                                 
1351                                 while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
1352                                         md = md->next;
1353                                 }
1354                                 
1355                                 hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
1356                                 BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
1357                                 sprintf(hmd->modifier.name, "Hook-%s", ob->id.name+2);
1358                         }
1359                         else if (hmd->indexar) MEM_freeN(hmd->indexar); /* reassign, hook was set */
1360                 
1361                         hmd->object= ob;
1362                         hmd->indexar= indexar;
1363                         VECCOPY(hmd->cent, cent);
1364                         hmd->totindex= tot;
1365                         BLI_strncpy(hmd->name, name, 32);
1366                         
1367                         // TODO: need to take into account bone targets here too now...
1368                         if(mode==1 || mode==2) {
1369                                 /* matrix calculus */
1370                                 /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
1371                                 /*        (parentinv         )                          */
1372                                 
1373                                 where_is_object(scene, ob);
1374                                 
1375                                 Mat4Invert(ob->imat, ob->obmat);
1376                                 /* apparently this call goes from right to left... */
1377                                 Mat4MulSerie(hmd->parentinv, ob->imat, obedit->obmat, NULL, 
1378                                                          NULL, NULL, NULL, NULL, NULL);
1379                         }
1380                 }
1381         }
1382         else if(mode==3) { /* remove */
1383                 BLI_remlink(&obedit->modifiers, md);
1384                 modifier_free(md);
1385         }
1386         else if(mode==5) { /* select */
1387                 object_hook_select(obedit, hmd);
1388         }
1389         else if(mode==6) { /* clear offset */
1390                 where_is_object(scene, ob);     /* ob is hook->parent */
1391
1392                 Mat4Invert(ob->imat, ob->obmat);
1393                 /* this call goes from right to left... */
1394                 Mat4MulSerie(hmd->parentinv, ob->imat, obedit->obmat, NULL, 
1395                                          NULL, NULL, NULL, NULL, NULL);
1396         }
1397
1398         DAG_scene_sort(scene);
1399 }
1400
1401
1402 /* use this when the loc/size/rot of the parent has changed but the children should stay in the same place
1403  * apply-size-rot or object center for eg */
1404 static void ignore_parent_tx(Scene *scene, Object *ob ) 
1405 {
1406         Object workob;
1407         Object *ob_child;
1408         
1409         /* a change was made, adjust the children to compensate */
1410         for (ob_child=G.main->object.first; ob_child; ob_child=ob_child->id.next) {
1411                 if (ob_child->parent == ob) {
1412                         ED_object_apply_obmat(ob_child);
1413                         what_does_parent(scene, ob_child, &workob);
1414                         Mat4Invert(ob_child->parentinv, workob.obmat);
1415                 }
1416         }
1417 }
1418
1419
1420 void add_hook_menu(Scene *scene, View3D *v3d)
1421 {
1422         Object *obedit= scene->obedit;  // XXX get from context
1423         int mode;
1424         
1425         if(obedit==NULL) return;
1426         
1427         if(modifiers_findByType(obedit, eModifierType_Hook))
1428                 mode= pupmenu("Hooks %t|Add, To New Empty %x1|Add, To Selected Object %x2|Remove... %x3|Reassign... %x4|Select... %x5|Clear Offset...%x6");
1429         else
1430                 mode= pupmenu("Hooks %t|Add, New Empty %x1|Add, To Selected Object %x2");
1431
1432         if(mode<1) return;
1433                 
1434         /* do operations */
1435         add_hook(scene, v3d, mode);
1436 }
1437
1438 /* ******************** clear parent operator ******************* */
1439
1440 static EnumPropertyItem prop_clear_parent_types[] = {
1441         {0, "CLEAR", 0, "Clear Parent", ""},
1442         {1, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation (Clear Track)", ""},
1443         {2, "CLEAR_INVERSE", 0, "Clear Parent Inverse", ""},
1444         {0, NULL, 0, NULL, NULL}
1445 };
1446
1447 /* note, poll should check for editable scene */
1448 static int parent_clear_exec(bContext *C, wmOperator *op)
1449 {
1450         int type= RNA_enum_get(op->ptr, "type");
1451         
1452         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
1453
1454                 if(type == 0) {
1455                         ob->parent= NULL;
1456                 }                       
1457                 else if(type == 1) {
1458                         ob->parent= NULL;
1459                         ob->track= NULL;
1460                         ED_object_apply_obmat(ob);
1461                 }
1462                 else if(type == 2)
1463                         Mat4One(ob->parentinv);
1464
1465                 ob->recalc |= OB_RECALC;
1466         }
1467         CTX_DATA_END;
1468         
1469         DAG_scene_sort(CTX_data_scene(C));
1470         ED_anim_dag_flush_update(C);
1471         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1472
1473         return OPERATOR_FINISHED;
1474 }
1475
1476 void OBJECT_OT_parent_clear(wmOperatorType *ot)
1477 {
1478         /* identifiers */
1479         ot->name= "Clear Parent";
1480         ot->description = "Clear the object's parenting.";
1481         ot->idname= "OBJECT_OT_parent_clear";
1482         
1483         /* api callbacks */
1484         ot->invoke= WM_menu_invoke;
1485         ot->exec= parent_clear_exec;
1486         
1487         ot->poll= ED_operator_object_active;
1488         
1489         /* flags */
1490         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1491         
1492         RNA_def_enum(ot->srna, "type", prop_clear_parent_types, 0, "Type", "");
1493 }
1494
1495 /* ******************** clear track operator ******************* */
1496
1497
1498 static EnumPropertyItem prop_clear_track_types[] = {
1499         {0, "CLEAR", 0, "Clear Track", ""},
1500         {1, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation (Clear Track)", ""},
1501         {0, NULL, 0, NULL, NULL}
1502 };
1503
1504 /* note, poll should check for editable scene */
1505 static int object_track_clear_exec(bContext *C, wmOperator *op)
1506 {
1507         int type= RNA_enum_get(op->ptr, "type");
1508
1509         if(CTX_data_edit_object(C)) {
1510                 BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in EditMode");
1511                 return OPERATOR_CANCELLED;
1512         }
1513         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
1514                 ob->track= NULL;
1515                 ob->recalc |= OB_RECALC;
1516                 
1517                 if(type == 1)
1518                         ED_object_apply_obmat(ob);
1519         }
1520         CTX_DATA_END;
1521
1522         DAG_scene_sort(CTX_data_scene(C));
1523         ED_anim_dag_flush_update(C);
1524
1525         return OPERATOR_FINISHED;
1526 }
1527
1528 void OBJECT_OT_track_clear(wmOperatorType *ot)
1529 {
1530         /* identifiers */
1531         ot->name= "Clear track";
1532         ot->description = "Clear tracking constraint or flag from object.";
1533         ot->idname= "OBJECT_OT_track_clear";
1534         
1535         /* api callbacks */
1536         ot->invoke= WM_menu_invoke;
1537         ot->exec= object_track_clear_exec;
1538         
1539         ot->poll= ED_operator_scene_editable;
1540         
1541         /* flags */
1542         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1543         
1544         RNA_def_enum(ot->srna, "type", prop_clear_track_types, 0, "Type", "");
1545 }
1546
1547 /* *****************Selection Operators******************* */
1548 static EnumPropertyItem prop_select_types[] = {
1549         {0, "EXCLUSIVE", 0, "Exclusive", ""},
1550         {1, "EXTEND", 0, "Extend", ""},
1551         {0, NULL, 0, NULL, NULL}
1552 };
1553
1554 /* ****** Select by Type ****** */
1555
1556 static int object_select_by_type_exec(bContext *C, wmOperator *op)
1557 {
1558         short obtype, seltype;
1559         
1560         obtype = RNA_enum_get(op->ptr, "type");
1561         seltype = RNA_enum_get(op->ptr, "seltype");
1562                 
1563         if (seltype == 0) {
1564                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1565                         ED_base_object_select(base, BA_DESELECT);
1566                 }
1567                 CTX_DATA_END;
1568         }
1569         
1570         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1571                 if(base->object->type==obtype) {
1572                         ED_base_object_select(base, BA_SELECT);
1573                 }
1574         }
1575         CTX_DATA_END;
1576         
1577         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1578         
1579         return OPERATOR_FINISHED;
1580 }
1581
1582 void OBJECT_OT_select_by_type(wmOperatorType *ot)
1583 {
1584         /* identifiers */
1585         ot->name= "Select By Type";
1586         ot->description = "Select all visible objects that are of a type.";
1587         ot->idname= "OBJECT_OT_select_by_type";
1588         
1589         /* api callbacks */
1590         ot->invoke= WM_menu_invoke;
1591         ot->exec= object_select_by_type_exec;
1592         ot->poll= ED_operator_scene_editable;
1593         
1594         /* flags */
1595         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1596         
1597         RNA_def_enum(ot->srna, "seltype", prop_select_types, 0, "Selection", "Extend selection or clear selection then select");
1598         RNA_def_enum(ot->srna, "type", prop_object_types, 1, "Type", "");
1599
1600 }
1601 /* ****** selection by links *******/
1602
1603 static EnumPropertyItem prop_select_linked_types[] = {
1604         {1, "IPO", 0, "Object IPO", ""}, // XXX depreceated animation system stuff...
1605         {2, "OBDATA", 0, "Ob Data", ""},
1606         {3, "MATERIAL", 0, "Material", ""},
1607         {4, "TEXTURE", 0, "Texture", ""},
1608         {5, "DUPGROUP", 0, "Dupligroup", ""},
1609         {6, "PARTICLE", 0, "Particle System", ""},
1610         {0, NULL, 0, NULL, NULL}
1611 };
1612
1613 static int object_select_linked_exec(bContext *C, wmOperator *op)
1614 {
1615         Scene *scene= CTX_data_scene(C);
1616         Object *ob;
1617         void *obdata = NULL;
1618         Material *mat = NULL, *mat1;
1619         Tex *tex=0;
1620         int a, b;
1621         int nr = RNA_enum_get(op->ptr, "type");
1622         short changed = 0, seltype;
1623         /* events (nr):
1624          * Object Ipo: 1
1625          * ObData: 2
1626          * Current Material: 3
1627          * Current Texture: 4
1628          * DupliGroup: 5
1629          * PSys: 6
1630          */
1631
1632         seltype = RNA_enum_get(op->ptr, "seltype");
1633         
1634         if (seltype == 0) {
1635                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1636                         ED_base_object_select(base, BA_DESELECT);
1637                 }
1638                 CTX_DATA_END;
1639         }
1640         
1641         ob= OBACT;
1642         if(ob==0){ 
1643                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
1644                 return OPERATOR_CANCELLED;
1645         }
1646         
1647         if(nr==1) {     
1648                         // XXX old animation system
1649                 //ipo= ob->ipo;
1650                 //if(ipo==0) return OPERATOR_CANCELLED;
1651                 return OPERATOR_CANCELLED;
1652         }
1653         else if(nr==2) {
1654                 if(ob->data==0) return OPERATOR_CANCELLED;
1655                 obdata= ob->data;
1656         }
1657         else if(nr==3 || nr==4) {
1658                 mat= give_current_material(ob, ob->actcol);
1659                 if(mat==0) return OPERATOR_CANCELLED;
1660                 if(nr==4) {
1661                         if(mat->mtex[ (int)mat->texact ]) tex= mat->mtex[ (int)mat->texact ]->tex;
1662                         if(tex==0) return OPERATOR_CANCELLED;
1663                 }
1664         }
1665         else if(nr==5) {
1666                 if(ob->dup_group==NULL) return OPERATOR_CANCELLED;
1667         }
1668         else if(nr==6) {
1669                 if(ob->particlesystem.first==NULL) return OPERATOR_CANCELLED;
1670         }
1671         else return OPERATOR_CANCELLED;
1672         
1673         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1674                 if(nr==1) {
1675                                 // XXX old animation system
1676                         //if(base->object->ipo==ipo) base->flag |= SELECT;
1677                         //changed = 1;
1678                 }
1679                 else if(nr==2) {
1680                         if(base->object->data==obdata) base->flag |= SELECT;
1681                         changed = 1;
1682                 }
1683                 else if(nr==3 || nr==4) {
1684                         ob= base->object;
1685                         
1686                         for(a=1; a<=ob->totcol; a++) {
1687                                 mat1= give_current_material(ob, a);
1688                                 if(nr==3) {
1689                                         if(mat1==mat) base->flag |= SELECT;
1690                                         changed = 1;
1691                                 }
1692                                 else if(mat1 && nr==4) {
1693                                         for(b=0; b<MAX_MTEX; b++) {
1694                                                 if(mat1->mtex[b]) {
1695                                                         if(tex==mat1->mtex[b]->tex) {
1696                                                                 base->flag |= SELECT;
1697                                                                 changed = 1;
1698                                                                 break;
1699                                                         }
1700                                                 }
1701                                         }
1702                                 }
1703                         }
1704                 }
1705                 else if(nr==5) {
1706                         if(base->object->dup_group==ob->dup_group) {
1707                                  base->flag |= SELECT;
1708                                  changed = 1;
1709                         }
1710                 }
1711                 else if(nr==6) {
1712                         /* loop through other, then actives particles*/
1713                         ParticleSystem *psys;
1714                         ParticleSystem *psys_act;
1715                         
1716                         for(psys=base->object->particlesystem.first; psys; psys=psys->next) {
1717                                 for(psys_act=ob->particlesystem.first; psys_act; psys_act=psys_act->next) {
1718                                         if (psys->part == psys_act->part) {
1719                                                 base->flag |= SELECT;
1720                                                 changed = 1;
1721                                                 break;
1722                                         }
1723                                 }
1724                                 
1725                                 if (base->flag & SELECT) {
1726                                         break;
1727                                 }
1728                         }
1729                 }
1730                 base->object->flag= base->flag;
1731         }
1732         CTX_DATA_END;
1733         
1734         if (changed) {
1735                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1736                 return OPERATOR_FINISHED;
1737         }
1738         
1739         return OPERATOR_CANCELLED;
1740 }
1741
1742 void OBJECT_OT_select_linked(wmOperatorType *ot)
1743 {
1744         /* identifiers */
1745         ot->name= "Select Linked";
1746         ot->description = "Select all visible objects that are linked.";
1747         ot->idname= "OBJECT_OT_select_linked";
1748         
1749         /* api callbacks */
1750         ot->invoke= WM_menu_invoke;
1751         ot->exec= object_select_linked_exec;
1752         ot->poll= ED_operator_scene_editable;
1753         
1754         /* flags */
1755         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1756         
1757         RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", "");
1758         RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select");
1759
1760 }
1761
1762 /* ****** selection grouped *******/
1763
1764 static EnumPropertyItem prop_select_grouped_types[] = {
1765         {1, "CHILDREN_RECURSIVE", 0, "Children", ""}, // XXX depreceated animation system stuff...
1766         {2, "CHILDREN", 0, "Immediate Children", ""},
1767         {3, "PARENT", 0, "Parent", ""},
1768         {4, "SIBLINGS", 0, "Siblings", "Shared Parent"},
1769         {5, "TYPE", 0, "Type", "Shared object type"},
1770         {6, "LAYER", 0, "Layer", "Shared layers"},
1771         {7, "GROUP", 0, "Group", "Shared group"},
1772         {8, "HOOK", 0, "Hook", ""},
1773         {9, "PASS", 0, "Pass", "Render pass Index"},
1774         {10, "COLOR", 0, "Color", "Object Color"},
1775         {11, "PROPERTIES", 0, "Properties", "Game Properties"},
1776         {0, NULL, 0, NULL, NULL}
1777 };
1778
1779
1780 static short select_grouped_children(bContext *C, Object *ob, int recursive)
1781 {
1782         short changed = 0;
1783
1784         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
1785                 if (ob == base->object->parent) {
1786                         if (!(base->flag & SELECT)) {
1787                                 ED_base_object_select(base, BA_SELECT);
1788                                 changed = 1;
1789                         }
1790
1791                         if (recursive)
1792                                 changed |= select_grouped_children(C, base->object, 1);
1793                 }
1794         }
1795         CTX_DATA_END;
1796         return changed;
1797 }
1798
1799 static short select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */
1800 {
1801         Scene *scene= CTX_data_scene(C);
1802         View3D *v3d= CTX_wm_view3d(C);
1803
1804         short changed = 0;
1805         Base *baspar, *basact= CTX_data_active_base(C);
1806
1807         if (!basact || !(basact->object->parent)) return 0; /* we know OBACT is valid */
1808
1809         baspar= object_in_scene(basact->object->parent, scene);
1810
1811         /* can be NULL if parent in other scene */
1812         if(baspar && BASE_SELECTABLE(v3d, baspar)) {
1813                 ED_base_object_select(basact, BA_DESELECT);
1814                 ED_base_object_select(baspar, BA_SELECT);
1815                 ED_base_object_activate(C, baspar);
1816                 changed = 1;
1817         }
1818         return changed;
1819 }
1820
1821
1822 #define GROUP_MENU_MAX  24
1823 static short select_grouped_group(bContext *C, Object *ob)      /* Select objects in the same group as the active */
1824 {
1825         short changed = 0;
1826         Group *group, *ob_groups[GROUP_MENU_MAX];
1827         //char str[10 + (24*GROUP_MENU_MAX)];
1828         //char *p = str;
1829         int group_count=0; //, menu, i;
1830
1831         for (   group=G.main->group.first;
1832                         group && group_count < GROUP_MENU_MAX;
1833                         group=group->id.next
1834                 ) {
1835                 if (object_in_group (ob, group)) {
1836                         ob_groups[group_count] = group;
1837                         group_count++;
1838                 }
1839         }
1840
1841         if (!group_count)
1842                 return 0;
1843
1844         else if (group_count == 1) {
1845                 group = ob_groups[0];
1846                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1847                         if (!(base->flag & SELECT) && object_in_group(base->object, group)) {
1848                                 ED_base_object_select(base, BA_SELECT);
1849                                 changed = 1;
1850                         }
1851                 }
1852                 CTX_DATA_END;
1853                 return changed;
1854         }
1855 #if 0 // XXX hows this work in 2.5?
1856         /* build the menu. */
1857         p += sprintf(str, "Groups%%t");
1858         for (i=0; i<group_count; i++) {
1859                 group = ob_groups[i];
1860                 p += sprintf (p, "|%s%%x%i", group->id.name+2, i);
1861         }
1862
1863         menu = pupmenu (str);
1864         if (menu == -1)
1865                 return 0;
1866
1867         group = ob_groups[menu];
1868         for (base= FIRSTBASE; base; base= base->next) {
1869                 if (!(base->flag & SELECT) && object_in_group(base->object, group)) {
1870                         ED_base_object_select(base, BA_SELECT);
1871                         changed = 1;
1872                 }
1873         }
1874 #endif
1875         return changed;
1876 }
1877
1878 static short select_grouped_object_hooks(bContext *C, Object *ob)
1879 {
1880         Scene *scene= CTX_data_scene(C);
1881         View3D *v3d= CTX_wm_view3d(C);
1882
1883         short changed = 0;
1884         Base *base;
1885         ModifierData *md;
1886         HookModifierData *hmd;
1887
1888         for (md = ob->modifiers.first; md; md=md->next) {
1889                 if (md->type==eModifierType_Hook) {
1890                         hmd= (HookModifierData*) md;
1891                         if (hmd->object && !(hmd->object->flag & SELECT)) {
1892                                 base= object_in_scene(hmd->object, scene);
1893                                 if (base && (BASE_SELECTABLE(v3d, base))) {
1894                                         ED_base_object_select(base, BA_SELECT);
1895                                         changed = 1;
1896                                 }
1897                         }
1898                 }
1899         }
1900         return changed;
1901 }
1902
1903 /* Select objects woth the same parent as the active (siblings),
1904  * parent can be NULL also */
1905 static short select_grouped_siblings(bContext *C, Object *ob)
1906 {
1907         short changed = 0;
1908
1909         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
1910                 if ((base->object->parent==ob->parent)  && !(base->flag & SELECT)) {
1911                         ED_base_object_select(base, BA_SELECT);
1912                         changed = 1;
1913                 }
1914         }
1915         CTX_DATA_END;
1916         return changed;
1917 }
1918
1919 static short select_grouped_type(bContext *C, Object *ob)
1920 {
1921         short changed = 0;
1922
1923         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
1924                 if ((base->object->type == ob->type) && !(base->flag & SELECT)) {
1925                         ED_base_object_select(base, BA_SELECT);
1926                         changed = 1;
1927                 }
1928         }
1929         CTX_DATA_END;
1930         return changed;
1931 }
1932
1933 static short select_grouped_layer(bContext *C, Object *ob)
1934 {
1935         char changed = 0;
1936
1937         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
1938                 if ((base->lay & ob->lay) && !(base->flag & SELECT)) {
1939                         ED_base_object_select(base, BA_SELECT);
1940                         changed = 1;
1941                 }
1942         }
1943         CTX_DATA_END;
1944         return changed;
1945 }
1946
1947 static short select_grouped_index_object(bContext *C, Object *ob)
1948 {
1949         char changed = 0;
1950
1951         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
1952                 if ((base->object->index == ob->index) && !(base->flag & SELECT)) {
1953                         ED_base_object_select(base, BA_SELECT);
1954                         changed = 1;
1955                 }
1956         }
1957         CTX_DATA_END;
1958         return changed;
1959 }
1960
1961 static short select_grouped_color(bContext *C, Object *ob)
1962 {
1963         char changed = 0;
1964
1965         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
1966                 if (!(base->flag & SELECT) && (FloatCompare(base->object->col, ob->col, 0.005f))) {
1967                         ED_base_object_select(base, BA_SELECT);
1968                         changed = 1;
1969                 }
1970         }
1971         CTX_DATA_END;
1972         return changed;
1973 }
1974
1975 static short objects_share_gameprop(Object *a, Object *b)
1976 {
1977         bProperty *prop;
1978         /*make a copy of all its properties*/
1979
1980         for( prop= a->prop.first; prop; prop = prop->next ) {
1981                 if ( get_ob_property(b, prop->name) )
1982                         return 1;
1983         }
1984         return 0;
1985 }
1986
1987 static short select_grouped_gameprops(bContext *C, Object *ob)
1988 {
1989         char changed = 0;
1990
1991         CTX_DATA_BEGIN(C, Base*, base, selectable_bases) {
1992                 if (!(base->flag & SELECT) && (objects_share_gameprop(base->object, ob))) {
1993                         ED_base_object_select(base, BA_SELECT);
1994                         changed = 1;
1995                 }
1996         }
1997         CTX_DATA_END;
1998         return changed;
1999 }
2000
2001 static int object_select_grouped_exec(bContext *C, wmOperator *op)
2002 {
2003         Scene *scene= CTX_data_scene(C);
2004         Object *ob;
2005         int nr = RNA_enum_get(op->ptr, "type");
2006         short changed = 0, seltype;
2007
2008         seltype = RNA_enum_get(op->ptr, "seltype");
2009         
2010         if (seltype == 0) {
2011                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
2012                         ED_base_object_select(base, BA_DESELECT);
2013                 }
2014                 CTX_DATA_END;
2015         }
2016         
2017         ob= OBACT;
2018         if(ob==0){ 
2019                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
2020                 return OPERATOR_CANCELLED;
2021         }
2022         
2023         if(nr==1)               changed = select_grouped_children(C, ob, 1);
2024         else if(nr==2)  changed = select_grouped_children(C, ob, 0);
2025         else if(nr==3)  changed = select_grouped_parent(C);
2026         else if(nr==4)  changed = select_grouped_siblings(C, ob);
2027         else if(nr==5)  changed = select_grouped_type(C, ob);
2028         else if(nr==6)  changed = select_grouped_layer(C, ob);
2029         else if(nr==7)  changed = select_grouped_group(C, ob);
2030         else if(nr==8)  changed = select_grouped_object_hooks(C, ob);
2031         else if(nr==9)  changed = select_grouped_index_object(C, ob);
2032         else if(nr==10) changed = select_grouped_color(C, ob);
2033         else if(nr==11) changed = select_grouped_gameprops(C, ob);
2034         
2035         if (changed) {
2036                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
2037                 return OPERATOR_FINISHED;
2038         }
2039         
2040         return OPERATOR_CANCELLED;
2041 }
2042
2043 void OBJECT_OT_select_grouped(wmOperatorType *ot)
2044 {
2045         /* identifiers */
2046         ot->name= "Select Grouped";
2047         ot->description = "Select all visible objects grouped by various properties.";
2048         ot->idname= "OBJECT_OT_select_grouped";
2049         
2050         /* api callbacks */
2051         ot->invoke= WM_menu_invoke;
2052         ot->exec= object_select_grouped_exec;
2053         ot->poll= ED_operator_scene_editable;
2054         
2055         /* flags */
2056         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2057         
2058         RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
2059         RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select");
2060
2061 }
2062
2063 /* ****** selection by layer *******/
2064
2065 static int object_select_by_layer_exec(bContext *C, wmOperator *op)
2066 {
2067         unsigned int layernum;
2068         short seltype;
2069         
2070         seltype = RNA_enum_get(op->ptr, "seltype");
2071         layernum = RNA_int_get(op->ptr, "layer");
2072         
2073         if (seltype == 0) {
2074                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
2075                         ED_base_object_select(base, BA_DESELECT);
2076                 }
2077                 CTX_DATA_END;
2078         }
2079                 
2080         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
2081                 if(base->lay == (1<< (layernum -1)))
2082                         ED_base_object_select(base, BA_SELECT);
2083         }
2084         CTX_DATA_END;
2085         
2086         /* undo? */
2087         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
2088         
2089         return OPERATOR_FINISHED;
2090 }
2091
2092 void OBJECT_OT_select_by_layer(wmOperatorType *ot)
2093 {
2094         /* identifiers */
2095         ot->name= "select by layer";
2096         ot->description = "Select all visible objects on a layer.";
2097         ot->idname= "OBJECT_OT_select_by_layer";
2098         
2099         /* api callbacks */
2100         /*ot->invoke = XXX - need a int grid popup*/
2101         ot->exec= object_select_by_layer_exec;
2102         ot->poll= ED_operator_scene_editable;
2103         
2104         /* flags */
2105         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2106         
2107         RNA_def_int(ot->srna, "layer", 1, 1, 20, "Layer", "", 1, 20);
2108         RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select");
2109 }
2110
2111 /* ****** invert selection *******/
2112 static int object_select_inverse_exec(bContext *C, wmOperator *op)
2113 {
2114         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
2115                 if (base->flag & SELECT)
2116                         ED_base_object_select(base, BA_DESELECT);
2117                 else
2118                         ED_base_object_select(base, BA_SELECT);
2119         }
2120         CTX_DATA_END;
2121         
2122         /* undo? */
2123         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
2124         
2125         return OPERATOR_FINISHED;
2126 }
2127
2128 void OBJECT_OT_select_inverse(wmOperatorType *ot)
2129 {
2130         
2131         /* identifiers */
2132         ot->name= "Select Inverse";
2133         ot->description = "Invert selection of all visible objects.";
2134         ot->idname= "OBJECT_OT_select_inverse";
2135         
2136         /* api callbacks */
2137         ot->exec= object_select_inverse_exec;
2138         ot->poll= ED_operator_scene_editable;
2139         
2140         /* flags */
2141         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2142         
2143 }
2144 /* ****** (de)select All *******/
2145
2146 static int object_select_de_select_all_exec(bContext *C, wmOperator *op)
2147 {
2148         
2149         int a=0, ok=0; 
2150         
2151         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
2152                 if (base->flag & SELECT) {
2153                         ok= a= 1;
2154                         break;
2155                 }
2156                 else ok=1;
2157         }
2158         CTX_DATA_END;
2159         
2160         if (!ok) return OPERATOR_PASS_THROUGH;
2161         
2162         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
2163                 if (a) ED_base_object_select(base, BA_DESELECT);
2164                 else ED_base_object_select(base, BA_SELECT);
2165         }
2166         CTX_DATA_END;
2167         
2168         /* undo? */
2169         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
2170         
2171         return OPERATOR_FINISHED;
2172 }
2173
2174 void OBJECT_OT_select_all_toggle(wmOperatorType *ot)
2175 {
2176         
2177         /* identifiers */
2178         ot->name= "deselect all";
2179         ot->description = "(de)select all visible objects in scene.";
2180         ot->idname= "OBJECT_OT_select_all_toggle";
2181         
2182         /* api callbacks */
2183         ot->exec= object_select_de_select_all_exec;
2184         ot->poll= ED_operator_scene_editable;
2185         
2186         /* flags */
2187         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2188         
2189 }
2190 /* ****** random selection *******/
2191
2192 static int object_select_random_exec(bContext *C, wmOperator *op)
2193 {       
2194         float percent;
2195         short seltype;
2196         
2197         seltype = RNA_enum_get(op->ptr, "seltype");
2198         
2199         if (seltype == 0) {
2200                 CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
2201                         ED_base_object_select(base, BA_DESELECT);
2202                 }
2203                 CTX_DATA_END;
2204         }
2205         percent = RNA_float_get(op->ptr, "percent");
2206                 
2207         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
2208                 if (BLI_frand() < percent) {
2209                                 ED_base_object_select(base, BA_SELECT);
2210                 }
2211         }
2212         CTX_DATA_END;
2213         
2214         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
2215         
2216         return OPERATOR_FINISHED;
2217 }
2218
2219 void OBJECT_OT_select_random(wmOperatorType *ot)
2220 {
2221         /* identifiers */
2222         ot->name= "Random select";
2223         ot->description = "Set select on random visible objects.";
2224         ot->idname= "OBJECT_OT_select_random";
2225         
2226         /* api callbacks */
2227         /*ot->invoke= object_select_random_invoke XXX - need a number popup ;*/
2228         ot->exec = object_select_random_exec;
2229         ot->poll= ED_operator_scene_editable;
2230         
2231         /* flags */
2232         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2233         
2234         RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "percentage of objects to randomly select", 0.0001f, 1.0f);
2235         RNA_def_enum(ot->srna, "seltype", prop_select_types, 1, "Selection", "Extend selection or clear selection then select");
2236 }
2237
2238 /* ******** Clear object Translation *********** */
2239
2240 static int object_location_clear_exec(bContext *C, wmOperator *op)
2241 {
2242         int armature_clear= 0;
2243
2244         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
2245                 if(!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
2246                         if ((ob->protectflag & OB_LOCK_LOCX)==0)
2247                                 ob->loc[0]= ob->dloc[0]= 0.0f;
2248                         if ((ob->protectflag & OB_LOCK_LOCY)==0)
2249                                 ob->loc[1]= ob->dloc[1]= 0.0f;
2250                         if ((ob->protectflag & OB_LOCK_LOCZ)==0)
2251                                 ob->loc[2]= ob->dloc[2]= 0.0f;
2252                 }
2253                 ob->recalc |= OB_RECALC_OB;
2254         }
2255         CTX_DATA_END;
2256
2257         if(armature_clear==0) /* in this case flush was done */
2258                 ED_anim_dag_flush_update(C);    
2259         
2260         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2261         
2262         return OPERATOR_FINISHED;
2263 }
2264
2265
2266 void OBJECT_OT_location_clear(wmOperatorType *ot)
2267 {
2268         
2269         /* identifiers */
2270         ot->name= "Clear Location";
2271         ot->description = "Clear the object's location.";
2272         ot->idname= "OBJECT_OT_location_clear";
2273         
2274         /* api callbacks */
2275         ot->invoke= WM_operator_confirm;
2276         ot->exec= object_location_clear_exec;
2277         ot->poll= ED_operator_object_active;
2278         
2279         /* flags */
2280         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2281 }
2282
2283 static int object_rotation_clear_exec(bContext *C, wmOperator *op)
2284 {
2285         int armature_clear= 0;
2286
2287         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
2288                 if(!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
2289                         /* eulers can only get cleared if they are not protected */
2290                         if ((ob->protectflag & OB_LOCK_ROTX)==0)
2291                                 ob->rot[0]= ob->drot[0]= 0.0f;
2292                         if ((ob->protectflag & OB_LOCK_ROTY)==0)
2293                                 ob->rot[1]= ob->drot[1]= 0.0f;
2294                         if ((ob->protectflag & OB_LOCK_ROTZ)==0)
2295                                 ob->rot[2]= ob->drot[2]= 0.0f;
2296                 }
2297                 ob->recalc |= OB_RECALC_OB;
2298         }
2299         CTX_DATA_END;
2300
2301         if(armature_clear==0) /* in this case flush was done */
2302                 ED_anim_dag_flush_update(C);    
2303         
2304         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2305         
2306         return OPERATOR_FINISHED;
2307 }
2308
2309
2310 void OBJECT_OT_rotation_clear(wmOperatorType *ot)
2311 {
2312         
2313         /* identifiers */
2314         ot->name= "Clear Rotation";
2315         ot->description = "Clear the object's rotation.";
2316         ot->idname= "OBJECT_OT_rotation_clear";
2317         
2318         /* api callbacks */
2319         ot->invoke= WM_operator_confirm;
2320         ot->exec= object_rotation_clear_exec;
2321         ot->poll= ED_operator_object_active;
2322         
2323         /* flags */
2324         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2325 }
2326
2327 static int object_scale_clear_exec(bContext *C, wmOperator *op)
2328 {
2329         int armature_clear= 0;
2330
2331         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
2332                 if(!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
2333                         if ((ob->protectflag & OB_LOCK_SCALEX)==0) {
2334                                 ob->dsize[0]= 0.0f;
2335                                 ob->size[0]= 1.0f;
2336                         }
2337                         if ((ob->protectflag & OB_LOCK_SCALEY)==0) {
2338                                 ob->dsize[1]= 0.0f;
2339                                 ob->size[1]= 1.0f;
2340                         }
2341                         if ((ob->protectflag & OB_LOCK_SCALEZ)==0) {
2342                                 ob->dsize[2]= 0.0f;
2343                                 ob->size[2]= 1.0f;
2344                         }
2345                 }
2346                 ob->recalc |= OB_RECALC_OB;
2347         }
2348         CTX_DATA_END;
2349         
2350         if(armature_clear==0) /* in this case flush was done */
2351                 ED_anim_dag_flush_update(C);    
2352         
2353         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2354         
2355         return OPERATOR_FINISHED;
2356 }
2357
2358 void OBJECT_OT_scale_clear(wmOperatorType *ot)
2359 {
2360         
2361         /* identifiers */
2362         ot->name= "Clear Scale";
2363         ot->description = "Clear the object's scale.";
2364         ot->idname= "OBJECT_OT_scale_clear";
2365         
2366         /* api callbacks */
2367         ot->invoke= WM_operator_confirm;
2368         ot->exec= object_scale_clear_exec;
2369         ot->poll= ED_operator_object_active;
2370         
2371         /* flags */
2372         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2373 }
2374
2375 static int object_origin_clear_exec(bContext *C, wmOperator *op)
2376 {
2377         float *v1, *v3, mat[3][3];
2378         int armature_clear= 0;
2379
2380         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
2381                 if(ob->parent) {
2382                         v1= ob->loc;
2383                         v3= ob->parentinv[3];
2384                         
2385                         Mat3CpyMat4(mat, ob->parentinv);
2386                         VECCOPY(v3, v1);
2387                         v3[0]= -v3[0];
2388                         v3[1]= -v3[1];
2389                         v3[2]= -v3[2];
2390                         Mat3MulVecfl(mat, v3);
2391                 }
2392                 ob->recalc |= OB_RECALC_OB;
2393         }
2394         CTX_DATA_END;
2395
2396         if(armature_clear==0) /* in this case flush was done */
2397                 ED_anim_dag_flush_update(C);    
2398         
2399         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
2400         
2401         return OPERATOR_FINISHED;
2402 }
2403
2404 void OBJECT_OT_origin_clear(wmOperatorType *ot)
2405 {
2406
2407         /* identifiers */
2408         ot->name= "Clear Origin";
2409         ot->description = "Clear the object's origin.";
2410         ot->idname= "OBJECT_OT_origin_clear";
2411         
2412         /* api callbacks */
2413         ot->invoke= WM_operator_confirm;
2414         ot->exec= object_origin_clear_exec;
2415         ot->poll= ED_operator_object_active;
2416         
2417         /* flags */
2418         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2419 }
2420
2421 /* ********* clear/set restrict view *********/
2422 static int object_restrictview_clear_exec(bContext *C, wmOperator *op)
2423 {
2424         ScrArea *sa= CTX_wm_area(C);
2425         View3D *v3d= sa->spacedata.first;
2426         Scene *scene= CTX_data_scene(C);
2427         Base *base;
2428         int changed = 0;
2429         
2430         /* XXX need a context loop to handle such cases */
2431         for(base = FIRSTBASE; base; base=base->next){
2432                 if((base->lay & v3d->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) {
2433                         base->flag |= SELECT;
2434                         base->object->flag = base->flag;
2435                         base->object->restrictflag &= ~OB_RESTRICT_VIEW; 
2436                         changed = 1;
2437                 }
2438         }
2439         if (changed) {
2440                 DAG_scene_sort(scene);
2441                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
2442         }
2443
2444         return OPERATOR_FINISHED;
2445 }
2446
2447 void OBJECT_OT_restrictview_clear(wmOperatorType *ot)
2448 {
2449         
2450         /* identifiers */
2451         ot->name= "Clear Restrict View";
2452         ot->description = "Reveal the object by setting the restrictview flag.";
2453         ot->idname= "OBJECT_OT_restrictview_clear";
2454         
2455         /* api callbacks */
2456         ot->exec= object_restrictview_clear_exec;
2457         ot->poll= ED_operator_view3d_active;
2458         
2459         /* flags */
2460         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2461 }
2462
2463 static int object_restrictview_set_exec(bContext *C, wmOperator *op)
2464 {
2465         Scene *scene= CTX_data_scene(C);
2466         short changed = 0;
2467         int unselected= RNA_boolean_get(op->ptr, "unselected");
2468         
2469         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
2470                 if(!unselected) {
2471                         if (base->flag & SELECT){
2472                                 base->flag &= ~SELECT;
2473                                 base->object->flag = base->flag;
2474                                 base->object->restrictflag |= OB_RESTRICT_VIEW;
2475                                 changed = 1;
2476                                 if (base==BASACT) {
2477                                         ED_base_object_activate(C, NULL);
2478                                 }
2479                         }
2480                 }
2481                 else {
2482                         if (!(base->flag & SELECT)){
2483                                 base->object->restrictflag |= OB_RESTRICT_VIEW;
2484                                 changed = 1;
2485                         }
2486                 }       
2487         }
2488         CTX_DATA_END;
2489
2490         if (changed) {
2491                 DAG_scene_sort(scene);
2492                 
2493                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
2494                 
2495         }
2496
2497         return OPERATOR_FINISHED;
2498 }
2499
2500 void OBJECT_OT_restrictview_set(wmOperatorType *ot)
2501 {
2502         /* identifiers */
2503         ot->name= "Set Restrict View";
2504         ot->description = "Hide the object by setting the restrictview flag.";
2505         ot->idname= "OBJECT_OT_restrictview_set";
2506         
2507         /* api callbacks */
2508         ot->exec= object_restrictview_set_exec;
2509         ot->poll= ED_operator_view3d_active;
2510         
2511         /* flags */
2512         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2513         
2514         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects.");
2515         
2516 }
2517 /* ************* Slow Parent ******************* */
2518 static int object_slowparent_set_exec(bContext *C, wmOperator *op)
2519 {
2520
2521         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
2522                 
2523                 if(base->object->parent) base->object->partype |= PARSLOW;
2524                 base->object->recalc |= OB_RECALC_OB;
2525                 
2526         }
2527         CTX_DATA_END;
2528
2529         ED_anim_dag_flush_update(C);    
2530         
2531         WM_event_add_notifier(C, NC_SCENE, CTX_data_scene(C));
2532         
2533         return OPERATOR_FINISHED;
2534 }
2535
2536 void OBJECT_OT_slowparent_set(wmOperatorType *ot)
2537 {
2538         
2539         /* identifiers */
2540         ot->name= "Set Slow Parent";
2541         ot->description = "Set the object's slow parent.";
2542         ot->idname= "OBJECT_OT_slow_parent_set";
2543         
2544         /* api callbacks */
2545         ot->invoke= WM_operator_confirm;
2546         ot->exec= object_slowparent_set_exec;
2547         ot->poll= ED_operator_view3d_active;
2548         
2549         /* flags */
2550         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2551 }
2552
2553 static int object_slowparent_clear_exec(bContext *C, wmOperator *op)
2554 {
2555         Scene *scene= CTX_data_scene(C);
2556
2557         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
2558                 if(base->object->parent) {
2559                         if(base->object->partype & PARSLOW) {
2560                                 base->object->partype -= PARSLOW;
2561                                 where_is_object(scene, base->object);
2562                                 base->object->partype |= PARSLOW;
2563                                 base->object->recalc |= OB_RECALC_OB;
2564                         }
2565                 }
2566                 
2567         }
2568         CTX_DATA_END;
2569
2570         ED_anim_dag_flush_update(C);    
2571         
2572         WM_event_add_notifier(C, NC_SCENE, CTX_data_scene(C));
2573         
2574         return OPERATOR_FINISHED;
2575 }
2576
2577 void OBJECT_OT_slowparent_clear(wmOperatorType *ot)
2578 {
2579         
2580         /* identifiers */
2581         ot->name= "Clear Slow Parent";
2582         ot->description = "Clear the object's slow parent.";
2583         ot->idname= "OBJECT_OT_slow_parent_clear";
2584         
2585         /* api callbacks */
2586         ot->invoke= WM_operator_confirm;
2587         ot->exec= object_slowparent_clear_exec;
2588         ot->poll= ED_operator_view3d_active;
2589         
2590         /* flags */
2591         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2592 }
2593 /* ******************** **************** */
2594
2595 // XXX
2596 #define BEZSELECTED_HIDDENHANDLES(bezt)   ((G.f & G_HIDDENHANDLES) ? (bezt)->f2 & SELECT : BEZSELECTED(bezt))
2597 /* only in edit mode */
2598 void make_vertex_parent(Scene *scene, Object *obedit, View3D *v3d)
2599 {
2600         EditVert *eve;
2601         Base *base;
2602         Nurb *nu;
2603         BezTriple *bezt;
2604         BPoint *bp;
2605         Object *par, *ob;
2606         int a, v1=0, v2=0, v3=0, v4=0, nr=1;
2607         
2608         /* we need 1 to 3 selected vertices */
2609         
2610         if(obedit->type==OB_MESH) {
2611                 Mesh *me= obedit->data;
2612                 EditMesh *em = BKE_mesh_get_editmesh(me);
2613
2614                 eve= em->verts.first;
2615                 while(eve) {
2616                         if(eve->f & 1) {
2617                                 if(v1==0) v1= nr;
2618                                 else if(v2==0) v2= nr;
2619                                 else if(v3==0) v3= nr;
2620                                 else if(v4==0) v4= nr;
2621                                 else break;
2622                         }
2623                         nr++;
2624                         eve= eve->next;
2625                 }
2626
2627                 BKE_mesh_end_editmesh(me, em);
2628         }
2629         else if(ELEM(obedit->type, OB_SURF, OB_CURVE)) {
2630                 ListBase *editnurb= curve_get_editcurve(obedit);
2631
2632                 nu= editnurb->first;
2633                 while(nu) {
2634                         if((nu->type & 7)==CU_BEZIER) {
2635                                 bezt= nu->bezt;
2636                                 a= nu->pntsu;
2637                                 while(a--) {
2638                                         if(BEZSELECTED_HIDDENHANDLES(bezt)) {
2639                                                 if(v1==0) v1= nr;
2640                                                 else if(v2==0) v2= nr;
2641                                                 else if(v3==0) v3= nr;
2642                                                 else if(v4==0) v4= nr;
2643                                                 else break;
2644                                         }
2645                                         nr++;
2646                                         bezt++;
2647                                 }
2648                         }
2649                         else {
2650                                 bp= nu->bp;
2651                                 a= nu->pntsu*nu->pntsv;
2652                                 while(a--) {
2653                                         if(bp->f1 & SELECT) {
2654                                                 if(v1==0) v1= nr;
2655                                                 else if(v2==0) v2= nr;
2656                                                 else if(v3==0) v3= nr;
2657                                                 else if(v4==0) v4= nr;
2658                                                 else break;
2659                                         }
2660                                         nr++;
2661                                         bp++;
2662                                 }
2663                         }
2664                         nu= nu->next;
2665                 }
2666         }
2667         else if(obedit->type==OB_LATTICE) {
2668                 Lattice *lt= obedit->data;
2669                 
2670                 a= lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw;
2671                 bp= lt->editlatt->def;
2672                 while(a--) {
2673                         if(bp->f1 & SELECT) {
2674                                 if(v1==0) v1= nr;
2675                                 else if(v2==0) v2= nr;
2676                                 else if(v3==0) v3= nr;
2677                                 else if(v4==0) v4= nr;
2678                                 else break;
2679                         }
2680                         nr++;
2681                         bp++;
2682                 }
2683         }
2684         
2685         if(v4 || !((v1 && v2==0 && v3==0) || (v1 && v2 && v3)) ) {
2686                 error("Select either 1 or 3 vertices to parent to");
2687                 return;
2688         }
2689         
2690         if(okee("Make vertex parent")==0) return;
2691         
2692         for(base= FIRSTBASE; base; base= base->next) {
2693                 if(TESTBASELIB(v3d, base)) {
2694                         if(base!=BASACT) {
2695                                 
2696                                 ob= base->object;
2697                                 ob->recalc |= OB_RECALC;
2698                                 par= BASACT->object->parent;
2699                                 
2700                                 while(par) {
2701                                         if(par==ob) break;
2702                                         par= par->parent;
2703                                 }
2704                                 if(par) {
2705                                         error("Loop in parents");
2706                                 }
2707                                 else {
2708                                         Object workob;
2709                                         
2710                                         ob->parent= BASACT->object;
2711                                         if(v3) {
2712                                                 ob->partype= PARVERT3;
2713                                                 ob->par1= v1-1;
2714                                                 ob->par2= v2-1;
2715                                                 ob->par3= v3-1;
2716
2717                                                 /* inverse parent matrix */
2718                                                 what_does_parent(scene, ob, &workob);
2719                                                 Mat4Invert(ob->parentinv, workob.obmat);
2720                                         }
2721                                         else {
2722                                                 ob->partype= PARVERT1;
2723                                                 ob->par1= v1-1;
2724
2725                                                 /* inverse parent matrix */
2726                                                 what_does_parent(scene, ob, &workob);
2727                                                 Mat4Invert(ob->parentinv, workob.obmat);
2728                                         }
2729                                 }
2730                         }
2731                 }
2732         }
2733         
2734         DAG_scene_sort(scene);
2735 }
2736
2737
2738 /* ******************** make proxy operator *********************** */
2739
2740 /* present menu listing the possible objects within the group to proxify */
2741 static void proxy_group_objects_menu (bContext *C, wmOperator *op, Object *ob, Group *group)
2742 {
2743         uiPopupMenu *pup;
2744         uiLayout *layout;
2745         GroupObject *go;
2746         int len=0;
2747         
2748         /* check if there are any objects within the group to assign for */
2749         for (go= group->gobject.first; go; go= go->next) {
2750                 if (go->ob) len++;
2751         }
2752         if (len==0) return;
2753         
2754         /* now create the menu to draw */
2755         pup= uiPupMenuBegin(C, "Make Proxy For:", 0);
2756         layout= uiPupMenuLayout(pup);
2757         
2758         for (go= group->gobject.first; go; go= go->next) {
2759                 if (go->ob) {
2760                         PointerRNA props_ptr;
2761                         
2762                         /* create operator menu item with relevant properties filled in */
2763                         props_ptr= uiItemFullO(layout, go->ob->id.name+2, 0, op->idname, NULL, WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS);
2764                         RNA_string_set(&props_ptr, "object", go->ob->id.name+2);
2765                         RNA_string_set(&props_ptr, "group_object", go->ob->id.name+2);
2766                 }
2767         }
2768         
2769         /* display the menu, and be done */
2770         uiPupMenuEnd(C, pup);
2771 }
2772
2773 /* set the object to proxify */
2774 static int make_proxy_invoke (bContext *C, wmOperator *op, wmEvent *evt)
2775 {
2776         Scene *scene= CTX_data_scene(C);
2777         Object *ob= CTX_data_active_object(C);
2778         
2779         /* sanity checks */
2780         if (!scene || scene->id.lib || !ob)
2781                 return OPERATOR_CANCELLED;
2782                 
2783         /* Get object to work on - use a menu if we need to... */
2784         if (ob->dup_group && ob->dup_group->id.lib) {
2785                 /* gives menu with list of objects in group */
2786                 proxy_group_objects_menu(C, op, ob, ob->dup_group);
2787         }
2788         else if (ob->id.lib) {
2789                 uiPopupMenu *pup= uiPupMenuBegin(C, "OK?", ICON_QUESTION);
2790                 uiLayout *layout= uiPupMenuLayout(pup);
2791                 PointerRNA props_ptr;
2792                 
2793                 /* create operator menu item with relevant properties filled in */
2794                 props_ptr= uiItemFullO(layout, op->type->name, 0, op->idname, props_ptr.data, WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS);
2795                 RNA_string_set(&props_ptr, "object", ob->id.name+2);
2796                 
2797                 /* present the menu and be done... */
2798                 uiPupMenuEnd(C, pup);
2799         }
2800         else {
2801                 /* error.. cannot continue */
2802                 BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or group");
2803         }
2804         
2805         /* this invoke just calls another instance of this operator... */
2806         return OPERATOR_CANCELLED;
2807 }
2808
2809 static int make_proxy_exec (bContext *C, wmOperator *op)
2810 {
2811         Object *ob=NULL, *gob=NULL;
2812         Scene *scene= CTX_data_scene(C);
2813         char ob_name[21], gob_name[21];
2814         
2815         /* get object and group object
2816          *      - firstly names
2817          *      - then pointers from context 
2818          */
2819         RNA_string_get(op->ptr, "object", ob_name);
2820         RNA_string_get(op->ptr, "group_object", gob_name);
2821         
2822         if (gob_name[0]) {
2823                 Group *group;
2824                 GroupObject *go;
2825                 
2826                 /* active object is group object... */
2827                 // FIXME: we should get the nominated name instead
2828                 gob= CTX_data_active_object(C);
2829                 group= gob->dup_group;
2830                 
2831                 /* find the object to affect */
2832                 for (go= group->gobject.first; go; go= go->next) {
2833                         if ((go->ob) && strcmp(go->ob->id.name+2, gob_name)==0) {
2834                                 ob= go->ob;
2835                                 break;
2836                         }
2837                 }
2838         }
2839         else {
2840                 /* just use the active object for now */
2841                 // FIXME: we should get the nominated name instead
2842                 ob= CTX_data_active_object(C);
2843         }
2844         
2845         if (ob) {
2846                 Object *newob;
2847                 Base *newbase, *oldbase= BASACT;
2848                 char name[32];
2849                 
2850                 /* Add new object for the proxy */
2851                 newob= add_object(scene, OB_EMPTY);
2852                 if (gob)
2853                         strcpy(name, gob->id.name+2);
2854                 else
2855                         strcpy(name, ob->id.name+2);
2856                 strcat(name, "_proxy");
2857                 rename_id(&newob->id, name);
2858                 
2859                 /* set layers OK */
2860                 newbase= BASACT;        /* add_object sets active... */
2861                 newbase->lay= oldbase->lay;
2862                 newob->lay= newbase->lay;
2863                 
2864                 /* remove base, leave user count of object, it gets linked in object_make_proxy */
2865                 if (gob==NULL) {
2866                         BLI_remlink(&scene->base, oldbase);
2867                         MEM_freeN(oldbase);
2868                 }
2869                 
2870                 object_make_proxy(newob, ob, gob);
2871                 
2872                 /* depsgraph flushes are needed for the new data */
2873                 DAG_scene_sort(scene);
2874                 DAG_object_flush_update(scene, newob, OB_RECALC);
2875                 
2876                 WM_event_add_notifier(C, NC_OBJECT, NULL);
2877         }
2878         else {
2879                 BKE_report(op->reports, RPT_ERROR, "No object to make proxy for");
2880                 return OPERATOR_CANCELLED;
2881         }
2882         
2883         return OPERATOR_FINISHED;
2884 }
2885
2886 void OBJECT_OT_proxy_make (wmOperatorType *ot)
2887 {
2888         /* identifiers */
2889         ot->name= "Make Proxy";
2890         ot->idname= "OBJECT_OT_proxy_make";
2891         ot->description= "Add empty object to become local replacement data of a library-linked object";
2892         
2893         /* callbacks */
2894         ot->invoke= make_proxy_invoke;
2895         ot->exec= make_proxy_exec;
2896         ot->poll= ED_operator_object_active;
2897         
2898         /* flags */
2899         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2900         
2901         /* properties */
2902         RNA_def_string(ot->srna, "object", "", 19, "Proxy Object", "Name of lib-linked/grouped object to make a proxy for.");
2903         RNA_def_string(ot->srna, "group_object", "", 19, "Group Object", "Name of group instancer (if applicable).");
2904 }
2905
2906 /* ******************** make parent operator *********************** */
2907
2908 #define PAR_OBJECT                              0
2909 #define PAR_ARMATURE                    1
2910 #define PAR_ARMATURE_NAME               2
2911 #define PAR_ARMATURE_ENVELOPE   3
2912 #define PAR_ARMATURE_AUTO               4
2913 #define PAR_BONE                                5
2914 #define PAR_CURVE                               6
2915 #define PAR_FOLLOW                              7
2916 #define PAR_PATH_CONST                  8
2917 #define PAR_LATTICE                             9
2918 #define PAR_VERTEX                              10
2919 #define PAR_TRIA                                11
2920
2921 static EnumPropertyItem prop_make_parent_types[] = {
2922         {PAR_OBJECT, "OBJECT", 0, "Object", ""},
2923         {PAR_ARMATURE, "ARMATURE", 0, "Armature Deform", ""},
2924         {PAR_ARMATURE_NAME, "ARMATURE_NAME", 0, "   With Empty Groups", ""},
2925         {PAR_ARMATURE_AUTO, "ARMATURE_AUTO", 0, "   With Automatic Weights", ""},
2926         {PAR_ARMATURE_ENVELOPE, "ARMATURE_ENVELOPE", 0, "   With Envelope Weights", ""},
2927         {PAR_BONE, "BONE", 0, "Bone", ""},
2928         {PAR_CURVE, "CURVE", 0, "Curve Deform", ""},
2929         {PAR_FOLLOW, "FOLLOW", 0, "Follow Path", ""},
2930         {PAR_PATH_CONST, "PATH_CONST", 0, "Path Constraint", ""},
2931         {PAR_LATTICE, "LATTICE", 0, "Lattice Deform", ""},
2932         {PAR_VERTEX, "VERTEX", 0, "Vertex", ""},
2933         {PAR_TRIA, "TRIA", 0, "Triangle", ""},
2934         {0, NULL, 0, NULL, NULL}
2935 };
2936
2937 static int test_parent_loop(Object *par, Object *ob)
2938 {
2939         /* test if 'ob' is a parent somewhere in par's parents */
2940         
2941         if(par == NULL) return 0;
2942         if(ob == par) return 1;
2943         
2944         return test_parent_loop(par->parent, ob);
2945 }
2946
2947 void ED_object_parent(Object *ob, Object *par, int type, const char *substr)
2948 {
2949         if(!par || test_parent_loop(par, ob)) {
2950                 ob->parent= NULL;
2951                 ob->partype= PAROBJECT;
2952                 ob->parsubstr[0]= 0;
2953                 return;
2954         }
2955
2956         /* this could use some more checks */
2957
2958         ob->parent= par;
2959         ob->partype &= ~PARTYPE;
2960         ob->partype |= type;
2961         BLI_strncpy(ob->parsubstr, substr, sizeof(ob->parsubstr));
2962 }
2963
2964 static int parent_set_exec(bContext *C, wmOperator *op)
2965 {
2966         Scene *scene= CTX_data_scene(C);
2967         Object *par= CTX_data_active_object(C);
2968         bPoseChannel *pchan= NULL;
2969         int partype= RNA_enum_get(op->ptr, "type");
2970         int pararm= ELEM4(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
2971         
2972         par->recalc |= OB_RECALC_OB;
2973         
2974         /* preconditions */
2975         if(partype==PAR_FOLLOW || partype==PAR_PATH_CONST) {
2976                 if(par->type!=OB_CURVE)
2977                         return OPERATOR_CANCELLED;
2978                 else {
2979                         Curve *cu= par->data;
2980                         
2981                         if((cu->flag & CU_PATH)==0) {
2982                                 cu->flag |= CU_PATH|CU_FOLLOW;
2983                                 makeDispListCurveTypes(scene, par, 0);  /* force creation of path data */
2984                         }
2985                         else cu->flag |= CU_FOLLOW;
2986                         
2987                         /* fall back on regular parenting now */
2988                         partype= PAR_OBJECT;
2989                 }               
2990         }
2991         else if(partype==PAR_BONE) {
2992                 pchan= get_active_posechannel(par);
2993                 
2994                 if(pchan==NULL) {
2995                         error("No active Bone");
2996                         return OPERATOR_CANCELLED;
2997                 }
2998         }
2999         
3000         /* context itterator */
3001         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
3002                 
3003                 if(ob!=par) {
3004                         
3005                         if( test_parent_loop(par, ob) ) {
3006                                 error("Loop in parents");
3007                         }
3008                         else {
3009                                 Object workob;
3010                                 
3011                                 /* apply transformation of previous parenting */
3012                                 ED_object_apply_obmat(ob);
3013                                 
3014                                 ob->parent= par;
3015                                 
3016                                 /* handle types */
3017                                 if (pchan)
3018                                         strcpy (ob->parsubstr, pchan->name);
3019                                 else
3020                                         ob->parsubstr[0]= 0;
3021                                 
3022                                 /* constraint */
3023                                 if(partype==PAR_PATH_CONST) {
3024                                         bConstraint *con;
3025                                         bFollowPathConstraint *data;
3026                                         float cmat[4][4], vec[3];
3027                                         
3028                                         con = add_new_constraint(CONSTRAINT_TYPE_FOLLOWPATH);
3029                                         strcpy (con->name, "AutoPath");
3030                                         
3031                                         data = con->data;
3032                                         data->tar = par;
3033                                         
3034                                         add_constraint_to_object(con, ob);
3035                                         
3036                                         get_constraint_target_matrix(con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra - give_timeoffset(ob));
3037                                         VecSubf(vec, ob->obmat[3], cmat[3]);
3038                                         
3039                                         ob->loc[0] = vec[0];
3040                                         ob->loc[1] = vec[1];
3041                                 }
3042                                 else if(pararm && ob->type==OB_MESH && par->type == OB_ARMATURE) {
3043                                         if(partype == PAR_ARMATURE_NAME)
3044                                                 create_vgroups_from_armature(scene, ob, par, ARM_GROUPS_NAME);
3045                                         else if(partype == PAR_ARMATURE_ENVELOPE)
3046                                                 create_vgroups_from_armature(scene, ob, par, ARM_GROUPS_ENVELOPE);
3047                                         else if(partype == PAR_ARMATURE_AUTO)
3048                                                 create_vgroups_from_armature(scene, ob, par, ARM_GROUPS_AUTO);
3049                                         
3050                                         /* get corrected inverse */
3051                                         ob->partype= PAROBJECT;
3052                                         what_does_parent(scene, ob, &workob);
3053                                         
3054                                         ob->partype= PARSKEL;
3055
3056                                         Mat4Invert(ob->parentinv, workob.obmat);
3057                                 }
3058                                 else {
3059                                         /* calculate inverse parent matrix */
3060                                         what_does_parent(scene, ob, &workob);
3061                                         Mat4Invert(ob->parentinv, workob.obmat);
3062                                 }
3063                                 
3064                                 ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
3065                                 
3066                                 if( ELEM(partype, PAR_CURVE, PAR_LATTICE) || pararm )
3067                                         ob->partype= PARSKEL; /* note, dna define, not operator property */
3068                                 else
3069                                         ob->partype= PAROBJECT; /* note, dna define, not operator property */
3070                         }
3071                 }
3072         }
3073         CTX_DATA_END;
3074         
3075         DAG_scene_sort(CTX_data_scene(C));
3076         ED_anim_dag_flush_update(C);
3077         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
3078         
3079         return OPERATOR_FINISHED;
3080 }
3081
3082 static int parent_set_invoke(bContext *C, wmOperator *op, wmEvent *event)
3083 {
3084         Object *ob= CTX_data_active_object(C);
3085         uiPopupMenu *pup= uiPupMenuBegin(C, "Set Parent To", 0);
3086         uiLayout *layout= uiPupMenuLayout(pup);
3087         
3088         uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
3089         uiItemEnumO(layout, NULL, 0, "OBJECT_OT_parent_set", "type", PAR_OBJECT);
3090         
3091         /* ob becomes parent, make the associated menus */
3092         if(ob->type==OB_ARMATURE) {
3093                 uiItemEnumO(layout, NULL, 0, "OBJECT_OT_parent_set", "type", PAR_ARMATURE);
3094                 uiItemEnumO(layout, NULL, 0, "OBJECT_OT_parent_set", "type", PAR_ARMATURE_NAME);
3095                 uiItemEnumO(layout, NULL, 0, "OBJECT_OT_parent_set", "type", PAR_ARMATURE_ENVELOPE);
3096                 uiItemEnumO(layout, NULL, 0, "OBJECT_OT_parent_set", "type", PAR_ARMATURE_AUTO);
3097                 uiItemEnumO(layout, NULL, 0, "OBJECT_OT_parent_set", "type", PAR_BONE);
3098         }
3099         else if(ob->type==OB_CURVE) {
3100                 uiItemEnumO(layout, NULL, 0, "OBJECT_OT_parent_set", "type", PAR_CURVE);
3101                 uiItemEnumO(layout, NULL, 0, "OBJECT_OT_parent_set", "type", PAR_FOLLOW);
3102                 uiItemEnumO(layout, NULL, 0, "OBJECT_OT_parent_set", "type", PAR_PATH_CONST);
3103         }
3104         else if(ob->type == OB_LATTICE) {
3105                 uiItemEnumO(layout, NULL, 0, "OBJECT_OT_parent_set", "type", PAR_LATTICE);
3106         }
3107         
3108         uiPupMenuEnd(C, pup);
3109         
3110         return OPERATOR_CANCELLED;
3111 }
3112
3113
3114 void OBJECT_OT_parent_set(wmOperatorType *ot)
3115 {
3116         /* identifiers */
3117         ot->name= "Make Parent";
3118         ot->description = "Set the object's parenting.";
3119         ot->idname= "OBJECT_OT_parent_set";
3120         
3121         /* api callbacks */
3122         ot->invoke= parent_set_invoke;
3123         ot->exec= parent_set_exec;
3124         
3125         ot->poll= ED_operator_object_active;
3126         
3127         /* flags */
3128         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3129         
3130         RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
3131 }
3132
3133 /* *** make track ***** */
3134 static EnumPropertyItem prop_make_track_types[] = {
3135         {1, "TRACKTO", 0, "TrackTo Constraint", ""},
3136         {2, "LOCKTRACK", 0, "LockTrack Constraint", ""},
3137         {3, "OLDTRACK", 0, "Old Track", ""},
3138         {0, NULL, 0, NULL, NULL}
3139 };
3140
3141 static int track_set_exec(bContext *C, wmOperator *op)
3142 {
3143         Scene *scene= CTX_data_scene(C);
3144         int type= RNA_enum_get(op->ptr, "type");
3145                 
3146         if(type == 1) {
3147                 bConstraint *con;
3148                 bTrackToConstraint *data;
3149
3150                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
3151                         if(base!=BASACT) {
3152                                 con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
3153                                 strcpy (con->name, "AutoTrack");
3154
3155                                 data = con->data;
3156                                 data->tar = BASACT->object;
3157                                 base->object->recalc |= OB_RECALC;
3158                                 
3159                                 /* Lamp and Camera track differently by default */
3160                                 if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
3161                                         data->reserved1 = TRACK_nZ;
3162                                         data->reserved2 = UP_Y;
3163                                 }
3164
3165                                 add_constraint_to_object(con, base->object);
3166                         }
3167                 }
3168                 CTX_DATA_END;
3169         }
3170         else if(type == 2) {
3171                 bConstraint *con;
3172                 bLockTrackConstraint *data;
3173
3174                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
3175                         if(base!=BASACT) {
3176                                 con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
3177                                 strcpy (con->name, "AutoTrack");
3178
3179                                 data = con->data;
3180                                 data->tar = BASACT->object;
3181                                 base->object->recalc |= OB_RECALC;
3182                                 
3183                                 /* Lamp and Camera track differently by default */
3184                                 if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
3185                                         data->trackflag = TRACK_nZ;
3186                                         data->lockflag = LOCK_Y;
3187                                 }
3188
3189                                 add_constraint_to_object(con, base->object);
3190                         }
3191                 }
3192                 CTX_DATA_END;
3193         }
3194         else {
3195                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
3196                         if(base!=BASACT) {
3197                                 base->object->track= BASACT->object;
3198                      &nb