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