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