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