Shift-A adds Armature Object (in Object Mode) or Bone (in Edit Mode) again. Still...
[blender-staging.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_particle.h"
102 #include "BKE_property.h"
103 #include "BKE_report.h"
104 #include "BKE_sca.h"
105 #include "BKE_scene.h"
106 #include "BKE_softbody.h"
107 #include "BKE_subsurf.h"
108 #include "BKE_texture.h"
109 #include "BKE_utildefines.h"
110 #include "BKE_modifier.h"
111
112 #include "ED_anim_api.h"
113 #include "ED_armature.h"
114 #include "ED_curve.h"
115 #include "ED_editparticle.h"
116 #include "ED_mesh.h"
117 #include "ED_object.h"
118 #include "ED_screen.h"
119 #include "ED_types.h"
120 #include "ED_util.h"
121 #include "ED_view3d.h"
122
123 #include "BMF_Api.h"
124
125 #include "BIF_transform.h"
126
127 #include "UI_interface.h"
128
129 #include "RNA_access.h"
130 #include "RNA_define.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() {}
144 static int pupmenu() {return 0;}
145 static int pupmenu_col() {return 0;}
146 static int okee() {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         /* activating a non-mesh, should end a couple of modes... */
183         if(base && base->object->type!=OB_MESH)
184                 ED_view3d_exit_paint_modes(C);
185         
186         /* sets scene->basact */
187         BASACT= base;
188         
189         if(base) {
190                 
191                 /* XXX old signals, remember to handle notifiers now! */
192                 //              select_actionchannel_by_name(base->object->action, "Object", 1);
193                 
194                 /* disable temporal locks */
195                 for(tbase=FIRSTBASE; tbase; tbase= tbase->next) {
196                         if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) {
197                                 tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK;
198                                 DAG_object_flush_update(scene, tbase->object, OB_RECALC_DATA);
199                         }
200                 }
201                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
202         }
203         else
204                 WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, NULL);
205 }
206
207
208 /*
209  * Returns true if the Object data is a from an external blend file (libdata)
210  */
211 int object_data_is_libdata(Object *ob)
212 {
213         if (!ob) return 0;
214         if (ob->proxy) return 0;
215         if (ob->id.lib) return 1;
216         if (!ob->data) return 0;
217         if (((ID *)ob->data)->lib) return 1;
218         return 0;
219 }
220
221
222
223 /* exported */
224 void ED_object_base_init_from_view(bContext *C, Base *base)
225 {
226         View3D *v3d= CTX_wm_view3d(C);
227         Scene *scene= CTX_data_scene(C);
228         Object *ob= base->object;
229         
230         if (scene==NULL)
231                 return;
232         
233         if (v3d==NULL) {
234                 base->lay = scene->lay;
235                 VECCOPY(ob->loc, scene->cursor);
236         } 
237         else {
238                 if (v3d->localview) {
239                         base->lay= ob->lay= v3d->layact | v3d->lay;
240                         VECCOPY(ob->loc, v3d->cursor);
241                 } 
242                 else {
243                         base->lay= ob->lay= v3d->layact;
244                         VECCOPY(ob->loc, scene->cursor);
245                 }
246                 
247                 if (U.flag & USER_ADD_VIEWALIGNED) {
248                         ARegion *ar= CTX_wm_region(C);
249                         if(ar) {
250                                 RegionView3D *rv3d= ar->regiondata;
251                                 
252                                 rv3d->viewquat[0]= -rv3d->viewquat[0];
253                                 QuatToEul(rv3d->viewquat, ob->rot);
254                                 rv3d->viewquat[0]= -rv3d->viewquat[0];
255                         }
256                 }
257         }
258         where_is_object(scene, ob);
259 }
260
261 /* ******************* add object operator ****************** */
262
263 static EnumPropertyItem prop_object_types[] = {
264         {OB_EMPTY, "EMPTY", "Empty", ""},
265         {OB_MESH, "MESH", "Mesh", ""},
266         {OB_CURVE, "CURVE", "Curve", ""},
267         {OB_SURF, "SURFACE", "Surface", ""},
268         {OB_FONT, "TEXT", "Text", ""},
269         {OB_MBALL, "META", "Meta", ""},
270         {OB_LAMP, "LAMP", "Lamp", ""},
271         {OB_CAMERA, "CAMERA", "Camera", ""},
272         {OB_ARMATURE, "ARMATURE", "Armature", ""},
273         {OB_LATTICE, "LATTICE", "Lattice", ""},
274         {0, NULL, NULL, NULL}
275 };
276
277
278
279 void add_object_draw(Scene *scene, View3D *v3d, int type)       /* for toolbox or menus, only non-editmode stuff */
280 {
281         /* keep here to get things compile, remove later */
282 }
283
284 /* for object add primitive operators */
285 static Object *object_add_type(bContext *C, int type)
286 {
287         Scene *scene= CTX_data_scene(C);
288         Object *ob;
289         
290         /* XXX hrms, this is editor level operator, remove? */
291         ED_view3d_exit_paint_modes(C);
292         
293         /* for as long scene has editmode... */
294         if (CTX_data_edit_object(C)) 
295                 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* freedata, and undo */
296         
297         /* deselects all, sets scene->basact */
298         ob= add_object(scene, type);
299         /* editor level activate, notifiers */
300         ED_base_object_activate(C, BASACT);
301         
302         /* more editor stuff */
303         ED_object_base_init_from_view(C, BASACT);
304         
305         DAG_scene_sort(scene);
306         
307         return ob;
308 }
309
310 /* for object add operator */
311 static int object_add_exec(bContext *C, wmOperator *op)
312 {
313         object_add_type(C, RNA_int_get(op->ptr, "type"));
314         
315         return OPERATOR_FINISHED;
316 }
317
318 void OBJECT_OT_object_add(wmOperatorType *ot)
319 {
320         /* identifiers */
321         ot->name= "Add Object";
322         ot->idname= "OBJECT_OT_object_add";
323         
324         /* api callbacks */
325         ot->invoke= WM_menu_invoke;
326         ot->exec= object_add_exec;
327         
328         ot->poll= ED_operator_scene_editable;
329         
330         /* flags */
331         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
332         
333         RNA_def_enum(ot->srna, "type", prop_object_types, 0, "Type", "");
334 }
335
336 /* ***************** add primitives *************** */
337 /* ******  work both in and outside editmode ****** */
338
339 static EnumPropertyItem prop_mesh_types[] = {
340         {0, "PLANE", "Plane", ""},
341         {1, "CUBE", "Cube", ""},
342         {2, "CIRCLE", "Circle", ""},
343         {3, "UVSPHERE", "UVsphere", ""},
344         {4, "ICOSPHERE", "Icosphere", ""},
345         {5, "CYLINDER", "Cylinder", ""},
346         {6, "CONE", "Cone", ""},
347         {7, "GRID", "Grid", ""},
348         {8, "MONKEY", "Monkey", ""},
349         {0, NULL, NULL, NULL}
350 };
351
352 static int object_add_mesh_exec(bContext *C, wmOperator *op)
353 {
354         Object *obedit= CTX_data_edit_object(C);
355         int newob= 0;
356         
357         if(obedit==NULL || obedit->type!=OB_MESH) {
358                 object_add_type(C, OB_MESH);
359                 ED_object_enter_editmode(C, 0);
360                 newob = 1;
361         }
362         else DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
363
364         switch(RNA_enum_get(op->ptr, "type")) {
365                 case 0:
366                         WM_operator_name_call(C, "MESH_OT_add_primitive_plane", WM_OP_INVOKE_REGION_WIN, NULL);
367                         break;
368                 case 1:
369                         WM_operator_name_call(C, "MESH_OT_add_primitive_cube", WM_OP_INVOKE_REGION_WIN, NULL);
370                         break;
371                 case 2:
372                         WM_operator_name_call(C, "MESH_OT_add_primitive_circle", WM_OP_INVOKE_REGION_WIN, NULL);
373                         break;
374                 case 3:
375                         WM_operator_name_call(C, "MESH_OT_add_primitive_uv_sphere", WM_OP_INVOKE_REGION_WIN, NULL);
376                         break;
377                 case 4:
378                         WM_operator_name_call(C, "MESH_OT_add_primitive_ico_sphere", WM_OP_INVOKE_REGION_WIN, NULL);
379                         break;
380                 case 5:
381                         WM_operator_name_call(C, "MESH_OT_add_primitive_cylinder", WM_OP_INVOKE_REGION_WIN, NULL);
382                         break;
383                 case 6:
384                         WM_operator_name_call(C, "MESH_OT_add_primitive_cone", WM_OP_INVOKE_REGION_WIN, NULL);
385                         break;
386                 case 7:
387                         WM_operator_name_call(C, "MESH_OT_add_primitive_grid", WM_OP_INVOKE_REGION_WIN, NULL);
388                         break;
389                 case 8:
390                         WM_operator_name_call(C, "MESH_OT_add_primitive_monkey", WM_OP_INVOKE_REGION_WIN, NULL);
391                         break;
392         }
393         /* userdef */
394         if (newob && (U.flag & USER_ADD_EDITMODE)==0) {
395                 ED_object_exit_editmode(C, EM_FREEDATA);
396         }
397         
398         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
399         
400         return OPERATOR_FINISHED;
401 }
402
403
404 void OBJECT_OT_mesh_add(wmOperatorType *ot)
405 {
406         /* identifiers */
407         ot->name= "Add Mesh";
408         ot->idname= "OBJECT_OT_mesh_add";
409         
410         /* api callbacks */
411         ot->invoke= WM_menu_invoke;
412         ot->exec= object_add_mesh_exec;
413         
414         ot->poll= ED_operator_scene_editable;
415         
416         /* flags */
417         ot->flag= 0;
418         
419         RNA_def_enum(ot->srna, "type", prop_mesh_types, 0, "Primitive", "");
420 }
421
422 static EnumPropertyItem prop_curve_types[] = {
423         {CU_BEZIER|CU_2D|CU_PRIM_CURVE, "BEZIER_CURVE", "Bezier Curve", ""},
424         {CU_BEZIER|CU_2D|CU_PRIM_CIRCLE, "BEZIER_CIRCLE", "Bezier Circle", ""},
425         {CU_NURBS|CU_2D|CU_PRIM_CURVE, "NURBS_CURVE", "NURBS Curve", ""},
426         {CU_NURBS|CU_2D|CU_PRIM_CIRCLE, "NURBS_CIRCLE", "NURBS Circle", ""},
427         {CU_NURBS|CU_2D|CU_PRIM_PATH, "PATH", "Path", ""},
428         {0, NULL, NULL, NULL}
429 };
430
431 static int object_add_curve_exec(bContext *C, wmOperator *op)
432 {
433         Object *obedit= CTX_data_edit_object(C);
434         ListBase *editnurb;
435         Nurb *nu;
436         int newob= 0;
437         
438         if(obedit==NULL || obedit->type!=OB_CURVE) {
439                 object_add_type(C, OB_CURVE);
440                 ED_object_enter_editmode(C, 0);
441                 newob = 1;
442         }
443         else DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
444         
445         obedit= CTX_data_edit_object(C);
446         nu= add_nurbs_primitive(C, RNA_enum_get(op->ptr, "type"), newob);
447         editnurb= curve_get_editcurve(obedit);
448         BLI_addtail(editnurb, nu);
449         
450         /* userdef */
451         if (newob && (U.flag & USER_ADD_EDITMODE)==0) {
452                 ED_object_exit_editmode(C, EM_FREEDATA);
453         }
454         
455         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
456         
457         return OPERATOR_FINISHED;
458 }
459
460 static int object_add_curve_invoke(bContext *C, wmOperator *op, wmEvent *event)
461 {
462         Object *obedit= CTX_data_edit_object(C);
463         uiMenuItem *head;
464
465         head= uiPupMenuBegin(op->type->name, 0);
466         if(!obedit || obedit->type == OB_CURVE)
467                 uiMenuItemsEnumO(head, op->type->idname, "type");
468         else
469                 uiMenuItemsEnumO(head, "OBJECT_OT_surface_add", "type");
470         uiPupMenuEnd(C, head);
471
472         return OPERATOR_CANCELLED;
473 }
474
475 void OBJECT_OT_curve_add(wmOperatorType *ot)
476 {
477         /* identifiers */
478         ot->name= "Add Curve";
479         ot->idname= "OBJECT_OT_curve_add";
480         
481         /* api callbacks */
482         ot->invoke= object_add_curve_invoke;
483         ot->exec= object_add_curve_exec;
484         
485         ot->poll= ED_operator_scene_editable;
486         
487         /* flags */
488         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
489         
490         RNA_def_enum(ot->srna, "type", prop_curve_types, 0, "Primitive", "");
491 }
492
493 static EnumPropertyItem prop_surface_types[]= {
494         {CU_PRIM_CURVE|CU_NURBS, "NURBS_CURVE", "NURBS Curve", ""},
495         {CU_PRIM_CIRCLE|CU_NURBS, "NURBS_CIRCLE", "NURBS Circle", ""},
496         {CU_PRIM_PATCH|CU_NURBS, "NURBS_SURFACE", "NURBS Surface", ""},
497         {CU_PRIM_TUBE|CU_NURBS, "NURBS_TUBE", "NURBS Tube", ""},
498         {CU_PRIM_SPHERE|CU_NURBS, "NURBS_SPHERE", "NURBS Sphere", ""},
499         {CU_PRIM_DONUT|CU_NURBS, "NURBS_DONUT", "NURBS Donut", ""},
500         {0, NULL, NULL, NULL}
501 };
502
503 static int object_add_surface_exec(bContext *C, wmOperator *op)
504 {
505         Object *obedit= CTX_data_edit_object(C);
506         ListBase *editnurb;
507         Nurb *nu;
508         int newob= 0;
509         
510         if(obedit==NULL || obedit->type!=OB_SURF) {
511                 object_add_type(C, OB_SURF);
512                 ED_object_enter_editmode(C, 0);
513                 newob = 1;
514         }
515         else DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
516         
517         obedit= CTX_data_edit_object(C);
518         nu= add_nurbs_primitive(C, RNA_enum_get(op->ptr, "type"), newob);
519         editnurb= curve_get_editcurve(obedit);
520         BLI_addtail(editnurb, nu);
521         
522         /* userdef */
523         if (newob && (U.flag & USER_ADD_EDITMODE)==0) {
524                 ED_object_exit_editmode(C, EM_FREEDATA);
525         }
526         
527         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
528         
529         return OPERATOR_FINISHED;
530 }
531
532 void OBJECT_OT_surface_add(wmOperatorType *ot)
533 {
534         /* identifiers */
535         ot->name= "Add Surface";
536         ot->idname= "OBJECT_OT_surface_add";
537         
538         /* api callbacks */
539         ot->invoke= WM_menu_invoke;
540         ot->exec= object_add_surface_exec;
541         
542         ot->poll= ED_operator_scene_editable;
543         
544         /* flags */
545         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
546         
547         RNA_def_enum(ot->srna, "type", prop_surface_types, 0, "Primitive", "");
548 }
549
550 static int object_add_text_exec(bContext *C, wmOperator *op)
551 {
552         Object *obedit= CTX_data_edit_object(C);
553         
554         if(obedit && obedit->type==OB_FONT)
555                 return OPERATOR_CANCELLED;
556
557         object_add_type(C, OB_FONT);
558         obedit= CTX_data_active_object(C);
559
560         if(U.flag & USER_ADD_EDITMODE)
561                 ED_object_enter_editmode(C, 0);
562         
563         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
564         
565         return OPERATOR_FINISHED;
566 }
567
568 void OBJECT_OT_text_add(wmOperatorType *ot)
569 {
570         /* identifiers */
571         ot->name= "Add Text";
572         ot->idname= "OBJECT_OT_text_add";
573         
574         /* api callbacks */
575         ot->exec= object_add_text_exec;
576         ot->poll= ED_operator_scene_editable;
577         
578         /* flags */
579         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
580 }
581
582 static int object_add_armature_exec(bContext *C, wmOperator *op)
583 {
584         Object *obedit= CTX_data_edit_object(C);
585         int newob= 0;
586         
587         if ((obedit==NULL) || (obedit->type != OB_ARMATURE)) {
588                 object_add_type(C, OB_ARMATURE);
589                 ED_object_enter_editmode(C, 0);
590                 newob = 1;
591         }
592         else DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
593         
594         //nu= add_nurbs_primitive(C, RNA_enum_get(op->ptr, "type"), newob);
595         //editnurb= curve_get_editcurve(CTX_data_edit_object(C));
596         //BLI_addtail(editnurb, nu);
597         
598         /* userdef */
599         if (newob && (U.flag & USER_ADD_EDITMODE)==0) {
600                 ED_object_exit_editmode(C, EM_FREEDATA);
601         }
602         
603         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
604         
605         return OPERATOR_FINISHED;
606 }
607
608 void OBJECT_OT_armature_add(wmOperatorType *ot)
609 {       
610         /* identifiers */
611         ot->name= "Add Armature";
612         ot->idname= "OBJECT_OT_armature_add";
613         
614         /* api callbacks */
615         ot->exec= object_add_armature_exec;
616         ot->poll= ED_operator_scene_editable;
617         
618         /* flags */
619         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
620 }
621
622
623 static int object_add_primitive_invoke(bContext *C, wmOperator *op, wmEvent *event)
624 {
625         uiMenuItem *head= uiPupMenuBegin("Add Object", 0);
626         
627         uiMenuLevelEnumO(head, "OBJECT_OT_mesh_add", "type");
628         uiMenuLevelEnumO(head, "OBJECT_OT_curve_add", "type");
629         uiMenuLevelEnumO(head, "OBJECT_OT_surface_add", "type");
630         uiMenuItemO(head, 0, "OBJECT_OT_text_add");
631         uiMenuItemEnumO(head, "", 0, "OBJECT_OT_object_add", "type", OB_MBALL);
632         uiMenuItemEnumO(head, "", 0, "OBJECT_OT_object_add", "type", OB_CAMERA);
633         uiMenuItemEnumO(head, "", 0, "OBJECT_OT_object_add", "type", OB_LAMP);
634         uiMenuItemEnumO(head, "", 0, "OBJECT_OT_object_add", "type", OB_EMPTY);
635         uiMenuItemO(head, 0, "OBJECT_OT_armature_add");
636         uiMenuItemEnumO(head, "", 0, "OBJECT_OT_object_add", "type", OB_LATTICE);
637         
638         uiPupMenuEnd(C, head);
639         
640         /* this operator is only for a menu, not used further */
641         return OPERATOR_CANCELLED;
642 }
643
644 /* only used as menu */
645 void OBJECT_OT_primitive_add(wmOperatorType *ot)
646 {
647         /* identifiers */
648         ot->name= "Add Primitive";
649         ot->idname= "OBJECT_OT_primitive_add";
650         
651         /* api callbacks */
652         ot->invoke= object_add_primitive_invoke;
653         
654         ot->poll= ED_operator_scene_editable;
655         
656         /* flags */
657         ot->flag= 0;
658 }
659
660
661 /* ******************************* */
662
663 /* remove base from a specific scene */
664 /* note: now unlinks constraints as well */
665 void ED_base_object_free_and_unlink(Scene *scene, Base *base)
666 {
667         BLI_remlink(&scene->base, base);
668         free_libblock_us(&G.main->object, base->object);
669         if(scene->basact==base) scene->basact= NULL;
670         MEM_freeN(base);
671 }
672
673 static int object_delete_exec(bContext *C, wmOperator *op)
674 {
675         Scene *scene= CTX_data_scene(C);
676         int islamp= 0;
677         
678         if(CTX_data_edit_object(C)) 
679                 return OPERATOR_CANCELLED;
680         
681         ED_view3d_exit_paint_modes(C);
682
683         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
684
685                 if(base->object->type==OB_LAMP) islamp= 1;
686                 
687                 /* remove from current scene only */
688                 ED_base_object_free_and_unlink(scene, base);
689         }
690         CTX_DATA_END;
691
692         if(islamp) reshadeall_displist(scene);  /* only frees displist */
693         
694         DAG_scene_sort(scene);
695         ED_anim_dag_flush_update(C);
696         
697         WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, CTX_data_scene(C));
698         
699         return OPERATOR_FINISHED;
700 }
701
702 void OBJECT_OT_delete(wmOperatorType *ot)
703 {
704         
705         /* identifiers */
706         ot->name= "Delete Objects";
707         ot->idname= "OBJECT_OT_delete";
708         
709         /* api callbacks */
710         ot->invoke= WM_operator_confirm;
711         ot->exec= object_delete_exec;
712         ot->poll= ED_operator_scene_editable;
713         
714         /* flags */
715         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
716         
717 }
718
719
720 static void single_object_users__forwardModifierLinks(void *userData, Object *ob, Object **obpoin)
721 {
722         ID_NEW(*obpoin);
723 }
724
725 static void copy_object__forwardModifierLinks(void *userData, Object *ob,
726                                               ID **idpoin)
727 {
728         /* this is copied from ID_NEW; it might be better to have a macro */
729         if(*idpoin && (*idpoin)->newid) *idpoin = (*idpoin)->newid;
730 }
731
732
733 /* after copying objects, copied data should get new pointers */
734 static void copy_object_set_idnew(Scene *scene, View3D *v3d, int dupflag)
735 {
736         Base *base;
737         Object *ob;
738         Material *ma, *mao;
739         ID *id;
740 #if 0 // XXX old animation system
741         Ipo *ipo;
742         bActionStrip *strip;
743 #endif // XXX old animation system
744         int a;
745         
746         /* XXX check object pointers */
747         for(base= FIRSTBASE; base; base= base->next) {
748                 if(TESTBASELIB(v3d, base)) {
749                         ob= base->object;
750                         relink_constraints(&ob->constraints);
751                         if (ob->pose){
752                                 bPoseChannel *chan;
753                                 for (chan = ob->pose->chanbase.first; chan; chan=chan->next){
754                                         relink_constraints(&chan->constraints);
755                                 }
756                         }
757                         modifiers_foreachIDLink(ob, copy_object__forwardModifierLinks, NULL);
758                         ID_NEW(ob->parent);
759                         ID_NEW(ob->track);
760                         ID_NEW(ob->proxy);
761                         ID_NEW(ob->proxy_group);
762                         
763 #if 0 // XXX old animation system
764                         for(strip= ob->nlastrips.first; strip; strip= strip->next) {
765                                 bActionModifier *amod;
766                                 for(amod= strip->modifiers.first; amod; amod= amod->next)
767                                         ID_NEW(amod->ob);
768                         }
769 #endif // XXX old animation system
770                 }
771         }
772         
773         /* materials */
774         if( dupflag & USER_DUP_MAT) {
775                 mao= G.main->mat.first;
776                 while(mao) {
777                         if(mao->id.newid) {
778                                 
779                                 ma= (Material *)mao->id.newid;
780                                 
781                                 if(dupflag & USER_DUP_TEX) {
782                                         for(a=0; a<MAX_MTEX; a++) {
783                                                 if(ma->mtex[a]) {
784                                                         id= (ID *)ma->mtex[a]->tex;
785                                                         if(id) {
786                                                                 ID_NEW_US(ma->mtex[a]->tex)
787                                                                 else ma->mtex[a]->tex= copy_texture(ma->mtex[a]->tex);
788                                                                 id->us--;
789                                                         }
790                                                 }
791                                         }
792                                 }
793 #if 0 // XXX old animation system
794                                 id= (ID *)ma->ipo;
795                                 if(id) {
796                                         ID_NEW_US(ma->ipo)
797                                         else ma->ipo= copy_ipo(ma->ipo);
798                                         id->us--;
799                                 }
800 #endif // XXX old animation system
801                         }
802                         mao= mao->id.next;
803                 }
804         }
805         
806 #if 0 // XXX old animation system
807         /* lamps */
808         if( dupflag & USER_DUP_IPO) {
809                 Lamp *la= G.main->lamp.first;
810                 while(la) {
811                         if(la->id.newid) {
812                                 Lamp *lan= (Lamp *)la->id.newid;
813                                 id= (ID *)lan->ipo;
814                                 if(id) {
815                                         ID_NEW_US(lan->ipo)
816                                         else lan->ipo= copy_ipo(lan->ipo);
817                                         id->us--;
818                                 }
819                         }
820                         la= la->id.next;
821                 }
822         }
823         
824         /* ipos */
825         ipo= G.main->ipo.first;
826         while(ipo) {
827                 if(ipo->id.lib==NULL && ipo->id.newid) {
828                         Ipo *ipon= (Ipo *)ipo->id.newid;
829                         IpoCurve *icu;
830                         for(icu= ipon->curve.first; icu; icu= icu->next) {
831                                 if(icu->driver) {
832                                         ID_NEW(icu->driver->ob);
833                                 }
834                         }
835                 }
836                 ipo= ipo->id.next;
837         }
838 #endif // XXX old animation system
839         
840         set_sca_new_poins();
841         
842         clear_id_newpoins();
843         
844 }
845
846 static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float *cent)
847 {
848         EditVert *eve;
849         int *index, nr, totvert=0;
850         
851         for(eve= em->verts.first; eve; eve= eve->next) {
852                 if(eve->f & SELECT) totvert++;
853         }
854         if(totvert==0) return 0;
855         
856         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
857         *tot= totvert;
858         nr= 0;
859         cent[0]= cent[1]= cent[2]= 0.0;
860         
861         for(eve= em->verts.first; eve; eve= eve->next) {
862                 if(eve->f & SELECT) {
863                         *index= nr; index++;
864                         VecAddf(cent, cent, eve->co);
865                 }
866                 nr++;
867         }
868         
869         VecMulf(cent, 1.0f/(float)totvert);
870         
871         return totvert;
872 }
873
874 static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, float *cent)
875 {
876         MDeformVert *dvert;
877         EditVert *eve;
878         int i, totvert=0;
879         
880         cent[0]= cent[1]= cent[2]= 0.0;
881         
882         if(obedit->actdef) {
883                 
884                 /* find the vertices */
885                 for(eve= em->verts.first; eve; eve= eve->next) {
886                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
887
888                         if(dvert) {
889                                 for(i=0; i<dvert->totweight; i++){
890                                         if(dvert->dw[i].def_nr == (obedit->actdef-1)) {
891                                                 totvert++;
892                                                 VecAddf(cent, cent, eve->co);
893                                         }
894                                 }
895                         }
896                 }
897                 if(totvert) {
898                         bDeformGroup *defGroup = BLI_findlink(&obedit->defbase, obedit->actdef-1);
899                         strcpy(name, defGroup->name);
900                         VecMulf(cent, 1.0f/(float)totvert);
901                         return 1;
902                 }
903         }
904         
905         return 0;
906 }       
907
908 static void select_editmesh_hook(Object *ob, HookModifierData *hmd)
909 {
910         Mesh *me= ob->data;
911         EditMesh *em= me->edit_mesh;
912         EditVert *eve;
913         int index=0, nr=0;
914         
915         for(eve= em->verts.first; eve; eve= eve->next, nr++) {
916                 if(nr==hmd->indexar[index]) {
917                         eve->f |= SELECT;
918                         if(index < hmd->totindex-1) index++;
919                 }
920         }
921         EM_select_flush(em);
922 }
923
924 static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent)
925 {
926         BPoint *bp;
927         int *index, nr, totvert=0, a;
928         
929         /* count */
930         a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
931         bp= editlatt->def;
932         while(a--) {
933                 if(bp->f1 & SELECT) {
934                         if(bp->hide==0) totvert++;
935                 }
936                 bp++;
937         }
938
939         if(totvert==0) return 0;
940         
941         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
942         *tot= totvert;
943         nr= 0;
944         cent[0]= cent[1]= cent[2]= 0.0;
945         
946         a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
947         bp= editlatt->def;
948         while(a--) {
949                 if(bp->f1 & SELECT) {
950                         if(bp->hide==0) {
951                                 *index= nr; index++;
952                                 VecAddf(cent, cent, bp->vec);
953                         }
954                 }
955                 bp++;
956                 nr++;
957         }
958         
959         VecMulf(cent, 1.0f/(float)totvert);
960         
961         return totvert;
962 }
963
964 static void select_editlattice_hook(Object *obedit, HookModifierData *hmd)
965 {
966         Lattice *lt= obedit->data;
967         BPoint *bp;
968         int index=0, nr=0, a;
969         
970         /* count */
971         a= lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw;
972         bp= lt->editlatt->def;
973         while(a--) {
974                 if(hmd->indexar[index]==nr) {
975                         bp->f1 |= SELECT;
976                         if(index < hmd->totindex-1) index++;
977                 }
978                 nr++;
979                 bp++;
980         }
981 }
982
983 static int return_editcurve_indexar(Object *obedit, int *tot, int **indexar, float *cent)
984 {
985         ListBase *editnurb= curve_get_editcurve(obedit);
986         Nurb *nu;
987         BPoint *bp;
988         BezTriple *bezt;
989         int *index, a, nr, totvert=0;
990         
991         for(nu= editnurb->first; nu; nu= nu->next) {
992                 if((nu->type & 7)==CU_BEZIER) {
993                         bezt= nu->bezt;
994                         a= nu->pntsu;
995                         while(a--) {
996                                 if(bezt->f1 & SELECT) totvert++;
997                                 if(bezt->f2 & SELECT) totvert++;
998                                 if(bezt->f3 & SELECT) totvert++;
999                                 bezt++;
1000                         }
1001                 }
1002                 else {
1003                         bp= nu->bp;
1004                         a= nu->pntsu*nu->pntsv;
1005                         while(a--) {
1006                                 if(bp->f1 & SELECT) totvert++;
1007                                 bp++;
1008                         }
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         for(nu= editnurb->first; nu; nu= nu->next) {
1019                 if((nu->type & 7)==CU_BEZIER) {
1020                         bezt= nu->bezt;
1021                         a= nu->pntsu;
1022                         while(a--) {
1023                                 if(bezt->f1 & SELECT) {
1024                                         *index= nr; index++;
1025                                         VecAddf(cent, cent, bezt->vec[0]);
1026                                 }
1027                                 nr++;
1028                                 if(bezt->f2 & SELECT) {
1029                                         *index= nr; index++;
1030                                         VecAddf(cent, cent, bezt->vec[1]);
1031                                 }
1032                                 nr++;
1033                                 if(bezt->f3 & SELECT) {
1034                                         *index= nr; index++;
1035                                         VecAddf(cent, cent, bezt->vec[2]);
1036                                 }
1037                                 nr++;
1038                                 bezt++;
1039                         }
1040                 }
1041                 else {
1042                         bp= nu->bp;
1043                         a= nu->pntsu*nu->pntsv;
1044                         while(a--) {
1045                                 if(bp->f1 & SELECT) {
1046                                         *index= nr; index++;
1047                                         VecAddf(cent, cent, bp->vec);
1048                                 }
1049                                 nr++;
1050                                 bp++;
1051                         }
1052                 }
1053         }
1054         
1055         VecMulf(cent, 1.0f/(float)totvert);
1056         
1057         return totvert;
1058 }
1059
1060 void ED_object_apply_obmat(Object *ob)
1061 {
1062         float mat[3][3], imat[3][3], tmat[3][3];
1063         
1064         /* from obmat to loc rot size */
1065         
1066         if(ob==NULL) return;
1067         Mat3CpyMat4(mat, ob->obmat);
1068         
1069         VECCOPY(ob->loc, ob->obmat[3]);
1070
1071         Mat3ToEul(mat, ob->rot);
1072         EulToMat3(ob->rot, tmat);
1073
1074         Mat3Inv(imat, tmat);
1075         
1076         Mat3MulMat3(tmat, imat, mat);
1077         
1078         ob->size[0]= tmat[0][0];
1079         ob->size[1]= tmat[1][1];
1080         ob->size[2]= tmat[2][2];
1081         
1082 }
1083
1084 int hook_getIndexArray(Object *obedit, int *tot, int **indexar, char *name, float *cent_r)
1085 {
1086         *indexar= NULL;
1087         *tot= 0;
1088         name[0]= 0;
1089         
1090         switch(obedit->type) {
1091                 case OB_MESH:
1092                 {
1093                         Mesh *me= obedit->data;
1094                         /* check selected vertices first */
1095                         if( return_editmesh_indexar(me->edit_mesh, tot, indexar, cent_r)) return 1;
1096                         else return return_editmesh_vgroup(obedit, me->edit_mesh, name, cent_r);
1097                 }
1098                 case OB_CURVE:
1099                 case OB_SURF:
1100                         return return_editcurve_indexar(obedit, tot, indexar, cent_r);
1101                 case OB_LATTICE:
1102                 {
1103                         Lattice *lt= obedit->data;
1104                         return return_editlattice_indexar(lt->editlatt, tot, indexar, cent_r);
1105                 }
1106                 default:
1107                         return 0;
1108         }
1109 }
1110
1111 static void select_editcurve_hook(Object *obedit, HookModifierData *hmd)
1112 {
1113         ListBase *editnurb= curve_get_editcurve(obedit);
1114         Nurb *nu;
1115         BPoint *bp;
1116         BezTriple *bezt;
1117         int index=0, a, nr=0;
1118         
1119         for(nu= editnurb->first; nu; nu= nu->next) {
1120                 if((nu->type & 7)==CU_BEZIER) {
1121                         bezt= nu->bezt;
1122                         a= nu->pntsu;
1123                         while(a--) {
1124                                 if(nr == hmd->indexar[index]) {
1125                                         bezt->f1 |= SELECT;
1126                                         if(index<hmd->totindex-1) index++;
1127                                 }
1128                                 nr++;
1129                                 if(nr == hmd->indexar[index]) {
1130                                         bezt->f2 |= SELECT;
1131                                         if(index<hmd->totindex-1) index++;
1132                                 }
1133                                 nr++;
1134                                 if(nr == hmd->indexar[index]) {
1135                                         bezt->f3 |= SELECT;
1136                                         if(index<hmd->totindex-1) index++;
1137                                 }
1138                                 nr++;
1139                                 
1140                                 bezt++;
1141                         }
1142                 }
1143                 else {
1144                         bp= nu->bp;
1145                         a= nu->pntsu*nu->pntsv;
1146                         while(a--) {
1147                                 if(nr == hmd->indexar[index]) {
1148                                         bp->f1 |= SELECT;
1149                                         if(index<hmd->totindex-1) index++;
1150                                 }
1151                                 nr++;
1152                                 bp++;
1153                         }
1154                 }
1155         }
1156 }
1157
1158 void obedit_hook_select(Object *ob, HookModifierData *hmd) 
1159 {
1160         
1161         if(ob->type==OB_MESH) select_editmesh_hook(ob, hmd);
1162         else if(ob->type==OB_LATTICE) select_editlattice_hook(ob, hmd);
1163         else if(ob->type==OB_CURVE) select_editcurve_hook(ob, hmd);
1164         else if(ob->type==OB_SURF) select_editcurve_hook(ob, hmd);
1165 }
1166
1167
1168 void add_hook(Scene *scene, View3D *v3d, int mode)
1169 {
1170         ModifierData *md = NULL;
1171         HookModifierData *hmd = NULL;
1172         Object *ob=NULL;
1173         Object *obedit= scene->obedit;  // XXX get from context
1174         
1175         if(obedit==NULL) return;
1176         
1177         /* preconditions */
1178         if(mode==2) { /* selected object */
1179                 Base *base;
1180                 for(base= FIRSTBASE; base; base= base->next) {
1181                         if(TESTBASELIB(v3d, base)) {
1182                                 if(base!=BASACT) {
1183                                         ob= base->object;
1184                                         break;
1185                                 }
1186                         }
1187                 }
1188                 if(ob==NULL) {
1189                         error("Requires selected Object");
1190                         return;
1191                 }
1192         }
1193         else if(mode!=1) {
1194                 int maxlen=0, a, nr;
1195                 char *cp;
1196                 
1197                 /* make pupmenu with hooks */
1198                 for(md=obedit->modifiers.first; md; md= md->next) {
1199                         if (md->type==eModifierType_Hook) 
1200                                 maxlen+=32;
1201                 }
1202                 
1203                 if(maxlen==0) {
1204                         error("Object has no hooks yet");
1205                         return;
1206                 }
1207                 
1208                 cp= MEM_callocN(maxlen+32, "temp string");
1209                 if(mode==3) strcpy(cp, "Remove %t|");
1210                 else if(mode==4) strcpy(cp, "Reassign %t|");
1211                 else if(mode==5) strcpy(cp, "Select %t|");
1212                 else if(mode==6) strcpy(cp, "Clear Offset %t|");
1213                 
1214                 for(md=obedit->modifiers.first; md; md= md->next) {
1215                         if (md->type==eModifierType_Hook) {
1216                                 strcat(cp, md->name);
1217                                 strcat(cp, " |");
1218                         }
1219                 }
1220                 
1221                 nr= pupmenu(cp);
1222                 MEM_freeN(cp);
1223                 
1224                 if(nr<1) return;
1225                 
1226                 a= 1;
1227                 for(md=obedit->modifiers.first; md; md=md->next) {
1228                         if (md->type==eModifierType_Hook) {
1229                                 if(a==nr) break;
1230                                 a++;
1231                         }
1232                 }
1233                 
1234                 hmd = (HookModifierData*) md;
1235                 ob= hmd->object;
1236         }
1237
1238         /* do it, new hooks or reassign */
1239         if(mode==1 || mode==2 || mode==4) {
1240                 float cent[3];
1241                 int tot, ok, *indexar;
1242                 char name[32];
1243                 
1244                 ok = hook_getIndexArray(obedit, &tot, &indexar, name, cent);
1245                 
1246                 if(ok==0) {
1247                         error("Requires selected vertices or active Vertex Group");
1248                 }
1249                 else {
1250                         
1251                         if(mode==1) {
1252                                 Base *base= BASACT, *newbase;
1253                                 
1254                                 ob= add_object(scene, OB_EMPTY);
1255                                 /* set layers OK */
1256                                 newbase= BASACT;
1257                                 newbase->lay= base->lay;
1258                                 ob->lay= newbase->lay;
1259                                 
1260                                 /* transform cent to global coords for loc */
1261                                 VecMat4MulVecfl(ob->loc, obedit->obmat, cent);
1262                                 
1263                                 /* restore, add_object sets active */
1264                                 BASACT= base;
1265                         }
1266                         /* if mode is 2 or 4, ob has been set */
1267                         
1268                         /* new hook */
1269                         if(mode==1 || mode==2) {
1270                                 ModifierData *md = obedit->modifiers.first;
1271                                 
1272                                 while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
1273                                         md = md->next;
1274                                 }
1275                                 
1276                                 hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
1277                                 BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
1278                                 sprintf(hmd->modifier.name, "Hook-%s", ob->id.name+2);
1279                         }
1280                         else if (hmd->indexar) MEM_freeN(hmd->indexar); /* reassign, hook was set */
1281                 
1282                         hmd->object= ob;
1283                         hmd->indexar= indexar;
1284                         VECCOPY(hmd->cent, cent);
1285                         hmd->totindex= tot;
1286                         BLI_strncpy(hmd->name, name, 32);
1287                         
1288                         if(mode==1 || mode==2) {
1289                                 /* matrix calculus */
1290                                 /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
1291                                 /*        (parentinv         )                          */
1292                                 
1293                                 where_is_object(scene, ob);
1294                                 
1295                                 Mat4Invert(ob->imat, ob->obmat);
1296                                 /* apparently this call goes from right to left... */
1297                                 Mat4MulSerie(hmd->parentinv, ob->imat, obedit->obmat, NULL, 
1298                                                          NULL, NULL, NULL, NULL, NULL);
1299                         }
1300                 }
1301         }
1302         else if(mode==3) { /* remove */
1303                 BLI_remlink(&obedit->modifiers, md);
1304                 modifier_free(md);
1305         }
1306         else if(mode==5) { /* select */
1307                 obedit_hook_select(obedit, hmd);
1308         }
1309         else if(mode==6) { /* clear offset */
1310                 where_is_object(scene, ob);     /* ob is hook->parent */
1311
1312                 Mat4Invert(ob->imat, ob->obmat);
1313                 /* this call goes from right to left... */
1314                 Mat4MulSerie(hmd->parentinv, ob->imat, obedit->obmat, NULL, 
1315                                          NULL, NULL, NULL, NULL, NULL);
1316         }
1317
1318         DAG_scene_sort(scene);
1319 }
1320
1321
1322 /* use this when the loc/size/rot of the parent has changed but the children should stay in the same place
1323  * apply-size-rot or object center for eg */
1324 static void ignore_parent_tx(Scene *scene, Object *ob ) 
1325 {
1326         Object workob;
1327         Object *ob_child;
1328         
1329         /* a change was made, adjust the children to compensate */
1330         for (ob_child=G.main->object.first; ob_child; ob_child=ob_child->id.next) {
1331                 if (ob_child->parent == ob) {
1332                         ED_object_apply_obmat(ob_child);
1333                         what_does_parent(scene, ob_child, &workob);
1334                         Mat4Invert(ob_child->parentinv, workob.obmat);
1335                 }
1336         }
1337 }
1338
1339
1340 void add_hook_menu(Scene *scene, View3D *v3d)
1341 {
1342         Object *obedit= scene->obedit;  // XXX get from context
1343         int mode;
1344         
1345         if(obedit==NULL) return;
1346         
1347         if(modifiers_findByType(obedit, eModifierType_Hook))
1348                 mode= pupmenu("Hooks %t|Add, To New Empty %x1|Add, To Selected Object %x2|Remove... %x3|Reassign... %x4|Select... %x5|Clear Offset...%x6");
1349         else
1350                 mode= pupmenu("Hooks %t|Add, New Empty %x1|Add, To Selected Object %x2");
1351
1352         if(mode<1) return;
1353                 
1354         /* do operations */
1355         add_hook(scene, v3d, mode);
1356 }
1357
1358 /* ******************** clear parent operator ******************* */
1359
1360 static EnumPropertyItem prop_clear_parent_types[] = {
1361         {0, "CLEAR", "Clear Parent", ""},
1362         {1, "CLEAR_KEEP_TRANSFORM", "Clear and Keep Transformation (Clear Track)", ""},
1363         {2, "CLEAR_INVERSE", "Clear Parent Inverse", ""},
1364         {0, NULL, NULL, NULL}
1365 };
1366
1367 /* note, poll should check for editable scene */
1368 static int clear_parent_exec(bContext *C, wmOperator *op)
1369 {
1370         
1371         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
1372
1373                 if(RNA_enum_is_equal(op->ptr, "type", "CLEAR")) {
1374                         ob->parent= NULL;
1375                 }                       
1376                 if(RNA_enum_is_equal(op->ptr, "type", "CLEAR_KEEP_TRANSFORM")) {
1377                         ob->parent= NULL;
1378                         ob->track= NULL;
1379                         ED_object_apply_obmat(ob);
1380                 }
1381                 if(RNA_enum_is_equal(op->ptr, "type", "CLEAR_INVERSE")) {
1382                         Mat4One(ob->parentinv);
1383                 }
1384                 ob->recalc |= OB_RECALC;
1385         }
1386         CTX_DATA_END;
1387         
1388         DAG_scene_sort(CTX_data_scene(C));
1389         ED_anim_dag_flush_update(C);
1390         
1391         return OPERATOR_FINISHED;
1392 }
1393
1394 void OBJECT_OT_clear_parent(wmOperatorType *ot)
1395 {
1396         /* identifiers */
1397         ot->name= "Clear parent";
1398         ot->idname= "OBJECT_OT_clear_parent";
1399         
1400         /* api callbacks */
1401         ot->invoke= WM_menu_invoke;
1402         ot->exec= clear_parent_exec;
1403         
1404         ot->poll= ED_operator_object_active;
1405         
1406         /* flags */
1407         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1408         
1409         RNA_def_enum(ot->srna, "type", prop_clear_parent_types, 0, "Type", "");
1410 }
1411
1412 /* ******************** clear track operator ******************* */
1413
1414
1415 static EnumPropertyItem prop_clear_track_types[] = {
1416         {0, "CLEAR", "Clear Track", ""},
1417         {1, "CLEAR_KEEP_TRANSFORM", "Clear and Keep Transformation (Clear Track)", ""},
1418         {0, NULL, NULL, NULL}
1419 };
1420
1421 /* note, poll should check for editable scene */
1422 static int object_clear_track_exec(bContext *C, wmOperator *op)
1423 {
1424         if(CTX_data_edit_object(C)) {
1425                 BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in EditMode");
1426                 return OPERATOR_CANCELLED;
1427         }
1428         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
1429                 ob->track= NULL;
1430                 ob->recalc |= OB_RECALC;
1431                 
1432                 if(RNA_enum_is_equal(op->ptr, "type", "CLEAR_KEEP_TRANSFORM")) {
1433                         ED_object_apply_obmat(ob);
1434                 }                       
1435         }
1436         CTX_DATA_END;
1437
1438         DAG_scene_sort(CTX_data_scene(C));
1439         ED_anim_dag_flush_update(C);
1440
1441         return OPERATOR_FINISHED;
1442 }
1443
1444 void OBJECT_OT_clear_track(wmOperatorType *ot)
1445 {
1446         /* identifiers */
1447         ot->name= "Clear track";
1448         ot->idname= "OBJECT_OT_clear_track";
1449         
1450         /* api callbacks */
1451         ot->invoke= WM_menu_invoke;
1452         ot->exec= object_clear_track_exec;
1453         
1454         ot->poll= ED_operator_scene_editable;
1455         
1456         /* flags */
1457         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1458         
1459         RNA_def_enum(ot->srna, "type", prop_clear_track_types, 0, "Type", "");
1460 }
1461
1462
1463 /* ***************************** */
1464 /* ****** Select by Type ****** */
1465
1466 static int object_select_by_type_exec(bContext *C, wmOperator *op)
1467 {
1468         short obtype;
1469         
1470         obtype = RNA_enum_get(op->ptr, "type");
1471                 
1472         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1473                 if(base->object->type==obtype) {
1474                         ED_base_object_select(base, BA_SELECT);
1475                 }
1476         }
1477         CTX_DATA_END;
1478         
1479         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1480         
1481         return OPERATOR_FINISHED;
1482 }
1483
1484 void OBJECT_OT_select_by_type(wmOperatorType *ot)
1485 {
1486         /* identifiers */
1487         ot->name= "Select By Type";
1488         ot->idname= "OBJECT_OT_select_by_type";
1489         
1490         /* api callbacks */
1491         ot->invoke= WM_menu_invoke;
1492         ot->exec= object_select_by_type_exec;
1493         ot->poll= ED_operator_scene_editable;
1494         
1495         /* flags */
1496         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1497         
1498         RNA_def_enum(ot->srna, "type", prop_object_types, 0, "Type", "");
1499
1500 }
1501 /* ****** selection by links *******/
1502
1503 static EnumPropertyItem prop_select_linked_types[] = {
1504         {1, "IPO", "Object IPO", ""}, // XXX depreceated animation system stuff...
1505         {2, "OBDATA", "Ob Data", ""},
1506         {3, "MATERIAL", "Material", ""},
1507         {4, "TEXTURE", "Texture", ""},
1508         {5, "DUPGROUP", "Dupligroup", ""},
1509         {6, "PARTICLE", "Particle System", ""},
1510         {0, NULL, NULL, NULL}
1511 };
1512
1513 static int object_select_linked_exec(bContext *C, wmOperator *op)
1514 {
1515         Scene *scene= CTX_data_scene(C);
1516         Object *ob;
1517         void *obdata = NULL;
1518         Material *mat = NULL, *mat1;
1519         Tex *tex=0;
1520         int a, b;
1521         int nr = RNA_enum_get(op->ptr, "type");
1522         short changed = 0;
1523         /* events (nr):
1524          * Object Ipo: 1
1525          * ObData: 2
1526          * Current Material: 3
1527          * Current Texture: 4
1528          * DupliGroup: 5
1529          * PSys: 6
1530          */
1531         
1532         
1533         ob= OBACT;
1534         if(ob==0){ 
1535                 BKE_report(op->reports, RPT_ERROR, "No Active Object");
1536                 return OPERATOR_CANCELLED;
1537         }
1538         
1539         if(nr==1) {     
1540                         // XXX old animation system
1541                 //ipo= ob->ipo;
1542                 //if(ipo==0) return OPERATOR_CANCELLED;
1543                 return OPERATOR_CANCELLED;
1544         }
1545         else if(nr==2) {
1546                 if(ob->data==0) return OPERATOR_CANCELLED;
1547                 obdata= ob->data;
1548         }
1549         else if(nr==3 || nr==4) {
1550                 mat= give_current_material(ob, ob->actcol);
1551                 if(mat==0) return OPERATOR_CANCELLED;
1552                 if(nr==4) {
1553                         if(mat->mtex[ (int)mat->texact ]) tex= mat->mtex[ (int)mat->texact ]->tex;
1554                         if(tex==0) return OPERATOR_CANCELLED;
1555                 }
1556         }
1557         else if(nr==5) {
1558                 if(ob->dup_group==NULL) return OPERATOR_CANCELLED;
1559         }
1560         else if(nr==6) {
1561                 if(ob->particlesystem.first==NULL) return OPERATOR_CANCELLED;
1562         }
1563         else return OPERATOR_CANCELLED;
1564         
1565         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1566                 if (!(base->flag & SELECT)) {
1567                         if(nr==1) {
1568                                         // XXX old animation system
1569                                 //if(base->object->ipo==ipo) base->flag |= SELECT;
1570                                 //changed = 1;
1571                         }
1572                         else if(nr==2) {
1573                                 if(base->object->data==obdata) base->flag |= SELECT;
1574                                 changed = 1;
1575                         }
1576                         else if(nr==3 || nr==4) {
1577                                 ob= base->object;
1578                                 
1579                                 for(a=1; a<=ob->totcol; a++) {
1580                                         mat1= give_current_material(ob, a);
1581                                         if(nr==3) {
1582                                                 if(mat1==mat) base->flag |= SELECT;
1583                                                 changed = 1;
1584                                         }
1585                                         else if(mat1 && nr==4) {
1586                                                 for(b=0; b<MAX_MTEX; b++) {
1587                                                         if(mat1->mtex[b]) {
1588                                                                 if(tex==mat1->mtex[b]->tex) {
1589                                                                         base->flag |= SELECT;
1590                                                                         changed = 1;
1591                                                                         break;
1592                                                                 }
1593                                                         }
1594                                                 }
1595                                         }
1596                                 }
1597                         }
1598                         else if(nr==5) {
1599                                 if(base->object->dup_group==ob->dup_group) {
1600                                          base->flag |= SELECT;
1601                                          changed = 1;
1602                                 }
1603                         }
1604                         else if(nr==6) {
1605                                 /* loop through other, then actives particles*/
1606                                 ParticleSystem *psys;
1607                                 ParticleSystem *psys_act;
1608                                 
1609                                 for(psys=base->object->particlesystem.first; psys; psys=psys->next) {
1610                                         for(psys_act=ob->particlesystem.first; psys_act; psys_act=psys_act->next) {
1611                                                 if (psys->part == psys_act->part) {
1612                                                         base->flag |= SELECT;
1613                                                         changed = 1;
1614                                                         break;
1615                                                 }
1616                                         }
1617                                         
1618                                         if (base->flag & SELECT) {
1619                                                 break;
1620                                         }
1621                                 }
1622                         }
1623                         base->object->flag= base->flag;
1624                 }
1625         }
1626         CTX_DATA_END;
1627         
1628         if (changed) {
1629                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1630                 return OPERATOR_FINISHED;
1631         }
1632         
1633         return OPERATOR_CANCELLED;
1634 }
1635
1636 void OBJECT_OT_select_linked(wmOperatorType *ot)
1637 {
1638         /* identifiers */
1639         ot->name= "Select Linked";
1640         ot->idname= "OBJECT_OT_select_linked";
1641         
1642         /* api callbacks */
1643         ot->invoke= WM_menu_invoke;
1644         ot->exec= object_select_linked_exec;
1645         ot->poll= ED_operator_scene_editable;
1646         
1647         /* flags */
1648         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1649         
1650         RNA_def_enum(ot->srna, "type", prop_select_linked_types, 0, "Type", "");
1651
1652 }
1653 /* ****** selection by layer *******/
1654
1655 static int object_select_by_layer_exec(bContext *C, wmOperator *op)
1656 {
1657         unsigned int layernum;
1658         
1659         layernum = RNA_int_get(op->ptr, "layer");
1660                 
1661         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1662                 if(base->lay == (1<< (layernum -1)))
1663                         ED_base_object_select(base, BA_SELECT);
1664         }
1665         CTX_DATA_END;
1666         
1667         /* undo? */
1668         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1669         
1670         return OPERATOR_FINISHED;
1671 }
1672
1673 void OBJECT_OT_select_by_layer(wmOperatorType *ot)
1674 {
1675         /* identifiers */
1676         ot->name= "Selection by layer";
1677         ot->idname= "OBJECT_OT_select_by_layer";
1678         
1679         /* api callbacks */
1680         /*ot->invoke = XXX - need a int grid popup*/
1681         ot->exec= object_select_by_layer_exec;
1682         ot->poll= ED_operator_scene_editable;
1683         
1684         /* flags */
1685         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1686         
1687         RNA_def_int(ot->srna, "layer", 1, 1, 20, "Layer", "", 1, 20);
1688 }
1689
1690 /* ****** invert selection *******/
1691 static int object_select_invert_exec(bContext *C, wmOperator *op)
1692 {
1693         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1694                 if (base->flag & SELECT)
1695                         ED_base_object_select(base, BA_DESELECT);
1696                 else
1697                         ED_base_object_select(base, BA_SELECT);
1698         }
1699         CTX_DATA_END;
1700         
1701         /* undo? */
1702         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1703         
1704         return OPERATOR_FINISHED;
1705 }
1706
1707 void OBJECT_OT_select_invert(wmOperatorType *ot)
1708 {
1709         
1710         /* identifiers */
1711         ot->name= "Invert selection";
1712         ot->idname= "OBJECT_OT_select_invert";
1713         
1714         /* api callbacks */
1715         ot->exec= object_select_invert_exec;
1716         ot->poll= ED_operator_scene_editable;
1717         
1718         /* flags */
1719         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1720         
1721 }
1722 /* ****** (de)select All *******/
1723
1724 static int object_de_select_all_exec(bContext *C, wmOperator *op)
1725 {
1726         
1727         int a=0, ok=0; 
1728         
1729         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1730                 if (base->flag & SELECT) {
1731                         ok= a= 1;
1732                         break;
1733                 }
1734                 else ok=1;
1735         }
1736         CTX_DATA_END;
1737         
1738         if (!ok) return OPERATOR_PASS_THROUGH;
1739         
1740         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1741                 if (a) ED_base_object_select(base, BA_DESELECT);
1742                 else ED_base_object_select(base, BA_SELECT);
1743         }
1744         CTX_DATA_END;
1745         
1746         /* undo? */
1747         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1748         
1749         return OPERATOR_FINISHED;
1750 }
1751
1752 void OBJECT_OT_de_select_all(wmOperatorType *ot)
1753 {
1754         
1755         /* identifiers */
1756         ot->name= "deselect all";
1757         ot->idname= "OBJECT_OT_de_select_all";
1758         
1759         /* api callbacks */
1760         ot->exec= object_de_select_all_exec;
1761         ot->poll= ED_operator_scene_editable;
1762         
1763         /* flags */
1764         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1765         
1766 }
1767 /* ****** random selection *******/
1768
1769 static int object_select_random_exec(bContext *C, wmOperator *op)
1770 {       
1771         float percent;
1772         
1773         percent = RNA_float_get(op->ptr, "percent");
1774                 
1775         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
1776                 if ((!base->flag & SELECT && BLI_frand() < percent)) {
1777                                 ED_base_object_select(base, BA_SELECT);
1778                 }
1779         }
1780         CTX_DATA_END;
1781         
1782         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
1783         
1784         return OPERATOR_FINISHED;
1785 }
1786
1787 void OBJECT_OT_select_random(wmOperatorType *ot)
1788 {
1789         /* identifiers */
1790         ot->name= "Random selection";
1791         ot->idname= "OBJECT_OT_select_random";
1792         
1793         /* api callbacks */
1794         /*ot->invoke= object_select_random_invoke XXX - need a number popup ;*/
1795         ot->exec = object_select_random_exec;
1796         ot->poll= ED_operator_scene_editable;
1797         
1798         /* flags */
1799         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1800         
1801         RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "percentage of objects to randomly select", 0.0001f, 1.0f);
1802 }
1803
1804 /* ******** Clear object Translation *********** */
1805
1806 static int object_clear_location_exec(bContext *C, wmOperator *op)
1807 {
1808         int armature_clear= 0;
1809
1810         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
1811                 if((G.f & G_WEIGHTPAINT)==0) {
1812                         if ((ob->protectflag & OB_LOCK_LOCX)==0)
1813                                 ob->loc[0]= ob->dloc[0]= 0.0f;
1814                         if ((ob->protectflag & OB_LOCK_LOCY)==0)
1815                                 ob->loc[1]= ob->dloc[1]= 0.0f;
1816                         if ((ob->protectflag & OB_LOCK_LOCZ)==0)
1817                                 ob->loc[2]= ob->dloc[2]= 0.0f;
1818                 }
1819                 ob->recalc |= OB_RECALC_OB;
1820         }
1821         CTX_DATA_END;
1822
1823         if(armature_clear==0) /* in this case flush was done */
1824                 ED_anim_dag_flush_update(C);    
1825         
1826         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1827         
1828         return OPERATOR_FINISHED;
1829 }
1830
1831
1832 void OBJECT_OT_clear_location(wmOperatorType *ot)
1833 {
1834         
1835         /* identifiers */
1836         ot->name= "Clear Object Location";
1837         ot->idname= "OBJECT_OT_clear_location";
1838         
1839         /* api callbacks */
1840         ot->invoke= WM_operator_confirm;
1841         ot->exec= object_clear_location_exec;
1842         ot->poll= ED_operator_object_active;
1843         
1844         /* flags */
1845         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1846 }
1847
1848 static int object_clear_rotation_exec(bContext *C, wmOperator *op)
1849 {
1850         int armature_clear= 0;
1851
1852         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
1853                 if((G.f & G_WEIGHTPAINT)==0) {
1854                         /* eulers can only get cleared if they are not protected */
1855                         if ((ob->protectflag & OB_LOCK_ROTX)==0)
1856                                 ob->rot[0]= ob->drot[0]= 0.0f;
1857                         if ((ob->protectflag & OB_LOCK_ROTY)==0)
1858                                 ob->rot[1]= ob->drot[1]= 0.0f;
1859                         if ((ob->protectflag & OB_LOCK_ROTZ)==0)
1860                                 ob->rot[2]= ob->drot[2]= 0.0f;
1861                 }
1862                 ob->recalc |= OB_RECALC_OB;
1863         }
1864         CTX_DATA_END;
1865
1866         if(armature_clear==0) /* in this case flush was done */
1867                 ED_anim_dag_flush_update(C);    
1868         
1869         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1870         
1871         return OPERATOR_FINISHED;
1872 }
1873
1874
1875 void OBJECT_OT_clear_rotation(wmOperatorType *ot)
1876 {
1877         
1878         /* identifiers */
1879         ot->name= "Clear Object Rotation";
1880         ot->idname= "OBJECT_OT_clear_rotation";
1881         
1882         /* api callbacks */
1883         ot->invoke= WM_operator_confirm;
1884         ot->exec= object_clear_rotation_exec;
1885         ot->poll= ED_operator_object_active;
1886         
1887         /* flags */
1888         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1889 }
1890
1891 static int object_clear_scale_exec(bContext *C, wmOperator *op)
1892 {
1893         int armature_clear= 0;
1894
1895         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
1896                 if((G.f & G_WEIGHTPAINT)==0) {
1897                         if ((ob->protectflag & OB_LOCK_SCALEX)==0) {
1898                                 ob->dsize[0]= 0.0f;
1899                                 ob->size[0]= 1.0f;
1900                         }
1901                         if ((ob->protectflag & OB_LOCK_SCALEY)==0) {
1902                                 ob->dsize[1]= 0.0f;
1903                                 ob->size[1]= 1.0f;
1904                         }
1905                         if ((ob->protectflag & OB_LOCK_SCALEZ)==0) {
1906                                 ob->dsize[2]= 0.0f;
1907                                 ob->size[2]= 1.0f;
1908                         }
1909                 }
1910                 ob->recalc |= OB_RECALC_OB;
1911         }
1912         CTX_DATA_END;
1913         
1914         if(armature_clear==0) /* in this case flush was done */
1915                 ED_anim_dag_flush_update(C);    
1916         
1917         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1918         
1919         return OPERATOR_FINISHED;
1920 }
1921
1922 void OBJECT_OT_clear_scale(wmOperatorType *ot)
1923 {
1924         
1925         /* identifiers */
1926         ot->name= "Clear Object Scale";
1927         ot->idname= "OBJECT_OT_clear_scale";
1928         
1929         /* api callbacks */
1930         ot->invoke= WM_operator_confirm;
1931         ot->exec= object_clear_scale_exec;
1932         ot->poll= ED_operator_object_active;
1933         
1934         /* flags */
1935         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1936 }
1937
1938 static int object_clear_origin_exec(bContext *C, wmOperator *op)
1939 {
1940         float *v1, *v3, mat[3][3];
1941         int armature_clear= 0;
1942
1943         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
1944                 if(ob->parent) {
1945                         v1= ob->loc;
1946                         v3= ob->parentinv[3];
1947                         
1948                         Mat3CpyMat4(mat, ob->parentinv);
1949                         VECCOPY(v3, v1);
1950                         v3[0]= -v3[0];
1951                         v3[1]= -v3[1];
1952                         v3[2]= -v3[2];
1953                         Mat3MulVecfl(mat, v3);
1954                 }
1955                 ob->recalc |= OB_RECALC_OB;
1956         }
1957         CTX_DATA_END;
1958
1959         if(armature_clear==0) /* in this case flush was done */
1960                 ED_anim_dag_flush_update(C);    
1961         
1962         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
1963         
1964         return OPERATOR_FINISHED;
1965 }
1966
1967 void OBJECT_OT_clear_origin(wmOperatorType *ot)
1968 {
1969
1970         /* identifiers */
1971         ot->name= "Clear Object Origin";
1972         ot->idname= "OBJECT_OT_clear_origin";
1973         
1974         /* api callbacks */
1975         ot->invoke= WM_operator_confirm;
1976         ot->exec= object_clear_origin_exec;
1977         ot->poll= ED_operator_object_active;
1978         
1979         /* flags */
1980         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1981 }
1982
1983 /* ********* clear/set restrict view *********/
1984 static int object_clear_restrictview_exec(bContext *C, wmOperator *op)
1985 {
1986         ScrArea *sa= CTX_wm_area(C);
1987         View3D *v3d= sa->spacedata.first;
1988         Scene *scene= CTX_data_scene(C);
1989         Base *base;
1990         int changed = 0;
1991         
1992         /* XXX need a context loop to handle such cases */
1993         for(base = FIRSTBASE; base; base=base->next){
1994                 if((base->lay & v3d->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) {
1995                         base->flag |= SELECT;
1996                         base->object->flag = base->flag;
1997                         base->object->restrictflag &= ~OB_RESTRICT_VIEW; 
1998                         changed = 1;
1999                 }
2000         }
2001         if (changed) {
2002                 DAG_scene_sort(scene);
2003                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
2004         }
2005
2006         return OPERATOR_FINISHED;
2007 }
2008
2009 void OBJECT_OT_clear_restrictview(wmOperatorType *ot)
2010 {
2011         
2012         /* identifiers */
2013         ot->name= "Clear restrict view";
2014         ot->idname= "OBJECT_OT_clear_restrictview";
2015         
2016         /* api callbacks */
2017         ot->invoke= WM_operator_confirm;
2018         ot->exec= object_clear_restrictview_exec;
2019         ot->poll= ED_operator_view3d_active;
2020         
2021         /* flags */
2022         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2023 }
2024
2025 static EnumPropertyItem prop_set_restrictview_types[] = {
2026         {0, "SELECTED", "Selected", ""},
2027         {1, "UNSELECTED", "Unselected ", ""},
2028         {0, NULL, NULL, NULL}
2029 };
2030
2031 static int object_set_restrictview_exec(bContext *C, wmOperator *op)
2032 {
2033         Scene *scene= CTX_data_scene(C);
2034         short changed = 0;
2035         
2036         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
2037                 if(RNA_enum_is_equal(op->ptr, "type", "SELECTED")){
2038                         if (base->flag & SELECT){
2039                                 base->flag &= ~SELECT;
2040                                 base->object->flag = base->flag;
2041                                 base->object->restrictflag |= OB_RESTRICT_VIEW;
2042                                 changed = 1;
2043                                 if (base==BASACT) {
2044                                         ED_base_object_activate(C, NULL);
2045                                 }
2046                         }
2047                 }
2048                 else if (RNA_enum_is_equal(op->ptr, "type", "UNSELECTED")){
2049                         if (!(base->flag & SELECT)){
2050                                 base->object->restrictflag |= OB_RESTRICT_VIEW;
2051                                 changed = 1;
2052                         }
2053                 }       
2054         }
2055         CTX_DATA_END;
2056
2057         if (changed) {
2058                 DAG_scene_sort(scene);
2059                 
2060                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
2061                 
2062         }
2063
2064         return OPERATOR_FINISHED;
2065 }
2066
2067 void OBJECT_OT_set_restrictview(wmOperatorType *ot)
2068 {
2069         /* identifiers */
2070         ot->name= "Set restrict view";
2071         ot->idname= "OBJECT_OT_set_restrictview";
2072         
2073         /* api callbacks */
2074         ot->invoke= WM_menu_invoke;
2075         ot->exec= object_set_restrictview_exec;
2076         ot->poll= ED_operator_view3d_active;
2077         
2078         /* flags */
2079         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2080         
2081         RNA_def_enum(ot->srna, "type", prop_set_restrictview_types, 0, "Type", "");
2082         
2083 }
2084 /* ************* Slow Parent ******************* */
2085 static int object_set_slowparent_exec(bContext *C, wmOperator *op)
2086 {
2087
2088         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
2089                 
2090                 if(base->object->parent) base->object->partype |= PARSLOW;
2091                 base->object->recalc |= OB_RECALC_OB;
2092                 
2093         }
2094         CTX_DATA_END;
2095
2096         ED_anim_dag_flush_update(C);    
2097         
2098         WM_event_add_notifier(C, NC_SCENE, CTX_data_scene(C));
2099         
2100         return OPERATOR_FINISHED;
2101 }
2102
2103 void OBJECT_OT_set_slowparent(wmOperatorType *ot)
2104 {
2105         
2106         /* identifiers */
2107         ot->name= "Set Slow Parent";
2108         ot->idname= "OBJECT_OT_set_slow_parent";
2109         
2110         /* api callbacks */
2111         ot->invoke= WM_operator_confirm;
2112         ot->exec= object_set_slowparent_exec;
2113         ot->poll= ED_operator_view3d_active;
2114         
2115         /* flags */
2116         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2117 }
2118
2119 static int object_clear_slowparent_exec(bContext *C, wmOperator *op)
2120 {
2121         Scene *scene= CTX_data_scene(C);
2122
2123         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
2124                 if(base->object->parent) {
2125                         if(base->object->partype & PARSLOW) {
2126                                 base->object->partype -= PARSLOW;
2127                                 where_is_object(scene, base->object);
2128                                 base->object->partype |= PARSLOW;
2129                                 base->object->recalc |= OB_RECALC_OB;
2130                         }
2131                 }
2132                 
2133         }
2134         CTX_DATA_END;
2135
2136         ED_anim_dag_flush_update(C);    
2137         
2138         WM_event_add_notifier(C, NC_SCENE, CTX_data_scene(C));
2139         
2140         return OPERATOR_FINISHED;
2141 }
2142
2143 void OBJECT_OT_clear_slowparent(wmOperatorType *ot)
2144 {
2145         
2146         /* identifiers */
2147         ot->name= "Clear Slow Parent";
2148         ot->idname= "OBJECT_OT_clear_slow_parent";
2149         
2150         /* api callbacks */
2151         ot->invoke= WM_operator_confirm;
2152         ot->exec= object_clear_slowparent_exec;
2153         ot->poll= ED_operator_view3d_active;
2154         
2155         /* flags */
2156         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2157 }
2158 /* ******************** **************** */
2159
2160 // XXX
2161 #define BEZSELECTED_HIDDENHANDLES(bezt)   ((G.f & G_HIDDENHANDLES) ? (bezt)->f2 & SELECT : BEZSELECTED(bezt))
2162 /* only in edit mode */
2163 void make_vertex_parent(Scene *scene, Object *obedit, View3D *v3d)
2164 {
2165         EditVert *eve;
2166         Base *base;
2167         Nurb *nu;
2168         BezTriple *bezt;
2169         BPoint *bp;
2170         Object *par, *ob;
2171         int a, v1=0, v2=0, v3=0, v4=0, nr=1;
2172         
2173         /* we need 1 to 3 selected vertices */
2174         
2175         if(obedit->type==OB_MESH) {
2176                 Mesh *me= obedit->data;
2177                 
2178                 eve= me->edit_mesh->verts.first;
2179                 while(eve) {
2180                         if(eve->f & 1) {
2181                                 if(v1==0) v1= nr;
2182                                 else if(v2==0) v2= nr;
2183                                 else if(v3==0) v3= nr;
2184                                 else if(v4==0) v4= nr;
2185                                 else break;
2186                         }
2187                         nr++;
2188                         eve= eve->next;
2189                 }
2190         }
2191         else if(ELEM(obedit->type, OB_SURF, OB_CURVE)) {
2192                 ListBase *editnurb= curve_get_editcurve(obedit);
2193
2194                 nu= editnurb->first;
2195                 while(nu) {
2196                         if((nu->type & 7)==CU_BEZIER) {
2197                                 bezt= nu->bezt;
2198                                 a= nu->pntsu;
2199                                 while(a--) {
2200                                         if(BEZSELECTED_HIDDENHANDLES(bezt)) {
2201                                                 if(v1==0) v1= nr;
2202                                                 else if(v2==0) v2= nr;
2203                                                 else if(v3==0) v3= nr;
2204                                                 else if(v4==0) v4= nr;
2205                                                 else break;
2206                                         }
2207                                         nr++;
2208                                         bezt++;
2209                                 }
2210                         }
2211                         else {
2212                                 bp= nu->bp;
2213                                 a= nu->pntsu*nu->pntsv;
2214                                 while(a--) {
2215                                         if(bp->f1 & SELECT) {
2216                                                 if(v1==0) v1= nr;
2217                                                 else if(v2==0) v2= nr;
2218                                                 else if(v3==0) v3= nr;
2219                                                 else if(v4==0) v4= nr;
2220                                                 else break;
2221                                         }
2222                                         nr++;
2223                                         bp++;
2224                                 }
2225                         }
2226                         nu= nu->next;
2227                 }
2228         }
2229         else if(obedit->type==OB_LATTICE) {
2230                 Lattice *lt= obedit->data;
2231                 
2232                 a= lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw;
2233                 bp= lt->editlatt->def;
2234                 while(a--) {
2235                         if(bp->f1 & SELECT) {
2236                                 if(v1==0) v1= nr;
2237                                 else if(v2==0) v2= nr;
2238                                 else if(v3==0) v3= nr;
2239                                 else if(v4==0) v4= nr;
2240                                 else break;
2241                         }
2242                         nr++;
2243                         bp++;
2244                 }
2245         }
2246         
2247         if(v4 || !((v1 && v2==0 && v3==0) || (v1 && v2 && v3)) ) {
2248                 error("Select either 1 or 3 vertices to parent to");
2249                 return;
2250         }
2251         
2252         if(okee("Make vertex parent")==0) return;
2253         
2254         for(base= FIRSTBASE; base; base= base->next) {
2255                 if(TESTBASELIB(v3d, base)) {
2256                         if(base!=BASACT) {
2257                                 
2258                                 ob= base->object;
2259                                 ob->recalc |= OB_RECALC;
2260                                 par= BASACT->object->parent;
2261                                 
2262                                 while(par) {
2263                                         if(par==ob) break;
2264                                         par= par->parent;
2265                                 }
2266                                 if(par) {
2267                                         error("Loop in parents");
2268                                 }
2269                                 else {
2270                                         Object workob;
2271                                         
2272                                         ob->parent= BASACT->object;
2273                                         if(v3) {
2274                                                 ob->partype= PARVERT3;
2275                                                 ob->par1= v1-1;
2276                                                 ob->par2= v2-1;
2277                                                 ob->par3= v3-1;
2278
2279                                                 /* inverse parent matrix */
2280                                                 what_does_parent(scene, ob, &workob);
2281                                                 Mat4Invert(ob->parentinv, workob.obmat);
2282                                         }
2283                                         else {
2284                                                 ob->partype= PARVERT1;
2285                                                 ob->par1= v1-1;
2286
2287                                                 /* inverse parent matrix */
2288                                                 what_does_parent(scene, ob, &workob);
2289                                                 Mat4Invert(ob->parentinv, workob.obmat);
2290                                         }
2291                                 }
2292                         }
2293                 }
2294         }
2295         
2296         DAG_scene_sort(scene);
2297 }
2298
2299 static Object *group_objects_menu(Group *group)
2300 {
2301         GroupObject *go;
2302         int len= 0;
2303         short a, nr;
2304         char *str;
2305                 
2306         for(go= group->gobject.first; go; go= go->next) {
2307                 if(go->ob)
2308                         len++;
2309         }
2310         if(len==0) return NULL;
2311         
2312         str= MEM_callocN(40+32*len, "menu");
2313         
2314         strcpy(str, "Make Proxy for: %t");
2315         a= strlen(str);
2316         for(nr=1, go= group->gobject.first; go; go= go->next, nr++) {
2317                 a+= sprintf(str+a, "|%s %%x%d", go->ob->id.name+2, nr);
2318         }
2319         
2320         a= pupmenu_col(str, 20);
2321         MEM_freeN(str);
2322         if(a>0) {
2323                 go= BLI_findlink(&group->gobject, a-1);
2324                 return go->ob;
2325         }
2326         return NULL;
2327 }
2328
2329
2330 /* adds empty object to become local replacement data of a library-linked object */
2331 void make_proxy(Scene *scene)
2332 {
2333         Object *ob= OBACT;
2334         Object *gob= NULL;
2335         
2336         if(scene->id.lib) return;
2337         if(ob==NULL) return;
2338         
2339         
2340         if(ob->dup_group && ob->dup_group->id.lib) {
2341                 gob= ob;
2342                 /* gives menu with list of objects in group */
2343                 ob= group_objects_menu(ob->dup_group);
2344         }
2345         else if(ob->id.lib) {
2346                 if(okee("Make Proxy Object")==0)
2347                 return;
2348         }
2349         else {
2350                 error("Can only make proxy for a referenced object or group");
2351                 return;
2352         }
2353         
2354         if(ob) {
2355                 Object *newob;
2356                 Base *newbase, *oldbase= BASACT;
2357                 char name[32];
2358                 
2359                 newob= add_object(scene, OB_EMPTY);
2360                 if(gob)
2361                         strcpy(name, gob->id.name+2);
2362                 else
2363                         strcpy(name, ob->id.name+2);
2364                 strcat(name, "_proxy");
2365                 rename_id(&newob->id, name);
2366                 
2367                 /* set layers OK */
2368                 newbase= BASACT;        /* add_object sets active... */
2369                 newbase->lay= oldbase->lay;
2370                 newob->lay= newbase->lay;
2371                 
2372                 /* remove base, leave user count of object, it gets linked in object_make_proxy */
2373                 if(gob==NULL) {
2374                         BLI_remlink(&scene->base, oldbase);
2375                         MEM_freeN(oldbase);
2376                 }               
2377                 object_make_proxy(newob, ob, gob);
2378                 
2379                 DAG_scene_sort(scene);
2380                 DAG_object_flush_update(scene, newob, OB_RECALC);
2381         }
2382 }
2383
2384 /* ******************** make parent operator *********************** */
2385
2386 #define PAR_OBJECT              0
2387 #define PAR_ARMATURE    1
2388 #define PAR_BONE                2
2389 #define PAR_CURVE               3
2390 #define PAR_FOLLOW              4
2391 #define PAR_PATH_CONST  5
2392 #define PAR_LATTICE             6
2393 #define PAR_VERTEX              7
2394 #define PAR_TRIA                8
2395
2396 static EnumPropertyItem prop_make_parent_types[] = {
2397         {PAR_OBJECT, "OBJECT", "Object", ""},
2398         {PAR_ARMATURE, "ARMATURE", "Armature Deform", ""},
2399         {PAR_BONE, "BONE", "Bone", ""},
2400         {PAR_CURVE, "CURVE", "Curve Deform", ""},
2401         {PAR_FOLLOW, "FOLLOW", "Follow Path", ""},
2402         {PAR_PATH_CONST, "PATH_CONST", "Path Constraint", ""},
2403         {PAR_LATTICE, "LATTICE", "Lattice Deform", ""},
2404         {PAR_VERTEX, "VERTEX", "Vertex", ""},
2405         {PAR_TRIA, "TRIA", "Triangle", ""},
2406         {0, NULL, NULL, NULL}
2407 };
2408
2409 static int test_parent_loop(Object *par, Object *ob)
2410 {
2411         /* test if 'ob' is a parent somewhere in par's parents */
2412         
2413         if(par == NULL) return 0;
2414         if(ob == par) return 1;
2415         
2416         return test_parent_loop(par->parent, ob);
2417 }
2418
2419
2420 static int make_parent_exec(bContext *C, wmOperator *op)
2421 {
2422         Scene *scene= CTX_data_scene(C);
2423         Object *par= CTX_data_active_object(C);
2424         bPoseChannel *pchan= NULL;
2425         int partype= RNA_enum_get(op->ptr, "type");
2426         
2427         par->recalc |= OB_RECALC_OB;
2428         
2429         /* preconditions */
2430         if(partype==PAR_FOLLOW || partype==PAR_PATH_CONST) {
2431                 if(par->type!=OB_CURVE)
2432                         return OPERATOR_CANCELLED;
2433                 else {
2434                         Curve *cu= par->data;
2435                         
2436                         if((cu->flag & CU_PATH)==0) {
2437                                 cu->flag |= CU_PATH|CU_FOLLOW;
2438                                 makeDispListCurveTypes(scene, par, 0);  /* force creation of path data */
2439                         }
2440                         else cu->flag |= CU_FOLLOW;
2441                         
2442                         /* fall back on regular parenting now */
2443                         partype= PAR_OBJECT;
2444                 }               
2445         }
2446         else if(partype==PAR_BONE) {
2447                 pchan= get_active_posechannel(par);
2448                 
2449                 if(pchan==NULL) {
2450                         error("No active Bone");
2451                         return OPERATOR_CANCELLED;
2452                 }
2453         }
2454         
2455         /* context itterator */
2456         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
2457                 
2458                 if(ob!=par) {
2459                         
2460                         if( test_parent_loop(par, ob) ) {
2461                                 error("Loop in parents");
2462                         }
2463                         else {
2464                                 Object workob;
2465                                 
2466                                 /* apply transformation of previous parenting */
2467                                 ED_object_apply_obmat(ob);
2468                                 
2469                                 ob->parent= par;
2470                                 
2471                                 /* handle types */
2472                                 if (pchan)
2473                                         strcpy (ob->parsubstr, pchan->name);
2474                                 else
2475                                         ob->parsubstr[0]= 0;
2476                                 
2477                                 /* constraint */
2478                                 if(partype==PAR_PATH_CONST) {
2479                                         bConstraint *con;
2480                                         bFollowPathConstraint *data;
2481                                         float cmat[4][4], vec[3];
2482                                         
2483                                         con = add_new_constraint(CONSTRAINT_TYPE_FOLLOWPATH);
2484                                         strcpy (con->name, "AutoPath");
2485                                         
2486                                         data = con->data;
2487                                         data->tar = par;
2488                                         
2489                                         add_constraint_to_object(con, ob);
2490                                         
2491                                         get_constraint_target_matrix(con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra - give_timeoffset(ob));
2492                                         VecSubf(vec, ob->obmat[3], cmat[3]);
2493                                         
2494                                         ob->loc[0] = vec[0];
2495                                         ob->loc[1] = vec[1];
2496                                 }
2497                                 else if(partype==PAR_ARMATURE && ob->type==OB_MESH && par->type == OB_ARMATURE) {
2498                                         
2499                                         if(1) {
2500                                                 /* Prompt the user as to whether he wants to
2501                                                 * add some vertex groups based on the bones
2502                                                 * in the parent armature.
2503                                                 */
2504                                                 create_vgroups_from_armature(scene, ob, par);
2505                                                 
2506                                                 /* get corrected inverse */
2507                                                 ob->partype= PAROBJECT;
2508                                                 what_does_parent(scene, ob, &workob);
2509                                                 
2510                                                 ob->partype= PARSKEL;
2511                                         }
2512                                         else
2513                                                 what_does_parent(scene, ob, &workob);
2514                                         
2515                                         Mat4Invert(ob->parentinv, workob.obmat);
2516                                 }
2517                                 else {
2518                                         /* calculate inverse parent matrix */
2519                                         what_does_parent(scene, ob, &workob);
2520                                         Mat4Invert(ob->parentinv, workob.obmat);
2521                                 }
2522                                 
2523                                 ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
2524                                 
2525                                 if( ELEM3(partype, PAR_CURVE, PAR_ARMATURE, PAR_LATTICE) )
2526                                         ob->partype= PARSKEL; /* note, dna define, not operator property */
2527                                 else
2528                                         ob->partype= PAROBJECT; /* note, dna define, not operator property */
2529                         }
2530                 }
2531         }
2532         CTX_DATA_END;
2533         
2534         DAG_scene_sort(CTX_data_scene(C));
2535         ED_anim_dag_flush_update(C);    
2536         
2537         return OPERATOR_FINISHED;
2538 }
2539
2540 static int make_parent_invoke(bContext *C, wmOperator *op, wmEvent *event)
2541 {
2542         Object *ob= CTX_data_active_object(C);
2543         uiMenuItem *head= uiPupMenuBegin("Make Parent To", 0);
2544         
2545         uiMenuContext(head, WM_OP_EXEC_DEFAULT);
2546         uiMenuItemEnumO(head, "", 0, "OBJECT_OT_make_parent", "type", PAR_OBJECT);
2547         
2548         /* ob becomes parent, make the associated menus */
2549         if(ob->type==OB_ARMATURE) {
2550                 uiMenuItemEnumO(head, "", 0, "OBJECT_OT_make_parent", "type", PAR_ARMATURE);
2551                 uiMenuItemEnumO(head, "", 0, "OBJECT_OT_make_parent", "type", PAR_BONE);
2552         }
2553         else if(ob->type==OB_CURVE) {
2554                 uiMenuItemEnumO(head, "", 0, "OBJECT_OT_make_parent", "type", PAR_CURVE);
2555                 uiMenuItemEnumO(head, "", 0, "OBJECT_OT_make_parent", "type", PAR_FOLLOW);
2556                 uiMenuItemEnumO(head, "", 0, "OBJECT_OT_make_parent", "type", PAR_PATH_CONST);
2557         }
2558         else if(ob->type == OB_LATTICE) {
2559                 uiMenuItemEnumO(head, "", 0, "OBJECT_OT_make_parent", "type", PAR_LATTICE);
2560         }
2561         
2562         uiPupMenuEnd(C, head);
2563         
2564         return OPERATOR_CANCELLED;
2565 }
2566
2567
2568 void OBJECT_OT_make_parent(wmOperatorType *ot)
2569 {
2570         /* identifiers */
2571         ot->name= "Make parent";
2572         ot->idname= "OBJECT_OT_make_parent";
2573         
2574         /* api callbacks */
2575         ot->invoke= make_parent_invoke;
2576         ot->exec= make_parent_exec;
2577         
2578         ot->poll= ED_operator_object_active;
2579         
2580         /* flags */
2581         ot->flag= 0;
2582         
2583         RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
2584 }
2585
2586 /* *** make track ***** */
2587 static EnumPropertyItem prop_make_track_types[] = {
2588         {1, "TRACKTO", "TrackTo Constraint", ""},
2589         {2, "LOCKTRACK", "LockTrack Constraint", ""},
2590         {3, "OLDTRACK", "Old Track", ""},
2591         {0, NULL, NULL, NULL}
2592 };
2593
2594 static int make_track_exec(bContext *C, wmOperator *op)
2595 {
2596         Scene *scene= CTX_data_scene(C);
2597                 
2598         if(RNA_enum_is_equal(op->ptr, "type", "TRACKTO")){
2599                 bConstraint *con;
2600                 bTrackToConstraint *data;
2601
2602                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
2603                         if(base!=BASACT) {
2604                                 con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
2605                                 strcpy (con->name, "AutoTrack");
2606
2607                                 data = con->data;
2608                                 data->tar = BASACT->object;
2609                                 base->object->recalc |= OB_RECALC;
2610                                 
2611                                 /* Lamp and Camera track differently by default */
2612                                 if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
2613                                         data->reserved1 = TRACK_nZ;
2614                                         data->reserved2 = UP_Y;
2615                                 }
2616
2617                                 add_constraint_to_object(con, base->object);
2618                         }
2619                 }
2620                 CTX_DATA_END;
2621         }
2622         else if(RNA_enum_is_equal(op->ptr, "type", "LOCKTRACK")){
2623                 bConstraint *con;
2624                 bLockTrackConstraint *data;
2625
2626                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
2627                         if(base!=BASACT) {
2628                                 con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
2629                                 strcpy (con->name, "AutoTrack");
2630
2631                                 data = con->data;
2632                                 data->tar = BASACT->object;
2633                                 base->object->recalc |= OB_RECALC;
2634                                 
2635                                 /* Lamp and Camera track differently by default */
2636                                 if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
2637                                         data->trackflag = TRACK_nZ;
2638                                         data->lockflag = LOCK_Y;
2639                                 }
2640
2641                                 add_constraint_to_object(con, base->object);
2642                         }
2643                 }
2644                 CTX_DATA_END;
2645         }
2646         else if(RNA_enum_is_equal(op->ptr, "type", "OLDTRACK")){
2647                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
2648                         if(base!=BASACT) {
2649                                 base->object->track= BASACT->object;
2650                                 base->object->recalc |= OB_RECALC;
2651                         }
2652                 }
2653                 CTX_DATA_END;
2654         }
2655         DAG_scene_sort(CTX_data_scene(C));
2656         ED_anim_dag_flush_update(C);    
2657         
2658         return OPERATOR_FINISHED;
2659 }
2660
2661 void OBJECT_OT_make_track(wmOperatorType *ot)
2662 {
2663         /* identifiers */
2664         ot->name= "Make Track";
2665         ot->idname= "OBJECT_OT_make_track";
2666         
2667         /* api callbacks */
2668         ot->invoke= WM_menu_invoke;
2669         ot->exec= make_track_exec;
2670         
2671         ot->poll= ED_operator_scene_editable;
2672         
2673         /* flags */
2674         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2675         
2676         RNA_def_enum(ot->srna, "type", prop_make_track_types, 0, "Type", "");
2677 }
2678
2679 /* ************* Make Dupli Real ********* */
2680 static void make_object_duplilist_real(Scene *scene, View3D *v3d, Base *base)
2681 {
2682         Base *basen;
2683         Object *ob;
2684         ListBase *lb;
2685         DupliObject *dob;
2686         
2687         if(!base && !(base = BASACT))
2688                 return;
2689         
2690         if(!(base->object->transflag & OB_DUPLI))
2691                 return;
2692         
2693         lb= object_duplilist(scene, base->object);
2694         
2695         for(dob= lb->first; dob; dob= dob->next) {
2696                 ob= copy_object(dob->ob);
2697                 /* font duplis can have a totcol without material, we get them from parent
2698                 * should be implemented better...
2699                 */
2700                 if(ob->mat==NULL) ob->totcol= 0;
2701                 
2702                 basen= MEM_dupallocN(base);
2703                 basen->flag &= ~OB_FROMDUPLI;
2704                 BLI_addhead(&scene->base, basen);       /* addhead: othwise eternal loop */
2705                 basen->object= ob;
2706                 ob->ipo= NULL;          /* make sure apply works */
2707                 ob->parent= ob->track= NULL;
2708                 ob->disp.first= ob->disp.last= NULL;
2709                 ob->transflag &= ~OB_DUPLI;     
2710                 
2711                 Mat4CpyMat4(ob->obmat, dob->mat);
2712                 ED_object_apply_obmat(ob);
2713         }
2714         
2715         copy_object_set_idnew(scene, v3d, 0);
2716         
2717         free_object_duplilist(lb);
2718         
2719         base->object->transflag &= ~OB_DUPLI;   
2720 }
2721
2722
2723 static int object_make_dupli_real_exec(bContext *C, wmOperator *op)
2724 {
2725         Scene *scene= CTX_data_scene(C);
2726         ScrArea *sa= CTX_wm_area(C);
2727         View3D *v3d= sa->spacedata.first;
2728         
2729         clear_id_newpoins();
2730                 
2731         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
2732                 make_object_duplilist_real(scene, v3d, base);
2733         }
2734         CTX_DATA_END;
2735
2736         DAG_scene_sort(CTX_data_scene(C));
2737         ED_anim_dag_flush_update(C);    
2738         WM_event_add_notifier(C, NC_SCENE, CTX_data_scene(C));
2739         
2740         return OPERATOR_FINISHED;
2741 }
2742
2743 void OBJECT_OT_make_dupli_real(wmOperatorType *ot)
2744 {
2745         
2746         /* identifiers */
2747         ot->name= "Make Dupli Real";
2748         ot->idname= "OBJECT_OT_make_dupli_real";
2749         
2750         /* api callbacks */
2751         ot->invoke= WM_operator_confirm;
2752         ot->exec= object_make_dupli_real_exec;
2753         
2754         ot->poll= ED_operator_scene_editable;
2755         
2756         /* flags */
2757         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2758 }
2759 /* ******************* Set Object Center ********************** */
2760
2761 static EnumPropertyItem prop_set_center_types[] = {
2762         {0, "CENTER", "ObData to Center", "Move object data around Object center"},
2763         {1, "CENTERNEW", "Center New", "Move Object center to center of object data"},
2764         {2, "CENTERCURSOR", "Center Cursor", "Move Object Center to position of the 3d cursor"},
2765         {0, NULL, NULL, NULL}
2766 };
2767
2768 /* 0 == do center, 1 == center new, 2 == center cursor */
2769 static int object_set_center_exec(bContext *C, wmOperator *op)
2770 {
2771         Scene *scene= CTX_data_scene(C);
2772         ScrArea *sa= CTX_wm_area(C);
2773         View3D *v3d= sa->spacedata.first;
2774         Object *obedit= CTX_data_edit_object(C);
2775         Object *ob;
2776         Mesh *me, *tme;
2777         Curve *cu;
2778 /*      BezTriple *bezt;
2779         BPoint *bp; */
2780         Nurb *nu, *nu1;
2781         EditVert *eve;
2782         float cent[3], centn[3], min[3], max[3], omat[3][3];
2783         int a, total= 0;
2784         int centermode = RNA_enum_get(op->ptr, "type");
2785         
2786         /* keep track of what is changed */
2787         int tot_change=0, tot_lib_error=0, tot_multiuser_arm_error=0;
2788         MVert *mvert;
2789
2790         if(scene->id.lib || v3d==NULL){
2791                 BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed on Lib data");
2792                  return OPERATOR_CANCELLED;
2793         }
2794         if (obedit && centermode > 0) {
2795                 BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in EditMode");
2796                 return OPERATOR_CANCELLED;
2797         }       
2798         cent[0]= cent[1]= cent[2]= 0.0; 
2799         
2800         if(obedit) {
2801
2802                 INIT_MINMAX(min, max);
2803         
2804                 if(obedit->type==OB_MESH) {
2805                         Mesh *me= obedit->data;
2806                         
2807                         for(eve= me->edit_mesh->verts.first; eve; eve= eve->next) {
2808                                 if(v3d->around==V3D_CENTROID) {
2809                                         total++;
2810                                         VECADD(cent, cent, eve->co);
2811                                 }
2812                                 else {
2813                                         DO_MINMAX(eve->co, min, max);
2814                                 }
2815                         }
2816                         
2817                         if(v3d->around==V3D_CENTROID) {
2818                                 VecMulf(cent, 1.0f/(float)total);
2819                         }
2820                         else {
2821                                 cent[0]= (min[0]+max[0])/2.0f;
2822                                 cent[1]= (min[1]+max[1])/2.0f;
2823                                 cent[2]= (min[2]+max[2])/2.0f;
2824                         }
2825                         
2826                         for(eve= me->edit_mesh->verts.first; eve; eve= eve->next) {
2827                                 VecSubf(eve->co, eve->co, cent);                        
2828                         }
2829                         
2830                         recalc_editnormals(me->edit_mesh);
2831                         tot_change++;
2832                         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2833                 }
2834         }
2835         
2836         /* reset flags */
2837         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
2838                         base->object->flag &= ~OB_DONE;
2839         }
2840         CTX_DATA_END;
2841         
2842         for (me= G.main->mesh.first; me; me= me->id.next) {
2843                 me->flag &= ~ME_ISDONE;
2844         }
2845         
2846         CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
2847                 if((base->object->flag & OB_DONE)==0) {
2848                         base->object->flag |= OB_DONE;
2849                                 
2850                         if(obedit==NULL && (me=get_mesh(base->object)) ) {
2851                                 if (me->id.lib) {
2852                                         tot_lib_error++;
2853                                 } else {
2854                                         if(centermode==2) {
2855                                                 VECCOPY(cent, give_cursor(scene, v3d));
2856                                                 Mat4Invert(base->object->imat, base->object->obmat);
2857                                                 Mat4MulVecfl(base->object->imat, cent);
2858                                         } else {
2859                                                 INIT_MINMAX(min, max);
2860                                                 mvert= me->mvert;
2861                                                 for(a=0; a<me->totvert; a++, mvert++) {
2862                                                         DO_MINMAX(mvert->co, min, max);
2863                                                 }
2864                                         
2865                                                 cent[0]= (min[0]+max[0])/2.0f;
2866                                                 cent[1]= (min[1]+max[1])/2.0f;
2867                                                 cent[2]= (min[2]+max[2])/2.0f;
2868                                         }
2869
2870                                         mvert= me->mvert;
2871                                         for(a=0; a<me->totvert; a++, mvert++) {
2872                                                 VecSubf(mvert->co, mvert->co, cent);
2873                                         }
2874                                         
2875                                         if (me->key) {
2876                                                 KeyBlock *kb;
2877                                                 for (kb=me->key->block.first; kb; kb=kb->next) {
2878                                                         float *fp= kb->data;
2879                                                         
2880                                                         for (a=0; a<kb->totelem; a++, fp+=3) {
2881                                                                 VecSubf(fp, fp, cent);
2882                                                         }
2883                                                 }
2884                                         }
2885                                                 
2886                                         me->flag |= ME_ISDONE;
2887                                                 
2888                                         if(centermode) {
2889                                                 Mat3CpyMat4(omat, base->object->obmat);
2890                                                 
2891                                                 VECCOPY(centn, cent);
2892                                                 Mat3MulVecfl(omat, centn);
2893                                                 base->object->loc[0]+= centn[0];
2894                                                 base->object->loc[1]+= centn[1];
2895                                                 base->object->loc[2]+= centn[2];
2896                                                 
2897                                                 where_is_object(scene, base->object);
2898                                                 ignore_parent_tx(scene, base->object);
2899                                                 
2900                                                 /* other users? */
2901                                                 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
2902                                                         ob = base->object;
2903                                                         if((ob->flag & OB_DONE)==0) {
2904                                                                 tme= get_mesh(ob);
2905                                                                 
2906                                                                 if(tme==me) {
2907                                                                         
2908                                                                         ob->flag |= OB_DONE;
2909                                                                         ob->recalc= OB_RECALC_OB|OB_RECALC_DATA;
2910
2911                                                                         Mat3CpyMat4(omat, ob->obmat);
2912                                                                         VECCOPY(centn, cent);
2913                                                                         Mat3MulVecfl(omat, centn);
2914                                                                         ob->loc[0]+= centn[0];
2915                                                                         ob->loc[1]+= centn[1];
2916                                                                         ob->loc[2]+= centn[2];
2917                                                                         
2918                                                                         where_is_object(scene, ob);
2919                                                                         ignore_parent_tx(scene, ob);
2920                                                                         
2921                                                                         if(tme && (tme->flag & ME_ISDONE)==0) {
2922                                                                                 mvert= tme->mvert;
2923                                                                                 for(a=0; a<tme->totvert; a++, mvert++) {
2924                                                                                         VecSubf(mvert->co, mvert->co, cent);
2925                                                                                 }
2926                                                                                 
2927                                                                                 if (tme->key) {
2928                                                                                         KeyBlock *kb;
2929                                                                                         for (kb=tme->key->block.first; kb; kb=kb->next) {
2930                                                                                                 float *fp= kb->data;
2931                                                                                                 
2932                                                                                                 for (a=0; a<kb->totelem; a++, fp+=3) {
2933                                                                                                         VecSubf(fp, fp, cent);
2934                                                                                                 }
2935                                                                                         }
2936                                                                                 }
2937                                                                                 
2938                                                                                 tme->flag |= ME_ISDONE;
2939                                                                         }
2940                                                                 }
2941                                                         }
2942                                                         
2943                                                         ob= ob->id.next;
2944                                                 }
2945                                                 CTX_DATA_END;
2946                                         }
2947                                         tot_change++;
2948                                 }
2949                         }
2950                         else if (ELEM(base->object->type, OB_CURVE, OB_SURF)) {
2951                                 
2952                                 /* weak code here... (ton) */
2953                                 if(obedit==base->object) {
2954                                         ListBase *editnurb= curve_get_editcurve(obedit);
2955
2956                                         nu1= editnurb->first;
2957                                         cu= obedit->data;
2958                                 }
2959                                 else {
2960                                         cu= base->object->data;
2961                                         nu1= cu->nurb.first;
2962                                 }
2963                                 
2964                                 if (cu->id.lib) {
2965                                         tot_lib_error++;
2966                                 } else {
2967                                         if(centermode==2) {
2968                                                 VECCOPY(cent, give_cursor(scene, v3d));
2969                                                 Mat4Invert(base->object->imat, base->object->obmat);
2970                                                 Mat4MulVecfl(base->object->imat, cent);
2971
2972                                                 /* don't allow Z change if curve is 2D */
2973                                                 if( !( cu->flag & CU_3D ) )
2974                                                         cent[2] = 0.0;
2975                                         } 
2976                                         else {
2977                                                 INIT_MINMAX(min, max);
2978                                                 
2979                                                 nu= nu1;
2980                                                 while(nu) {
2981                                                         minmaxNurb(nu, min, max);
2982                                                         nu= nu->next;
2983                                                 }
2984                                                 
2985                                                 cent[0]= (min[0]+max[0])/2.0f;
2986                                                 cent[1]= (min[1]+max[1])/2.0f;
2987                                                 cent[2]= (min[2]+max[2])/2.0f;
2988                                         }
2989                                         
2990                                         nu= nu1;
2991                                         while(nu) {
2992                                                 if( (nu->type & 7)==1) {
2993                                                         a= nu->pntsu;
2994                                                         while (a--) {
2995                                                                 VecSubf(nu->bezt[a].vec[0], nu->bezt[a].vec[0], cent);
2996                                                                 VecSubf(nu->bezt[a].vec[1], nu->bezt[a].vec[1], cent);
2997                                                                 VecSubf(nu->bezt[a].vec[2], nu->bezt[a].vec[2], cent);
2998                                                         }
2999                                                 }
3000                                                 else {
3001                                                         a= nu->pntsu*nu->pntsv;
3002                                                         while (a--)
3003                                                                 VecSubf(nu->bp[a].vec, nu->bp[a].vec, cent);