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