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