svn merge ^/trunk/blender -r46300:46330
[blender.git] / source / blender / editors / object / object_hook.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation, 2002-2008 full recode
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/object/object_hook.c
27  *  \ingroup edobj
28  */
29
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_math.h"
37 #include "BLI_listbase.h"
38 #include "BLI_string.h"
39 #include "BLI_utildefines.h"
40
41 #include "DNA_curve_types.h"
42 #include "DNA_lattice_types.h"
43 #include "DNA_mesh_types.h"
44 #include "DNA_meshdata_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_scene_types.h"
47
48 #include "BKE_action.h"
49 #include "BKE_context.h"
50 #include "BKE_depsgraph.h"
51 #include "BKE_main.h"
52 #include "BKE_mesh.h"
53 #include "BKE_modifier.h"
54 #include "BKE_object.h"
55 #include "BKE_report.h"
56 #include "BKE_scene.h"
57 #include "BKE_deform.h"
58 #include "BKE_tessmesh.h"
59
60 #include "RNA_define.h"
61 #include "RNA_access.h"
62 #include "RNA_enum_types.h"
63
64 #include "ED_curve.h"
65 #include "ED_mesh.h"
66 #include "ED_screen.h"
67
68 #include "WM_types.h"
69 #include "WM_api.h"
70
71 #include "UI_resources.h"
72
73 #include "object_intern.h"
74
75 static int return_editmesh_indexar(BMEditMesh *em, int *tot, int **indexar, float *cent)
76 {
77         BMVert *eve;
78         BMIter iter;
79         int *index, nr, totvert = 0;
80         
81         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
82                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) totvert++;
83         }
84         if (totvert == 0) return 0;
85         
86         *indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
87         *tot = totvert;
88         nr = 0;
89         zero_v3(cent);
90         
91         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
92                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
93                         *index = nr; index++;
94                         add_v3_v3(cent, eve->co);
95                 }
96                 nr++;
97         }
98         
99         mul_v3_fl(cent, 1.0f / (float)totvert);
100         
101         return totvert;
102 }
103
104 static int return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *name, float *cent)
105 {
106         zero_v3(cent);
107
108         if (obedit->actdef) {
109                 const int defgrp_index = obedit->actdef - 1;
110                 int totvert = 0;
111
112                 MDeformVert *dvert;
113                 BMVert *eve;
114                 BMIter iter;
115
116                 /* find the vertices */
117                 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
118                         dvert = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
119
120                         if (dvert) {
121                                 if (defvert_find_weight(dvert, defgrp_index) > 0.0f) {
122                                         add_v3_v3(cent, eve->co);
123                                         totvert++;
124                                 }
125                         }
126                 }
127                 if (totvert) {
128                         bDeformGroup *dg = BLI_findlink(&obedit->defbase, defgrp_index);
129                         BLI_strncpy(name, dg->name, sizeof(dg->name));
130                         mul_v3_fl(cent, 1.0f / (float)totvert);
131                         return 1;
132                 }
133         }
134         
135         return 0;
136 }       
137
138 static void select_editbmesh_hook(Object *ob, HookModifierData *hmd)
139 {
140         Mesh *me = ob->data;
141         BMEditMesh *em = me->edit_btmesh;
142         BMVert *eve;
143         BMIter iter;
144         int index = 0, nr = 0;
145         
146         if (hmd->indexar == NULL)
147                 return;
148         
149         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
150                 if (nr == hmd->indexar[index]) {
151                         BM_vert_select_set(em->bm, eve, TRUE);
152                         if (index < hmd->totindex - 1) index++;
153                 }
154
155                 nr++;
156         }
157
158         EDBM_select_flush(em);
159 }
160
161 static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent)
162 {
163         BPoint *bp;
164         int *index, nr, totvert = 0, a;
165         
166         /* count */
167         a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
168         bp = editlatt->def;
169         while (a--) {
170                 if (bp->f1 & SELECT) {
171                         if (bp->hide == 0) totvert++;
172                 }
173                 bp++;
174         }
175
176         if (totvert == 0) return 0;
177         
178         *indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
179         *tot = totvert;
180         nr = 0;
181         zero_v3(cent);
182         
183         a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
184         bp = editlatt->def;
185         while (a--) {
186                 if (bp->f1 & SELECT) {
187                         if (bp->hide == 0) {
188                                 *index = nr; index++;
189                                 add_v3_v3(cent, bp->vec);
190                         }
191                 }
192                 bp++;
193                 nr++;
194         }
195         
196         mul_v3_fl(cent, 1.0f / (float)totvert);
197         
198         return totvert;
199 }
200
201 static void select_editlattice_hook(Object *obedit, HookModifierData *hmd)
202 {
203         Lattice *lt = obedit->data, *editlt;
204         BPoint *bp;
205         int index = 0, nr = 0, a;
206
207         editlt = lt->editlatt->latt;
208         /* count */
209         a = editlt->pntsu * editlt->pntsv * editlt->pntsw;
210         bp = editlt->def;
211         while (a--) {
212                 if (hmd->indexar[index] == nr) {
213                         bp->f1 |= SELECT;
214                         if (index < hmd->totindex - 1) index++;
215                 }
216                 nr++;
217                 bp++;
218         }
219 }
220
221 static int return_editcurve_indexar(Object *obedit, int *tot, int **indexar, float *cent)
222 {
223         ListBase *editnurb = object_editcurve_get(obedit);
224         Nurb *nu;
225         BPoint *bp;
226         BezTriple *bezt;
227         int *index, a, nr, totvert = 0;
228         
229         for (nu = editnurb->first; nu; nu = nu->next) {
230                 if (nu->type == CU_BEZIER) {
231                         bezt = nu->bezt;
232                         a = nu->pntsu;
233                         while (a--) {
234                                 if (bezt->f1 & SELECT) totvert++;
235                                 if (bezt->f2 & SELECT) totvert++;
236                                 if (bezt->f3 & SELECT) totvert++;
237                                 bezt++;
238                         }
239                 }
240                 else {
241                         bp = nu->bp;
242                         a = nu->pntsu * nu->pntsv;
243                         while (a--) {
244                                 if (bp->f1 & SELECT) totvert++;
245                                 bp++;
246                         }
247                 }
248         }
249         if (totvert == 0) return 0;
250         
251         *indexar = index = MEM_mallocN(4 * totvert, "hook indexar");
252         *tot = totvert;
253         nr = 0;
254         zero_v3(cent);
255         
256         for (nu = editnurb->first; nu; nu = nu->next) {
257                 if (nu->type == CU_BEZIER) {
258                         bezt = nu->bezt;
259                         a = nu->pntsu;
260                         while (a--) {
261                                 if (bezt->f1 & SELECT) {
262                                         *index = nr; index++;
263                                         add_v3_v3(cent, bezt->vec[0]);
264                                 }
265                                 nr++;
266                                 if (bezt->f2 & SELECT) {
267                                         *index = nr; index++;
268                                         add_v3_v3(cent, bezt->vec[1]);
269                                 }
270                                 nr++;
271                                 if (bezt->f3 & SELECT) {
272                                         *index = nr; index++;
273                                         add_v3_v3(cent, bezt->vec[2]);
274                                 }
275                                 nr++;
276                                 bezt++;
277                         }
278                 }
279                 else {
280                         bp = nu->bp;
281                         a = nu->pntsu * nu->pntsv;
282                         while (a--) {
283                                 if (bp->f1 & SELECT) {
284                                         *index = nr; index++;
285                                         add_v3_v3(cent, bp->vec);
286                                 }
287                                 nr++;
288                                 bp++;
289                         }
290                 }
291         }
292         
293         mul_v3_fl(cent, 1.0f / (float)totvert);
294         
295         return totvert;
296 }
297
298 static int object_hook_index_array(Scene *scene, Object *obedit, int *tot, int **indexar, char *name, float *cent_r)
299 {
300         *indexar = NULL;
301         *tot = 0;
302         name[0] = 0;
303         
304         switch (obedit->type) {
305                 case OB_MESH:
306                 {
307                         Mesh *me = obedit->data;
308
309                         BMEditMesh *em;
310
311                         EDBM_mesh_load(obedit);
312                         EDBM_mesh_make(scene->toolsettings, scene, obedit);
313
314                         em = me->edit_btmesh;
315
316                         /* 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 = BKE_object_add(scene, OB_EMPTY);
418         
419         basedit = BKE_scene_base_find(scene, obedit);
420         base = BKE_scene_base_find(scene, ob);
421         base->lay = ob->lay = obedit->lay;
422         
423         /* icky, BKE_object_add 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         BKE_object_where_is_calc(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         {
488                 if (ob != obedit) {
489                         obsel = ob;
490                         break;
491                 }
492         }
493         CTX_DATA_END;
494         
495         if (!obsel) {
496                 BKE_report(op->reports, RPT_ERROR, "Can't add hook with no other selected objects");
497                 return OPERATOR_CANCELLED;
498         }
499         
500         add_hook_object(bmain, scene, obedit, obsel, OBJECT_ADDHOOK_SELOB);
501         
502         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
503         return OPERATOR_FINISHED;
504 }
505
506 void OBJECT_OT_hook_add_selobj(wmOperatorType *ot)
507 {
508         /* identifiers */
509         ot->name = "Hook to Selected Object";
510         ot->description = "Hook selected vertices to the first selected Object";
511         ot->idname = "OBJECT_OT_hook_add_selob";
512         
513         /* api callbacks */
514         ot->exec = object_add_hook_selob_exec;
515         ot->poll = hook_op_edit_poll;
516         
517         /* flags */
518         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
519 }
520
521 static int object_add_hook_newob_exec(bContext *C, wmOperator *UNUSED(op))
522 {
523         Main *bmain = CTX_data_main(C);
524         Scene *scene = CTX_data_scene(C);
525         Object *obedit = CTX_data_edit_object(C);
526
527         add_hook_object(bmain, scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB);
528         
529         WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
530         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
531         return OPERATOR_FINISHED;
532 }
533
534 void OBJECT_OT_hook_add_newobj(wmOperatorType *ot)
535 {
536         /* identifiers */
537         ot->name = "Hook to New Object";
538         ot->description = "Hook selected vertices to the first selected Object";
539         ot->idname = "OBJECT_OT_hook_add_newob";
540         
541         /* api callbacks */
542         ot->exec = object_add_hook_newob_exec;
543         ot->poll = hook_op_edit_poll;
544         
545         /* flags */
546         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
547 }
548
549 static int object_hook_remove_exec(bContext *C, wmOperator *op)
550 {
551         int num = RNA_enum_get(op->ptr, "modifier");
552         Object *ob = NULL;
553         HookModifierData *hmd = NULL;
554
555         ob = CTX_data_edit_object(C);
556         hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
557
558         if (!ob || !hmd) {
559                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
560                 return OPERATOR_CANCELLED;
561         }
562         
563         /* remove functionality */
564         
565         BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
566         modifier_free((ModifierData *)hmd);
567         
568         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
569         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
570         
571         return OPERATOR_FINISHED;
572 }
573
574 static EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
575 {       
576         Object *ob = CTX_data_edit_object(C);
577         EnumPropertyItem tmp = {0, "", 0, "", ""};
578         EnumPropertyItem *item = NULL;
579         ModifierData *md = NULL;
580         int a, totitem = 0;
581         
582         if (!ob)
583                 return DummyRNA_NULL_items;
584         
585         for (a = 0, md = ob->modifiers.first; md; md = md->next, a++) {
586                 if (md->type == eModifierType_Hook) {
587                         tmp.value = a;
588                         tmp.icon = ICON_HOOK;
589                         tmp.identifier = md->name;
590                         tmp.name = md->name;
591                         RNA_enum_item_add(&item, &totitem, &tmp);
592                 }
593         }
594         
595         RNA_enum_item_end(&item, &totitem);
596         *free = 1;
597         
598         return item;
599 }
600
601 void OBJECT_OT_hook_remove(wmOperatorType *ot)
602 {
603         PropertyRNA *prop;
604         
605         /* identifiers */
606         ot->name = "Remove Hook";
607         ot->idname = "OBJECT_OT_hook_remove";
608         ot->description = "Remove a hook from the active object";
609         
610         /* api callbacks */
611         ot->exec = object_hook_remove_exec;
612         ot->invoke = WM_menu_invoke;
613         ot->poll = hook_op_edit_poll;
614         
615         /* flags */
616         /* this operator removes modifier which isn't stored in local undo stack,
617          * so redoing it from redo panel gives totally weird results  */
618         ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
619         
620         /* properties */
621         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
622         RNA_def_enum_funcs(prop, hook_mod_itemf);
623         ot->prop = prop;
624 }
625
626 static int object_hook_reset_exec(bContext *C, wmOperator *op)
627 {
628         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
629         int num = RNA_enum_get(op->ptr, "modifier");
630         Object *ob = NULL;
631         HookModifierData *hmd = NULL;
632         
633         if (ptr.data) {     /* if modifier context is available, use that */
634                 ob = ptr.id.data;
635                 hmd = ptr.data;
636         } 
637         else {          /* use the provided property */
638                 ob = CTX_data_edit_object(C);
639                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
640         }
641         if (!ob || !hmd) {
642                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
643                 return OPERATOR_CANCELLED;
644         }
645         
646         /* reset functionality */
647         if (hmd->object) {
648                 bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
649                 
650                 if (hmd->subtarget[0] && pchan) {
651                         float imat[4][4], mat[4][4];
652                         
653                         /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
654                         mult_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
655                         
656                         invert_m4_m4(imat, mat);
657                         mul_serie_m4(hmd->parentinv, imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
658                 }
659                 else {
660                         invert_m4_m4(hmd->object->imat, hmd->object->obmat);
661                         mul_serie_m4(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
662                 }
663         }
664         
665         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
666         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
667         
668         return OPERATOR_FINISHED;
669 }
670
671 void OBJECT_OT_hook_reset(wmOperatorType *ot)
672 {
673         PropertyRNA *prop;
674         
675         /* identifiers */
676         ot->name = "Reset Hook";
677         ot->description = "Recalculate and clear offset transformation";
678         ot->idname = "OBJECT_OT_hook_reset";
679         
680         /* callbacks */
681         ot->exec = object_hook_reset_exec;
682         ot->poll = hook_op_edit_poll;
683         
684         /* flags */
685         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
686         
687         /* properties */
688         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
689         RNA_def_enum_funcs(prop, hook_mod_itemf);
690 }
691
692 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
693 {
694         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
695         int num = RNA_enum_get(op->ptr, "modifier");
696         Object *ob = NULL;
697         HookModifierData *hmd = NULL;
698         Scene *scene = CTX_data_scene(C);
699         float bmat[3][3], imat[3][3];
700         
701         if (ptr.data) {  /* if modifier context is available, use that */
702                 ob = ptr.id.data;
703                 hmd = ptr.data;
704         } 
705         else {  /* use the provided property */
706                 ob = CTX_data_edit_object(C);
707                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
708         }
709         if (!ob || !hmd) {
710                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
711                 return OPERATOR_CANCELLED;
712         }
713         
714         /* recenter functionality */
715         copy_m3_m4(bmat, ob->obmat);
716         invert_m3_m3(imat, bmat);
717         
718         sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
719         mul_m3_v3(imat, hmd->cent);
720         
721         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
722         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
723         
724         return OPERATOR_FINISHED;
725 }
726
727 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
728 {
729         PropertyRNA *prop;
730         
731         /* identifiers */
732         ot->name = "Recenter Hook";
733         ot->description = "Set hook center to cursor position";
734         ot->idname = "OBJECT_OT_hook_recenter";
735         
736         /* callbacks */
737         ot->exec = object_hook_recenter_exec;
738         ot->poll = hook_op_edit_poll;
739         
740         /* flags */
741         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
742         
743         /* properties */
744         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
745         RNA_def_enum_funcs(prop, hook_mod_itemf);
746 }
747
748 static int object_hook_assign_exec(bContext *C, wmOperator *op)
749 {
750         Scene *scene = CTX_data_scene(C);
751         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
752         int num = RNA_enum_get(op->ptr, "modifier");
753         Object *ob = NULL;
754         HookModifierData *hmd = NULL;
755         float cent[3];
756         char name[MAX_NAME];
757         int *indexar, tot;
758         
759         if (ptr.data) {     /* if modifier context is available, use that */
760                 ob = ptr.id.data;
761                 hmd = ptr.data;
762         } 
763         else {          /* use the provided property */
764                 ob = CTX_data_edit_object(C);
765                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
766         }
767         if (!ob || !hmd) {
768                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
769                 return OPERATOR_CANCELLED;
770         }
771         
772         /* assign functionality */
773         
774         if (!object_hook_index_array(scene, ob, &tot, &indexar, name, cent)) {
775                 BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
776                 return OPERATOR_CANCELLED;
777         }
778         if (hmd->indexar)
779                 MEM_freeN(hmd->indexar);
780         
781         copy_v3_v3(hmd->cent, cent);
782         hmd->indexar = indexar;
783         hmd->totindex = tot;
784         
785         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
786         WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
787         
788         return OPERATOR_FINISHED;
789 }
790
791 void OBJECT_OT_hook_assign(wmOperatorType *ot)
792 {
793         PropertyRNA *prop;
794         
795         /* identifiers */
796         ot->name = "Assign to Hook";
797         ot->description = "Assign the selected vertices to a hook";
798         ot->idname = "OBJECT_OT_hook_assign";
799         
800         /* callbacks */
801         ot->exec = object_hook_assign_exec;
802         ot->poll = hook_op_edit_poll;
803         
804         /* flags */
805         /* this operator changes data stored in modifier which doesn't get pushed to undo stack,
806          * so redoing it from redo panel gives totally weird results  */
807         ot->flag = /*OPTYPE_REGISTER|*/ OPTYPE_UNDO;
808         
809         /* properties */
810         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
811         RNA_def_enum_funcs(prop, hook_mod_itemf);
812 }
813
814 static int object_hook_select_exec(bContext *C, wmOperator *op)
815 {
816         PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
817         int num = RNA_enum_get(op->ptr, "modifier");
818         Object *ob = NULL;
819         HookModifierData *hmd = NULL;
820         
821         if (ptr.data) {     /* if modifier context is available, use that */
822                 ob = ptr.id.data;
823                 hmd = ptr.data;
824         } 
825         else {          /* use the provided property */
826                 ob = CTX_data_edit_object(C);
827                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
828         }
829         if (!ob || !hmd) {
830                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
831                 return OPERATOR_CANCELLED;
832         }
833         
834         /* select functionality */
835         object_hook_select(ob, hmd);
836         
837         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
838         
839         return OPERATOR_FINISHED;
840 }
841
842 void OBJECT_OT_hook_select(wmOperatorType *ot)
843 {
844         PropertyRNA *prop;
845         
846         /* identifiers */
847         ot->name = "Select Hook";
848         ot->description = "Select affected vertices on mesh";
849         ot->idname = "OBJECT_OT_hook_select";
850         
851         /* callbacks */
852         ot->exec = object_hook_select_exec;
853         ot->poll = hook_op_edit_poll;
854         
855         /* flags */
856         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
857         
858         /* properties */
859         prop = RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
860         RNA_def_enum_funcs(prop, hook_mod_itemf);
861 }
862