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