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