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