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