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