Big i18n commit: add "reports" from bmesh/readfile/tracking/dynapaint (and a few...
[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, "Cannot 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, "Cannot 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 = CTX_data_edit_object(C);
589         HookModifierData *hmd = NULL;
590
591         hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
592         if (!hmd) {
593                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
594                 return OPERATOR_CANCELLED;
595         }
596         
597         /* remove functionality */
598         
599         BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
600         modifier_free((ModifierData *)hmd);
601         
602         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
603         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
604         
605         return OPERATOR_FINISHED;
606 }
607
608 static EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
609 {       
610         Object *ob = CTX_data_edit_object(C);
611         EnumPropertyItem tmp = {0, "", 0, "", ""};
612         EnumPropertyItem *item = NULL;
613         ModifierData *md = NULL;
614         int a, totitem = 0;
615         
616         if (!ob)
617                 return DummyRNA_NULL_items;
618         
619         for (a = 0, md = ob->modifiers.first; md; md = md->next, a++) {
620                 if (md->type == eModifierType_Hook) {
621                         tmp.value = a;
622                         tmp.icon = ICON_HOOK;
623                         tmp.identifier = md->name;
624                         tmp.name = md->name;
625                         RNA_enum_item_add(&item, &totitem, &tmp);
626                 }
627         }
628         
629         RNA_enum_item_end(&item, &totitem);
630         *free = 1;
631         
632         return item;
633 }
634
635 void OBJECT_OT_hook_remove(wmOperatorType *ot)
636 {
637         PropertyRNA *prop;
638         
639         /* identifiers */
640         ot->name = "Remove Hook";
641         ot->idname = "OBJECT_OT_hook_remove";
642         ot->description = "Remove a hook from the active object";
643         
644         /* api callbacks */
645         ot->exec = object_hook_remove_exec;
646         ot->invoke = WM_menu_invoke;
647         ot->poll = hook_op_edit_poll;
648         
649         /* flags */
650         /* this operator removes modifier which isn't stored in local undo stack,
651          * so redoing it from redo panel gives totally weird results  */
652         ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
653         
654         /* properties */
655         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
656         RNA_def_enum_funcs(prop, hook_mod_itemf);
657         ot->prop = prop;
658 }
659
660 static int object_hook_reset_exec(bContext *C, wmOperator *op)
661 {
662         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
663         int num = RNA_enum_get(op->ptr, "modifier");
664         Object *ob = NULL;
665         HookModifierData *hmd = NULL;
666         
667         if (ptr.data) {     /* if modifier context is available, use that */
668                 ob = ptr.id.data;
669                 hmd = ptr.data;
670         }
671         else {          /* use the provided property */
672                 ob = CTX_data_edit_object(C);
673                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
674         }
675         if (!ob || !hmd) {
676                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
677                 return OPERATOR_CANCELLED;
678         }
679         
680         /* reset functionality */
681         if (hmd->object) {
682                 bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
683                 
684                 if (hmd->subtarget[0] && pchan) {
685                         float imat[4][4], mat[4][4];
686                         
687                         /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
688                         mult_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
689                         
690                         invert_m4_m4(imat, mat);
691                         mul_serie_m4(hmd->parentinv, imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
692                 }
693                 else {
694                         invert_m4_m4(hmd->object->imat, hmd->object->obmat);
695                         mul_serie_m4(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
696                 }
697         }
698         
699         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
700         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
701         
702         return OPERATOR_FINISHED;
703 }
704
705 void OBJECT_OT_hook_reset(wmOperatorType *ot)
706 {
707         PropertyRNA *prop;
708         
709         /* identifiers */
710         ot->name = "Reset Hook";
711         ot->description = "Recalculate and clear offset transformation";
712         ot->idname = "OBJECT_OT_hook_reset";
713         
714         /* callbacks */
715         ot->exec = object_hook_reset_exec;
716         ot->poll = hook_op_edit_poll;
717         
718         /* flags */
719         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
720         
721         /* properties */
722         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
723         RNA_def_enum_funcs(prop, hook_mod_itemf);
724 }
725
726 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
727 {
728         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
729         int num = RNA_enum_get(op->ptr, "modifier");
730         Object *ob = NULL;
731         HookModifierData *hmd = NULL;
732         Scene *scene = CTX_data_scene(C);
733         float bmat[3][3], imat[3][3];
734         
735         if (ptr.data) {  /* if modifier context is available, use that */
736                 ob = ptr.id.data;
737                 hmd = ptr.data;
738         }
739         else {  /* use the provided property */
740                 ob = CTX_data_edit_object(C);
741                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
742         }
743         if (!ob || !hmd) {
744                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
745                 return OPERATOR_CANCELLED;
746         }
747         
748         /* recenter functionality */
749         copy_m3_m4(bmat, ob->obmat);
750         invert_m3_m3(imat, bmat);
751         
752         sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
753         mul_m3_v3(imat, hmd->cent);
754         
755         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
756         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
757         
758         return OPERATOR_FINISHED;
759 }
760
761 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
762 {
763         PropertyRNA *prop;
764         
765         /* identifiers */
766         ot->name = "Recenter Hook";
767         ot->description = "Set hook center to cursor position";
768         ot->idname = "OBJECT_OT_hook_recenter";
769         
770         /* callbacks */
771         ot->exec = object_hook_recenter_exec;
772         ot->poll = hook_op_edit_poll;
773         
774         /* flags */
775         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
776         
777         /* properties */
778         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
779         RNA_def_enum_funcs(prop, hook_mod_itemf);
780 }
781
782 static int object_hook_assign_exec(bContext *C, wmOperator *op)
783 {
784         Scene *scene = CTX_data_scene(C);
785         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
786         int num = RNA_enum_get(op->ptr, "modifier");
787         Object *ob = NULL;
788         HookModifierData *hmd = NULL;
789         float cent[3];
790         char name[MAX_NAME];
791         int *indexar, tot;
792         
793         if (ptr.data) {     /* if modifier context is available, use that */
794                 ob = ptr.id.data;
795                 hmd = ptr.data;
796         }
797         else {          /* use the provided property */
798                 ob = CTX_data_edit_object(C);
799                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
800         }
801         if (!ob || !hmd) {
802                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
803                 return OPERATOR_CANCELLED;
804         }
805         
806         /* assign functionality */
807         
808         if (!object_hook_index_array(scene, ob, &tot, &indexar, name, cent)) {
809                 BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
810                 return OPERATOR_CANCELLED;
811         }
812         if (hmd->indexar)
813                 MEM_freeN(hmd->indexar);
814         
815         copy_v3_v3(hmd->cent, cent);
816         hmd->indexar = indexar;
817         hmd->totindex = tot;
818         
819         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
820         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
821         
822         return OPERATOR_FINISHED;
823 }
824
825 void OBJECT_OT_hook_assign(wmOperatorType *ot)
826 {
827         PropertyRNA *prop;
828         
829         /* identifiers */
830         ot->name = "Assign to Hook";
831         ot->description = "Assign the selected vertices to a hook";
832         ot->idname = "OBJECT_OT_hook_assign";
833         
834         /* callbacks */
835         ot->exec = object_hook_assign_exec;
836         ot->poll = hook_op_edit_poll;
837         
838         /* flags */
839         /* this operator changes data stored in modifier which doesn't get pushed to undo stack,
840          * so redoing it from redo panel gives totally weird results  */
841         ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
842         
843         /* properties */
844         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
845         RNA_def_enum_funcs(prop, hook_mod_itemf);
846 }
847
848 static int object_hook_select_exec(bContext *C, wmOperator *op)
849 {
850         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
851         int num = RNA_enum_get(op->ptr, "modifier");
852         Object *ob = NULL;
853         HookModifierData *hmd = NULL;
854         
855         if (ptr.data) {     /* if modifier context is available, use that */
856                 ob = ptr.id.data;
857                 hmd = ptr.data;
858         }
859         else {          /* use the provided property */
860                 ob = CTX_data_edit_object(C);
861                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
862         }
863         if (!ob || !hmd) {
864                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
865                 return OPERATOR_CANCELLED;
866         }
867         
868         /* select functionality */
869         object_hook_select(ob, hmd);
870         
871         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
872         
873         return OPERATOR_FINISHED;
874 }
875
876 void OBJECT_OT_hook_select(wmOperatorType *ot)
877 {
878         PropertyRNA *prop;
879         
880         /* identifiers */
881         ot->name = "Select Hook";
882         ot->description = "Select affected vertices on mesh";
883         ot->idname = "OBJECT_OT_hook_select";
884         
885         /* callbacks */
886         ot->exec = object_hook_select_exec;
887         ot->poll = hook_op_edit_poll;
888         
889         /* flags */
890         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
891         
892         /* properties */
893         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
894         RNA_def_enum_funcs(prop, hook_mod_itemf);
895 }
896