* Re-implemented/refactored 3D View hooks menu.
[blender.git] / source / blender / editors / object / object_hook.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
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "BLI_math.h"
34 #include "BLI_editVert.h"
35 #include "BLI_listbase.h"
36 #include "BLI_string.h"
37
38 #include "DNA_action_types.h"
39 #include "DNA_curve_types.h"
40 #include "DNA_lattice_types.h"
41 #include "DNA_mesh_types.h"
42 #include "DNA_meshdata_types.h"
43 #include "DNA_modifier_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_view3d_types.h"
47 #include "DNA_windowmanager_types.h"
48
49 #include "BKE_action.h"
50 #include "BKE_context.h"
51 #include "BKE_customdata.h"
52 #include "BKE_depsgraph.h"
53 #include "BKE_mesh.h"
54 #include "BKE_modifier.h"
55 #include "BKE_object.h"
56 #include "BKE_report.h"
57 #include "BKE_scene.h"
58
59 #include "RNA_define.h"
60 #include "RNA_access.h"
61
62 #include "ED_curve.h"
63 #include "ED_mesh.h"
64 #include "ED_object.h"
65 #include "ED_view3d.h"
66 #include "ED_screen.h"
67
68 #include "WM_types.h"
69 #include "WM_api.h"
70
71 #include "UI_interface.h"
72 #include "UI_resources.h"
73
74 #include "object_intern.h"
75
76 static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float *cent)
77 {
78         EditVert *eve;
79         int *index, nr, totvert=0;
80         
81         for(eve= em->verts.first; eve; eve= eve->next) {
82                 if(eve->f & SELECT) totvert++;
83         }
84         if(totvert==0) return 0;
85         
86         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
87         *tot= totvert;
88         nr= 0;
89         cent[0]= cent[1]= cent[2]= 0.0;
90         
91         for(eve= em->verts.first; eve; eve= eve->next) {
92                 if(eve->f & SELECT) {
93                         *index= nr; index++;
94                         add_v3_v3v3(cent, cent, eve->co);
95                 }
96                 nr++;
97         }
98         
99         mul_v3_fl(cent, 1.0f/(float)totvert);
100         
101         return totvert;
102 }
103
104 static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, float *cent)
105 {
106         MDeformVert *dvert;
107         EditVert *eve;
108         int i, totvert=0;
109         
110         cent[0]= cent[1]= cent[2]= 0.0;
111         
112         if(obedit->actdef) {
113                 
114                 /* find the vertices */
115                 for(eve= em->verts.first; eve; eve= eve->next) {
116                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
117
118                         if(dvert) {
119                                 for(i=0; i<dvert->totweight; i++){
120                                         if(dvert->dw[i].def_nr == (obedit->actdef-1)) {
121                                                 totvert++;
122                                                 add_v3_v3v3(cent, cent, eve->co);
123                                         }
124                                 }
125                         }
126                 }
127                 if(totvert) {
128                         bDeformGroup *defGroup = BLI_findlink(&obedit->defbase, obedit->actdef-1);
129                         strcpy(name, defGroup->name);
130                         mul_v3_fl(cent, 1.0f/(float)totvert);
131                         return 1;
132                 }
133         }
134         
135         return 0;
136 }       
137
138 static void select_editmesh_hook(Object *ob, HookModifierData *hmd)
139 {
140         Mesh *me= ob->data;
141         EditMesh *em= BKE_mesh_get_editmesh(me);
142         EditVert *eve;
143         int index=0, nr=0;
144         
145         if (hmd->indexar == NULL)
146                 return;
147         
148         for(eve= em->verts.first; eve; eve= eve->next, nr++) {
149                 if(nr==hmd->indexar[index]) {
150                         eve->f |= SELECT;
151                         if(index < hmd->totindex-1) index++;
152                 }
153         }
154         EM_select_flush(em);
155
156         BKE_mesh_end_editmesh(me, em);
157 }
158
159 static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent)
160 {
161         BPoint *bp;
162         int *index, nr, totvert=0, a;
163         
164         /* count */
165         a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
166         bp= editlatt->def;
167         while(a--) {
168                 if(bp->f1 & SELECT) {
169                         if(bp->hide==0) totvert++;
170                 }
171                 bp++;
172         }
173
174         if(totvert==0) return 0;
175         
176         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
177         *tot= totvert;
178         nr= 0;
179         cent[0]= cent[1]= cent[2]= 0.0;
180         
181         a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
182         bp= editlatt->def;
183         while(a--) {
184                 if(bp->f1 & SELECT) {
185                         if(bp->hide==0) {
186                                 *index= nr; index++;
187                                 add_v3_v3v3(cent, cent, bp->vec);
188                         }
189                 }
190                 bp++;
191                 nr++;
192         }
193         
194         mul_v3_fl(cent, 1.0f/(float)totvert);
195         
196         return totvert;
197 }
198
199 static void select_editlattice_hook(Object *obedit, HookModifierData *hmd)
200 {
201         Lattice *lt= obedit->data;
202         BPoint *bp;
203         int index=0, nr=0, a;
204         
205         /* count */
206         a= lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw;
207         bp= lt->editlatt->def;
208         while(a--) {
209                 if(hmd->indexar[index]==nr) {
210                         bp->f1 |= SELECT;
211                         if(index < hmd->totindex-1) index++;
212                 }
213                 nr++;
214                 bp++;
215         }
216 }
217
218 static int return_editcurve_indexar(Object *obedit, int *tot, int **indexar, float *cent)
219 {
220         ListBase *editnurb= curve_get_editcurve(obedit);
221         Nurb *nu;
222         BPoint *bp;
223         BezTriple *bezt;
224         int *index, a, nr, totvert=0;
225         
226         for(nu= editnurb->first; nu; nu= nu->next) {
227                 if(nu->type == CU_BEZIER) {
228                         bezt= nu->bezt;
229                         a= nu->pntsu;
230                         while(a--) {
231                                 if(bezt->f1 & SELECT) totvert++;
232                                 if(bezt->f2 & SELECT) totvert++;
233                                 if(bezt->f3 & SELECT) totvert++;
234                                 bezt++;
235                         }
236                 }
237                 else {
238                         bp= nu->bp;
239                         a= nu->pntsu*nu->pntsv;
240                         while(a--) {
241                                 if(bp->f1 & SELECT) totvert++;
242                                 bp++;
243                         }
244                 }
245         }
246         if(totvert==0) return 0;
247         
248         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
249         *tot= totvert;
250         nr= 0;
251         cent[0]= cent[1]= cent[2]= 0.0;
252         
253         for(nu= editnurb->first; nu; nu= nu->next) {
254                 if(nu->type == CU_BEZIER) {
255                         bezt= nu->bezt;
256                         a= nu->pntsu;
257                         while(a--) {
258                                 if(bezt->f1 & SELECT) {
259                                         *index= nr; index++;
260                                         add_v3_v3v3(cent, cent, bezt->vec[0]);
261                                 }
262                                 nr++;
263                                 if(bezt->f2 & SELECT) {
264                                         *index= nr; index++;
265                                         add_v3_v3v3(cent, cent, bezt->vec[1]);
266                                 }
267                                 nr++;
268                                 if(bezt->f3 & SELECT) {
269                                         *index= nr; index++;
270                                         add_v3_v3v3(cent, cent, bezt->vec[2]);
271                                 }
272                                 nr++;
273                                 bezt++;
274                         }
275                 }
276                 else {
277                         bp= nu->bp;
278                         a= nu->pntsu*nu->pntsv;
279                         while(a--) {
280                                 if(bp->f1 & SELECT) {
281                                         *index= nr; index++;
282                                         add_v3_v3v3(cent, cent, bp->vec);
283                                 }
284                                 nr++;
285                                 bp++;
286                         }
287                 }
288         }
289         
290         mul_v3_fl(cent, 1.0f/(float)totvert);
291         
292         return totvert;
293 }
294
295 static int object_hook_index_array(Object *obedit, int *tot, int **indexar, char *name, float *cent_r)
296 {
297         *indexar= NULL;
298         *tot= 0;
299         name[0]= 0;
300         
301         switch(obedit->type) {
302                 case OB_MESH:
303                 {
304                         Mesh *me= obedit->data;
305                         EditMesh *em = BKE_mesh_get_editmesh(me);
306
307                         /* check selected vertices first */
308                         if( return_editmesh_indexar(em, tot, indexar, cent_r)) {
309                                 BKE_mesh_end_editmesh(me, em);
310                                 return 1;
311                         } else {
312                                 int ret = return_editmesh_vgroup(obedit, em, name, cent_r);
313                                 BKE_mesh_end_editmesh(me, em);
314                                 return ret;
315                         }
316                 }
317                 case OB_CURVE:
318                 case OB_SURF:
319                         return return_editcurve_indexar(obedit, tot, indexar, cent_r);
320                 case OB_LATTICE:
321                 {
322                         Lattice *lt= obedit->data;
323                         return return_editlattice_indexar(lt->editlatt, tot, indexar, cent_r);
324                 }
325                 default:
326                         return 0;
327         }
328 }
329
330 static void select_editcurve_hook(Object *obedit, HookModifierData *hmd)
331 {
332         ListBase *editnurb= curve_get_editcurve(obedit);
333         Nurb *nu;
334         BPoint *bp;
335         BezTriple *bezt;
336         int index=0, a, nr=0;
337         
338         for(nu= editnurb->first; nu; nu= nu->next) {
339                 if(nu->type == CU_BEZIER) {
340                         bezt= nu->bezt;
341                         a= nu->pntsu;
342                         while(a--) {
343                                 if(nr == hmd->indexar[index]) {
344                                         bezt->f1 |= SELECT;
345                                         if(index<hmd->totindex-1) index++;
346                                 }
347                                 nr++;
348                                 if(nr == hmd->indexar[index]) {
349                                         bezt->f2 |= SELECT;
350                                         if(index<hmd->totindex-1) index++;
351                                 }
352                                 nr++;
353                                 if(nr == hmd->indexar[index]) {
354                                         bezt->f3 |= SELECT;
355                                         if(index<hmd->totindex-1) index++;
356                                 }
357                                 nr++;
358                                 
359                                 bezt++;
360                         }
361                 }
362                 else {
363                         bp= nu->bp;
364                         a= nu->pntsu*nu->pntsv;
365                         while(a--) {
366                                 if(nr == hmd->indexar[index]) {
367                                         bp->f1 |= SELECT;
368                                         if(index<hmd->totindex-1) index++;
369                                 }
370                                 nr++;
371                                 bp++;
372                         }
373                 }
374         }
375 }
376
377 static void object_hook_select(Object *ob, HookModifierData *hmd) 
378 {
379         if (hmd->indexar == NULL)
380                 return;
381         
382         if(ob->type==OB_MESH) select_editmesh_hook(ob, hmd);
383         else if(ob->type==OB_LATTICE) select_editlattice_hook(ob, hmd);
384         else if(ob->type==OB_CURVE) select_editcurve_hook(ob, hmd);
385         else if(ob->type==OB_SURF) select_editcurve_hook(ob, hmd);
386 }
387
388 static Object *add_hook_object_new(Scene *scene, Object *obedit)
389 {
390         Base *base, *basedit;
391         Object *ob;
392
393         ob= add_object(scene, OB_EMPTY);
394         
395         basedit = object_in_scene(obedit, scene);
396         base = object_in_scene(ob, scene);
397         base->lay = ob->lay = obedit->lay;
398         
399         /* icky, add_object sets new base as active.
400          * so set it back to the original edit object */
401         scene->basact = basedit;
402
403         return ob;
404 }
405
406
407 static void add_hook_object(Scene *scene, Object *obedit, Object *ob, int mode)
408 {
409         ModifierData *md=NULL;
410         HookModifierData *hmd = NULL;
411         float cent[3];
412         int tot, ok, *indexar;
413         char name[32];
414         
415         ok = object_hook_index_array(obedit, &tot, &indexar, name, cent);
416         
417         if (!ok) return;        // XXX error("Requires selected vertices or active Vertex Group");
418         
419         if (mode==OBJECT_ADDHOOK_NEWOB && !ob) {
420                 
421                 ob = add_hook_object_new(scene, obedit);
422                 
423                 /* transform cent to global coords for loc */
424                 mul_v3_m4v3(ob->loc, obedit->obmat, cent);
425         }
426         
427         md = obedit->modifiers.first;
428         while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
429                 md = md->next;
430         }
431         
432         hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
433         BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
434         sprintf(hmd->modifier.name, "Hook-%s", ob->id.name+2);
435         modifier_unique_name(&obedit->modifiers, (ModifierData*)hmd);
436         
437         hmd->object= ob;
438         hmd->indexar= indexar;
439         copy_v3_v3(hmd->cent, cent);
440         hmd->totindex= tot;
441         BLI_strncpy(hmd->name, name, 32);
442         
443         /* matrix calculus */
444         /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
445         /*        (parentinv         )                          */
446         where_is_object(scene, ob);
447         
448         invert_m4_m4(ob->imat, ob->obmat);
449         /* apparently this call goes from right to left... */
450         mul_serie_m4(hmd->parentinv, ob->imat, obedit->obmat, NULL, 
451                                  NULL, NULL, NULL, NULL, NULL);
452         
453         DAG_scene_sort(scene);
454 }
455
456 static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
457 {
458         Scene *scene= CTX_data_scene(C);
459         Object *obedit = CTX_data_edit_object(C);
460         Object *obsel=NULL;
461         
462         CTX_DATA_BEGIN(C, Object*, ob, selected_objects)
463         {
464                 if (ob != obedit) {
465                         obsel = ob;
466                         break;
467                 }
468         }
469         CTX_DATA_END;
470         
471         if (!obsel) {
472                 BKE_report(op->reports, RPT_ERROR, "Can't add hook with no other selected objects.");
473                 return OPERATOR_CANCELLED;
474         }
475         
476         add_hook_object(scene, obedit, obsel, OBJECT_ADDHOOK_SELOB);
477         
478         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
479         return OPERATOR_FINISHED;
480 }
481
482 void OBJECT_OT_hook_add_selobj(wmOperatorType *ot)
483 {
484         /* identifiers */
485         ot->name= "Hook to Selected Object";
486         ot->description= "Hook selected vertices to the first selected Object.";
487         ot->idname= "OBJECT_OT_hook_add_selob";
488         
489         /* api callbacks */
490         ot->exec= object_add_hook_selob_exec;
491         ot->poll= ED_operator_editmesh;
492         
493         /* flags */
494         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
495 }
496
497 static int object_add_hook_newob_exec(bContext *C, wmOperator *op)
498 {
499         Scene *scene= CTX_data_scene(C);
500         Object *obedit = CTX_data_edit_object(C);
501
502         add_hook_object(scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB);
503         
504         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
505         return OPERATOR_FINISHED;
506 }
507
508 void OBJECT_OT_hook_add_newobj(wmOperatorType *ot)
509 {
510         /* identifiers */
511         ot->name= "Hook to New Object";
512         ot->description= "Hook selected vertices to the first selected Object.";
513         ot->idname= "OBJECT_OT_hook_add_newob";
514         
515         /* api callbacks */
516         ot->exec= object_add_hook_newob_exec;
517         ot->poll= ED_operator_editmesh;
518         
519         /* flags */
520         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
521 }
522
523 static EnumPropertyItem hook_mod_items[]= {
524 {0, NULL, 0, NULL, NULL}};
525
526 static int object_hook_remove_exec(bContext *C, wmOperator *op)
527 {
528         int num= RNA_enum_get(op->ptr, "modifier");
529         Object *ob=NULL;
530         HookModifierData *hmd=NULL;
531
532         ob = CTX_data_edit_object(C);
533         hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
534
535         if (!ob || !hmd) {
536                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
537                 return OPERATOR_CANCELLED;
538         }
539         
540         /* remove functionality */
541         
542         BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
543         modifier_free((ModifierData *)hmd);
544         
545         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
546         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
547         
548         return OPERATOR_FINISHED;
549 }
550
551 static EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *ptr, int *free)
552 {       
553         Object *ob = CTX_data_edit_object(C);
554         EnumPropertyItem tmp = {0, "", 0, "", ""};
555         EnumPropertyItem *item= NULL;
556         ModifierData *md = NULL;
557         int a, totitem= 0;
558         
559         if(!ob)
560                 return hook_mod_items;
561         
562         for(a=0, md=ob->modifiers.first; md; md= md->next, a++) {
563                 if (md->type==eModifierType_Hook) {
564                         tmp.value= a;
565                         tmp.icon = ICON_HOOK;
566                         tmp.identifier= md->name;
567                         tmp.name= md->name;
568                         RNA_enum_item_add(&item, &totitem, &tmp);
569                 }
570         }
571         
572         RNA_enum_item_end(&item, &totitem);
573         *free= 1;
574         
575         return item;
576 }
577
578 void OBJECT_OT_hook_remove(wmOperatorType *ot)
579 {
580         PropertyRNA *prop;
581         
582         /* identifiers */
583         ot->name= "Remove Hook";
584         ot->idname= "OBJECT_OT_hook_remove";
585         ot->description= "Remove a hook from the active object.";
586         
587         /* api callbacks */
588         ot->poll= ED_operator_editmesh;
589         ot->exec= object_hook_remove_exec;
590         ot->invoke= WM_menu_invoke;
591         
592         /* flags */
593         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
594         
595         /* properties */
596         prop= RNA_def_enum(ot->srna, "modifier", hook_mod_items, 0, "Modifier", "Modifier number to remove.");
597         RNA_def_enum_funcs(prop, hook_mod_itemf);
598 }
599
600 static int object_hook_reset_exec(bContext *C, wmOperator *op)
601 {
602         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
603         int num= RNA_enum_get(op->ptr, "modifier");
604         Object *ob=NULL;
605         HookModifierData *hmd=NULL;
606         
607         if (ptr.data) {         /* if modifier context is available, use that */
608                 ob = ptr.id.data;
609                 hmd= ptr.data;
610         } else {                        /* use the provided property */
611                 ob = CTX_data_edit_object(C);
612                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
613         }
614         if (!ob || !hmd) {
615                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
616                 return OPERATOR_CANCELLED;
617         }
618         
619         /* reset functionality */
620         
621         if(hmd->object) {
622                 bPoseChannel *pchan= get_pose_channel(hmd->object->pose, hmd->subtarget);
623                 
624                 if(hmd->subtarget[0] && pchan) {
625                         float imat[4][4], mat[4][4];
626                         
627                         /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
628                         mul_m4_m4m4(mat, pchan->pose_mat, hmd->object->obmat);
629                         
630                         invert_m4_m4(imat, mat);
631                         mul_serie_m4(hmd->parentinv, imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
632                 }
633                 else {
634                         invert_m4_m4(hmd->object->imat, hmd->object->obmat);
635                         mul_serie_m4(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
636                 }
637         }
638         
639         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
640         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
641         
642         return OPERATOR_FINISHED;
643 }
644
645 void OBJECT_OT_hook_reset(wmOperatorType *ot)
646 {
647         PropertyRNA *prop;
648         
649         ot->name= "Reset Hook";
650         ot->description= "Recalculate and and clear offset transformation.";
651         ot->idname= "OBJECT_OT_hook_reset";
652         
653         ot->poll= ED_operator_editmesh;
654         ot->exec= object_hook_reset_exec;
655         
656         /* flags */
657         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
658         
659         /* properties */
660         prop= RNA_def_enum(ot->srna, "modifier", hook_mod_items, 0, "Modifier", "Modifier number to assign to.");
661         RNA_def_enum_funcs(prop, hook_mod_itemf);
662 }
663
664 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
665 {
666         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
667         int num= RNA_enum_get(op->ptr, "modifier");
668         Object *ob=NULL;
669         HookModifierData *hmd=NULL;
670         Scene *scene = CTX_data_scene(C);
671         float bmat[3][3], imat[3][3];
672         
673         if (ptr.data) {         /* if modifier context is available, use that */
674                 ob = ptr.id.data;
675                 hmd= ptr.data;
676         } else {                        /* use the provided property */
677                 ob = CTX_data_edit_object(C);
678                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
679         }
680         if (!ob || !hmd) {
681                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
682                 return OPERATOR_CANCELLED;
683         }
684         
685         /* recenter functionality */
686         
687         copy_m3_m4(bmat, ob->obmat);
688         invert_m3_m3(imat, bmat);
689         
690         sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
691         mul_m3_v3(imat, hmd->cent);
692         
693         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
694         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
695         
696         return OPERATOR_FINISHED;
697 }
698
699 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
700 {
701         PropertyRNA *prop;
702         
703         ot->name= "Recenter Hook";
704         ot->description= "Set hook center to cursor position.";
705         ot->idname= "OBJECT_OT_hook_recenter";
706         
707         ot->poll= ED_operator_editmesh;
708         ot->exec= object_hook_recenter_exec;
709         
710         /* flags */
711         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
712         
713         /* properties */
714         prop= RNA_def_enum(ot->srna, "modifier", hook_mod_items, 0, "Modifier", "Modifier number to assign to.");
715         RNA_def_enum_funcs(prop, hook_mod_itemf);
716 }
717
718 static int object_hook_assign_exec(bContext *C, wmOperator *op)
719 {
720         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
721         int num= RNA_enum_get(op->ptr, "modifier");
722         Object *ob=NULL;
723         HookModifierData *hmd=NULL;
724         float cent[3];
725         char name[32];
726         int *indexar, tot;
727         
728         if (ptr.data) {         /* if modifier context is available, use that */
729                 ob = ptr.id.data;
730                 hmd= ptr.data;
731         } else {                        /* use the provided property */
732                 ob = CTX_data_edit_object(C);
733                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
734         }
735         if (!ob || !hmd) {
736                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
737                 return OPERATOR_CANCELLED;
738         }
739         
740         /* assign functionality */
741         
742         if(!object_hook_index_array(ob, &tot, &indexar, name, cent)) {
743                 BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
744                 return OPERATOR_CANCELLED;
745         }
746         if(hmd->indexar)
747                 MEM_freeN(hmd->indexar);
748         
749         copy_v3_v3(hmd->cent, cent);
750         hmd->indexar= indexar;
751         hmd->totindex= tot;
752         
753         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
754         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
755         
756         return OPERATOR_FINISHED;
757 }
758
759 void OBJECT_OT_hook_assign(wmOperatorType *ot)
760 {
761         PropertyRNA *prop;
762         
763         ot->name= "Assign to Hook";
764         ot->description= "Assign the selected vertices to a hook.";
765         ot->idname= "OBJECT_OT_hook_assign";
766         
767         ot->poll= ED_operator_editmesh;
768         ot->exec= object_hook_assign_exec;
769         
770         /* flags */
771         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
772         
773         /* properties */
774         prop= RNA_def_enum(ot->srna, "modifier", hook_mod_items, 0, "Modifier", "Modifier number to assign to.");
775         RNA_def_enum_funcs(prop, hook_mod_itemf);
776 }
777
778 static int object_hook_select_exec(bContext *C, wmOperator *op)
779 {
780         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
781         int num= RNA_enum_get(op->ptr, "modifier");
782         Object *ob=NULL;
783         HookModifierData *hmd=NULL;
784         
785         if (ptr.data) {         /* if modifier context is available, use that */
786                 ob = ptr.id.data;
787                 hmd= ptr.data;
788         } else {                        /* use the provided property */
789                 ob = CTX_data_edit_object(C);
790                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
791         }
792         if (!ob || !hmd) {
793                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
794                 return OPERATOR_CANCELLED;
795         }
796         
797         /* select functionality */
798         
799         object_hook_select(ob, hmd);
800         
801         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
802         
803         return OPERATOR_FINISHED;
804 }
805
806 void OBJECT_OT_hook_select(wmOperatorType *ot)
807 {
808         PropertyRNA *prop;
809         
810         ot->name= "Select Hook";
811         ot->description= "Selects effected vertices on mesh.";
812         ot->idname= "OBJECT_OT_hook_select";
813         
814         ot->poll= ED_operator_editmesh;
815         ot->exec= object_hook_select_exec;
816         
817         /* flags */
818         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
819         
820         /* properties */
821         prop= RNA_def_enum(ot->srna, "modifier", hook_mod_items, 0, "Modifier", "Modifier number to remove.");
822         RNA_def_enum_funcs(prop, hook_mod_itemf);
823 }
824