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