code cleanup: rename BKE_tessmesh -> BKE_editmesh, rename EditDerivedBMesh.tc ->...
[blender-staging.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 int return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *name, float *cent)
106 {
107         zero_v3(cent);
108
109         if (obedit->actdef) {
110                 const int defgrp_index = obedit->actdef - 1;
111                 int totvert = 0;
112
113                 MDeformVert *dvert;
114                 BMVert *eve;
115                 BMIter iter;
116
117                 /* find the vertices */
118                 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
119                         dvert = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
120
121                         if (dvert) {
122                                 if (defvert_find_weight(dvert, defgrp_index) > 0.0f) {
123                                         add_v3_v3(cent, eve->co);
124                                         totvert++;
125                                 }
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 1;
133                 }
134         }
135         
136         return 0;
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 int 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, scene, obedit);
314
315                         em = me->edit_btmesh;
316
317                         EDBM_mesh_normals_update(em);
318                         BMEdit_RecalcTessellation(em);
319
320                         /* check selected vertices first */
321                         if (return_editmesh_indexar(em, tot, indexar, cent_r)) {
322                                 return 1;
323                         }
324                         else {
325                                 int ret = return_editmesh_vgroup(obedit, em, name, cent_r);
326                                 return ret;
327                         }
328                 }
329                 case OB_CURVE:
330                 case OB_SURF:
331                         return return_editcurve_indexar(obedit, tot, indexar, cent_r);
332                 case OB_LATTICE:
333                 {
334                         Lattice *lt = obedit->data;
335                         return return_editlattice_indexar(lt->editlatt->latt, tot, indexar, cent_r);
336                 }
337                 default:
338                         return 0;
339         }
340 }
341
342 static void select_editcurve_hook(Object *obedit, HookModifierData *hmd)
343 {
344         ListBase *editnurb = object_editcurve_get(obedit);
345         Nurb *nu;
346         BPoint *bp;
347         BezTriple *bezt;
348         int index = 0, a, nr = 0;
349         
350         for (nu = editnurb->first; nu; nu = nu->next) {
351                 if (nu->type == CU_BEZIER) {
352                         bezt = nu->bezt;
353                         a = nu->pntsu;
354                         while (a--) {
355                                 if (nr == hmd->indexar[index]) {
356                                         bezt->f1 |= SELECT;
357                                         if (index < hmd->totindex - 1) index++;
358                                 }
359                                 nr++;
360                                 if (nr == hmd->indexar[index]) {
361                                         bezt->f2 |= SELECT;
362                                         if (index < hmd->totindex - 1) index++;
363                                 }
364                                 nr++;
365                                 if (nr == hmd->indexar[index]) {
366                                         bezt->f3 |= SELECT;
367                                         if (index < hmd->totindex - 1) index++;
368                                 }
369                                 nr++;
370                                 
371                                 bezt++;
372                         }
373                 }
374                 else {
375                         bp = nu->bp;
376                         a = nu->pntsu * nu->pntsv;
377                         while (a--) {
378                                 if (nr == hmd->indexar[index]) {
379                                         bp->f1 |= SELECT;
380                                         if (index < hmd->totindex - 1) index++;
381                                 }
382                                 nr++;
383                                 bp++;
384                         }
385                 }
386         }
387 }
388
389 static void object_hook_from_context(bContext *C, PointerRNA *ptr, const int num,
390                                      Object **r_ob, HookModifierData **r_hmd)
391 {
392         Object *ob;
393         HookModifierData *hmd;
394
395         if (ptr->data) {  /* if modifier context is available, use that */
396                 ob = ptr->id.data;
397                 hmd = ptr->data;
398         }
399         else {  /* use the provided property */
400                 ob = CTX_data_edit_object(C);
401                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
402         }
403
404         if (ob && hmd && (hmd->modifier.type == eModifierType_Hook)) {
405                 *r_ob = ob;
406                 *r_hmd = hmd;
407         }
408         else {
409                 *r_ob = NULL;
410                 *r_hmd = NULL;
411         }
412 }
413
414 static void object_hook_select(Object *ob, HookModifierData *hmd) 
415 {
416         if (hmd->indexar == NULL)
417                 return;
418         
419         if (ob->type == OB_MESH) select_editbmesh_hook(ob, hmd);
420         else if (ob->type == OB_LATTICE) select_editlattice_hook(ob, hmd);
421         else if (ob->type == OB_CURVE) select_editcurve_hook(ob, hmd);
422         else if (ob->type == OB_SURF) select_editcurve_hook(ob, hmd);
423 }
424
425 /* special poll operators for hook operators */
426 /* TODO: check for properties window modifier context too as alternative? */
427 static int hook_op_edit_poll(bContext *C)
428 {
429         Object *obedit = CTX_data_edit_object(C);
430         
431         if (obedit) {
432                 if (ED_operator_editmesh(C)) return 1;
433                 if (ED_operator_editsurfcurve(C)) return 1;
434                 if (ED_operator_editlattice(C)) return 1;
435                 //if (ED_operator_editmball(C)) return 1;
436         }
437         
438         return 0;
439 }
440
441 static Object *add_hook_object_new(Scene *scene, Object *obedit)
442 {
443         Base *base, *basedit;
444         Object *ob;
445
446         ob = BKE_object_add(scene, OB_EMPTY);
447         
448         basedit = BKE_scene_base_find(scene, obedit);
449         base = BKE_scene_base_find(scene, ob);
450         base->lay = ob->lay = obedit->lay;
451         
452         /* icky, BKE_object_add sets new base as active.
453          * so set it back to the original edit object */
454         scene->basact = basedit;
455
456         return ob;
457 }
458
459 static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob, int mode, ReportList *reports)
460 {
461         ModifierData *md = NULL;
462         HookModifierData *hmd = NULL;
463         float cent[3];
464         int tot, ok, *indexar;
465         char name[MAX_NAME];
466         
467         ok = object_hook_index_array(scene, obedit, &tot, &indexar, name, cent);
468
469         if (!ok) {
470                 BKE_report(reports, RPT_ERROR, "Requires selected vertices or active vertex group");
471                 return FALSE;
472         }
473
474         if (mode == OBJECT_ADDHOOK_NEWOB && !ob) {
475                 
476                 ob = add_hook_object_new(scene, obedit);
477                 
478                 /* transform cent to global coords for loc */
479                 mul_v3_m4v3(ob->loc, obedit->obmat, cent);
480         }
481         
482         md = obedit->modifiers.first;
483         while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) {
484                 md = md->next;
485         }
486         
487         hmd = (HookModifierData *) modifier_new(eModifierType_Hook);
488         BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
489         BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name + 2);
490         modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd);
491         
492         hmd->object = ob;
493         hmd->indexar = indexar;
494         copy_v3_v3(hmd->cent, cent);
495         hmd->totindex = tot;
496         BLI_strncpy(hmd->name, name, sizeof(hmd->name));
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                         BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget));
503                 }
504                 else {
505                         BKE_report(reports, RPT_WARNING, "Armature has no active object bone");
506                 }
507         }
508
509         /* matrix calculus */
510         /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
511         /*        (parentinv         )                          */
512         BKE_object_where_is_calc(scene, ob);
513         
514         invert_m4_m4(ob->imat, ob->obmat);
515         /* apparently this call goes from right to left... */
516         mul_serie_m4(hmd->parentinv, ob->imat, obedit->obmat, NULL,
517                      NULL, NULL, NULL, NULL, NULL);
518         
519         DAG_relations_tag_update(bmain);
520
521         return TRUE;
522 }
523
524 static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
525 {
526         Main *bmain = CTX_data_main(C);
527         Scene *scene = CTX_data_scene(C);
528         Object *obedit = CTX_data_edit_object(C);
529         Object *obsel = NULL;
530         const int use_bone = RNA_boolean_get(op->ptr, "use_bone");
531         const int mode = use_bone ? OBJECT_ADDHOOK_SELOB_BONE : OBJECT_ADDHOOK_SELOB;
532         
533         CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
534         {
535                 if (ob != obedit) {
536                         obsel = ob;
537                         break;
538                 }
539         }
540         CTX_DATA_END;
541         
542         if (!obsel) {
543                 BKE_report(op->reports, RPT_ERROR, "Cannot add hook with no other selected objects");
544                 return OPERATOR_CANCELLED;
545         }
546
547         if (use_bone && obsel->type != OB_ARMATURE) {
548                 BKE_report(op->reports, RPT_ERROR, "Cannot add hook bone for a non armature object");
549                 return OPERATOR_CANCELLED;
550         }
551         
552         if (add_hook_object(bmain, scene, obedit, obsel, mode, op->reports)) {
553                 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
554                 return OPERATOR_FINISHED;
555         }
556         else {
557                 return OPERATOR_CANCELLED;
558         }
559 }
560
561 void OBJECT_OT_hook_add_selob(wmOperatorType *ot)
562 {
563         /* identifiers */
564         ot->name = "Hook to Selected Object";
565         ot->description = "Hook selected vertices to the first selected Object";
566         ot->idname = "OBJECT_OT_hook_add_selob";
567         
568         /* api callbacks */
569         ot->exec = object_add_hook_selob_exec;
570         ot->poll = hook_op_edit_poll;
571         
572         /* flags */
573         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
574
575         RNA_def_boolean(ot->srna, "use_bone", FALSE, "Active Bone",
576                         "Assign the hook to the hook objects active bone");
577 }
578
579 static int object_add_hook_newob_exec(bContext *C, wmOperator *op)
580 {
581         Main *bmain = CTX_data_main(C);
582         Scene *scene = CTX_data_scene(C);
583         Object *obedit = CTX_data_edit_object(C);
584
585         if (add_hook_object(bmain, scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) {
586                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
587                 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
588                 return OPERATOR_FINISHED;
589         }
590         else {
591                 return OPERATOR_CANCELLED;
592         }
593 }
594
595 void OBJECT_OT_hook_add_newob(wmOperatorType *ot)
596 {
597         /* identifiers */
598         ot->name = "Hook to New Object";
599         ot->description = "Hook selected vertices to the first selected Object";
600         ot->idname = "OBJECT_OT_hook_add_newob";
601         
602         /* api callbacks */
603         ot->exec = object_add_hook_newob_exec;
604         ot->poll = hook_op_edit_poll;
605         
606         /* flags */
607         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
608 }
609
610 static int object_hook_remove_exec(bContext *C, wmOperator *op)
611 {
612         int num = RNA_enum_get(op->ptr, "modifier");
613         Object *ob = CTX_data_edit_object(C);
614         HookModifierData *hmd = NULL;
615
616         hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
617         if (!hmd) {
618                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
619                 return OPERATOR_CANCELLED;
620         }
621         
622         /* remove functionality */
623         
624         BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
625         modifier_free((ModifierData *)hmd);
626         
627         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
628         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
629         
630         return OPERATOR_FINISHED;
631 }
632
633 static EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
634 {       
635         Object *ob = CTX_data_edit_object(C);
636         EnumPropertyItem tmp = {0, "", 0, "", ""};
637         EnumPropertyItem *item = NULL;
638         ModifierData *md = NULL;
639         int a, totitem = 0;
640         
641         if (!ob)
642                 return DummyRNA_NULL_items;
643         
644         for (a = 0, md = ob->modifiers.first; md; md = md->next, a++) {
645                 if (md->type == eModifierType_Hook) {
646                         tmp.value = a;
647                         tmp.icon = ICON_HOOK;
648                         tmp.identifier = md->name;
649                         tmp.name = md->name;
650                         RNA_enum_item_add(&item, &totitem, &tmp);
651                 }
652         }
653         
654         RNA_enum_item_end(&item, &totitem);
655         *free = 1;
656         
657         return item;
658 }
659
660 void OBJECT_OT_hook_remove(wmOperatorType *ot)
661 {
662         PropertyRNA *prop;
663         
664         /* identifiers */
665         ot->name = "Remove Hook";
666         ot->idname = "OBJECT_OT_hook_remove";
667         ot->description = "Remove a hook from the active object";
668         
669         /* api callbacks */
670         ot->exec = object_hook_remove_exec;
671         ot->invoke = WM_menu_invoke;
672         ot->poll = hook_op_edit_poll;
673         
674         /* flags */
675         /* this operator removes modifier which isn't stored in local undo stack,
676          * so redoing it from redo panel gives totally weird results  */
677         ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
678         
679         /* properties */
680         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
681         RNA_def_enum_funcs(prop, hook_mod_itemf);
682         ot->prop = prop;
683 }
684
685 static int object_hook_reset_exec(bContext *C, wmOperator *op)
686 {
687         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
688         int num = RNA_enum_get(op->ptr, "modifier");
689         Object *ob = NULL;
690         HookModifierData *hmd = NULL;
691
692         object_hook_from_context(C, &ptr, num, &ob, &hmd);
693         if (hmd == NULL) {
694                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
695                 return OPERATOR_CANCELLED;
696         }
697         
698         /* reset functionality */
699         if (hmd->object) {
700                 bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
701                 
702                 if (hmd->subtarget[0] && pchan) {
703                         float imat[4][4], mat[4][4];
704                         
705                         /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
706                         mult_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
707                         
708                         invert_m4_m4(imat, mat);
709                         mul_serie_m4(hmd->parentinv, imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
710                 }
711                 else {
712                         invert_m4_m4(hmd->object->imat, hmd->object->obmat);
713                         mul_serie_m4(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
714                 }
715         }
716         
717         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
718         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
719         
720         return OPERATOR_FINISHED;
721 }
722
723 void OBJECT_OT_hook_reset(wmOperatorType *ot)
724 {
725         PropertyRNA *prop;
726         
727         /* identifiers */
728         ot->name = "Reset Hook";
729         ot->description = "Recalculate and clear offset transformation";
730         ot->idname = "OBJECT_OT_hook_reset";
731         
732         /* callbacks */
733         ot->exec = object_hook_reset_exec;
734         ot->poll = hook_op_edit_poll;
735         
736         /* flags */
737         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
738         
739         /* properties */
740         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
741         RNA_def_enum_funcs(prop, hook_mod_itemf);
742 }
743
744 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
745 {
746         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
747         int num = RNA_enum_get(op->ptr, "modifier");
748         Object *ob = NULL;
749         HookModifierData *hmd = NULL;
750         Scene *scene = CTX_data_scene(C);
751         float bmat[3][3], imat[3][3];
752         
753         object_hook_from_context(C, &ptr, num, &ob, &hmd);
754         if (hmd == NULL) {
755                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
756                 return OPERATOR_CANCELLED;
757         }
758         
759         /* recenter functionality */
760         copy_m3_m4(bmat, ob->obmat);
761         invert_m3_m3(imat, bmat);
762         
763         sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
764         mul_m3_v3(imat, hmd->cent);
765         
766         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
767         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
768         
769         return OPERATOR_FINISHED;
770 }
771
772 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
773 {
774         PropertyRNA *prop;
775         
776         /* identifiers */
777         ot->name = "Recenter Hook";
778         ot->description = "Set hook center to cursor position";
779         ot->idname = "OBJECT_OT_hook_recenter";
780         
781         /* callbacks */
782         ot->exec = object_hook_recenter_exec;
783         ot->poll = hook_op_edit_poll;
784         
785         /* flags */
786         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
787         
788         /* properties */
789         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
790         RNA_def_enum_funcs(prop, hook_mod_itemf);
791 }
792
793 static int object_hook_assign_exec(bContext *C, wmOperator *op)
794 {
795         Scene *scene = CTX_data_scene(C);
796         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
797         int num = RNA_enum_get(op->ptr, "modifier");
798         Object *ob = NULL;
799         HookModifierData *hmd = NULL;
800         float cent[3];
801         char name[MAX_NAME];
802         int *indexar, tot;
803         
804         object_hook_from_context(C, &ptr, num, &ob, &hmd);
805         if (hmd == NULL) {
806                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
807                 return OPERATOR_CANCELLED;
808         }
809         
810         /* assign functionality */
811         
812         if (!object_hook_index_array(scene, ob, &tot, &indexar, name, cent)) {
813                 BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
814                 return OPERATOR_CANCELLED;
815         }
816         if (hmd->indexar)
817                 MEM_freeN(hmd->indexar);
818         
819         copy_v3_v3(hmd->cent, cent);
820         hmd->indexar = indexar;
821         hmd->totindex = tot;
822         
823         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
824         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
825         
826         return OPERATOR_FINISHED;
827 }
828
829 void OBJECT_OT_hook_assign(wmOperatorType *ot)
830 {
831         PropertyRNA *prop;
832         
833         /* identifiers */
834         ot->name = "Assign to Hook";
835         ot->description = "Assign the selected vertices to a hook";
836         ot->idname = "OBJECT_OT_hook_assign";
837         
838         /* callbacks */
839         ot->exec = object_hook_assign_exec;
840         ot->poll = hook_op_edit_poll;
841         
842         /* flags */
843         /* this operator changes data stored in modifier which doesn't get pushed to undo stack,
844          * so redoing it from redo panel gives totally weird results  */
845         ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
846         
847         /* properties */
848         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
849         RNA_def_enum_funcs(prop, hook_mod_itemf);
850 }
851
852 static int object_hook_select_exec(bContext *C, wmOperator *op)
853 {
854         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
855         int num = RNA_enum_get(op->ptr, "modifier");
856         Object *ob = NULL;
857         HookModifierData *hmd = NULL;
858         
859         object_hook_from_context(C, &ptr, num, &ob, &hmd);
860         if (hmd == NULL) {
861                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
862                 return OPERATOR_CANCELLED;
863         }
864         
865         /* select functionality */
866         object_hook_select(ob, hmd);
867         
868         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
869         
870         return OPERATOR_FINISHED;
871 }
872
873 void OBJECT_OT_hook_select(wmOperatorType *ot)
874 {
875         PropertyRNA *prop;
876         
877         /* identifiers */
878         ot->name = "Select Hook";
879         ot->description = "Select affected vertices on mesh";
880         ot->idname = "OBJECT_OT_hook_select";
881         
882         /* callbacks */
883         ot->exec = object_hook_select_exec;
884         ot->poll = hook_op_edit_poll;
885         
886         /* flags */
887         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
888         
889         /* properties */
890         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
891         RNA_def_enum_funcs(prop, hook_mod_itemf);
892 }
893