merge with/from trunk at r35190
[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 #include "BLI_utildefines.h"
38
39 #include "DNA_curve_types.h"
40 #include "DNA_lattice_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_scene_types.h"
44
45 #include "BKE_action.h"
46 #include "BKE_context.h"
47 #include "BKE_depsgraph.h"
48 #include "BKE_main.h"
49 #include "BKE_mesh.h"
50 #include "BKE_modifier.h"
51 #include "BKE_object.h"
52 #include "BKE_report.h"
53 #include "BKE_scene.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, *editlt;
201         BPoint *bp;
202         int index=0, nr=0, a;
203
204         editlt= lt->editlatt->latt;
205         /* count */
206         a= editlt->pntsu*editlt->pntsv*editlt->pntsw;
207         bp= editlt->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_v3(cent, bezt->vec[0]);
261                                 }
262                                 nr++;
263                                 if(bezt->f2 & SELECT) {
264                                         *index= nr; index++;
265                                         add_v3_v3(cent, bezt->vec[1]);
266                                 }
267                                 nr++;
268                                 if(bezt->f3 & SELECT) {
269                                         *index= nr; index++;
270                                         add_v3_v3(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_v3(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                         BMEditMesh *em = me->edit_btmesh;
306
307                         /* check selected vertices first */
308                         if( return_editmesh_indexar(em, tot, indexar, cent_r)) {
309                                 return 1;
310                         } else {
311                                 int ret = return_editmesh_vgroup(obedit, em, name, cent_r);
312                                 return ret;
313                         }
314                 }
315                 case OB_CURVE:
316                 case OB_SURF:
317                         return return_editcurve_indexar(obedit, tot, indexar, cent_r);
318                 case OB_LATTICE:
319                 {
320                         Lattice *lt= obedit->data;
321                         return return_editlattice_indexar(lt->editlatt->latt, tot, indexar, cent_r);
322                 }
323                 default:
324                         return 0;
325         }
326 }
327
328 static void select_editcurve_hook(Object *obedit, HookModifierData *hmd)
329 {
330         ListBase *editnurb= curve_get_editcurve(obedit);
331         Nurb *nu;
332         BPoint *bp;
333         BezTriple *bezt;
334         int index=0, a, nr=0;
335         
336         for(nu= editnurb->first; nu; nu= nu->next) {
337                 if(nu->type == CU_BEZIER) {
338                         bezt= nu->bezt;
339                         a= nu->pntsu;
340                         while(a--) {
341                                 if(nr == hmd->indexar[index]) {
342                                         bezt->f1 |= SELECT;
343                                         if(index<hmd->totindex-1) index++;
344                                 }
345                                 nr++;
346                                 if(nr == hmd->indexar[index]) {
347                                         bezt->f2 |= SELECT;
348                                         if(index<hmd->totindex-1) index++;
349                                 }
350                                 nr++;
351                                 if(nr == hmd->indexar[index]) {
352                                         bezt->f3 |= SELECT;
353                                         if(index<hmd->totindex-1) index++;
354                                 }
355                                 nr++;
356                                 
357                                 bezt++;
358                         }
359                 }
360                 else {
361                         bp= nu->bp;
362                         a= nu->pntsu*nu->pntsv;
363                         while(a--) {
364                                 if(nr == hmd->indexar[index]) {
365                                         bp->f1 |= SELECT;
366                                         if(index<hmd->totindex-1) index++;
367                                 }
368                                 nr++;
369                                 bp++;
370                         }
371                 }
372         }
373 }
374
375 static void object_hook_select(Object *ob, HookModifierData *hmd) 
376 {
377         if (hmd->indexar == NULL)
378                 return;
379         
380         if(ob->type==OB_MESH) select_editbmesh_hook(ob, hmd);
381         else if(ob->type==OB_LATTICE) select_editlattice_hook(ob, hmd);
382         else if(ob->type==OB_CURVE) select_editcurve_hook(ob, hmd);
383         else if(ob->type==OB_SURF) select_editcurve_hook(ob, hmd);
384 }
385
386 /* special poll operators for hook operators */
387 // TODO: check for properties window modifier context too as alternative?
388 static int hook_op_edit_poll(bContext *C)
389 {
390         Object *obedit= CTX_data_edit_object(C);
391         
392         if (obedit) {
393                 if (ED_operator_editmesh(C)) return 1;
394                 if (ED_operator_editsurfcurve(C)) return 1;
395                 if (ED_operator_editlattice(C)) return 1;
396                 //if (ED_operator_editmball(C)) return 1;
397         }
398         
399         return 0;
400 }
401
402 static Object *add_hook_object_new(Scene *scene, Object *obedit)
403 {
404         Base *base, *basedit;
405         Object *ob;
406
407         ob= add_object(scene, OB_EMPTY);
408         
409         basedit = object_in_scene(obedit, scene);
410         base = object_in_scene(ob, scene);
411         base->lay = ob->lay = obedit->lay;
412         
413         /* icky, add_object sets new base as active.
414          * so set it back to the original edit object */
415         scene->basact = basedit;
416
417         return ob;
418 }
419
420 static void add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob, int mode)
421 {
422         ModifierData *md=NULL;
423         HookModifierData *hmd = NULL;
424         float cent[3];
425         int tot, ok, *indexar;
426         char name[32];
427         
428         ok = object_hook_index_array(obedit, &tot, &indexar, name, cent);
429         
430         if (!ok) return;        // XXX error("Requires selected vertices or active Vertex Group");
431         
432         if (mode==OBJECT_ADDHOOK_NEWOB && !ob) {
433                 
434                 ob = add_hook_object_new(scene, obedit);
435                 
436                 /* transform cent to global coords for loc */
437                 mul_v3_m4v3(ob->loc, obedit->obmat, cent);
438         }
439         
440         md = obedit->modifiers.first;
441         while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
442                 md = md->next;
443         }
444         
445         hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
446         BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
447         BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name+2);
448         modifier_unique_name(&obedit->modifiers, (ModifierData*)hmd);
449         
450         hmd->object= ob;
451         hmd->indexar= indexar;
452         copy_v3_v3(hmd->cent, cent);
453         hmd->totindex= tot;
454         BLI_strncpy(hmd->name, name, sizeof(hmd->name));
455         
456         /* matrix calculus */
457         /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
458         /*        (parentinv         )                          */
459         where_is_object(scene, ob);
460         
461         invert_m4_m4(ob->imat, ob->obmat);
462         /* apparently this call goes from right to left... */
463         mul_serie_m4(hmd->parentinv, ob->imat, obedit->obmat, NULL, 
464                                  NULL, NULL, NULL, NULL, NULL);
465         
466         DAG_scene_sort(bmain, scene);
467 }
468
469 static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
470 {
471         Main *bmain= CTX_data_main(C);
472         Scene *scene= CTX_data_scene(C);
473         Object *obedit = CTX_data_edit_object(C);
474         Object *obsel=NULL;
475         
476         CTX_DATA_BEGIN(C, Object*, ob, selected_objects)
477         {
478                 if (ob != obedit) {
479                         obsel = ob;
480                         break;
481                 }
482         }
483         CTX_DATA_END;
484         
485         if (!obsel) {
486                 BKE_report(op->reports, RPT_ERROR, "Can't add hook with no other selected objects.");
487                 return OPERATOR_CANCELLED;
488         }
489         
490         add_hook_object(bmain, scene, obedit, obsel, OBJECT_ADDHOOK_SELOB);
491         
492         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, obedit);
493         return OPERATOR_FINISHED;
494 }
495
496 void OBJECT_OT_hook_add_selobj(wmOperatorType *ot)
497 {
498         /* identifiers */
499         ot->name= "Hook to Selected Object";
500         ot->description= "Hook selected vertices to the first selected Object";
501         ot->idname= "OBJECT_OT_hook_add_selob";
502         
503         /* api callbacks */
504         ot->exec= object_add_hook_selob_exec;
505         ot->poll= hook_op_edit_poll;
506         
507         /* flags */
508         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
509 }
510
511 static int object_add_hook_newob_exec(bContext *C, wmOperator *UNUSED(op))
512 {
513         Main *bmain= CTX_data_main(C);
514         Scene *scene= CTX_data_scene(C);
515         Object *obedit = CTX_data_edit_object(C);
516
517         add_hook_object(bmain, scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB);
518         
519         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
520         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, obedit);
521         return OPERATOR_FINISHED;
522 }
523
524 void OBJECT_OT_hook_add_newobj(wmOperatorType *ot)
525 {
526         /* identifiers */
527         ot->name= "Hook to New Object";
528         ot->description= "Hook selected vertices to the first selected Object";
529         ot->idname= "OBJECT_OT_hook_add_newob";
530         
531         /* api callbacks */
532         ot->exec= object_add_hook_newob_exec;
533         ot->poll= hook_op_edit_poll;
534         
535         /* flags */
536         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
537 }
538
539 static int object_hook_remove_exec(bContext *C, wmOperator *op)
540 {
541         int num= RNA_enum_get(op->ptr, "modifier");
542         Object *ob=NULL;
543         HookModifierData *hmd=NULL;
544
545         ob = CTX_data_edit_object(C);
546         hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
547
548         if (!ob || !hmd) {
549                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
550                 return OPERATOR_CANCELLED;
551         }
552         
553         /* remove functionality */
554         
555         BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
556         modifier_free((ModifierData *)hmd);
557         
558         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
559         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
560         
561         return OPERATOR_FINISHED;
562 }
563
564 static EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
565 {       
566         Object *ob = CTX_data_edit_object(C);
567         EnumPropertyItem tmp = {0, "", 0, "", ""};
568         EnumPropertyItem *item= NULL;
569         ModifierData *md = NULL;
570         int a, totitem= 0;
571         
572         if(!ob)
573                 return DummyRNA_NULL_items;
574         
575         for(a=0, md=ob->modifiers.first; md; md= md->next, a++) {
576                 if (md->type==eModifierType_Hook) {
577                         tmp.value= a;
578                         tmp.icon = ICON_HOOK;
579                         tmp.identifier= md->name;
580                         tmp.name= md->name;
581                         RNA_enum_item_add(&item, &totitem, &tmp);
582                 }
583         }
584         
585         RNA_enum_item_end(&item, &totitem);
586         *free= 1;
587         
588         return item;
589 }
590
591 void OBJECT_OT_hook_remove(wmOperatorType *ot)
592 {
593         PropertyRNA *prop;
594         
595         /* identifiers */
596         ot->name= "Remove Hook";
597         ot->idname= "OBJECT_OT_hook_remove";
598         ot->description= "Remove a hook from the active object";
599         
600         /* api callbacks */
601         ot->exec= object_hook_remove_exec;
602         ot->invoke= WM_menu_invoke;
603         ot->poll= hook_op_edit_poll;
604         
605         /* flags */
606         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
607         
608         /* properties */
609         prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove.");
610         RNA_def_enum_funcs(prop, hook_mod_itemf);
611         ot->prop= prop;
612 }
613
614 static int object_hook_reset_exec(bContext *C, wmOperator *op)
615 {
616         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
617         int num= RNA_enum_get(op->ptr, "modifier");
618         Object *ob=NULL;
619         HookModifierData *hmd=NULL;
620         
621         if (ptr.data) {         /* if modifier context is available, use that */
622                 ob = ptr.id.data;
623                 hmd= ptr.data;
624         } 
625         else {                  /* use the provided property */
626                 ob = CTX_data_edit_object(C);
627                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
628         }
629         if (!ob || !hmd) {
630                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
631                 return OPERATOR_CANCELLED;
632         }
633         
634         /* reset functionality */
635         if(hmd->object) {
636                 bPoseChannel *pchan= get_pose_channel(hmd->object->pose, hmd->subtarget);
637                 
638                 if(hmd->subtarget[0] && pchan) {
639                         float imat[4][4], mat[4][4];
640                         
641                         /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
642                         mul_m4_m4m4(mat, pchan->pose_mat, hmd->object->obmat);
643                         
644                         invert_m4_m4(imat, mat);
645                         mul_serie_m4(hmd->parentinv, imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
646                 }
647                 else {
648                         invert_m4_m4(hmd->object->imat, hmd->object->obmat);
649                         mul_serie_m4(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
650                 }
651         }
652         
653         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
654         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
655         
656         return OPERATOR_FINISHED;
657 }
658
659 void OBJECT_OT_hook_reset(wmOperatorType *ot)
660 {
661         PropertyRNA *prop;
662         
663         /* identifiers */
664         ot->name= "Reset Hook";
665         ot->description= "Recalculate and clear offset transformation";
666         ot->idname= "OBJECT_OT_hook_reset";
667         
668         /* callbacks */
669         ot->exec= object_hook_reset_exec;
670         ot->poll= hook_op_edit_poll;
671         
672         /* flags */
673         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
674         
675         /* properties */
676         prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
677         RNA_def_enum_funcs(prop, hook_mod_itemf);
678 }
679
680 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
681 {
682         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
683         int num= RNA_enum_get(op->ptr, "modifier");
684         Object *ob=NULL;
685         HookModifierData *hmd=NULL;
686         Scene *scene = CTX_data_scene(C);
687         float bmat[3][3], imat[3][3];
688         
689         if (ptr.data) {         /* if modifier context is available, use that */
690                 ob = ptr.id.data;
691                 hmd= ptr.data;
692         } 
693         else {                  /* use the provided property */
694                 ob = CTX_data_edit_object(C);
695                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
696         }
697         if (!ob || !hmd) {
698                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
699                 return OPERATOR_CANCELLED;
700         }
701         
702         /* recenter functionality */
703         copy_m3_m4(bmat, ob->obmat);
704         invert_m3_m3(imat, bmat);
705         
706         sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
707         mul_m3_v3(imat, hmd->cent);
708         
709         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
710         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
711         
712         return OPERATOR_FINISHED;
713 }
714
715 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
716 {
717         PropertyRNA *prop;
718         
719         /* identifiers */
720         ot->name= "Recenter Hook";
721         ot->description= "Set hook center to cursor position";
722         ot->idname= "OBJECT_OT_hook_recenter";
723         
724         /* callbacks */
725         ot->exec= object_hook_recenter_exec;
726         ot->poll= hook_op_edit_poll;
727         
728         /* flags */
729         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
730         
731         /* properties */
732         prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
733         RNA_def_enum_funcs(prop, hook_mod_itemf);
734 }
735
736 static int object_hook_assign_exec(bContext *C, wmOperator *op)
737 {
738         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
739         int num= RNA_enum_get(op->ptr, "modifier");
740         Object *ob=NULL;
741         HookModifierData *hmd=NULL;
742         float cent[3];
743         char name[32];
744         int *indexar, tot;
745         
746         if (ptr.data) {         /* if modifier context is available, use that */
747                 ob = ptr.id.data;
748                 hmd= ptr.data;
749         } 
750         else {                  /* use the provided property */
751                 ob = CTX_data_edit_object(C);
752                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
753         }
754         if (!ob || !hmd) {
755                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
756                 return OPERATOR_CANCELLED;
757         }
758         
759         /* assign functionality */
760         
761         if(!object_hook_index_array(ob, &tot, &indexar, name, cent)) {
762                 BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
763                 return OPERATOR_CANCELLED;
764         }
765         if(hmd->indexar)
766                 MEM_freeN(hmd->indexar);
767         
768         copy_v3_v3(hmd->cent, cent);
769         hmd->indexar= indexar;
770         hmd->totindex= tot;
771         
772         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
773         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
774         
775         return OPERATOR_FINISHED;
776 }
777
778 void OBJECT_OT_hook_assign(wmOperatorType *ot)
779 {
780         PropertyRNA *prop;
781         
782         /* identifiers */
783         ot->name= "Assign to Hook";
784         ot->description= "Assign the selected vertices to a hook";
785         ot->idname= "OBJECT_OT_hook_assign";
786         
787         /* callbacks */
788         ot->exec= object_hook_assign_exec;
789         ot->poll= hook_op_edit_poll;
790         
791         /* flags */
792         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
793         
794         /* properties */
795         prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
796         RNA_def_enum_funcs(prop, hook_mod_itemf);
797 }
798
799 static int object_hook_select_exec(bContext *C, wmOperator *op)
800 {
801         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
802         int num= RNA_enum_get(op->ptr, "modifier");
803         Object *ob=NULL;
804         HookModifierData *hmd=NULL;
805         
806         if (ptr.data) {         /* if modifier context is available, use that */
807                 ob = ptr.id.data;
808                 hmd= ptr.data;
809         } 
810         else {                  /* use the provided property */
811                 ob = CTX_data_edit_object(C);
812                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
813         }
814         if (!ob || !hmd) {
815                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
816                 return OPERATOR_CANCELLED;
817         }
818         
819         /* select functionality */
820         object_hook_select(ob, hmd);
821         
822         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
823         
824         return OPERATOR_FINISHED;
825 }
826
827 void OBJECT_OT_hook_select(wmOperatorType *ot)
828 {
829         PropertyRNA *prop;
830         
831         /* identifiers */
832         ot->name= "Select Hook";
833         ot->description= "Selects effected vertices on mesh";
834         ot->idname= "OBJECT_OT_hook_select";
835         
836         /* callbacks */
837         ot->exec= object_hook_select_exec;
838         ot->poll= hook_op_edit_poll;
839         
840         /* flags */
841         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
842         
843         /* properties */
844         prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove.");
845         RNA_def_enum_funcs(prop, hook_mod_itemf);
846 }
847