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