2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation, 2002-2008 full recode
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/editors/object/object_hook.c
34 #include "MEM_guardedalloc.h"
37 #include "BLI_editVert.h"
38 #include "BLI_listbase.h"
39 #include "BLI_string.h"
40 #include "BLI_utildefines.h"
42 #include "DNA_curve_types.h"
43 #include "DNA_lattice_types.h"
44 #include "DNA_meshdata_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_scene_types.h"
48 #include "BKE_action.h"
49 #include "BKE_context.h"
50 #include "BKE_depsgraph.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"
60 #include "RNA_define.h"
61 #include "RNA_access.h"
62 #include "RNA_enum_types.h"
66 #include "ED_screen.h"
71 #include "UI_resources.h"
73 #include "object_intern.h"
75 static int return_editmesh_indexar(BMEditMesh *em, int *tot, int **indexar, float *cent)
79 int *index, nr, totvert=0;
81 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
82 if(BM_TestHFlag(eve, BM_SELECT)) totvert++;
84 if(totvert==0) return 0;
86 *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
91 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
92 if(BM_TestHFlag(eve, BM_SELECT)) {
94 add_v3_v3(cent, eve->co);
99 mul_v3_fl(cent, 1.0f/(float)totvert);
104 static int return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *name, float *cent)
109 const int defgrp_index= obedit->actdef-1;
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 if(defvert_find_weight(dvert, defgrp_index) > 0.0f) {
122 add_v3_v3(cent, eve->co);
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);
138 static void select_editbmesh_hook(Object *ob, HookModifierData *hmd)
141 BMEditMesh *em= me->edit_btmesh;
146 if (hmd->indexar == NULL)
149 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
150 if(nr==hmd->indexar[index]) {
151 BM_Select(em->bm, eve, TRUE);
152 if(index < hmd->totindex-1) index++;
158 EDBM_selectmode_flush(em);
161 static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent)
164 int *index, nr, totvert=0, a;
167 a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
170 if(bp->f1 & SELECT) {
171 if(bp->hide==0) totvert++;
176 if(totvert==0) return 0;
178 *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
181 cent[0]= cent[1]= cent[2]= 0.0;
183 a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
186 if(bp->f1 & SELECT) {
189 add_v3_v3(cent, bp->vec);
196 mul_v3_fl(cent, 1.0f/(float)totvert);
201 static void select_editlattice_hook(Object *obedit, HookModifierData *hmd)
203 Lattice *lt= obedit->data, *editlt;
205 int index=0, nr=0, a;
207 editlt= lt->editlatt->latt;
209 a= editlt->pntsu*editlt->pntsv*editlt->pntsw;
212 if(hmd->indexar[index]==nr) {
214 if(index < hmd->totindex-1) index++;
221 static int return_editcurve_indexar(Object *obedit, int *tot, int **indexar, float *cent)
223 ListBase *editnurb= object_editcurve_get(obedit);
227 int *index, a, nr, totvert=0;
229 for(nu= editnurb->first; nu; nu= nu->next) {
230 if(nu->type == CU_BEZIER) {
234 if(bezt->f1 & SELECT) totvert++;
235 if(bezt->f2 & SELECT) totvert++;
236 if(bezt->f3 & SELECT) totvert++;
242 a= nu->pntsu*nu->pntsv;
244 if(bp->f1 & SELECT) totvert++;
249 if(totvert==0) return 0;
251 *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
254 cent[0]= cent[1]= cent[2]= 0.0;
256 for(nu= editnurb->first; nu; nu= nu->next) {
257 if(nu->type == CU_BEZIER) {
261 if(bezt->f1 & SELECT) {
263 add_v3_v3(cent, bezt->vec[0]);
266 if(bezt->f2 & SELECT) {
268 add_v3_v3(cent, bezt->vec[1]);
271 if(bezt->f3 & SELECT) {
273 add_v3_v3(cent, bezt->vec[2]);
281 a= nu->pntsu*nu->pntsv;
283 if(bp->f1 & SELECT) {
285 add_v3_v3(cent, bp->vec);
293 mul_v3_fl(cent, 1.0f/(float)totvert);
298 static int object_hook_index_array(Scene *scene, Object *obedit, int *tot, int **indexar, char *name, float *cent_r)
304 switch(obedit->type) {
307 Mesh *me= obedit->data;
311 EDBM_LoadEditBMesh(scene, obedit);
312 EDBM_MakeEditBMesh(scene->toolsettings, scene, obedit);
314 em = me->edit_btmesh;
316 /* check selected vertices first */
317 if( return_editmesh_indexar(em, tot, indexar, cent_r)) {
320 int ret = return_editmesh_vgroup(obedit, em, name, cent_r);
326 return return_editcurve_indexar(obedit, tot, indexar, cent_r);
329 Lattice *lt= obedit->data;
330 return return_editlattice_indexar(lt->editlatt->latt, tot, indexar, cent_r);
337 static void select_editcurve_hook(Object *obedit, HookModifierData *hmd)
339 ListBase *editnurb= object_editcurve_get(obedit);
343 int index=0, a, nr=0;
345 for(nu= editnurb->first; nu; nu= nu->next) {
346 if(nu->type == CU_BEZIER) {
350 if(nr == hmd->indexar[index]) {
352 if(index<hmd->totindex-1) index++;
355 if(nr == hmd->indexar[index]) {
357 if(index<hmd->totindex-1) index++;
360 if(nr == hmd->indexar[index]) {
362 if(index<hmd->totindex-1) index++;
371 a= nu->pntsu*nu->pntsv;
373 if(nr == hmd->indexar[index]) {
375 if(index<hmd->totindex-1) index++;
384 static void object_hook_select(Object *ob, HookModifierData *hmd)
386 if (hmd->indexar == NULL)
389 if(ob->type==OB_MESH) select_editbmesh_hook(ob, hmd);
390 else if(ob->type==OB_LATTICE) select_editlattice_hook(ob, hmd);
391 else if(ob->type==OB_CURVE) select_editcurve_hook(ob, hmd);
392 else if(ob->type==OB_SURF) select_editcurve_hook(ob, hmd);
395 /* special poll operators for hook operators */
396 // TODO: check for properties window modifier context too as alternative?
397 static int hook_op_edit_poll(bContext *C)
399 Object *obedit= CTX_data_edit_object(C);
402 if (ED_operator_editmesh(C)) return 1;
403 if (ED_operator_editsurfcurve(C)) return 1;
404 if (ED_operator_editlattice(C)) return 1;
405 //if (ED_operator_editmball(C)) return 1;
411 static Object *add_hook_object_new(Scene *scene, Object *obedit)
413 Base *base, *basedit;
416 ob= add_object(scene, OB_EMPTY);
418 basedit = object_in_scene(obedit, scene);
419 base = object_in_scene(ob, scene);
420 base->lay = ob->lay = obedit->lay;
422 /* icky, add_object sets new base as active.
423 * so set it back to the original edit object */
424 scene->basact = basedit;
429 static void add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob, int mode)
431 ModifierData *md=NULL;
432 HookModifierData *hmd = NULL;
434 int tot, ok, *indexar;
437 ok = object_hook_index_array(scene, obedit, &tot, &indexar, name, cent);
439 if (!ok) return; // XXX error("Requires selected vertices or active Vertex Group");
441 if (mode==OBJECT_ADDHOOK_NEWOB && !ob) {
443 ob = add_hook_object_new(scene, obedit);
445 /* transform cent to global coords for loc */
446 mul_v3_m4v3(ob->loc, obedit->obmat, cent);
449 md = obedit->modifiers.first;
450 while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
454 hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
455 BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
456 BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name+2);
457 modifier_unique_name(&obedit->modifiers, (ModifierData*)hmd);
460 hmd->indexar= indexar;
461 copy_v3_v3(hmd->cent, cent);
463 BLI_strncpy(hmd->name, name, sizeof(hmd->name));
465 /* matrix calculus */
466 /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
468 where_is_object(scene, ob);
470 invert_m4_m4(ob->imat, ob->obmat);
471 /* apparently this call goes from right to left... */
472 mul_serie_m4(hmd->parentinv, ob->imat, obedit->obmat, NULL,
473 NULL, NULL, NULL, NULL, NULL);
475 DAG_scene_sort(bmain, scene);
478 static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
480 Main *bmain= CTX_data_main(C);
481 Scene *scene= CTX_data_scene(C);
482 Object *obedit = CTX_data_edit_object(C);
485 CTX_DATA_BEGIN(C, Object*, ob, selected_objects)
495 BKE_report(op->reports, RPT_ERROR, "Can't add hook with no other selected objects");
496 return OPERATOR_CANCELLED;
499 add_hook_object(bmain, scene, obedit, obsel, OBJECT_ADDHOOK_SELOB);
501 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, obedit);
502 return OPERATOR_FINISHED;
505 void OBJECT_OT_hook_add_selobj(wmOperatorType *ot)
508 ot->name= "Hook to Selected Object";
509 ot->description= "Hook selected vertices to the first selected Object";
510 ot->idname= "OBJECT_OT_hook_add_selob";
513 ot->exec= object_add_hook_selob_exec;
514 ot->poll= hook_op_edit_poll;
517 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
520 static int object_add_hook_newob_exec(bContext *C, wmOperator *UNUSED(op))
522 Main *bmain= CTX_data_main(C);
523 Scene *scene= CTX_data_scene(C);
524 Object *obedit = CTX_data_edit_object(C);
526 add_hook_object(bmain, scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB);
528 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
529 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, obedit);
530 return OPERATOR_FINISHED;
533 void OBJECT_OT_hook_add_newobj(wmOperatorType *ot)
536 ot->name= "Hook to New Object";
537 ot->description= "Hook selected vertices to the first selected Object";
538 ot->idname= "OBJECT_OT_hook_add_newob";
541 ot->exec= object_add_hook_newob_exec;
542 ot->poll= hook_op_edit_poll;
545 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
548 static int object_hook_remove_exec(bContext *C, wmOperator *op)
550 int num= RNA_enum_get(op->ptr, "modifier");
552 HookModifierData *hmd=NULL;
554 ob = CTX_data_edit_object(C);
555 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
558 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
559 return OPERATOR_CANCELLED;
562 /* remove functionality */
564 BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
565 modifier_free((ModifierData *)hmd);
567 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
568 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
570 return OPERATOR_FINISHED;
573 static EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
575 Object *ob = CTX_data_edit_object(C);
576 EnumPropertyItem tmp = {0, "", 0, "", ""};
577 EnumPropertyItem *item= NULL;
578 ModifierData *md = NULL;
582 return DummyRNA_NULL_items;
584 for(a=0, md=ob->modifiers.first; md; md= md->next, a++) {
585 if (md->type==eModifierType_Hook) {
587 tmp.icon = ICON_HOOK;
588 tmp.identifier= md->name;
590 RNA_enum_item_add(&item, &totitem, &tmp);
594 RNA_enum_item_end(&item, &totitem);
600 void OBJECT_OT_hook_remove(wmOperatorType *ot)
605 ot->name= "Remove Hook";
606 ot->idname= "OBJECT_OT_hook_remove";
607 ot->description= "Remove a hook from the active object";
610 ot->exec= object_hook_remove_exec;
611 ot->invoke= WM_menu_invoke;
612 ot->poll= hook_op_edit_poll;
615 /* this operator removes modifier which isn't stored in local undo stack,
616 so redoing it from redo panel gives totally weird results */
617 ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO;
620 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
621 RNA_def_enum_funcs(prop, hook_mod_itemf);
625 static int object_hook_reset_exec(bContext *C, wmOperator *op)
627 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
628 int num= RNA_enum_get(op->ptr, "modifier");
630 HookModifierData *hmd=NULL;
632 if (ptr.data) { /* if modifier context is available, use that */
636 else { /* use the provided property */
637 ob = CTX_data_edit_object(C);
638 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
641 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
642 return OPERATOR_CANCELLED;
645 /* reset functionality */
647 bPoseChannel *pchan= get_pose_channel(hmd->object->pose, hmd->subtarget);
649 if(hmd->subtarget[0] && pchan) {
650 float imat[4][4], mat[4][4];
652 /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
653 mult_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
655 invert_m4_m4(imat, mat);
656 mul_serie_m4(hmd->parentinv, imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
659 invert_m4_m4(hmd->object->imat, hmd->object->obmat);
660 mul_serie_m4(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
664 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
665 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
667 return OPERATOR_FINISHED;
670 void OBJECT_OT_hook_reset(wmOperatorType *ot)
675 ot->name= "Reset Hook";
676 ot->description= "Recalculate and clear offset transformation";
677 ot->idname= "OBJECT_OT_hook_reset";
680 ot->exec= object_hook_reset_exec;
681 ot->poll= hook_op_edit_poll;
684 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
687 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
688 RNA_def_enum_funcs(prop, hook_mod_itemf);
691 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
693 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
694 int num= RNA_enum_get(op->ptr, "modifier");
696 HookModifierData *hmd=NULL;
697 Scene *scene = CTX_data_scene(C);
698 float bmat[3][3], imat[3][3];
700 if (ptr.data) { /* if modifier context is available, use that */
704 else { /* use the provided property */
705 ob = CTX_data_edit_object(C);
706 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
709 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
710 return OPERATOR_CANCELLED;
713 /* recenter functionality */
714 copy_m3_m4(bmat, ob->obmat);
715 invert_m3_m3(imat, bmat);
717 sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
718 mul_m3_v3(imat, hmd->cent);
720 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
721 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
723 return OPERATOR_FINISHED;
726 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
731 ot->name= "Recenter Hook";
732 ot->description= "Set hook center to cursor position";
733 ot->idname= "OBJECT_OT_hook_recenter";
736 ot->exec= object_hook_recenter_exec;
737 ot->poll= hook_op_edit_poll;
740 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
743 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
744 RNA_def_enum_funcs(prop, hook_mod_itemf);
747 static int object_hook_assign_exec(bContext *C, wmOperator *op)
749 Scene *scene= CTX_data_scene(C);
750 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
751 int num= RNA_enum_get(op->ptr, "modifier");
753 HookModifierData *hmd=NULL;
758 if (ptr.data) { /* if modifier context is available, use that */
762 else { /* use the provided property */
763 ob = CTX_data_edit_object(C);
764 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
767 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
768 return OPERATOR_CANCELLED;
771 /* assign functionality */
773 if(!object_hook_index_array(scene, ob, &tot, &indexar, name, cent)) {
774 BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
775 return OPERATOR_CANCELLED;
778 MEM_freeN(hmd->indexar);
780 copy_v3_v3(hmd->cent, cent);
781 hmd->indexar= indexar;
784 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
785 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
787 return OPERATOR_FINISHED;
790 void OBJECT_OT_hook_assign(wmOperatorType *ot)
795 ot->name= "Assign to Hook";
796 ot->description= "Assign the selected vertices to a hook";
797 ot->idname= "OBJECT_OT_hook_assign";
800 ot->exec= object_hook_assign_exec;
801 ot->poll= hook_op_edit_poll;
804 /* this operator changes data stored in modifier which doesn't get pushed to undo stack,
805 so redoing it from redo panel gives totally weird results */
806 ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO;
809 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to");
810 RNA_def_enum_funcs(prop, hook_mod_itemf);
813 static int object_hook_select_exec(bContext *C, wmOperator *op)
815 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
816 int num= RNA_enum_get(op->ptr, "modifier");
818 HookModifierData *hmd=NULL;
820 if (ptr.data) { /* if modifier context is available, use that */
824 else { /* use the provided property */
825 ob = CTX_data_edit_object(C);
826 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
829 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
830 return OPERATOR_CANCELLED;
833 /* select functionality */
834 object_hook_select(ob, hmd);
836 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
838 return OPERATOR_FINISHED;
841 void OBJECT_OT_hook_select(wmOperatorType *ot)
846 ot->name= "Select Hook";
847 ot->description= "Select affected vertices on mesh";
848 ot->idname= "OBJECT_OT_hook_select";
851 ot->exec= object_hook_select_exec;
852 ot->poll= hook_op_edit_poll;
855 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
858 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove");
859 RNA_def_enum_funcs(prop, hook_mod_itemf);