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