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