Logic UI and Operators: adjusts on Layout + copy properties operator + fix on copy...
[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_customdata.h"
47 #include "BKE_depsgraph.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 #include "BKE_utildefines.h"
54
55 #include "RNA_define.h"
56 #include "RNA_access.h"
57 #include "RNA_enum_types.h"
58
59 #include "ED_curve.h"
60 #include "ED_mesh.h"
61 #include "ED_screen.h"
62
63 #include "WM_types.h"
64 #include "WM_api.h"
65
66 #include "UI_resources.h"
67
68 #include "object_intern.h"
69
70 static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float *cent)
71 {
72         EditVert *eve;
73         int *index, nr, totvert=0;
74         
75         for(eve= em->verts.first; eve; eve= eve->next) {
76                 if(eve->f & SELECT) totvert++;
77         }
78         if(totvert==0) return 0;
79         
80         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
81         *tot= totvert;
82         nr= 0;
83         cent[0]= cent[1]= cent[2]= 0.0;
84         
85         for(eve= em->verts.first; eve; eve= eve->next) {
86                 if(eve->f & SELECT) {
87                         *index= nr; index++;
88                         add_v3_v3(cent, eve->co);
89                 }
90                 nr++;
91         }
92         
93         mul_v3_fl(cent, 1.0f/(float)totvert);
94         
95         return totvert;
96 }
97
98 static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, float *cent)
99 {
100         MDeformVert *dvert;
101         EditVert *eve;
102         int i, totvert=0;
103         
104         cent[0]= cent[1]= cent[2]= 0.0;
105         
106         if(obedit->actdef) {
107                 
108                 /* find the vertices */
109                 for(eve= em->verts.first; eve; eve= eve->next) {
110                         dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
111
112                         if(dvert) {
113                                 for(i=0; i<dvert->totweight; i++){
114                                         if(dvert->dw[i].def_nr == (obedit->actdef-1)) {
115                                                 totvert++;
116                                                 add_v3_v3(cent, eve->co);
117                                         }
118                                 }
119                         }
120                 }
121                 if(totvert) {
122                         bDeformGroup *defGroup = BLI_findlink(&obedit->defbase, obedit->actdef-1);
123                         strcpy(name, defGroup->name);
124                         mul_v3_fl(cent, 1.0f/(float)totvert);
125                         return 1;
126                 }
127         }
128         
129         return 0;
130 }       
131
132 static void select_editmesh_hook(Object *ob, HookModifierData *hmd)
133 {
134         Mesh *me= ob->data;
135         EditMesh *em= BKE_mesh_get_editmesh(me);
136         EditVert *eve;
137         int index=0, nr=0;
138         
139         if (hmd->indexar == NULL)
140                 return;
141         
142         for(eve= em->verts.first; eve; eve= eve->next, nr++) {
143                 if(nr==hmd->indexar[index]) {
144                         eve->f |= SELECT;
145                         if(index < hmd->totindex-1) index++;
146                 }
147         }
148         EM_select_flush(em);
149
150         BKE_mesh_end_editmesh(me, em);
151 }
152
153 static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent)
154 {
155         BPoint *bp;
156         int *index, nr, totvert=0, a;
157         
158         /* count */
159         a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
160         bp= editlatt->def;
161         while(a--) {
162                 if(bp->f1 & SELECT) {
163                         if(bp->hide==0) totvert++;
164                 }
165                 bp++;
166         }
167
168         if(totvert==0) return 0;
169         
170         *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
171         *tot= totvert;
172         nr= 0;
173         cent[0]= cent[1]= cent[2]= 0.0;
174         
175         a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
176         bp= editlatt->def;
177         while(a--) {
178                 if(bp->f1 & SELECT) {
179                         if(bp->hide==0) {
180                                 *index= nr; index++;
181                                 add_v3_v3(cent, bp->vec);
182                         }
183                 }
184                 bp++;
185                 nr++;
186         }
187         
188         mul_v3_fl(cent, 1.0f/(float)totvert);
189         
190         return totvert;
191 }
192
193 static void select_editlattice_hook(Object *obedit, HookModifierData *hmd)
194 {
195         Lattice *lt= obedit->data;
196         BPoint *bp;
197         int index=0, nr=0, a;
198         
199         /* count */
200         a= lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw;
201         bp= lt->editlatt->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, 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(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(scene);
463 }
464
465 static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
466 {
467         Scene *scene= CTX_data_scene(C);
468         Object *obedit = CTX_data_edit_object(C);
469         Object *obsel=NULL;
470         
471         CTX_DATA_BEGIN(C, Object*, ob, selected_objects)
472         {
473                 if (ob != obedit) {
474                         obsel = ob;
475                         break;
476                 }
477         }
478         CTX_DATA_END;
479         
480         if (!obsel) {
481                 BKE_report(op->reports, RPT_ERROR, "Can't add hook with no other selected objects.");
482                 return OPERATOR_CANCELLED;
483         }
484         
485         add_hook_object(scene, obedit, obsel, OBJECT_ADDHOOK_SELOB);
486         
487         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, obedit);
488         return OPERATOR_FINISHED;
489 }
490
491 void OBJECT_OT_hook_add_selobj(wmOperatorType *ot)
492 {
493         /* identifiers */
494         ot->name= "Hook to Selected Object";
495         ot->description= "Hook selected vertices to the first selected Object";
496         ot->idname= "OBJECT_OT_hook_add_selob";
497         
498         /* api callbacks */
499         ot->exec= object_add_hook_selob_exec;
500         ot->poll= hook_op_edit_poll;
501         
502         /* flags */
503         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
504 }
505
506 static int object_add_hook_newob_exec(bContext *C, wmOperator *op)
507 {
508         Scene *scene= CTX_data_scene(C);
509         Object *obedit = CTX_data_edit_object(C);
510
511         add_hook_object(scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB);
512         
513         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
514         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, obedit);
515         return OPERATOR_FINISHED;
516 }
517
518 void OBJECT_OT_hook_add_newobj(wmOperatorType *ot)
519 {
520         /* identifiers */
521         ot->name= "Hook to New Object";
522         ot->description= "Hook selected vertices to the first selected Object";
523         ot->idname= "OBJECT_OT_hook_add_newob";
524         
525         /* api callbacks */
526         ot->exec= object_add_hook_newob_exec;
527         ot->poll= hook_op_edit_poll;
528         
529         /* flags */
530         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
531 }
532
533 static int object_hook_remove_exec(bContext *C, wmOperator *op)
534 {
535         int num= RNA_enum_get(op->ptr, "modifier");
536         Object *ob=NULL;
537         HookModifierData *hmd=NULL;
538
539         ob = CTX_data_edit_object(C);
540         hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
541
542         if (!ob || !hmd) {
543                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
544                 return OPERATOR_CANCELLED;
545         }
546         
547         /* remove functionality */
548         
549         BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
550         modifier_free((ModifierData *)hmd);
551         
552         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
553         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
554         
555         return OPERATOR_FINISHED;
556 }
557
558 static EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *ptr, int *free)
559 {       
560         Object *ob = CTX_data_edit_object(C);
561         EnumPropertyItem tmp = {0, "", 0, "", ""};
562         EnumPropertyItem *item= NULL;
563         ModifierData *md = NULL;
564         int a, totitem= 0;
565         
566         if(!ob)
567                 return DummyRNA_NULL_items;
568         
569         for(a=0, md=ob->modifiers.first; md; md= md->next, a++) {
570                 if (md->type==eModifierType_Hook) {
571                         tmp.value= a;
572                         tmp.icon = ICON_HOOK;
573                         tmp.identifier= md->name;
574                         tmp.name= md->name;
575                         RNA_enum_item_add(&item, &totitem, &tmp);
576                 }
577         }
578         
579         RNA_enum_item_end(&item, &totitem);
580         *free= 1;
581         
582         return item;
583 }
584
585 void OBJECT_OT_hook_remove(wmOperatorType *ot)
586 {
587         PropertyRNA *prop;
588         
589         /* identifiers */
590         ot->name= "Remove Hook";
591         ot->idname= "OBJECT_OT_hook_remove";
592         ot->description= "Remove a hook from the active object";
593         
594         /* api callbacks */
595         ot->exec= object_hook_remove_exec;
596         ot->invoke= WM_menu_invoke;
597         ot->poll= hook_op_edit_poll;
598         
599         /* flags */
600         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
601         
602         /* properties */
603         prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove.");
604         RNA_def_enum_funcs(prop, hook_mod_itemf);
605         ot->prop= prop;
606 }
607
608 static int object_hook_reset_exec(bContext *C, wmOperator *op)
609 {
610         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
611         int num= RNA_enum_get(op->ptr, "modifier");
612         Object *ob=NULL;
613         HookModifierData *hmd=NULL;
614         
615         if (ptr.data) {         /* if modifier context is available, use that */
616                 ob = ptr.id.data;
617                 hmd= ptr.data;
618         } 
619         else {                  /* use the provided property */
620                 ob = CTX_data_edit_object(C);
621                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
622         }
623         if (!ob || !hmd) {
624                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
625                 return OPERATOR_CANCELLED;
626         }
627         
628         /* reset functionality */
629         if(hmd->object) {
630                 bPoseChannel *pchan= get_pose_channel(hmd->object->pose, hmd->subtarget);
631                 
632                 if(hmd->subtarget[0] && pchan) {
633                         float imat[4][4], mat[4][4];
634                         
635                         /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
636                         mul_m4_m4m4(mat, pchan->pose_mat, hmd->object->obmat);
637                         
638                         invert_m4_m4(imat, mat);
639                         mul_serie_m4(hmd->parentinv, imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
640                 }
641                 else {
642                         invert_m4_m4(hmd->object->imat, hmd->object->obmat);
643                         mul_serie_m4(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
644                 }
645         }
646         
647         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
648         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
649         
650         return OPERATOR_FINISHED;
651 }
652
653 void OBJECT_OT_hook_reset(wmOperatorType *ot)
654 {
655         PropertyRNA *prop;
656         
657         /* identifiers */
658         ot->name= "Reset Hook";
659         ot->description= "Recalculate and clear offset transformation";
660         ot->idname= "OBJECT_OT_hook_reset";
661         
662         /* callbacks */
663         ot->exec= object_hook_reset_exec;
664         ot->poll= hook_op_edit_poll;
665         
666         /* flags */
667         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
668         
669         /* properties */
670         prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
671         RNA_def_enum_funcs(prop, hook_mod_itemf);
672 }
673
674 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
675 {
676         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
677         int num= RNA_enum_get(op->ptr, "modifier");
678         Object *ob=NULL;
679         HookModifierData *hmd=NULL;
680         Scene *scene = CTX_data_scene(C);
681         float bmat[3][3], imat[3][3];
682         
683         if (ptr.data) {         /* if modifier context is available, use that */
684                 ob = ptr.id.data;
685                 hmd= ptr.data;
686         } 
687         else {                  /* use the provided property */
688                 ob = CTX_data_edit_object(C);
689                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
690         }
691         if (!ob || !hmd) {
692                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
693                 return OPERATOR_CANCELLED;
694         }
695         
696         /* recenter functionality */
697         copy_m3_m4(bmat, ob->obmat);
698         invert_m3_m3(imat, bmat);
699         
700         sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
701         mul_m3_v3(imat, hmd->cent);
702         
703         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
704         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
705         
706         return OPERATOR_FINISHED;
707 }
708
709 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
710 {
711         PropertyRNA *prop;
712         
713         /* identifiers */
714         ot->name= "Recenter Hook";
715         ot->description= "Set hook center to cursor position";
716         ot->idname= "OBJECT_OT_hook_recenter";
717         
718         /* callbacks */
719         ot->exec= object_hook_recenter_exec;
720         ot->poll= hook_op_edit_poll;
721         
722         /* flags */
723         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
724         
725         /* properties */
726         prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
727         RNA_def_enum_funcs(prop, hook_mod_itemf);
728 }
729
730 static int object_hook_assign_exec(bContext *C, wmOperator *op)
731 {
732         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
733         int num= RNA_enum_get(op->ptr, "modifier");
734         Object *ob=NULL;
735         HookModifierData *hmd=NULL;
736         float cent[3];
737         char name[32];
738         int *indexar, tot;
739         
740         if (ptr.data) {         /* if modifier context is available, use that */
741                 ob = ptr.id.data;
742                 hmd= ptr.data;
743         } 
744         else {                  /* use the provided property */
745                 ob = CTX_data_edit_object(C);
746                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
747         }
748         if (!ob || !hmd) {
749                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
750                 return OPERATOR_CANCELLED;
751         }
752         
753         /* assign functionality */
754         
755         if(!object_hook_index_array(ob, &tot, &indexar, name, cent)) {
756                 BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
757                 return OPERATOR_CANCELLED;
758         }
759         if(hmd->indexar)
760                 MEM_freeN(hmd->indexar);
761         
762         copy_v3_v3(hmd->cent, cent);
763         hmd->indexar= indexar;
764         hmd->totindex= tot;
765         
766         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
767         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
768         
769         return OPERATOR_FINISHED;
770 }
771
772 void OBJECT_OT_hook_assign(wmOperatorType *ot)
773 {
774         PropertyRNA *prop;
775         
776         /* identifiers */
777         ot->name= "Assign to Hook";
778         ot->description= "Assign the selected vertices to a hook";
779         ot->idname= "OBJECT_OT_hook_assign";
780         
781         /* callbacks */
782         ot->exec= object_hook_assign_exec;
783         ot->poll= hook_op_edit_poll;
784         
785         /* flags */
786         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
787         
788         /* properties */
789         prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
790         RNA_def_enum_funcs(prop, hook_mod_itemf);
791 }
792
793 static int object_hook_select_exec(bContext *C, wmOperator *op)
794 {
795         PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
796         int num= RNA_enum_get(op->ptr, "modifier");
797         Object *ob=NULL;
798         HookModifierData *hmd=NULL;
799         
800         if (ptr.data) {         /* if modifier context is available, use that */
801                 ob = ptr.id.data;
802                 hmd= ptr.data;
803         } 
804         else {                  /* use the provided property */
805                 ob = CTX_data_edit_object(C);
806                 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
807         }
808         if (!ob || !hmd) {
809                 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
810                 return OPERATOR_CANCELLED;
811         }
812         
813         /* select functionality */
814         object_hook_select(ob, hmd);
815         
816         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
817         
818         return OPERATOR_FINISHED;
819 }
820
821 void OBJECT_OT_hook_select(wmOperatorType *ot)
822 {
823         PropertyRNA *prop;
824         
825         /* identifiers */
826         ot->name= "Select Hook";
827         ot->description= "Selects effected vertices on mesh";
828         ot->idname= "OBJECT_OT_hook_select";
829         
830         /* callbacks */
831         ot->exec= object_hook_select_exec;
832         ot->poll= hook_op_edit_poll;
833         
834         /* flags */
835         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
836         
837         /* properties */
838         prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove.");
839         RNA_def_enum_funcs(prop, hook_mod_itemf);
840 }
841