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