GPencil: Change Trace tooltips
[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_listbase.h"
30 #include "BLI_math.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_deform.h"
45 #include "BKE_editmesh.h"
46 #include "BKE_layer.h"
47 #include "BKE_main.h"
48 #include "BKE_modifier.h"
49 #include "BKE_object.h"
50 #include "BKE_report.h"
51 #include "BKE_scene.h"
52
53 #include "DEG_depsgraph.h"
54 #include "DEG_depsgraph_build.h"
55 #include "DEG_depsgraph_query.h"
56
57 #include "RNA_access.h"
58 #include "RNA_define.h"
59 #include "RNA_enum_types.h"
60
61 #include "ED_curve.h"
62 #include "ED_mesh.h"
63 #include "ED_screen.h"
64
65 #include "WM_api.h"
66 #include "WM_types.h"
67
68 #include "UI_resources.h"
69
70 #include "object_intern.h"
71
72 static int return_editmesh_indexar(BMEditMesh *em, int *r_tot, int **r_indexar, float r_cent[3])
73 {
74   BMVert *eve;
75   BMIter iter;
76   int *index, nr, totvert = 0;
77
78   BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
79     if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
80       totvert++;
81     }
82   }
83   if (totvert == 0) {
84     return 0;
85   }
86
87   *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
88   *r_tot = totvert;
89   nr = 0;
90   zero_v3(r_cent);
91
92   BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
93     if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
94       *index = nr;
95       index++;
96       add_v3_v3(r_cent, eve->co);
97     }
98     nr++;
99   }
100
101   mul_v3_fl(r_cent, 1.0f / (float)totvert);
102
103   return totvert;
104 }
105
106 static bool return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *r_name, float r_cent[3])
107 {
108   const int cd_dvert_offset = obedit->actdef ?
109                                   CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT) :
110                                   -1;
111
112   zero_v3(r_cent);
113
114   if (cd_dvert_offset != -1) {
115     const int defgrp_index = obedit->actdef - 1;
116     int totvert = 0;
117
118     MDeformVert *dvert;
119     BMVert *eve;
120     BMIter iter;
121
122     /* find the vertices */
123     BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
124       dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
125
126       if (BKE_defvert_find_weight(dvert, defgrp_index) > 0.0f) {
127         add_v3_v3(r_cent, eve->co);
128         totvert++;
129       }
130     }
131     if (totvert) {
132       bDeformGroup *dg = BLI_findlink(&obedit->defbase, defgrp_index);
133       BLI_strncpy(r_name, dg->name, sizeof(dg->name));
134       mul_v3_fl(r_cent, 1.0f / (float)totvert);
135       return true;
136     }
137   }
138
139   return false;
140 }
141
142 static void select_editbmesh_hook(Object *ob, HookModifierData *hmd)
143 {
144   Mesh *me = ob->data;
145   BMEditMesh *em = me->edit_mesh;
146   BMVert *eve;
147   BMIter iter;
148   int index = 0, nr = 0;
149
150   if (hmd->indexar == NULL) {
151     return;
152   }
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) {
158         index++;
159       }
160     }
161
162     nr++;
163   }
164
165   EDBM_select_flush(em);
166 }
167
168 static int return_editlattice_indexar(Lattice *editlatt,
169                                       int *r_tot,
170                                       int **r_indexar,
171                                       float r_cent[3])
172 {
173   BPoint *bp;
174   int *index, nr, totvert = 0, a;
175
176   /* count */
177   a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
178   bp = editlatt->def;
179   while (a--) {
180     if (bp->f1 & SELECT) {
181       if (bp->hide == 0) {
182         totvert++;
183       }
184     }
185     bp++;
186   }
187
188   if (totvert == 0) {
189     return 0;
190   }
191
192   *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
193   *r_tot = totvert;
194   nr = 0;
195   zero_v3(r_cent);
196
197   a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
198   bp = editlatt->def;
199   while (a--) {
200     if (bp->f1 & SELECT) {
201       if (bp->hide == 0) {
202         *index = nr;
203         index++;
204         add_v3_v3(r_cent, bp->vec);
205       }
206     }
207     bp++;
208     nr++;
209   }
210
211   mul_v3_fl(r_cent, 1.0f / (float)totvert);
212
213   return totvert;
214 }
215
216 static void select_editlattice_hook(Object *obedit, HookModifierData *hmd)
217 {
218   Lattice *lt = obedit->data, *editlt;
219   BPoint *bp;
220   int index = 0, nr = 0, a;
221
222   editlt = lt->editlatt->latt;
223   /* count */
224   a = editlt->pntsu * editlt->pntsv * editlt->pntsw;
225   bp = editlt->def;
226   while (a--) {
227     if (hmd->indexar[index] == nr) {
228       bp->f1 |= SELECT;
229       if (index < hmd->totindex - 1) {
230         index++;
231       }
232     }
233     nr++;
234     bp++;
235   }
236 }
237
238 static int return_editcurve_indexar(Object *obedit, int *r_tot, int **r_indexar, float r_cent[3])
239 {
240   ListBase *editnurb = object_editcurve_get(obedit);
241   BPoint *bp;
242   BezTriple *bezt;
243   int *index, a, nr, totvert = 0;
244
245   LISTBASE_FOREACH (Nurb *, nu, editnurb) {
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   LISTBASE_FOREACH (Nurb *, nu, editnurb) {
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_looptri_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   BPoint *bp;
380   BezTriple *bezt;
381   int index = 0, a, nr = 0;
382
383   LISTBASE_FOREACH (Nurb *, nu, editnurb) {
384     if (nu->type == CU_BEZIER) {
385       bezt = nu->bezt;
386       a = nu->pntsu;
387       while (a--) {
388         if (nr == hmd->indexar[index]) {
389           bezt->f1 |= SELECT;
390           if (index < hmd->totindex - 1) {
391             index++;
392           }
393         }
394         nr++;
395         if (nr == hmd->indexar[index]) {
396           bezt->f2 |= SELECT;
397           if (index < hmd->totindex - 1) {
398             index++;
399           }
400         }
401         nr++;
402         if (nr == hmd->indexar[index]) {
403           bezt->f3 |= SELECT;
404           if (index < hmd->totindex - 1) {
405             index++;
406           }
407         }
408         nr++;
409
410         bezt++;
411       }
412     }
413     else {
414       bp = nu->bp;
415       a = nu->pntsu * nu->pntsv;
416       while (a--) {
417         if (nr == hmd->indexar[index]) {
418           bp->f1 |= SELECT;
419           if (index < hmd->totindex - 1) {
420             index++;
421           }
422         }
423         nr++;
424         bp++;
425       }
426     }
427   }
428 }
429
430 static void object_hook_from_context(
431     bContext *C, PointerRNA *ptr, const int num, Object **r_ob, HookModifierData **r_hmd)
432 {
433   Object *ob;
434   HookModifierData *hmd;
435
436   if (ptr->data) { /* if modifier context is available, use that */
437     ob = (Object *)ptr->owner_id;
438     hmd = ptr->data;
439   }
440   else { /* use the provided property */
441     ob = CTX_data_edit_object(C);
442     hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
443   }
444
445   if (ob && hmd && (hmd->modifier.type == eModifierType_Hook)) {
446     *r_ob = ob;
447     *r_hmd = hmd;
448   }
449   else {
450     *r_ob = NULL;
451     *r_hmd = NULL;
452   }
453 }
454
455 static void object_hook_select(Object *ob, HookModifierData *hmd)
456 {
457   if (hmd->indexar == NULL) {
458     return;
459   }
460
461   if (ob->type == OB_MESH) {
462     select_editbmesh_hook(ob, hmd);
463   }
464   else if (ob->type == OB_LATTICE) {
465     select_editlattice_hook(ob, hmd);
466   }
467   else if (ob->type == OB_CURVE) {
468     select_editcurve_hook(ob, hmd);
469   }
470   else if (ob->type == OB_SURF) {
471     select_editcurve_hook(ob, hmd);
472   }
473 }
474
475 /* special poll operators for hook operators */
476 /* TODO: check for properties window modifier context too as alternative? */
477 static bool hook_op_edit_poll(bContext *C)
478 {
479   Object *obedit = CTX_data_edit_object(C);
480
481   if (obedit) {
482     if (ED_operator_editmesh(C)) {
483       return true;
484     }
485     if (ED_operator_editsurfcurve(C)) {
486       return true;
487     }
488     if (ED_operator_editlattice(C)) {
489       return true;
490     }
491     // if (ED_operator_editmball(C)) return true;
492   }
493
494   return false;
495 }
496
497 static Object *add_hook_object_new(Main *bmain, ViewLayer *view_layer, View3D *v3d, Object *obedit)
498 {
499   Base *basedit;
500   Object *ob;
501
502   ob = BKE_object_add(bmain, view_layer, OB_EMPTY, NULL);
503
504   basedit = BKE_view_layer_base_find(view_layer, obedit);
505   BLI_assert(view_layer->basact->object == ob);
506
507   if (v3d && v3d->localvd) {
508     view_layer->basact->local_view_bits |= v3d->local_view_uuid;
509   }
510
511   /* icky, BKE_object_add sets new base as active.
512    * so set it back to the original edit object */
513   view_layer->basact = basedit;
514
515   return ob;
516 }
517
518 static int add_hook_object(const bContext *C,
519                            Main *bmain,
520                            Scene *scene,
521                            ViewLayer *view_layer,
522                            View3D *v3d,
523                            Object *obedit,
524                            Object *ob,
525                            int mode,
526                            ReportList *reports)
527 {
528   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
529   ModifierData *md = NULL;
530   HookModifierData *hmd = NULL;
531   float cent[3];
532   float pose_mat[4][4];
533   int tot, ok, *indexar;
534   char name[MAX_NAME];
535
536   ok = object_hook_index_array(bmain, scene, obedit, &tot, &indexar, name, cent);
537
538   if (!ok) {
539     BKE_report(reports, RPT_ERROR, "Requires selected vertices or active vertex group");
540     return false;
541   }
542
543   if (mode == OBJECT_ADDHOOK_NEWOB && !ob) {
544
545     ob = add_hook_object_new(bmain, view_layer, v3d, obedit);
546
547     /* transform cent to global coords for loc */
548     mul_v3_m4v3(ob->loc, obedit->obmat, cent);
549   }
550
551   md = obedit->modifiers.first;
552   while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) {
553     md = md->next;
554   }
555
556   hmd = (HookModifierData *)BKE_modifier_new(eModifierType_Hook);
557   BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
558   BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name + 2);
559   BKE_modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd);
560
561   hmd->object = ob;
562   hmd->indexar = indexar;
563   copy_v3_v3(hmd->cent, cent);
564   hmd->totindex = tot;
565   BLI_strncpy(hmd->name, name, sizeof(hmd->name));
566
567   unit_m4(pose_mat);
568
569   invert_m4_m4(obedit->imat, obedit->obmat);
570   if (mode == OBJECT_ADDHOOK_NEWOB) {
571     /* pass */
572   }
573   else {
574     /* may overwrite with pose-bone location, below */
575     mul_v3_m4v3(cent, obedit->imat, ob->obmat[3]);
576   }
577
578   if (mode == OBJECT_ADDHOOK_SELOB_BONE) {
579     bArmature *arm = ob->data;
580     BLI_assert(ob->type == OB_ARMATURE);
581     if (arm->act_bone) {
582       bPoseChannel *pchan_act;
583
584       BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget));
585
586       pchan_act = BKE_pose_channel_active(ob);
587       if (LIKELY(pchan_act)) {
588         invert_m4_m4(pose_mat, pchan_act->pose_mat);
589         mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]);
590         mul_v3_m4v3(cent, obedit->imat, cent);
591       }
592     }
593     else {
594       BKE_report(reports, RPT_WARNING, "Armature has no active object bone");
595     }
596   }
597
598   copy_v3_v3(hmd->cent, cent);
599
600   /* matrix calculus */
601   /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
602   /*        (parentinv         )                          */
603   Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
604   Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
605   BKE_object_transform_copy(object_eval, ob);
606   BKE_object_where_is_calc(depsgraph, scene_eval, object_eval);
607
608   invert_m4_m4(object_eval->imat, object_eval->obmat);
609   /* apparently this call goes from right to left... */
610   mul_m4_series(hmd->parentinv, pose_mat, object_eval->imat, obedit->obmat);
611
612   DEG_relations_tag_update(bmain);
613
614   return true;
615 }
616
617 static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
618 {
619   Main *bmain = CTX_data_main(C);
620   Scene *scene = CTX_data_scene(C);
621   ViewLayer *view_layer = CTX_data_view_layer(C);
622   Object *obedit = CTX_data_edit_object(C);
623   Object *obsel = NULL;
624   const bool use_bone = RNA_boolean_get(op->ptr, "use_bone");
625   const int mode = use_bone ? OBJECT_ADDHOOK_SELOB_BONE : OBJECT_ADDHOOK_SELOB;
626
627   CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
628     if (ob != obedit) {
629       obsel = ob;
630       break;
631     }
632   }
633   CTX_DATA_END;
634
635   if (!obsel) {
636     BKE_report(op->reports, RPT_ERROR, "Cannot add hook with no other selected objects");
637     return OPERATOR_CANCELLED;
638   }
639
640   if (use_bone && obsel->type != OB_ARMATURE) {
641     BKE_report(op->reports, RPT_ERROR, "Cannot add hook bone for a non armature object");
642     return OPERATOR_CANCELLED;
643   }
644
645   if (add_hook_object(C, bmain, scene, view_layer, NULL, obedit, obsel, mode, op->reports)) {
646     WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
647     return OPERATOR_FINISHED;
648   }
649   return OPERATOR_CANCELLED;
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   return OPERATOR_CANCELLED;
689 }
690
691 void OBJECT_OT_hook_add_newob(wmOperatorType *ot)
692 {
693   /* identifiers */
694   ot->name = "Hook to New Object";
695   ot->description = "Hook selected vertices to a newly created object";
696   ot->idname = "OBJECT_OT_hook_add_newob";
697
698   /* api callbacks */
699   ot->exec = object_add_hook_newob_exec;
700   ot->poll = hook_op_edit_poll;
701
702   /* flags */
703   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
704 }
705
706 static int object_hook_remove_exec(bContext *C, wmOperator *op)
707 {
708   int num = RNA_enum_get(op->ptr, "modifier");
709   Object *ob = CTX_data_edit_object(C);
710   HookModifierData *hmd = NULL;
711
712   hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
713   if (!hmd) {
714     BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
715     return OPERATOR_CANCELLED;
716   }
717
718   /* remove functionality */
719
720   BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
721   BKE_modifier_free((ModifierData *)hmd);
722
723   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
724   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
725
726   return OPERATOR_FINISHED;
727 }
728
729 static const EnumPropertyItem *hook_mod_itemf(bContext *C,
730                                               PointerRNA *UNUSED(ptr),
731                                               PropertyRNA *UNUSED(prop),
732                                               bool *r_free)
733 {
734   Object *ob = CTX_data_edit_object(C);
735   EnumPropertyItem tmp = {0, "", 0, "", ""};
736   EnumPropertyItem *item = NULL;
737   ModifierData *md = NULL;
738   int a, totitem = 0;
739
740   if (!ob) {
741     return DummyRNA_NULL_items;
742   }
743
744   for (a = 0, md = ob->modifiers.first; md; md = md->next, a++) {
745     if (md->type == eModifierType_Hook) {
746       tmp.value = a;
747       tmp.icon = ICON_HOOK;
748       tmp.identifier = md->name;
749       tmp.name = md->name;
750       RNA_enum_item_add(&item, &totitem, &tmp);
751     }
752   }
753
754   RNA_enum_item_end(&item, &totitem);
755   *r_free = true;
756
757   return item;
758 }
759
760 void OBJECT_OT_hook_remove(wmOperatorType *ot)
761 {
762   PropertyRNA *prop;
763
764   /* identifiers */
765   ot->name = "Remove Hook";
766   ot->idname = "OBJECT_OT_hook_remove";
767   ot->description = "Remove a hook from the active object";
768
769   /* api callbacks */
770   ot->exec = object_hook_remove_exec;
771   ot->invoke = WM_menu_invoke;
772   ot->poll = hook_op_edit_poll;
773
774   /* flags */
775   /* this operator removes modifier which isn't stored in local undo stack,
776    * so redoing it from redo panel gives totally weird results  */
777   ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
778
779   /* properties */
780   prop = RNA_def_enum(
781       ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
782   RNA_def_enum_funcs(prop, hook_mod_itemf);
783   RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
784   ot->prop = prop;
785 }
786
787 static int object_hook_reset_exec(bContext *C, wmOperator *op)
788 {
789   PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
790   int num = RNA_enum_get(op->ptr, "modifier");
791   Object *ob = NULL;
792   HookModifierData *hmd = NULL;
793
794   object_hook_from_context(C, &ptr, num, &ob, &hmd);
795   if (hmd == NULL) {
796     BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
797     return OPERATOR_CANCELLED;
798   }
799
800   BKE_object_modifier_hook_reset(ob, hmd);
801
802   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
803   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
804
805   return OPERATOR_FINISHED;
806 }
807
808 void OBJECT_OT_hook_reset(wmOperatorType *ot)
809 {
810   PropertyRNA *prop;
811
812   /* identifiers */
813   ot->name = "Reset Hook";
814   ot->description = "Recalculate and clear offset transformation";
815   ot->idname = "OBJECT_OT_hook_reset";
816
817   /* callbacks */
818   ot->exec = object_hook_reset_exec;
819   ot->poll = hook_op_edit_poll;
820
821   /* flags */
822   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
823
824   /* properties */
825   prop = RNA_def_enum(
826       ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
827   RNA_def_enum_funcs(prop, hook_mod_itemf);
828   RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
829 }
830
831 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
832 {
833   PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
834   int num = RNA_enum_get(op->ptr, "modifier");
835   Object *ob = NULL;
836   HookModifierData *hmd = NULL;
837   Scene *scene = CTX_data_scene(C);
838   float bmat[3][3], imat[3][3];
839
840   object_hook_from_context(C, &ptr, num, &ob, &hmd);
841   if (hmd == NULL) {
842     BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
843     return OPERATOR_CANCELLED;
844   }
845
846   /* recenter functionality */
847   copy_m3_m4(bmat, ob->obmat);
848   invert_m3_m3(imat, bmat);
849
850   sub_v3_v3v3(hmd->cent, scene->cursor.location, ob->obmat[3]);
851   mul_m3_v3(imat, hmd->cent);
852
853   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
854   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
855
856   return OPERATOR_FINISHED;
857 }
858
859 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
860 {
861   PropertyRNA *prop;
862
863   /* identifiers */
864   ot->name = "Recenter Hook";
865   ot->description = "Set hook center to cursor position";
866   ot->idname = "OBJECT_OT_hook_recenter";
867
868   /* callbacks */
869   ot->exec = object_hook_recenter_exec;
870   ot->poll = hook_op_edit_poll;
871
872   /* flags */
873   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
874
875   /* properties */
876   prop = RNA_def_enum(
877       ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
878   RNA_def_enum_funcs(prop, hook_mod_itemf);
879   RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
880 }
881
882 static int object_hook_assign_exec(bContext *C, wmOperator *op)
883 {
884   Main *bmain = CTX_data_main(C);
885   Scene *scene = CTX_data_scene(C);
886   PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
887   int num = RNA_enum_get(op->ptr, "modifier");
888   Object *ob = NULL;
889   HookModifierData *hmd = NULL;
890   float cent[3];
891   char name[MAX_NAME];
892   int *indexar, tot;
893
894   object_hook_from_context(C, &ptr, num, &ob, &hmd);
895   if (hmd == NULL) {
896     BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
897     return OPERATOR_CANCELLED;
898   }
899
900   /* assign functionality */
901
902   if (!object_hook_index_array(bmain, scene, ob, &tot, &indexar, name, cent)) {
903     BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
904     return OPERATOR_CANCELLED;
905   }
906   if (hmd->indexar) {
907     MEM_freeN(hmd->indexar);
908   }
909
910   copy_v3_v3(hmd->cent, cent);
911   hmd->indexar = indexar;
912   hmd->totindex = tot;
913
914   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
915   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
916
917   return OPERATOR_FINISHED;
918 }
919
920 void OBJECT_OT_hook_assign(wmOperatorType *ot)
921 {
922   PropertyRNA *prop;
923
924   /* identifiers */
925   ot->name = "Assign to Hook";
926   ot->description = "Assign the selected vertices to a hook";
927   ot->idname = "OBJECT_OT_hook_assign";
928
929   /* callbacks */
930   ot->exec = object_hook_assign_exec;
931   ot->poll = hook_op_edit_poll;
932
933   /* flags */
934   /* this operator changes data stored in modifier which doesn't get pushed to undo stack,
935    * so redoing it from redo panel gives totally weird results  */
936   ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
937
938   /* properties */
939   prop = RNA_def_enum(
940       ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
941   RNA_def_enum_funcs(prop, hook_mod_itemf);
942   RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
943 }
944
945 static int object_hook_select_exec(bContext *C, wmOperator *op)
946 {
947   PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
948   int num = RNA_enum_get(op->ptr, "modifier");
949   Object *ob = NULL;
950   HookModifierData *hmd = NULL;
951
952   object_hook_from_context(C, &ptr, num, &ob, &hmd);
953   if (hmd == NULL) {
954     BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
955     return OPERATOR_CANCELLED;
956   }
957
958   /* select functionality */
959   object_hook_select(ob, hmd);
960
961   DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
962   WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
963
964   return OPERATOR_FINISHED;
965 }
966
967 void OBJECT_OT_hook_select(wmOperatorType *ot)
968 {
969   PropertyRNA *prop;
970
971   /* identifiers */
972   ot->name = "Select Hook";
973   ot->description = "Select affected vertices on mesh";
974   ot->idname = "OBJECT_OT_hook_select";
975
976   /* callbacks */
977   ot->exec = object_hook_select_exec;
978   ot->poll = hook_op_edit_poll;
979
980   /* flags */
981   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
982
983   /* properties */
984   prop = RNA_def_enum(
985       ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
986   RNA_def_enum_funcs(prop, hook_mod_itemf);
987   RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
988 }