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