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