4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * Contributor(s): Blender Foundation, 2002-2008 full recode
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/object/object_hook.c
36 #include "MEM_guardedalloc.h"
39 #include "BLI_editVert.h"
40 #include "BLI_listbase.h"
41 #include "BLI_string.h"
42 #include "BLI_utildefines.h"
44 #include "DNA_curve_types.h"
45 #include "DNA_lattice_types.h"
46 #include "DNA_meshdata_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_scene_types.h"
50 #include "BKE_action.h"
51 #include "BKE_context.h"
52 #include "BKE_depsgraph.h"
55 #include "BKE_modifier.h"
56 #include "BKE_object.h"
57 #include "BKE_report.h"
58 #include "BKE_scene.h"
59 #include "BKE_tessmesh.h"
61 #include "RNA_define.h"
62 #include "RNA_access.h"
63 #include "RNA_enum_types.h"
67 #include "ED_screen.h"
72 #include "UI_resources.h"
74 #include "object_intern.h"
76 static int return_editmesh_indexar(BMEditMesh *em, int *tot, int **indexar, float *cent)
80 int *index, nr, totvert=0;
82 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
83 if(BM_TestHFlag(eve, BM_SELECT)) totvert++;
85 if(totvert==0) return 0;
87 *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
90 cent[0]= cent[1]= cent[2]= 0.0;
92 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
93 if(BM_TestHFlag(eve, BM_SELECT)) {
95 add_v3_v3(cent, eve->co);
100 mul_v3_fl(cent, 1.0f/(float)totvert);
105 static int return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *name, float *cent)
112 cent[0]= cent[1]= cent[2]= 0.0;
116 /* find the vertices */
117 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
118 dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
121 for(i=0; i<dvert->totweight; i++){
122 if(dvert->dw[i].def_nr == (obedit->actdef-1)) {
124 add_v3_v3(cent, eve->co);
130 bDeformGroup *defGroup = BLI_findlink(&obedit->defbase, obedit->actdef-1);
131 strcpy(name, defGroup->name);
132 mul_v3_fl(cent, 1.0f/(float)totvert);
140 static void select_editbmesh_hook(Object *ob, HookModifierData *hmd)
143 BMEditMesh *em= me->edit_btmesh;
148 if (hmd->indexar == NULL)
151 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
152 if(nr==hmd->indexar[index]) {
153 BM_Select(em->bm, eve, 1);
154 if(index < hmd->totindex-1) index++;
160 EDBM_selectmode_flush(em);
163 static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent)
166 int *index, nr, totvert=0, a;
169 a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
172 if(bp->f1 & SELECT) {
173 if(bp->hide==0) totvert++;
178 if(totvert==0) return 0;
180 *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
183 cent[0]= cent[1]= cent[2]= 0.0;
185 a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
188 if(bp->f1 & SELECT) {
191 add_v3_v3(cent, bp->vec);
198 mul_v3_fl(cent, 1.0f/(float)totvert);
203 static void select_editlattice_hook(Object *obedit, HookModifierData *hmd)
205 Lattice *lt= obedit->data, *editlt;
207 int index=0, nr=0, a;
209 editlt= lt->editlatt->latt;
211 a= editlt->pntsu*editlt->pntsv*editlt->pntsw;
214 if(hmd->indexar[index]==nr) {
216 if(index < hmd->totindex-1) index++;
223 static int return_editcurve_indexar(Object *obedit, int *tot, int **indexar, float *cent)
225 ListBase *editnurb= curve_get_editcurve(obedit);
229 int *index, a, nr, totvert=0;
231 for(nu= editnurb->first; nu; nu= nu->next) {
232 if(nu->type == CU_BEZIER) {
236 if(bezt->f1 & SELECT) totvert++;
237 if(bezt->f2 & SELECT) totvert++;
238 if(bezt->f3 & SELECT) totvert++;
244 a= nu->pntsu*nu->pntsv;
246 if(bp->f1 & SELECT) totvert++;
251 if(totvert==0) return 0;
253 *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
256 cent[0]= cent[1]= cent[2]= 0.0;
258 for(nu= editnurb->first; nu; nu= nu->next) {
259 if(nu->type == CU_BEZIER) {
263 if(bezt->f1 & SELECT) {
265 add_v3_v3(cent, bezt->vec[0]);
268 if(bezt->f2 & SELECT) {
270 add_v3_v3(cent, bezt->vec[1]);
273 if(bezt->f3 & SELECT) {
275 add_v3_v3(cent, bezt->vec[2]);
283 a= nu->pntsu*nu->pntsv;
285 if(bp->f1 & SELECT) {
287 add_v3_v3(cent, bp->vec);
295 mul_v3_fl(cent, 1.0f/(float)totvert);
300 static int object_hook_index_array(Object *obedit, int *tot, int **indexar, char *name, float *cent_r)
306 switch(obedit->type) {
309 Mesh *me= obedit->data;
310 BMEditMesh *em = me->edit_btmesh;
312 /* check selected vertices first */
313 if( return_editmesh_indexar(em, tot, indexar, cent_r)) {
316 int ret = return_editmesh_vgroup(obedit, em, name, cent_r);
322 return return_editcurve_indexar(obedit, tot, indexar, cent_r);
325 Lattice *lt= obedit->data;
326 return return_editlattice_indexar(lt->editlatt->latt, tot, indexar, cent_r);
333 static void select_editcurve_hook(Object *obedit, HookModifierData *hmd)
335 ListBase *editnurb= curve_get_editcurve(obedit);
339 int index=0, a, nr=0;
341 for(nu= editnurb->first; nu; nu= nu->next) {
342 if(nu->type == CU_BEZIER) {
346 if(nr == hmd->indexar[index]) {
348 if(index<hmd->totindex-1) index++;
351 if(nr == hmd->indexar[index]) {
353 if(index<hmd->totindex-1) index++;
356 if(nr == hmd->indexar[index]) {
358 if(index<hmd->totindex-1) index++;
367 a= nu->pntsu*nu->pntsv;
369 if(nr == hmd->indexar[index]) {
371 if(index<hmd->totindex-1) index++;
380 static void object_hook_select(Object *ob, HookModifierData *hmd)
382 if (hmd->indexar == NULL)
385 if(ob->type==OB_MESH) select_editbmesh_hook(ob, hmd);
386 else if(ob->type==OB_LATTICE) select_editlattice_hook(ob, hmd);
387 else if(ob->type==OB_CURVE) select_editcurve_hook(ob, hmd);
388 else if(ob->type==OB_SURF) select_editcurve_hook(ob, hmd);
391 /* special poll operators for hook operators */
392 // TODO: check for properties window modifier context too as alternative?
393 static int hook_op_edit_poll(bContext *C)
395 Object *obedit= CTX_data_edit_object(C);
398 if (ED_operator_editmesh(C)) return 1;
399 if (ED_operator_editsurfcurve(C)) return 1;
400 if (ED_operator_editlattice(C)) return 1;
401 //if (ED_operator_editmball(C)) return 1;
407 static Object *add_hook_object_new(Scene *scene, Object *obedit)
409 Base *base, *basedit;
412 ob= add_object(scene, OB_EMPTY);
414 basedit = object_in_scene(obedit, scene);
415 base = object_in_scene(ob, scene);
416 base->lay = ob->lay = obedit->lay;
418 /* icky, add_object sets new base as active.
419 * so set it back to the original edit object */
420 scene->basact = basedit;
425 static void add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob, int mode)
427 ModifierData *md=NULL;
428 HookModifierData *hmd = NULL;
430 int tot, ok, *indexar;
433 ok = object_hook_index_array(obedit, &tot, &indexar, name, cent);
435 if (!ok) return; // XXX error("Requires selected vertices or active Vertex Group");
437 if (mode==OBJECT_ADDHOOK_NEWOB && !ob) {
439 ob = add_hook_object_new(scene, obedit);
441 /* transform cent to global coords for loc */
442 mul_v3_m4v3(ob->loc, obedit->obmat, cent);
445 md = obedit->modifiers.first;
446 while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
450 hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
451 BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
452 BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name+2);
453 modifier_unique_name(&obedit->modifiers, (ModifierData*)hmd);
456 hmd->indexar= indexar;
457 copy_v3_v3(hmd->cent, cent);
459 BLI_strncpy(hmd->name, name, sizeof(hmd->name));
461 /* matrix calculus */
462 /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
464 where_is_object(scene, ob);
466 invert_m4_m4(ob->imat, ob->obmat);
467 /* apparently this call goes from right to left... */
468 mul_serie_m4(hmd->parentinv, ob->imat, obedit->obmat, NULL,
469 NULL, NULL, NULL, NULL, NULL);
471 DAG_scene_sort(bmain, scene);
474 static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
476 Main *bmain= CTX_data_main(C);
477 Scene *scene= CTX_data_scene(C);
478 Object *obedit = CTX_data_edit_object(C);
481 CTX_DATA_BEGIN(C, Object*, ob, selected_objects)
491 BKE_report(op->reports, RPT_ERROR, "Can't add hook with no other selected objects.");
492 return OPERATOR_CANCELLED;
495 add_hook_object(bmain, scene, obedit, obsel, OBJECT_ADDHOOK_SELOB);
497 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, obedit);
498 return OPERATOR_FINISHED;
501 void OBJECT_OT_hook_add_selobj(wmOperatorType *ot)
504 ot->name= "Hook to Selected Object";
505 ot->description= "Hook selected vertices to the first selected Object";
506 ot->idname= "OBJECT_OT_hook_add_selob";
509 ot->exec= object_add_hook_selob_exec;
510 ot->poll= hook_op_edit_poll;
513 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
516 static int object_add_hook_newob_exec(bContext *C, wmOperator *UNUSED(op))
518 Main *bmain= CTX_data_main(C);
519 Scene *scene= CTX_data_scene(C);
520 Object *obedit = CTX_data_edit_object(C);
522 add_hook_object(bmain, scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB);
524 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
525 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, obedit);
526 return OPERATOR_FINISHED;
529 void OBJECT_OT_hook_add_newobj(wmOperatorType *ot)
532 ot->name= "Hook to New Object";
533 ot->description= "Hook selected vertices to the first selected Object";
534 ot->idname= "OBJECT_OT_hook_add_newob";
537 ot->exec= object_add_hook_newob_exec;
538 ot->poll= hook_op_edit_poll;
541 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
544 static int object_hook_remove_exec(bContext *C, wmOperator *op)
546 int num= RNA_enum_get(op->ptr, "modifier");
548 HookModifierData *hmd=NULL;
550 ob = CTX_data_edit_object(C);
551 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
554 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
555 return OPERATOR_CANCELLED;
558 /* remove functionality */
560 BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
561 modifier_free((ModifierData *)hmd);
563 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
564 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
566 return OPERATOR_FINISHED;
569 static EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
571 Object *ob = CTX_data_edit_object(C);
572 EnumPropertyItem tmp = {0, "", 0, "", ""};
573 EnumPropertyItem *item= NULL;
574 ModifierData *md = NULL;
578 return DummyRNA_NULL_items;
580 for(a=0, md=ob->modifiers.first; md; md= md->next, a++) {
581 if (md->type==eModifierType_Hook) {
583 tmp.icon = ICON_HOOK;
584 tmp.identifier= md->name;
586 RNA_enum_item_add(&item, &totitem, &tmp);
590 RNA_enum_item_end(&item, &totitem);
596 void OBJECT_OT_hook_remove(wmOperatorType *ot)
601 ot->name= "Remove Hook";
602 ot->idname= "OBJECT_OT_hook_remove";
603 ot->description= "Remove a hook from the active object";
606 ot->exec= object_hook_remove_exec;
607 ot->invoke= WM_menu_invoke;
608 ot->poll= hook_op_edit_poll;
611 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
614 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove.");
615 RNA_def_enum_funcs(prop, hook_mod_itemf);
619 static int object_hook_reset_exec(bContext *C, wmOperator *op)
621 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
622 int num= RNA_enum_get(op->ptr, "modifier");
624 HookModifierData *hmd=NULL;
626 if (ptr.data) { /* if modifier context is available, use that */
630 else { /* use the provided property */
631 ob = CTX_data_edit_object(C);
632 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
635 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
636 return OPERATOR_CANCELLED;
639 /* reset functionality */
641 bPoseChannel *pchan= get_pose_channel(hmd->object->pose, hmd->subtarget);
643 if(hmd->subtarget[0] && pchan) {
644 float imat[4][4], mat[4][4];
646 /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
647 mul_m4_m4m4(mat, pchan->pose_mat, hmd->object->obmat);
649 invert_m4_m4(imat, mat);
650 mul_serie_m4(hmd->parentinv, imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
653 invert_m4_m4(hmd->object->imat, hmd->object->obmat);
654 mul_serie_m4(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
658 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
659 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
661 return OPERATOR_FINISHED;
664 void OBJECT_OT_hook_reset(wmOperatorType *ot)
669 ot->name= "Reset Hook";
670 ot->description= "Recalculate and clear offset transformation";
671 ot->idname= "OBJECT_OT_hook_reset";
674 ot->exec= object_hook_reset_exec;
675 ot->poll= hook_op_edit_poll;
678 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
681 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
682 RNA_def_enum_funcs(prop, hook_mod_itemf);
685 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
687 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
688 int num= RNA_enum_get(op->ptr, "modifier");
690 HookModifierData *hmd=NULL;
691 Scene *scene = CTX_data_scene(C);
692 float bmat[3][3], imat[3][3];
694 if (ptr.data) { /* if modifier context is available, use that */
698 else { /* use the provided property */
699 ob = CTX_data_edit_object(C);
700 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
703 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
704 return OPERATOR_CANCELLED;
707 /* recenter functionality */
708 copy_m3_m4(bmat, ob->obmat);
709 invert_m3_m3(imat, bmat);
711 sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
712 mul_m3_v3(imat, hmd->cent);
714 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
715 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
717 return OPERATOR_FINISHED;
720 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
725 ot->name= "Recenter Hook";
726 ot->description= "Set hook center to cursor position";
727 ot->idname= "OBJECT_OT_hook_recenter";
730 ot->exec= object_hook_recenter_exec;
731 ot->poll= hook_op_edit_poll;
734 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
737 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
738 RNA_def_enum_funcs(prop, hook_mod_itemf);
741 static int object_hook_assign_exec(bContext *C, wmOperator *op)
743 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
744 int num= RNA_enum_get(op->ptr, "modifier");
746 HookModifierData *hmd=NULL;
751 if (ptr.data) { /* if modifier context is available, use that */
755 else { /* use the provided property */
756 ob = CTX_data_edit_object(C);
757 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
760 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
761 return OPERATOR_CANCELLED;
764 /* assign functionality */
766 if(!object_hook_index_array(ob, &tot, &indexar, name, cent)) {
767 BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
768 return OPERATOR_CANCELLED;
771 MEM_freeN(hmd->indexar);
773 copy_v3_v3(hmd->cent, cent);
774 hmd->indexar= indexar;
777 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
778 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
780 return OPERATOR_FINISHED;
783 void OBJECT_OT_hook_assign(wmOperatorType *ot)
788 ot->name= "Assign to Hook";
789 ot->description= "Assign the selected vertices to a hook";
790 ot->idname= "OBJECT_OT_hook_assign";
793 ot->exec= object_hook_assign_exec;
794 ot->poll= hook_op_edit_poll;
797 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
800 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
801 RNA_def_enum_funcs(prop, hook_mod_itemf);
804 static int object_hook_select_exec(bContext *C, wmOperator *op)
806 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
807 int num= RNA_enum_get(op->ptr, "modifier");
809 HookModifierData *hmd=NULL;
811 if (ptr.data) { /* if modifier context is available, use that */
815 else { /* use the provided property */
816 ob = CTX_data_edit_object(C);
817 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
820 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
821 return OPERATOR_CANCELLED;
824 /* select functionality */
825 object_hook_select(ob, hmd);
827 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
829 return OPERATOR_FINISHED;
832 void OBJECT_OT_hook_select(wmOperatorType *ot)
837 ot->name= "Select Hook";
838 ot->description= "Selects effected vertices on mesh";
839 ot->idname= "OBJECT_OT_hook_select";
842 ot->exec= object_hook_select_exec;
843 ot->poll= hook_op_edit_poll;
846 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
849 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove.");
850 RNA_def_enum_funcs(prop, hook_mod_itemf);