Merge branch 'master' into blender2.8
[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(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 int 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 *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         base = view_layer->basact;
460         base->lay = ob->lay = obedit->lay;
461         BLI_assert(view_layer->basact->object == ob);
462
463         /* icky, BKE_object_add sets new base as active.
464          * so set it back to the original edit object */
465         view_layer->basact = basedit;
466
467         return ob;
468 }
469
470 static int add_hook_object(const bContext *C, Main *bmain, Scene *scene, ViewLayer *view_layer, Object *obedit, Object *ob, int mode, ReportList *reports)
471 {
472         ModifierData *md = NULL;
473         HookModifierData *hmd = NULL;
474         float cent[3];
475         float pose_mat[4][4];
476         int tot, ok, *indexar;
477         char name[MAX_NAME];
478
479         ok = object_hook_index_array(bmain, scene, obedit, &tot, &indexar, name, cent);
480
481         if (!ok) {
482                 BKE_report(reports, RPT_ERROR, "Requires selected vertices or active vertex group");
483                 return false;
484         }
485
486         if (mode == OBJECT_ADDHOOK_NEWOB && !ob) {
487
488                 ob = add_hook_object_new(bmain, scene, view_layer, obedit);
489
490                 /* transform cent to global coords for loc */
491                 mul_v3_m4v3(ob->loc, obedit->obmat, cent);
492         }
493
494         md = obedit->modifiers.first;
495         while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) {
496                 md = md->next;
497         }
498
499         hmd = (HookModifierData *) modifier_new(eModifierType_Hook);
500         BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
501         BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name + 2);
502         modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd);
503
504         hmd->object = ob;
505         hmd->indexar = indexar;
506         copy_v3_v3(hmd->cent, cent);
507         hmd->totindex = tot;
508         BLI_strncpy(hmd->name, name, sizeof(hmd->name));
509
510         unit_m4(pose_mat);
511
512         invert_m4_m4(obedit->imat, obedit->obmat);
513         if (mode == OBJECT_ADDHOOK_NEWOB) {
514                 /* pass */
515         }
516         else {
517                 /* may overwrite with pose-bone location, below */
518                 mul_v3_m4v3(cent, obedit->imat, ob->obmat[3]);
519         }
520
521         if (mode == OBJECT_ADDHOOK_SELOB_BONE) {
522                 bArmature *arm = ob->data;
523                 BLI_assert(ob->type == OB_ARMATURE);
524                 if (arm->act_bone) {
525                         bPoseChannel *pchan_act;
526
527                         BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget));
528
529                         pchan_act = BKE_pose_channel_active(ob);
530                         if (LIKELY(pchan_act)) {
531                                 invert_m4_m4(pose_mat, pchan_act->pose_mat);
532                                 mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]);
533                                 mul_v3_m4v3(cent, obedit->imat, cent);
534                         }
535                 }
536                 else {
537                         BKE_report(reports, RPT_WARNING, "Armature has no active object bone");
538                 }
539         }
540
541         copy_v3_v3(hmd->cent, cent);
542
543
544         /* matrix calculus */
545         /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
546         /*        (parentinv         )                          */
547         BKE_object_where_is_calc(CTX_data_depsgraph(C), scene, ob);
548
549         invert_m4_m4(ob->imat, ob->obmat);
550         /* apparently this call goes from right to left... */
551         mul_m4_series(hmd->parentinv, pose_mat, ob->imat, obedit->obmat);
552
553         DEG_relations_tag_update(bmain);
554
555         return true;
556 }
557
558 static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
559 {
560         Main *bmain = CTX_data_main(C);
561         Scene *scene = CTX_data_scene(C);
562         ViewLayer *view_layer = CTX_data_view_layer(C);
563         Object *obedit = CTX_data_edit_object(C);
564         Object *obsel = NULL;
565         const bool use_bone = RNA_boolean_get(op->ptr, "use_bone");
566         const int mode = use_bone ? OBJECT_ADDHOOK_SELOB_BONE : OBJECT_ADDHOOK_SELOB;
567
568         CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
569         {
570                 if (ob != obedit) {
571                         obsel = ob;
572                         break;
573                 }
574         }
575         CTX_DATA_END;
576
577         if (!obsel) {
578                 BKE_report(op->reports, RPT_ERROR, "Cannot add hook with no other selected objects");
579                 return OPERATOR_CANCELLED;
580         }
581
582         if (use_bone && obsel->type != OB_ARMATURE) {
583                 BKE_report(op->reports, RPT_ERROR, "Cannot add hook bone for a non armature object");
584                 return OPERATOR_CANCELLED;
585         }
586
587         if (add_hook_object(C, bmain, scene, view_layer, obedit, obsel, mode, op->reports)) {
588                 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
589                 return OPERATOR_FINISHED;
590         }
591         else {
592                 return OPERATOR_CANCELLED;
593         }
594 }
595
596 void OBJECT_OT_hook_add_selob(wmOperatorType *ot)
597 {
598         /* identifiers */
599         ot->name = "Hook to Selected Object";
600         ot->description = "Hook selected vertices to the first selected object";
601         ot->idname = "OBJECT_OT_hook_add_selob";
602
603         /* api callbacks */
604         ot->exec = object_add_hook_selob_exec;
605         ot->poll = hook_op_edit_poll;
606
607         /* flags */
608         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
609
610         RNA_def_boolean(ot->srna, "use_bone", false, "Active Bone",
611                         "Assign the hook to the hook objects active bone");
612 }
613
614 static int object_add_hook_newob_exec(bContext *C, wmOperator *op)
615 {
616         Main *bmain = CTX_data_main(C);
617         Scene *scene = CTX_data_scene(C);
618         ViewLayer *view_layer = CTX_data_view_layer(C);
619         Object *obedit = CTX_data_edit_object(C);
620
621         if (add_hook_object(C, bmain, scene, view_layer, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) {
622                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
623                 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
624                 return OPERATOR_FINISHED;
625         }
626         else {
627                 return OPERATOR_CANCELLED;
628         }
629 }
630
631 void OBJECT_OT_hook_add_newob(wmOperatorType *ot)
632 {
633         /* identifiers */
634         ot->name = "Hook to New Object";
635         ot->description = "Hook selected vertices to a newly created object";
636         ot->idname = "OBJECT_OT_hook_add_newob";
637
638         /* api callbacks */
639         ot->exec = object_add_hook_newob_exec;
640         ot->poll = hook_op_edit_poll;
641
642         /* flags */
643         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
644 }
645
646 static int object_hook_remove_exec(bContext *C, wmOperator *op)
647 {
648         int num = RNA_enum_get(op->ptr, "modifier");
649         Object *ob = CTX_data_edit_object(C);
650         HookModifierData *hmd = NULL;
651
652         hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
653         if (!hmd) {
654                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
655                 return OPERATOR_CANCELLED;
656         }
657
658         /* remove functionality */
659
660         BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
661         modifier_free((ModifierData *)hmd);
662
663         DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
664         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
665
666         return OPERATOR_FINISHED;
667 }
668
669 static const EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
670 {
671         Object *ob = CTX_data_edit_object(C);
672         EnumPropertyItem tmp = {0, "", 0, "", ""};
673         EnumPropertyItem *item = NULL;
674         ModifierData *md = NULL;
675         int a, totitem = 0;
676
677         if (!ob)
678                 return DummyRNA_NULL_items;
679
680         for (a = 0, md = ob->modifiers.first; md; md = md->next, a++) {
681                 if (md->type == eModifierType_Hook) {
682                         tmp.value = a;
683                         tmp.icon = ICON_HOOK;
684                         tmp.identifier = md->name;
685                         tmp.name = md->name;
686                         RNA_enum_item_add(&item, &totitem, &tmp);
687                 }
688         }
689
690         RNA_enum_item_end(&item, &totitem);
691         *r_free = true;
692
693         return item;
694 }
695
696 void OBJECT_OT_hook_remove(wmOperatorType *ot)
697 {
698         PropertyRNA *prop;
699
700         /* identifiers */
701         ot->name = "Remove Hook";
702         ot->idname = "OBJECT_OT_hook_remove";
703         ot->description = "Remove a hook from the active object";
704
705         /* api callbacks */
706         ot->exec = object_hook_remove_exec;
707         ot->invoke = WM_menu_invoke;
708         ot->poll = hook_op_edit_poll;
709
710         /* flags */
711         /* this operator removes modifier which isn't stored in local undo stack,
712          * so redoing it from redo panel gives totally weird results  */
713         ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
714
715         /* properties */
716         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
717         RNA_def_enum_funcs(prop, hook_mod_itemf);
718         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
719         ot->prop = prop;
720 }
721
722 static int object_hook_reset_exec(bContext *C, wmOperator *op)
723 {
724         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
725         int num = RNA_enum_get(op->ptr, "modifier");
726         Object *ob = NULL;
727         HookModifierData *hmd = NULL;
728
729         object_hook_from_context(C, &ptr, num, &ob, &hmd);
730         if (hmd == NULL) {
731                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
732                 return OPERATOR_CANCELLED;
733         }
734
735         BKE_object_modifier_hook_reset(ob, hmd);
736
737         DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
738         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
739
740         return OPERATOR_FINISHED;
741 }
742
743 void OBJECT_OT_hook_reset(wmOperatorType *ot)
744 {
745         PropertyRNA *prop;
746
747         /* identifiers */
748         ot->name = "Reset Hook";
749         ot->description = "Recalculate and clear offset transformation";
750         ot->idname = "OBJECT_OT_hook_reset";
751
752         /* callbacks */
753         ot->exec = object_hook_reset_exec;
754         ot->poll = hook_op_edit_poll;
755
756         /* flags */
757         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
758
759         /* properties */
760         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
761         RNA_def_enum_funcs(prop, hook_mod_itemf);
762         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
763 }
764
765 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
766 {
767         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
768         int num = RNA_enum_get(op->ptr, "modifier");
769         Object *ob = NULL;
770         HookModifierData *hmd = NULL;
771         Scene *scene = CTX_data_scene(C);
772         float bmat[3][3], imat[3][3];
773
774         object_hook_from_context(C, &ptr, num, &ob, &hmd);
775         if (hmd == NULL) {
776                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
777                 return OPERATOR_CANCELLED;
778         }
779
780         /* recenter functionality */
781         copy_m3_m4(bmat, ob->obmat);
782         invert_m3_m3(imat, bmat);
783
784         sub_v3_v3v3(hmd->cent, scene->cursor.location, ob->obmat[3]);
785         mul_m3_v3(imat, hmd->cent);
786
787         DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
788         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
789
790         return OPERATOR_FINISHED;
791 }
792
793 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
794 {
795         PropertyRNA *prop;
796
797         /* identifiers */
798         ot->name = "Recenter Hook";
799         ot->description = "Set hook center to cursor position";
800         ot->idname = "OBJECT_OT_hook_recenter";
801
802         /* callbacks */
803         ot->exec = object_hook_recenter_exec;
804         ot->poll = hook_op_edit_poll;
805
806         /* flags */
807         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
808
809         /* properties */
810         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
811         RNA_def_enum_funcs(prop, hook_mod_itemf);
812         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
813 }
814
815 static int object_hook_assign_exec(bContext *C, wmOperator *op)
816 {
817         Main *bmain = CTX_data_main(C);
818         Scene *scene = CTX_data_scene(C);
819         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
820         int num = RNA_enum_get(op->ptr, "modifier");
821         Object *ob = NULL;
822         HookModifierData *hmd = NULL;
823         float cent[3];
824         char name[MAX_NAME];
825         int *indexar, tot;
826
827         object_hook_from_context(C, &ptr, num, &ob, &hmd);
828         if (hmd == NULL) {
829                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
830                 return OPERATOR_CANCELLED;
831         }
832
833         /* assign functionality */
834
835         if (!object_hook_index_array(bmain, scene, ob, &tot, &indexar, name, cent)) {
836                 BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
837                 return OPERATOR_CANCELLED;
838         }
839         if (hmd->indexar)
840                 MEM_freeN(hmd->indexar);
841
842         copy_v3_v3(hmd->cent, cent);
843         hmd->indexar = indexar;
844         hmd->totindex = tot;
845
846         DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
847         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
848
849         return OPERATOR_FINISHED;
850 }
851
852 void OBJECT_OT_hook_assign(wmOperatorType *ot)
853 {
854         PropertyRNA *prop;
855
856         /* identifiers */
857         ot->name = "Assign to Hook";
858         ot->description = "Assign the selected vertices to a hook";
859         ot->idname = "OBJECT_OT_hook_assign";
860
861         /* callbacks */
862         ot->exec = object_hook_assign_exec;
863         ot->poll = hook_op_edit_poll;
864
865         /* flags */
866         /* this operator changes data stored in modifier which doesn't get pushed to undo stack,
867          * so redoing it from redo panel gives totally weird results  */
868         ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
869
870         /* properties */
871         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
872         RNA_def_enum_funcs(prop, hook_mod_itemf);
873         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
874 }
875
876 static int object_hook_select_exec(bContext *C, wmOperator *op)
877 {
878         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
879         int num = RNA_enum_get(op->ptr, "modifier");
880         Object *ob = NULL;
881         HookModifierData *hmd = NULL;
882
883         object_hook_from_context(C, &ptr, num, &ob, &hmd);
884         if (hmd == NULL) {
885                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
886                 return OPERATOR_CANCELLED;
887         }
888
889         /* select functionality */
890         object_hook_select(ob, hmd);
891
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 }
918