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