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