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