Code cleanup: use r_ prefix for return args
[blender.git] / source / blender / editors / object / object_hook.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation, 2002-2008 full recode
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/object/object_hook.c
27  *  \ingroup edobj
28  */
29
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_math.h"
37 #include "BLI_listbase.h"
38 #include "BLI_string.h"
39 #include "BLI_utildefines.h"
40
41 #include "DNA_armature_types.h"
42 #include "DNA_curve_types.h"
43 #include "DNA_lattice_types.h"
44 #include "DNA_mesh_types.h"
45 #include "DNA_meshdata_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_scene_types.h"
48
49 #include "BKE_action.h"
50 #include "BKE_context.h"
51 #include "BKE_depsgraph.h"
52 #include "BKE_main.h"
53 #include "BKE_mesh.h"
54 #include "BKE_modifier.h"
55 #include "BKE_object.h"
56 #include "BKE_report.h"
57 #include "BKE_scene.h"
58 #include "BKE_deform.h"
59 #include "BKE_editmesh.h"
60
61 #include "RNA_define.h"
62 #include "RNA_access.h"
63 #include "RNA_enum_types.h"
64
65 #include "ED_curve.h"
66 #include "ED_mesh.h"
67 #include "ED_screen.h"
68 #include "ED_object.h"
69
70 #include "WM_types.h"
71 #include "WM_api.h"
72
73 #include "UI_resources.h"
74
75 #include "object_intern.h"
76
77 static int return_editmesh_indexar(
78         BMEditMesh *em,
79         int *r_tot, int **r_indexar, float r_cent[3])
80 {
81         BMVert *eve;
82         BMIter iter;
83         int *index, nr, totvert = 0;
84         
85         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
86                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) totvert++;
87         }
88         if (totvert == 0) return 0;
89         
90         *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
91         *r_tot = totvert;
92         nr = 0;
93         zero_v3(r_cent);
94         
95         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
96                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
97                         *index = nr; index++;
98                         add_v3_v3(r_cent, eve->co);
99                 }
100                 nr++;
101         }
102         
103         mul_v3_fl(r_cent, 1.0f / (float)totvert);
104         
105         return totvert;
106 }
107
108 static bool return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *r_name, float r_cent[3])
109 {
110         const int cd_dvert_offset = obedit->actdef ? CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT) : -1;
111
112         zero_v3(r_cent);
113
114         if (cd_dvert_offset != -1) {
115                 const int defgrp_index = obedit->actdef - 1;
116                 int totvert = 0;
117
118                 MDeformVert *dvert;
119                 BMVert *eve;
120                 BMIter iter;
121
122                 /* find the vertices */
123                 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
124                         dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
125
126                         if (defvert_find_weight(dvert, defgrp_index) > 0.0f) {
127                                 add_v3_v3(r_cent, eve->co);
128                                 totvert++;
129                         }
130                 }
131                 if (totvert) {
132                         bDeformGroup *dg = BLI_findlink(&obedit->defbase, defgrp_index);
133                         BLI_strncpy(r_name, dg->name, sizeof(dg->name));
134                         mul_v3_fl(r_cent, 1.0f / (float)totvert);
135                         return true;
136                 }
137         }
138         
139         return false;
140 }       
141
142 static void select_editbmesh_hook(Object *ob, HookModifierData *hmd)
143 {
144         Mesh *me = ob->data;
145         BMEditMesh *em = me->edit_btmesh;
146         BMVert *eve;
147         BMIter iter;
148         int index = 0, nr = 0;
149         
150         if (hmd->indexar == NULL)
151                 return;
152         
153         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
154                 if (nr == hmd->indexar[index]) {
155                         BM_vert_select_set(em->bm, eve, TRUE);
156                         if (index < hmd->totindex - 1) index++;
157                 }
158
159                 nr++;
160         }
161
162         EDBM_select_flush(em);
163 }
164
165 static int return_editlattice_indexar(
166         Lattice *editlatt,
167         int *r_tot, int **r_indexar, float r_cent[3])
168 {
169         BPoint *bp;
170         int *index, nr, totvert = 0, a;
171         
172         /* count */
173         a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
174         bp = editlatt->def;
175         while (a--) {
176                 if (bp->f1 & SELECT) {
177                         if (bp->hide == 0) totvert++;
178                 }
179                 bp++;
180         }
181
182         if (totvert == 0) return 0;
183         
184         *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
185         *r_tot = totvert;
186         nr = 0;
187         zero_v3(r_cent);
188         
189         a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
190         bp = editlatt->def;
191         while (a--) {
192                 if (bp->f1 & SELECT) {
193                         if (bp->hide == 0) {
194                                 *index = nr; index++;
195                                 add_v3_v3(r_cent, bp->vec);
196                         }
197                 }
198                 bp++;
199                 nr++;
200         }
201         
202         mul_v3_fl(r_cent, 1.0f / (float)totvert);
203         
204         return totvert;
205 }
206
207 static void select_editlattice_hook(Object *obedit, HookModifierData *hmd)
208 {
209         Lattice *lt = obedit->data, *editlt;
210         BPoint *bp;
211         int index = 0, nr = 0, a;
212
213         editlt = lt->editlatt->latt;
214         /* count */
215         a = editlt->pntsu * editlt->pntsv * editlt->pntsw;
216         bp = editlt->def;
217         while (a--) {
218                 if (hmd->indexar[index] == nr) {
219                         bp->f1 |= SELECT;
220                         if (index < hmd->totindex - 1) index++;
221                 }
222                 nr++;
223                 bp++;
224         }
225 }
226
227 static int return_editcurve_indexar(
228         Object *obedit,
229         int *r_tot, int **r_indexar, float r_cent[3])
230 {
231         ListBase *editnurb = object_editcurve_get(obedit);
232         Nurb *nu;
233         BPoint *bp;
234         BezTriple *bezt;
235         int *index, a, nr, totvert = 0;
236         
237         for (nu = editnurb->first; nu; nu = nu->next) {
238                 if (nu->type == CU_BEZIER) {
239                         bezt = nu->bezt;
240                         a = nu->pntsu;
241                         while (a--) {
242                                 if (bezt->f1 & SELECT) totvert++;
243                                 if (bezt->f2 & SELECT) totvert++;
244                                 if (bezt->f3 & SELECT) totvert++;
245                                 bezt++;
246                         }
247                 }
248                 else {
249                         bp = nu->bp;
250                         a = nu->pntsu * nu->pntsv;
251                         while (a--) {
252                                 if (bp->f1 & SELECT) totvert++;
253                                 bp++;
254                         }
255                 }
256         }
257         if (totvert == 0) return 0;
258         
259         *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
260         *r_tot = totvert;
261         nr = 0;
262         zero_v3(r_cent);
263         
264         for (nu = editnurb->first; nu; nu = nu->next) {
265                 if (nu->type == CU_BEZIER) {
266                         bezt = nu->bezt;
267                         a = nu->pntsu;
268                         while (a--) {
269                                 if (bezt->f1 & SELECT) {
270                                         *index = nr; index++;
271                                         add_v3_v3(r_cent, bezt->vec[0]);
272                                 }
273                                 nr++;
274                                 if (bezt->f2 & SELECT) {
275                                         *index = nr; index++;
276                                         add_v3_v3(r_cent, bezt->vec[1]);
277                                 }
278                                 nr++;
279                                 if (bezt->f3 & SELECT) {
280                                         *index = nr; index++;
281                                         add_v3_v3(r_cent, bezt->vec[2]);
282                                 }
283                                 nr++;
284                                 bezt++;
285                         }
286                 }
287                 else {
288                         bp = nu->bp;
289                         a = nu->pntsu * nu->pntsv;
290                         while (a--) {
291                                 if (bp->f1 & SELECT) {
292                                         *index = nr; index++;
293                                         add_v3_v3(r_cent, bp->vec);
294                                 }
295                                 nr++;
296                                 bp++;
297                         }
298                 }
299         }
300         
301         mul_v3_fl(r_cent, 1.0f / (float)totvert);
302         
303         return totvert;
304 }
305
306 static bool object_hook_index_array(Scene *scene, Object *obedit,
307                                     int *r_tot, int **r_indexar, char *r_name, float r_cent[3])
308 {
309         *r_indexar = NULL;
310         *r_tot = 0;
311         r_name[0] = 0;
312         
313         switch (obedit->type) {
314                 case OB_MESH:
315                 {
316                         Mesh *me = obedit->data;
317
318                         BMEditMesh *em;
319
320                         EDBM_mesh_load(obedit);
321                         EDBM_mesh_make(scene->toolsettings, obedit);
322
323                         em = me->edit_btmesh;
324
325                         EDBM_mesh_normals_update(em);
326                         BKE_editmesh_tessface_calc(em);
327
328                         /* check selected vertices first */
329                         if (return_editmesh_indexar(em, r_tot, r_indexar, r_cent) == 0) {
330                                 return return_editmesh_vgroup(obedit, em, r_name, r_cent);
331                         }
332                         return true;
333                 }
334                 case OB_CURVE:
335                 case OB_SURF:
336                         return return_editcurve_indexar(obedit, r_tot, r_indexar, r_cent);
337                 case OB_LATTICE:
338                 {
339                         Lattice *lt = obedit->data;
340                         return return_editlattice_indexar(lt->editlatt->latt, r_tot, r_indexar, r_cent);
341                 }
342                 default:
343                         return false;
344         }
345 }
346
347 static void select_editcurve_hook(Object *obedit, HookModifierData *hmd)
348 {
349         ListBase *editnurb = object_editcurve_get(obedit);
350         Nurb *nu;
351         BPoint *bp;
352         BezTriple *bezt;
353         int index = 0, a, nr = 0;
354         
355         for (nu = editnurb->first; nu; nu = nu->next) {
356                 if (nu->type == CU_BEZIER) {
357                         bezt = nu->bezt;
358                         a = nu->pntsu;
359                         while (a--) {
360                                 if (nr == hmd->indexar[index]) {
361                                         bezt->f1 |= SELECT;
362                                         if (index < hmd->totindex - 1) index++;
363                                 }
364                                 nr++;
365                                 if (nr == hmd->indexar[index]) {
366                                         bezt->f2 |= SELECT;
367                                         if (index < hmd->totindex - 1) index++;
368                                 }
369                                 nr++;
370                                 if (nr == hmd->indexar[index]) {
371                                         bezt->f3 |= SELECT;
372                                         if (index < hmd->totindex - 1) index++;
373                                 }
374                                 nr++;
375                                 
376                                 bezt++;
377                         }
378                 }
379                 else {
380                         bp = nu->bp;
381                         a = nu->pntsu * nu->pntsv;
382                         while (a--) {
383                                 if (nr == hmd->indexar[index]) {
384                                         bp->f1 |= SELECT;
385                                         if (index < hmd->totindex - 1) index++;
386                                 }
387                                 nr++;
388                                 bp++;
389                         }
390                 }
391         }
392 }
393
394 static void object_hook_from_context(bContext *C, PointerRNA *ptr, const int num,
395                                      Object **r_ob, HookModifierData **r_hmd)
396 {
397         Object *ob;
398         HookModifierData *hmd;
399
400         if (ptr->data) {  /* if modifier context is available, use that */
401                 ob = ptr->id.data;
402                 hmd = ptr->data;
403         }
404         else {  /* use the provided property */
405                 ob = CTX_data_edit_object(C);
406                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
407         }
408
409         if (ob && hmd && (hmd->modifier.type == eModifierType_Hook)) {
410                 *r_ob = ob;
411                 *r_hmd = hmd;
412         }
413         else {
414                 *r_ob = NULL;
415                 *r_hmd = NULL;
416         }
417 }
418
419 static void object_hook_select(Object *ob, HookModifierData *hmd) 
420 {
421         if (hmd->indexar == NULL)
422                 return;
423         
424         if (ob->type == OB_MESH) select_editbmesh_hook(ob, hmd);
425         else if (ob->type == OB_LATTICE) select_editlattice_hook(ob, hmd);
426         else if (ob->type == OB_CURVE) select_editcurve_hook(ob, hmd);
427         else if (ob->type == OB_SURF) select_editcurve_hook(ob, hmd);
428 }
429
430 /* special poll operators for hook operators */
431 /* TODO: check for properties window modifier context too as alternative? */
432 static int hook_op_edit_poll(bContext *C)
433 {
434         Object *obedit = CTX_data_edit_object(C);
435         
436         if (obedit) {
437                 if (ED_operator_editmesh(C)) return 1;
438                 if (ED_operator_editsurfcurve(C)) return 1;
439                 if (ED_operator_editlattice(C)) return 1;
440                 //if (ED_operator_editmball(C)) return 1;
441         }
442         
443         return 0;
444 }
445
446 static Object *add_hook_object_new(Main *bmain, Scene *scene, Object *obedit)
447 {
448         Base *base, *basedit;
449         Object *ob;
450
451         ob = BKE_object_add(bmain, scene, OB_EMPTY);
452         
453         basedit = BKE_scene_base_find(scene, obedit);
454         base = BKE_scene_base_find(scene, ob);
455         base->lay = ob->lay = obedit->lay;
456         
457         /* icky, BKE_object_add sets new base as active.
458          * so set it back to the original edit object */
459         scene->basact = basedit;
460
461         return ob;
462 }
463
464 static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob, int mode, ReportList *reports)
465 {
466         ModifierData *md = NULL;
467         HookModifierData *hmd = NULL;
468         float cent[3];
469         float pose_mat[4][4];
470         int tot, ok, *indexar;
471         char name[MAX_NAME];
472         
473         ok = object_hook_index_array(scene, obedit, &tot, &indexar, name, cent);
474
475         if (!ok) {
476                 BKE_report(reports, RPT_ERROR, "Requires selected vertices or active vertex group");
477                 return FALSE;
478         }
479
480         if (mode == OBJECT_ADDHOOK_NEWOB && !ob) {
481                 
482                 ob = add_hook_object_new(bmain, scene, obedit);
483                 
484                 /* transform cent to global coords for loc */
485                 mul_v3_m4v3(ob->loc, obedit->obmat, cent);
486         }
487         
488         md = obedit->modifiers.first;
489         while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) {
490                 md = md->next;
491         }
492         
493         hmd = (HookModifierData *) modifier_new(eModifierType_Hook);
494         BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
495         BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name + 2);
496         modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd);
497         
498         hmd->object = ob;
499         hmd->indexar = indexar;
500         copy_v3_v3(hmd->cent, cent);
501         hmd->totindex = tot;
502         BLI_strncpy(hmd->name, name, sizeof(hmd->name));
503         
504         unit_m4(pose_mat);
505
506         if (mode == OBJECT_ADDHOOK_SELOB_BONE) {
507                 bArmature *arm = ob->data;
508                 BLI_assert(ob->type == OB_ARMATURE);
509                 if (arm->act_bone) {
510                         bPoseChannel *pchan_act;
511
512                         BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget));
513
514                         pchan_act = BKE_pose_channel_active(ob);
515                         if (LIKELY(pchan_act)) {
516                                 invert_m4_m4(pose_mat, pchan_act->pose_mat);
517                         }
518                 }
519                 else {
520                         BKE_report(reports, RPT_WARNING, "Armature has no active object bone");
521                 }
522         }
523
524         /* matrix calculus */
525         /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
526         /*        (parentinv         )                          */
527         BKE_object_where_is_calc(scene, ob);
528         
529         invert_m4_m4(ob->imat, ob->obmat);
530         /* apparently this call goes from right to left... */
531         mul_serie_m4(hmd->parentinv, pose_mat, ob->imat, obedit->obmat,
532                      NULL, NULL, NULL, NULL, NULL);
533         
534         DAG_relations_tag_update(bmain);
535
536         return TRUE;
537 }
538
539 static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
540 {
541         Main *bmain = CTX_data_main(C);
542         Scene *scene = CTX_data_scene(C);
543         Object *obedit = CTX_data_edit_object(C);
544         Object *obsel = NULL;
545         const int use_bone = RNA_boolean_get(op->ptr, "use_bone");
546         const int mode = use_bone ? OBJECT_ADDHOOK_SELOB_BONE : OBJECT_ADDHOOK_SELOB;
547         
548         CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
549         {
550                 if (ob != obedit) {
551                         obsel = ob;
552                         break;
553                 }
554         }
555         CTX_DATA_END;
556         
557         if (!obsel) {
558                 BKE_report(op->reports, RPT_ERROR, "Cannot add hook with no other selected objects");
559                 return OPERATOR_CANCELLED;
560         }
561
562         if (use_bone && obsel->type != OB_ARMATURE) {
563                 BKE_report(op->reports, RPT_ERROR, "Cannot add hook bone for a non armature object");
564                 return OPERATOR_CANCELLED;
565         }
566         
567         if (add_hook_object(bmain, scene, obedit, obsel, mode, op->reports)) {
568                 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
569                 return OPERATOR_FINISHED;
570         }
571         else {
572                 return OPERATOR_CANCELLED;
573         }
574 }
575
576 void OBJECT_OT_hook_add_selob(wmOperatorType *ot)
577 {
578         /* identifiers */
579         ot->name = "Hook to Selected Object";
580         ot->description = "Hook selected vertices to the first selected object";
581         ot->idname = "OBJECT_OT_hook_add_selob";
582         
583         /* api callbacks */
584         ot->exec = object_add_hook_selob_exec;
585         ot->poll = hook_op_edit_poll;
586         
587         /* flags */
588         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
589
590         RNA_def_boolean(ot->srna, "use_bone", FALSE, "Active Bone",
591                         "Assign the hook to the hook objects active bone");
592 }
593
594 static int object_add_hook_newob_exec(bContext *C, wmOperator *op)
595 {
596         Main *bmain = CTX_data_main(C);
597         Scene *scene = CTX_data_scene(C);
598         Object *obedit = CTX_data_edit_object(C);
599
600         if (add_hook_object(bmain, scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) {
601                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
602                 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
603                 return OPERATOR_FINISHED;
604         }
605         else {
606                 return OPERATOR_CANCELLED;
607         }
608 }
609
610 void OBJECT_OT_hook_add_newob(wmOperatorType *ot)
611 {
612         /* identifiers */
613         ot->name = "Hook to New Object";
614         ot->description = "Hook selected vertices to a newly created object";
615         ot->idname = "OBJECT_OT_hook_add_newob";
616         
617         /* api callbacks */
618         ot->exec = object_add_hook_newob_exec;
619         ot->poll = hook_op_edit_poll;
620         
621         /* flags */
622         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
623 }
624
625 static int object_hook_remove_exec(bContext *C, wmOperator *op)
626 {
627         int num = RNA_enum_get(op->ptr, "modifier");
628         Object *ob = CTX_data_edit_object(C);
629         HookModifierData *hmd = NULL;
630
631         hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
632         if (!hmd) {
633                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
634                 return OPERATOR_CANCELLED;
635         }
636         
637         /* remove functionality */
638         
639         BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
640         modifier_free((ModifierData *)hmd);
641         
642         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
643         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
644         
645         return OPERATOR_FINISHED;
646 }
647
648 static EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
649 {       
650         Object *ob = CTX_data_edit_object(C);
651         EnumPropertyItem tmp = {0, "", 0, "", ""};
652         EnumPropertyItem *item = NULL;
653         ModifierData *md = NULL;
654         int a, totitem = 0;
655         
656         if (!ob)
657                 return DummyRNA_NULL_items;
658         
659         for (a = 0, md = ob->modifiers.first; md; md = md->next, a++) {
660                 if (md->type == eModifierType_Hook) {
661                         tmp.value = a;
662                         tmp.icon = ICON_HOOK;
663                         tmp.identifier = md->name;
664                         tmp.name = md->name;
665                         RNA_enum_item_add(&item, &totitem, &tmp);
666                 }
667         }
668         
669         RNA_enum_item_end(&item, &totitem);
670         *r_free = true;
671         
672         return item;
673 }
674
675 void OBJECT_OT_hook_remove(wmOperatorType *ot)
676 {
677         PropertyRNA *prop;
678         
679         /* identifiers */
680         ot->name = "Remove Hook";
681         ot->idname = "OBJECT_OT_hook_remove";
682         ot->description = "Remove a hook from the active object";
683         
684         /* api callbacks */
685         ot->exec = object_hook_remove_exec;
686         ot->invoke = WM_menu_invoke;
687         ot->poll = hook_op_edit_poll;
688         
689         /* flags */
690         /* this operator removes modifier which isn't stored in local undo stack,
691          * so redoing it from redo panel gives totally weird results  */
692         ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
693         
694         /* properties */
695         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
696         RNA_def_enum_funcs(prop, hook_mod_itemf);
697         ot->prop = prop;
698 }
699
700 static int object_hook_reset_exec(bContext *C, wmOperator *op)
701 {
702         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
703         int num = RNA_enum_get(op->ptr, "modifier");
704         Object *ob = NULL;
705         HookModifierData *hmd = NULL;
706
707         object_hook_from_context(C, &ptr, num, &ob, &hmd);
708         if (hmd == NULL) {
709                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
710                 return OPERATOR_CANCELLED;
711         }
712
713         BKE_object_modifier_hook_reset(ob, hmd);
714
715         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
716         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
717         
718         return OPERATOR_FINISHED;
719 }
720
721 void OBJECT_OT_hook_reset(wmOperatorType *ot)
722 {
723         PropertyRNA *prop;
724         
725         /* identifiers */
726         ot->name = "Reset Hook";
727         ot->description = "Recalculate and clear offset transformation";
728         ot->idname = "OBJECT_OT_hook_reset";
729         
730         /* callbacks */
731         ot->exec = object_hook_reset_exec;
732         ot->poll = hook_op_edit_poll;
733         
734         /* flags */
735         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
736         
737         /* properties */
738         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
739         RNA_def_enum_funcs(prop, hook_mod_itemf);
740 }
741
742 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
743 {
744         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
745         int num = RNA_enum_get(op->ptr, "modifier");
746         Object *ob = NULL;
747         HookModifierData *hmd = NULL;
748         Scene *scene = CTX_data_scene(C);
749         float bmat[3][3], imat[3][3];
750         
751         object_hook_from_context(C, &ptr, num, &ob, &hmd);
752         if (hmd == NULL) {
753                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
754                 return OPERATOR_CANCELLED;
755         }
756         
757         /* recenter functionality */
758         copy_m3_m4(bmat, ob->obmat);
759         invert_m3_m3(imat, bmat);
760         
761         sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
762         mul_m3_v3(imat, hmd->cent);
763         
764         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
765         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
766         
767         return OPERATOR_FINISHED;
768 }
769
770 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
771 {
772         PropertyRNA *prop;
773         
774         /* identifiers */
775         ot->name = "Recenter Hook";
776         ot->description = "Set hook center to cursor position";
777         ot->idname = "OBJECT_OT_hook_recenter";
778         
779         /* callbacks */
780         ot->exec = object_hook_recenter_exec;
781         ot->poll = hook_op_edit_poll;
782         
783         /* flags */
784         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
785         
786         /* properties */
787         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
788         RNA_def_enum_funcs(prop, hook_mod_itemf);
789 }
790
791 static int object_hook_assign_exec(bContext *C, wmOperator *op)
792 {
793         Scene *scene = CTX_data_scene(C);
794         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
795         int num = RNA_enum_get(op->ptr, "modifier");
796         Object *ob = NULL;
797         HookModifierData *hmd = NULL;
798         float cent[3];
799         char name[MAX_NAME];
800         int *indexar, tot;
801         
802         object_hook_from_context(C, &ptr, num, &ob, &hmd);
803         if (hmd == NULL) {
804                 BKE_report(op->reports, RPT_ERROR, "Could not 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         object_hook_from_context(C, &ptr, num, &ob, &hmd);
858         if (hmd == NULL) {
859                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
860                 return OPERATOR_CANCELLED;
861         }
862         
863         /* select functionality */
864         object_hook_select(ob, hmd);
865         
866         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
867         
868         return OPERATOR_FINISHED;
869 }
870
871 void OBJECT_OT_hook_select(wmOperatorType *ot)
872 {
873         PropertyRNA *prop;
874         
875         /* identifiers */
876         ot->name = "Select Hook";
877         ot->description = "Select affected vertices on mesh";
878         ot->idname = "OBJECT_OT_hook_select";
879         
880         /* callbacks */
881         ot->exec = object_hook_select_exec;
882         ot->poll = hook_op_edit_poll;
883         
884         /* flags */
885         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
886         
887         /* properties */
888         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
889         RNA_def_enum_funcs(prop, hook_mod_itemf);
890 }
891