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_deform.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(EditMesh *em, int *tot, int **indexar, float *cent)
79 int *index, nr, totvert=0;
81 for(eve= em->verts.first; eve; eve= eve->next) {
82 if(eve->f & SELECT) totvert++;
84 if(totvert==0) return 0;
86 *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
91 for(eve= em->verts.first; eve; eve= eve->next) {
94 add_v3_v3(cent, eve->co);
99 mul_v3_fl(cent, 1.0f/(float)totvert);
104 static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, float *cent)
109 const int defgrp_index= obedit->actdef-1;
115 /* find the vertices */
116 for(eve= em->verts.first; eve; eve= eve->next) {
117 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
120 if(defvert_find_weight(dvert, defgrp_index) > 0.0f) {
121 add_v3_v3(cent, eve->co);
127 bDeformGroup *dg = BLI_findlink(&obedit->defbase, defgrp_index);
128 BLI_strncpy(name, dg->name, sizeof(dg->name));
129 mul_v3_fl(cent, 1.0f/(float)totvert);
137 static void select_editmesh_hook(Object *ob, HookModifierData *hmd)
140 EditMesh *em= BKE_mesh_get_editmesh(me);
144 if (hmd->indexar == NULL)
147 for(eve= em->verts.first; eve; eve= eve->next, nr++) {
148 if(nr==hmd->indexar[index]) {
150 if(index < hmd->totindex-1) index++;
155 BKE_mesh_end_editmesh(me, em);
158 static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent)
161 int *index, nr, totvert=0, a;
164 a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
167 if(bp->f1 & SELECT) {
168 if(bp->hide==0) totvert++;
173 if(totvert==0) return 0;
175 *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
178 cent[0]= cent[1]= cent[2]= 0.0;
180 a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
183 if(bp->f1 & SELECT) {
186 add_v3_v3(cent, bp->vec);
193 mul_v3_fl(cent, 1.0f/(float)totvert);
198 static void select_editlattice_hook(Object *obedit, HookModifierData *hmd)
200 Lattice *lt= obedit->data, *editlt;
202 int index=0, nr=0, a;
204 editlt= lt->editlatt->latt;
206 a= editlt->pntsu*editlt->pntsv*editlt->pntsw;
209 if(hmd->indexar[index]==nr) {
211 if(index < hmd->totindex-1) index++;
218 static int return_editcurve_indexar(Object *obedit, int *tot, int **indexar, float *cent)
220 ListBase *editnurb= curve_get_editcurve(obedit);
224 int *index, a, nr, totvert=0;
226 for(nu= editnurb->first; nu; nu= nu->next) {
227 if(nu->type == CU_BEZIER) {
231 if(bezt->f1 & SELECT) totvert++;
232 if(bezt->f2 & SELECT) totvert++;
233 if(bezt->f3 & SELECT) totvert++;
239 a= nu->pntsu*nu->pntsv;
241 if(bp->f1 & SELECT) totvert++;
246 if(totvert==0) return 0;
248 *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
251 cent[0]= cent[1]= cent[2]= 0.0;
253 for(nu= editnurb->first; nu; nu= nu->next) {
254 if(nu->type == CU_BEZIER) {
258 if(bezt->f1 & SELECT) {
260 add_v3_v3(cent, bezt->vec[0]);
263 if(bezt->f2 & SELECT) {
265 add_v3_v3(cent, bezt->vec[1]);
268 if(bezt->f3 & SELECT) {
270 add_v3_v3(cent, bezt->vec[2]);
278 a= nu->pntsu*nu->pntsv;
280 if(bp->f1 & SELECT) {
282 add_v3_v3(cent, bp->vec);
290 mul_v3_fl(cent, 1.0f/(float)totvert);
295 static int object_hook_index_array(Object *obedit, int *tot, int **indexar, char *name, float *cent_r)
301 switch(obedit->type) {
304 Mesh *me= obedit->data;
305 EditMesh *em = BKE_mesh_get_editmesh(me);
307 /* check selected vertices first */
308 if( return_editmesh_indexar(em, tot, indexar, cent_r)) {
309 BKE_mesh_end_editmesh(me, em);
312 int ret = return_editmesh_vgroup(obedit, em, name, cent_r);
313 BKE_mesh_end_editmesh(me, em);
319 return return_editcurve_indexar(obedit, tot, indexar, cent_r);
322 Lattice *lt= obedit->data;
323 return return_editlattice_indexar(lt->editlatt->latt, tot, indexar, cent_r);
330 static void select_editcurve_hook(Object *obedit, HookModifierData *hmd)
332 ListBase *editnurb= curve_get_editcurve(obedit);
336 int index=0, a, nr=0;
338 for(nu= editnurb->first; nu; nu= nu->next) {
339 if(nu->type == CU_BEZIER) {
343 if(nr == hmd->indexar[index]) {
345 if(index<hmd->totindex-1) index++;
348 if(nr == hmd->indexar[index]) {
350 if(index<hmd->totindex-1) index++;
353 if(nr == hmd->indexar[index]) {
355 if(index<hmd->totindex-1) index++;
364 a= nu->pntsu*nu->pntsv;
366 if(nr == hmd->indexar[index]) {
368 if(index<hmd->totindex-1) index++;
377 static void object_hook_select(Object *ob, HookModifierData *hmd)
379 if (hmd->indexar == NULL)
382 if(ob->type==OB_MESH) select_editmesh_hook(ob, hmd);
383 else if(ob->type==OB_LATTICE) select_editlattice_hook(ob, hmd);
384 else if(ob->type==OB_CURVE) select_editcurve_hook(ob, hmd);
385 else if(ob->type==OB_SURF) select_editcurve_hook(ob, hmd);
388 /* special poll operators for hook operators */
389 // TODO: check for properties window modifier context too as alternative?
390 static int hook_op_edit_poll(bContext *C)
392 Object *obedit= CTX_data_edit_object(C);
395 if (ED_operator_editmesh(C)) return 1;
396 if (ED_operator_editsurfcurve(C)) return 1;
397 if (ED_operator_editlattice(C)) return 1;
398 //if (ED_operator_editmball(C)) return 1;
404 static Object *add_hook_object_new(Scene *scene, Object *obedit)
406 Base *base, *basedit;
409 ob= add_object(scene, OB_EMPTY);
411 basedit = object_in_scene(obedit, scene);
412 base = object_in_scene(ob, scene);
413 base->lay = ob->lay = obedit->lay;
415 /* icky, add_object sets new base as active.
416 * so set it back to the original edit object */
417 scene->basact = basedit;
422 static void add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob, int mode)
424 ModifierData *md=NULL;
425 HookModifierData *hmd = NULL;
427 int tot, ok, *indexar;
430 ok = object_hook_index_array(obedit, &tot, &indexar, name, cent);
432 if (!ok) return; // XXX error("Requires selected vertices or active Vertex Group");
434 if (mode==OBJECT_ADDHOOK_NEWOB && !ob) {
436 ob = add_hook_object_new(scene, obedit);
438 /* transform cent to global coords for loc */
439 mul_v3_m4v3(ob->loc, obedit->obmat, cent);
442 md = obedit->modifiers.first;
443 while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
447 hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
448 BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
449 BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name+2);
450 modifier_unique_name(&obedit->modifiers, (ModifierData*)hmd);
453 hmd->indexar= indexar;
454 copy_v3_v3(hmd->cent, cent);
456 BLI_strncpy(hmd->name, name, sizeof(hmd->name));
458 /* matrix calculus */
459 /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
461 where_is_object(scene, ob);
463 invert_m4_m4(ob->imat, ob->obmat);
464 /* apparently this call goes from right to left... */
465 mul_serie_m4(hmd->parentinv, ob->imat, obedit->obmat, NULL,
466 NULL, NULL, NULL, NULL, NULL);
468 DAG_scene_sort(bmain, scene);
471 static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
473 Main *bmain= CTX_data_main(C);
474 Scene *scene= CTX_data_scene(C);
475 Object *obedit = CTX_data_edit_object(C);
478 CTX_DATA_BEGIN(C, Object*, ob, selected_objects)
488 BKE_report(op->reports, RPT_ERROR, "Can't add hook with no other selected objects.");
489 return OPERATOR_CANCELLED;
492 add_hook_object(bmain, scene, obedit, obsel, OBJECT_ADDHOOK_SELOB);
494 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, obedit);
495 return OPERATOR_FINISHED;
498 void OBJECT_OT_hook_add_selobj(wmOperatorType *ot)
501 ot->name= "Hook to Selected Object";
502 ot->description= "Hook selected vertices to the first selected Object";
503 ot->idname= "OBJECT_OT_hook_add_selob";
506 ot->exec= object_add_hook_selob_exec;
507 ot->poll= hook_op_edit_poll;
510 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
513 static int object_add_hook_newob_exec(bContext *C, wmOperator *UNUSED(op))
515 Main *bmain= CTX_data_main(C);
516 Scene *scene= CTX_data_scene(C);
517 Object *obedit = CTX_data_edit_object(C);
519 add_hook_object(bmain, scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB);
521 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
522 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, obedit);
523 return OPERATOR_FINISHED;
526 void OBJECT_OT_hook_add_newobj(wmOperatorType *ot)
529 ot->name= "Hook to New Object";
530 ot->description= "Hook selected vertices to the first selected Object";
531 ot->idname= "OBJECT_OT_hook_add_newob";
534 ot->exec= object_add_hook_newob_exec;
535 ot->poll= hook_op_edit_poll;
538 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
541 static int object_hook_remove_exec(bContext *C, wmOperator *op)
543 int num= RNA_enum_get(op->ptr, "modifier");
545 HookModifierData *hmd=NULL;
547 ob = CTX_data_edit_object(C);
548 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
551 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
552 return OPERATOR_CANCELLED;
555 /* remove functionality */
557 BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
558 modifier_free((ModifierData *)hmd);
560 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
561 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
563 return OPERATOR_FINISHED;
566 static EnumPropertyItem *hook_mod_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
568 Object *ob = CTX_data_edit_object(C);
569 EnumPropertyItem tmp = {0, "", 0, "", ""};
570 EnumPropertyItem *item= NULL;
571 ModifierData *md = NULL;
575 return DummyRNA_NULL_items;
577 for(a=0, md=ob->modifiers.first; md; md= md->next, a++) {
578 if (md->type==eModifierType_Hook) {
580 tmp.icon = ICON_HOOK;
581 tmp.identifier= md->name;
583 RNA_enum_item_add(&item, &totitem, &tmp);
587 RNA_enum_item_end(&item, &totitem);
593 void OBJECT_OT_hook_remove(wmOperatorType *ot)
598 ot->name= "Remove Hook";
599 ot->idname= "OBJECT_OT_hook_remove";
600 ot->description= "Remove a hook from the active object";
603 ot->exec= object_hook_remove_exec;
604 ot->invoke= WM_menu_invoke;
605 ot->poll= hook_op_edit_poll;
608 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
611 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove.");
612 RNA_def_enum_funcs(prop, hook_mod_itemf);
616 static int object_hook_reset_exec(bContext *C, wmOperator *op)
618 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
619 int num= RNA_enum_get(op->ptr, "modifier");
621 HookModifierData *hmd=NULL;
623 if (ptr.data) { /* if modifier context is available, use that */
627 else { /* use the provided property */
628 ob = CTX_data_edit_object(C);
629 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
632 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
633 return OPERATOR_CANCELLED;
636 /* reset functionality */
638 bPoseChannel *pchan= get_pose_channel(hmd->object->pose, hmd->subtarget);
640 if(hmd->subtarget[0] && pchan) {
641 float imat[4][4], mat[4][4];
643 /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
644 mul_m4_m4m4(mat, pchan->pose_mat, hmd->object->obmat);
646 invert_m4_m4(imat, mat);
647 mul_serie_m4(hmd->parentinv, imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
650 invert_m4_m4(hmd->object->imat, hmd->object->obmat);
651 mul_serie_m4(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
655 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
656 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
658 return OPERATOR_FINISHED;
661 void OBJECT_OT_hook_reset(wmOperatorType *ot)
666 ot->name= "Reset Hook";
667 ot->description= "Recalculate and clear offset transformation";
668 ot->idname= "OBJECT_OT_hook_reset";
671 ot->exec= object_hook_reset_exec;
672 ot->poll= hook_op_edit_poll;
675 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
678 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
679 RNA_def_enum_funcs(prop, hook_mod_itemf);
682 static int object_hook_recenter_exec(bContext *C, wmOperator *op)
684 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
685 int num= RNA_enum_get(op->ptr, "modifier");
687 HookModifierData *hmd=NULL;
688 Scene *scene = CTX_data_scene(C);
689 float bmat[3][3], imat[3][3];
691 if (ptr.data) { /* if modifier context is available, use that */
695 else { /* use the provided property */
696 ob = CTX_data_edit_object(C);
697 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
700 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
701 return OPERATOR_CANCELLED;
704 /* recenter functionality */
705 copy_m3_m4(bmat, ob->obmat);
706 invert_m3_m3(imat, bmat);
708 sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
709 mul_m3_v3(imat, hmd->cent);
711 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
712 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
714 return OPERATOR_FINISHED;
717 void OBJECT_OT_hook_recenter(wmOperatorType *ot)
722 ot->name= "Recenter Hook";
723 ot->description= "Set hook center to cursor position";
724 ot->idname= "OBJECT_OT_hook_recenter";
727 ot->exec= object_hook_recenter_exec;
728 ot->poll= hook_op_edit_poll;
731 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
734 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
735 RNA_def_enum_funcs(prop, hook_mod_itemf);
738 static int object_hook_assign_exec(bContext *C, wmOperator *op)
740 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
741 int num= RNA_enum_get(op->ptr, "modifier");
743 HookModifierData *hmd=NULL;
748 if (ptr.data) { /* if modifier context is available, use that */
752 else { /* use the provided property */
753 ob = CTX_data_edit_object(C);
754 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
757 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
758 return OPERATOR_CANCELLED;
761 /* assign functionality */
763 if(!object_hook_index_array(ob, &tot, &indexar, name, cent)) {
764 BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
765 return OPERATOR_CANCELLED;
768 MEM_freeN(hmd->indexar);
770 copy_v3_v3(hmd->cent, cent);
771 hmd->indexar= indexar;
774 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
775 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
777 return OPERATOR_FINISHED;
780 void OBJECT_OT_hook_assign(wmOperatorType *ot)
785 ot->name= "Assign to Hook";
786 ot->description= "Assign the selected vertices to a hook";
787 ot->idname= "OBJECT_OT_hook_assign";
790 ot->exec= object_hook_assign_exec;
791 ot->poll= hook_op_edit_poll;
794 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
797 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to assign to.");
798 RNA_def_enum_funcs(prop, hook_mod_itemf);
801 static int object_hook_select_exec(bContext *C, wmOperator *op)
803 PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
804 int num= RNA_enum_get(op->ptr, "modifier");
806 HookModifierData *hmd=NULL;
808 if (ptr.data) { /* if modifier context is available, use that */
812 else { /* use the provided property */
813 ob = CTX_data_edit_object(C);
814 hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num);
817 BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier");
818 return OPERATOR_CANCELLED;
821 /* select functionality */
822 object_hook_select(ob, hmd);
824 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
826 return OPERATOR_FINISHED;
829 void OBJECT_OT_hook_select(wmOperatorType *ot)
834 ot->name= "Select Hook";
835 ot->description= "Selects effected vertices on mesh";
836 ot->idname= "OBJECT_OT_hook_select";
839 ot->exec= object_hook_select_exec;
840 ot->poll= hook_op_edit_poll;
843 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
846 prop= RNA_def_enum(ot->srna, "modifier", DummyRNA_NULL_items, 0, "Modifier", "Modifier number to remove.");
847 RNA_def_enum_funcs(prop, hook_mod_itemf);