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