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