Math Lib: rename mul_serie_m3 to mul_m3_series & reorder args
[blender-staging.git] / source / blender / editors / object / object_hook.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation, 2002-2008 full recode
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/object/object_hook.c
27  *  \ingroup edobj
28  */
29
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_math.h"
37 #include "BLI_listbase.h"
38 #include "BLI_string.h"
39 #include "BLI_utildefines.h"
40
41 #include "DNA_armature_types.h"
42 #include "DNA_curve_types.h"
43 #include "DNA_lattice_types.h"
44 #include "DNA_mesh_types.h"
45 #include "DNA_meshdata_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_scene_types.h"
48
49 #include "BKE_action.h"
50 #include "BKE_context.h"
51 #include "BKE_depsgraph.h"
52 #include "BKE_main.h"
53 #include "BKE_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_editmesh.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(
76         BMEditMesh *em,
77         int *r_tot, int **r_indexar, float r_cent[3])
78 {
79         BMVert *eve;
80         BMIter iter;
81         int *index, nr, totvert = 0;
82         
83         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
84                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) totvert++;
85         }
86         if (totvert == 0) return 0;
87         
88         *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
89         *r_tot = totvert;
90         nr = 0;
91         zero_v3(r_cent);
92         
93         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
94                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
95                         *index = nr; index++;
96                         add_v3_v3(r_cent, eve->co);
97                 }
98                 nr++;
99         }
100         
101         mul_v3_fl(r_cent, 1.0f / (float)totvert);
102         
103         return totvert;
104 }
105
106 static bool return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *r_name, float r_cent[3])
107 {
108         const int cd_dvert_offset = obedit->actdef ? CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT) : -1;
109
110         zero_v3(r_cent);
111
112         if (cd_dvert_offset != -1) {
113                 const int defgrp_index = obedit->actdef - 1;
114                 int totvert = 0;
115
116                 MDeformVert *dvert;
117                 BMVert *eve;
118                 BMIter iter;
119
120                 /* find the vertices */
121                 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
122                         dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
123
124                         if (defvert_find_weight(dvert, defgrp_index) > 0.0f) {
125                                 add_v3_v3(r_cent, eve->co);
126                                 totvert++;
127                         }
128                 }
129                 if (totvert) {
130                         bDeformGroup *dg = BLI_findlink(&obedit->defbase, defgrp_index);
131                         BLI_strncpy(r_name, dg->name, sizeof(dg->name));
132                         mul_v3_fl(r_cent, 1.0f / (float)totvert);
133                         return true;
134                 }
135         }
136         
137         return false;
138 }       
139
140 static void select_editbmesh_hook(Object *ob, HookModifierData *hmd)
141 {
142         Mesh *me = ob->data;
143         BMEditMesh *em = me->edit_btmesh;
144         BMVert *eve;
145         BMIter iter;
146         int index = 0, nr = 0;
147         
148         if (hmd->indexar == NULL)
149                 return;
150         
151         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
152                 if (nr == hmd->indexar[index]) {
153                         BM_vert_select_set(em->bm, eve, true);
154                         if (index < hmd->totindex - 1) index++;
155                 }
156
157                 nr++;
158         }
159
160         EDBM_select_flush(em);
161 }
162
163 static int return_editlattice_indexar(
164         Lattice *editlatt,
165         int *r_tot, int **r_indexar, float r_cent[3])
166 {
167         BPoint *bp;
168         int *index, nr, totvert = 0, a;
169         
170         /* count */
171         a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
172         bp = editlatt->def;
173         while (a--) {
174                 if (bp->f1 & SELECT) {
175                         if (bp->hide == 0) totvert++;
176                 }
177                 bp++;
178         }
179
180         if (totvert == 0) return 0;
181         
182         *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
183         *r_tot = totvert;
184         nr = 0;
185         zero_v3(r_cent);
186         
187         a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
188         bp = editlatt->def;
189         while (a--) {
190                 if (bp->f1 & SELECT) {
191                         if (bp->hide == 0) {
192                                 *index = nr; index++;
193                                 add_v3_v3(r_cent, bp->vec);
194                         }
195                 }
196                 bp++;
197                 nr++;
198         }
199         
200         mul_v3_fl(r_cent, 1.0f / (float)totvert);
201         
202         return totvert;
203 }
204
205 static void select_editlattice_hook(Object *obedit, HookModifierData *hmd)
206 {
207         Lattice *lt = obedit->data, *editlt;
208         BPoint *bp;
209         int index = 0, nr = 0, a;
210
211         editlt = lt->editlatt->latt;
212         /* count */
213         a = editlt->pntsu * editlt->pntsv * editlt->pntsw;
214         bp = editlt->def;
215         while (a--) {
216                 if (hmd->indexar[index] == nr) {
217                         bp->f1 |= SELECT;
218                         if (index < hmd->totindex - 1) index++;
219                 }
220                 nr++;
221                 bp++;
222         }
223 }
224
225 static int return_editcurve_indexar(
226         Object *obedit,
227         int *r_tot, int **r_indexar, float r_cent[3])
228 {
229         ListBase *editnurb = object_editcurve_get(obedit);
230         Nurb *nu;
231         BPoint *bp;
232         BezTriple *bezt;
233         int *index, a, nr, totvert = 0;
234         
235         for (nu = editnurb->first; nu; nu = nu->next) {
236                 if (nu->type == CU_BEZIER) {
237                         bezt = nu->bezt;
238                         a = nu->pntsu;
239                         while (a--) {
240                                 if (bezt->f1 & SELECT) totvert++;
241                                 if (bezt->f2 & SELECT) totvert++;
242                                 if (bezt->f3 & SELECT) totvert++;
243                                 bezt++;
244                         }
245                 }
246                 else {
247                         bp = nu->bp;
248                         a = nu->pntsu * nu->pntsv;
249                         while (a--) {
250                                 if (bp->f1 & SELECT) totvert++;
251                                 bp++;
252                         }
253                 }
254         }
255         if (totvert == 0) return 0;
256         
257         *r_indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
258         *r_tot = totvert;
259         nr = 0;
260         zero_v3(r_cent);
261         
262         for (nu = editnurb->first; nu; nu = nu->next) {
263                 if (nu->type == CU_BEZIER) {
264                         bezt = nu->bezt;
265                         a = nu->pntsu;
266                         while (a--) {
267                                 if (bezt->f1 & SELECT) {
268                                         *index = nr; index++;
269                                         add_v3_v3(r_cent, bezt->vec[0]);
270                                 }
271                                 nr++;
272                                 if (bezt->f2 & SELECT) {
273                                         *index = nr; index++;
274                                         add_v3_v3(r_cent, bezt->vec[1]);
275                                 }
276                                 nr++;
277                                 if (bezt->f3 & SELECT) {
278                                         *index = nr; index++;
279                                         add_v3_v3(r_cent, bezt->vec[2]);
280                                 }
281                                 nr++;
282                                 bezt++;
283                         }
284                 }
285                 else {
286                         bp = nu->bp;
287                         a = nu->pntsu * nu->pntsv;
288                         while (a--) {
289                                 if (bp->f1 & SELECT) {
290                                         *index = nr; index++;
291                                         add_v3_v3(r_cent, bp->vec);
292                                 }
293                                 nr++;
294                                 bp++;
295                         }
296                 }
297         }
298         
299         mul_v3_fl(r_cent, 1.0f / (float)totvert);
300         
301         return totvert;
302 }
303
304 static bool object_hook_index_array(Scene *scene, Object *obedit,
305                                     int *r_tot, int **r_indexar, char *r_name, float r_cent[3])
306 {
307         *r_indexar = NULL;
308         *r_tot = 0;
309         r_name[0] = 0;
310         
311         switch (obedit->type) {
312                 case OB_MESH:
313                 {
314                         Mesh *me = obedit->data;
315
316                         BMEditMesh *em;
317
318                         EDBM_mesh_load(obedit);
319                         EDBM_mesh_make(scene->toolsettings, obedit);
320
321                         em = me->edit_btmesh;
322
323                         EDBM_mesh_normals_update(em);
324                         BKE_editmesh_tessface_calc(em);
325
326                         /* check selected vertices first */
327                         if (return_editmesh_indexar(em, r_tot, r_indexar, r_cent) == 0) {
328                                 return return_editmesh_vgroup(obedit, em, r_name, r_cent);
329                         }
330                         return true;
331                 }
332                 case OB_CURVE:
333                 case OB_SURF:
334                         load_editNurb(obedit);
335                         make_editNurb(obedit);
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_m4_series(hmd->parentinv, pose_mat, ob->imat, obedit->obmat);
532         
533         DAG_relations_tag_update(bmain);
534
535         return true;
536 }
537
538 static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
539 {
540         Main *bmain = CTX_data_main(C);
541         Scene *scene = CTX_data_scene(C);
542         Object *obedit = CTX_data_edit_object(C);
543         Object *obsel = NULL;
544         const bool use_bone = RNA_boolean_get(op->ptr, "use_bone");
545         const int mode = use_bone ? OBJECT_ADDHOOK_SELOB_BONE : OBJECT_ADDHOOK_SELOB;
546         
547         CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
548         {
549                 if (ob != obedit) {
550                         obsel = ob;
551                         break;
552                 }
553         }
554         CTX_DATA_END;
555         
556         if (!obsel) {
557                 BKE_report(op->reports, RPT_ERROR, "Cannot add hook with no other selected objects");
558                 return OPERATOR_CANCELLED;
559         }
560
561         if (use_bone && obsel->type != OB_ARMATURE) {
562                 BKE_report(op->reports, RPT_ERROR, "Cannot add hook bone for a non armature object");
563                 return OPERATOR_CANCELLED;
564         }
565         
566         if (add_hook_object(bmain, scene, obedit, obsel, mode, op->reports)) {
567                 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
568                 return OPERATOR_FINISHED;
569         }
570         else {
571                 return OPERATOR_CANCELLED;
572         }
573 }
574
575 void OBJECT_OT_hook_add_selob(wmOperatorType *ot)
576 {
577         /* identifiers */
578         ot->name = "Hook to Selected Object";
579         ot->description = "Hook selected vertices to the first selected object";
580         ot->idname = "OBJECT_OT_hook_add_selob";
581         
582         /* api callbacks */
583         ot->exec = object_add_hook_selob_exec;
584         ot->poll = hook_op_edit_poll;
585         
586         /* flags */
587         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
588
589         RNA_def_boolean(ot->srna, "use_bone", false, "Active Bone",
590                         "Assign the hook to the hook objects active bone");
591 }
592
593 static int object_add_hook_newob_exec(bContext *C, wmOperator *op)
594 {
595         Main *bmain = CTX_data_main(C);
596         Scene *scene = CTX_data_scene(C);
597         Object *obedit = CTX_data_edit_object(C);
598
599         if (add_hook_object(bmain, scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) {
600                 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
601                 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
602                 return OPERATOR_FINISHED;
603         }
604         else {
605                 return OPERATOR_CANCELLED;
606         }
607 }
608
609 void OBJECT_OT_hook_add_newob(wmOperatorType *ot)
610 {
611         /* identifiers */
612         ot->name = "Hook to New Object";
613         ot->description = "Hook selected vertices to a newly created object";
614         ot->idname = "OBJECT_OT_hook_add_newob";
615         
616         /* api callbacks */
617         ot->exec = object_add_hook_newob_exec;
618         ot->poll = hook_op_edit_poll;
619         
620         /* flags */
621         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
622 }
623
624 static int object_hook_remove_exec(bContext *C, wmOperator *op)
625 {
626         int num = RNA_enum_get(op->ptr, "modifier");
627         Object *ob = CTX_data_edit_object(C);
628         HookModifierData *hmd = NULL;
629
630         hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
631         if (!hmd) {
632                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
633                 return OPERATOR_CANCELLED;
634         }
635         
636         /* remove functionality */
637         
638         BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
639         modifier_free((ModifierData *)hmd);
640         
641         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
642         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
643         
644         return OPERATOR_FINISHED;
645 }
646
647 static EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
648 {       
649         Object *ob = CTX_data_edit_object(C);
650         EnumPropertyItem tmp = {0, "", 0, "", ""};
651         EnumPropertyItem *item = NULL;
652         ModifierData *md = NULL;
653         int a, totitem = 0;
654         
655         if (!ob)
656                 return DummyRNA_NULL_items;
657         
658         for (a = 0, md = ob->modifiers.first; md; md = md->next, a++) {
659                 if (md->type == eModifierType_Hook) {
660                         tmp.value = a;
661                         tmp.icon = ICON_HOOK;
662                         tmp.identifier = md->name;
663                         tmp.name = md->name;
664                         RNA_enum_item_add(&item, &totitem, &tmp);
665                 }
666         }
667         
668         RNA_enum_item_end(&item, &totitem);
669         *r_free = true;
670         
671         return item;
672 }
673
674 void OBJECT_OT_hook_remove(wmOperatorType *ot)
675 {
676         PropertyRNA *prop;
677         
678         /* identifiers */
679         ot->name = "Remove Hook";
680         ot->idname = "OBJECT_OT_hook_remove";
681         ot->description = "Remove a hook from the active object";
682         
683         /* api callbacks */
684         ot->exec = object_hook_remove_exec;
685         ot->invoke = WM_menu_invoke;
686         ot->poll = hook_op_edit_poll;
687         
688         /* flags */
689         /* this operator removes modifier which isn't stored in local undo stack,
690          * so redoing it from redo panel gives totally weird results  */
691         ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
692         
693         /* properties */
694         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
695         RNA_def_enum_funcs(prop, hook_mod_itemf);
696         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
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         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
741 }
742
743 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
744 {
745         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
746         int num = RNA_enum_get(op->ptr, "modifier");
747         Object *ob = NULL;
748         HookModifierData *hmd = NULL;
749         Scene *scene = CTX_data_scene(C);
750         float bmat[3][3], imat[3][3];
751         
752         object_hook_from_context(C, &ptr, num, &ob, &hmd);
753         if (hmd == NULL) {
754                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
755                 return OPERATOR_CANCELLED;
756         }
757         
758         /* recenter functionality */
759         copy_m3_m4(bmat, ob->obmat);
760         invert_m3_m3(imat, bmat);
761         
762         sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
763         mul_m3_v3(imat, hmd->cent);
764         
765         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
766         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
767         
768         return OPERATOR_FINISHED;
769 }
770
771 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
772 {
773         PropertyRNA *prop;
774         
775         /* identifiers */
776         ot->name = "Recenter Hook";
777         ot->description = "Set hook center to cursor position";
778         ot->idname = "OBJECT_OT_hook_recenter";
779         
780         /* callbacks */
781         ot->exec = object_hook_recenter_exec;
782         ot->poll = hook_op_edit_poll;
783         
784         /* flags */
785         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
786         
787         /* properties */
788         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
789         RNA_def_enum_funcs(prop, hook_mod_itemf);
790         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
791 }
792
793 static int object_hook_assign_exec(bContext *C, wmOperator *op)
794 {
795         Scene *scene = CTX_data_scene(C);
796         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
797         int num = RNA_enum_get(op->ptr, "modifier");
798         Object *ob = NULL;
799         HookModifierData *hmd = NULL;
800         float cent[3];
801         char name[MAX_NAME];
802         int *indexar, tot;
803         
804         object_hook_from_context(C, &ptr, num, &ob, &hmd);
805         if (hmd == NULL) {
806                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
807                 return OPERATOR_CANCELLED;
808         }
809         
810         /* assign functionality */
811         
812         if (!object_hook_index_array(scene, ob, &tot, &indexar, name, cent)) {
813                 BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
814                 return OPERATOR_CANCELLED;
815         }
816         if (hmd->indexar)
817                 MEM_freeN(hmd->indexar);
818         
819         copy_v3_v3(hmd->cent, cent);
820         hmd->indexar = indexar;
821         hmd->totindex = tot;
822         
823         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
824         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
825         
826         return OPERATOR_FINISHED;
827 }
828
829 void OBJECT_OT_hook_assign(wmOperatorType *ot)
830 {
831         PropertyRNA *prop;
832         
833         /* identifiers */
834         ot->name = "Assign to Hook";
835         ot->description = "Assign the selected vertices to a hook";
836         ot->idname = "OBJECT_OT_hook_assign";
837         
838         /* callbacks */
839         ot->exec = object_hook_assign_exec;
840         ot->poll = hook_op_edit_poll;
841         
842         /* flags */
843         /* this operator changes data stored in modifier which doesn't get pushed to undo stack,
844          * so redoing it from redo panel gives totally weird results  */
845         ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
846         
847         /* properties */
848         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
849         RNA_def_enum_funcs(prop, hook_mod_itemf);
850         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
851 }
852
853 static int object_hook_select_exec(bContext *C, wmOperator *op)
854 {
855         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
856         int num = RNA_enum_get(op->ptr, "modifier");
857         Object *ob = NULL;
858         HookModifierData *hmd = NULL;
859         
860         object_hook_from_context(C, &ptr, num, &ob, &hmd);
861         if (hmd == NULL) {
862                 BKE_report(op->reports, RPT_ERROR, "Could not find hook modifier");
863                 return OPERATOR_CANCELLED;
864         }
865         
866         /* select functionality */
867         object_hook_select(ob, hmd);
868         
869         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
870         
871         return OPERATOR_FINISHED;
872 }
873
874 void OBJECT_OT_hook_select(wmOperatorType *ot)
875 {
876         PropertyRNA *prop;
877         
878         /* identifiers */
879         ot->name = "Select Hook";
880         ot->description = "Select affected vertices on mesh";
881         ot->idname = "OBJECT_OT_hook_select";
882         
883         /* callbacks */
884         ot->exec = object_hook_select_exec;
885         ot->poll = hook_op_edit_poll;
886         
887         /* flags */
888         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
889         
890         /* properties */
891         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
892         RNA_def_enum_funcs(prop, hook_mod_itemf);
893         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
894 }
895