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