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