d2c5a14b58906abe91f6940f0c9563c5bc39cc84
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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_mesh_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_modifier_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_view3d_types.h"
46 #include "DNA_windowmanager_types.h"
47
48 #include "BKE_context.h"
49 #include "BKE_customdata.h"
50 #include "BKE_depsgraph.h"
51 #include "BKE_mesh.h"
52 #include "BKE_modifier.h"
53 #include "BKE_object.h"
54
55 #include "RNA_define.h"
56 #include "RNA_access.h"
57
58 #include "ED_curve.h"
59 #include "ED_mesh.h"
60 #include "ED_object.h"
61 #include "ED_view3d.h"
62
63 #include "WM_types.h"
64 #include "WM_api.h"
65
66 #include "object_intern.h"
67
68 /* XXX operators for this are not implemented yet */
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_v3v3(cent, 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_v3v3(cent, 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_v3v3(cent, 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_v3v3(cent, cent, bezt->vec[0]);
255                                 }
256                                 nr++;
257                                 if(bezt->f2 & SELECT) {
258                                         *index= nr; index++;
259                                         add_v3_v3v3(cent, cent, bezt->vec[1]);
260                                 }
261                                 nr++;
262                                 if(bezt->f3 & SELECT) {
263                                         *index= nr; index++;
264                                         add_v3_v3v3(cent, 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_v3v3(cent, 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 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 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
383 void add_hook(Scene *scene, View3D *v3d, int mode)
384 {
385         ModifierData *md = NULL;
386         HookModifierData *hmd = NULL;
387         Object *ob=NULL;
388         Object *obedit= scene->obedit;  // XXX get from context
389         
390         if(obedit==NULL) return;
391         
392         /* preconditions */
393         if(mode==2) { /* selected object */
394                 Base *base;
395                 for(base= FIRSTBASE; base; base= base->next) {
396                         if(TESTBASELIB(v3d, base)) {
397                                 if(base!=BASACT) {
398                                         ob= base->object;
399                                         break;
400                                 }
401                         }
402                 }
403                 if(ob==NULL) {
404                         // XXX error("Requires selected Object");
405                         return;
406                 }
407         }
408         else if(mode!=1) {
409                 int maxlen=0, a, nr;
410                 char *cp;
411                 
412                 /* make pupmenu with hooks */
413                 for(md=obedit->modifiers.first; md; md= md->next) {
414                         if (md->type==eModifierType_Hook) 
415                                 maxlen+=32;
416                 }
417                 
418                 if(maxlen==0) {
419                         // XXX error("Object has no hooks yet");
420                         return;
421                 }
422                 
423                 cp= MEM_callocN(maxlen+32, "temp string");
424                 if(mode==3) strcpy(cp, "Remove %t|");
425                 else if(mode==4) strcpy(cp, "Reassign %t|");
426                 else if(mode==5) strcpy(cp, "Select %t|");
427                 else if(mode==6) strcpy(cp, "Clear Offset %t|");
428                 
429                 for(md=obedit->modifiers.first; md; md= md->next) {
430                         if (md->type==eModifierType_Hook) {
431                                 strcat(cp, md->name);
432                                 strcat(cp, " |");
433                         }
434                 }
435                 
436                 nr= 0; // XXX pupmenu(cp);
437                 MEM_freeN(cp);
438                 
439                 if(nr<1) return;
440                 
441                 a= 1;
442                 for(md=obedit->modifiers.first; md; md=md->next) {
443                         if (md->type==eModifierType_Hook) {
444                                 if(a==nr) break;
445                                 a++;
446                         }
447                 }
448                 
449                 hmd = (HookModifierData*) md;
450                 ob= hmd->object;
451         }
452
453         /* do it, new hooks or reassign */
454         if(mode==1 || mode==2 || mode==4) {
455                 float cent[3];
456                 int tot, ok, *indexar;
457                 char name[32];
458                 
459                 ok = object_hook_index_array(obedit, &tot, &indexar, name, cent);
460                 
461                 if(ok==0) {
462                         // XXX error("Requires selected vertices or active Vertex Group");
463                 }
464                 else {
465                         
466                         if(mode==1) {
467                                 Base *base= BASACT, *newbase;
468                                 
469                                 ob= add_object(scene, OB_EMPTY);
470                                 /* set layers OK */
471                                 newbase= BASACT;
472                                 newbase->lay= base->lay;
473                                 ob->lay= newbase->lay;
474                                 
475                                 /* transform cent to global coords for loc */
476                                 mul_v3_m4v3(ob->loc, obedit->obmat, cent);
477                                 
478                                 /* restore, add_object sets active */
479                                 BASACT= base;
480                         }
481                         /* if mode is 2 or 4, ob has been set */
482                         
483                         /* new hook */
484                         if(mode==1 || mode==2) {
485                                 ModifierData *md = obedit->modifiers.first;
486                                 
487                                 while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
488                                         md = md->next;
489                                 }
490                                 
491                                 hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
492                                 BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
493                                 sprintf(hmd->modifier.name, "Hook-%s", ob->id.name+2);
494                                 modifier_unique_name(&obedit->modifiers, (ModifierData*)hmd);
495                         }
496                         else if (hmd->indexar) MEM_freeN(hmd->indexar); /* reassign, hook was set */
497                 
498                         hmd->object= ob;
499                         hmd->indexar= indexar;
500                         copy_v3_v3(hmd->cent, cent);
501                         hmd->totindex= tot;
502                         BLI_strncpy(hmd->name, name, 32);
503                         
504                         // TODO: need to take into account bone targets here too now...
505                         if(mode==1 || mode==2) {
506                                 /* matrix calculus */
507                                 /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
508                                 /*        (parentinv         )                          */
509                                 
510                                 where_is_object(scene, ob);
511                                 
512                                 invert_m4_m4(ob->imat, ob->obmat);
513                                 /* apparently this call goes from right to left... */
514                                 mul_serie_m4(hmd->parentinv, ob->imat, obedit->obmat, NULL, 
515                                                          NULL, NULL, NULL, NULL, NULL);
516                         }
517                 }
518         }
519         else if(mode==3) { /* remove */
520                 BLI_remlink(&obedit->modifiers, md);
521                 modifier_free(md);
522         }
523         else if(mode==5) { /* select */
524                 // FIXME: this is now OBJECT_OT_hook_select
525                 object_hook_select(obedit, hmd);
526         }
527         else if(mode==6) { /* clear offset */
528                 // FIXME: this is now OBJECT_OT_hook_reset operator
529                 where_is_object(scene, ob);     /* ob is hook->parent */
530
531                 invert_m4_m4(ob->imat, ob->obmat);
532                 /* this call goes from right to left... */
533                 mul_serie_m4(hmd->parentinv, ob->imat, obedit->obmat, NULL, 
534                                          NULL, NULL, NULL, NULL, NULL);
535         }
536
537         DAG_scene_sort(scene);
538 }
539
540 void add_hook_menu(Scene *scene, View3D *v3d)
541 {
542         Object *obedit= scene->obedit;  // XXX get from context
543         int mode;
544         
545         if(obedit==NULL) return;
546         
547         if(modifiers_findByType(obedit, eModifierType_Hook))
548                 mode= 0; // XXX pupmenu("Hooks %t|Add, To New Empty %x1|Add, To Selected Object %x2|Remove... %x3|Reassign... %x4|Select... %x5|Clear Offset...%x6");
549         else
550                 mode= 0; // XXX pupmenu("Hooks %t|Add, New Empty %x1|Add, To Selected Object %x2");
551
552         if(mode<1) return;
553                 
554         /* do operations */
555         add_hook(scene, v3d, mode);
556 }
557
558 void hookmenu(Scene *scene, View3D *v3d)
559 {
560         /* only called in object mode */
561         short event, changed=0;
562         Object *ob;
563         Base *base;
564         ModifierData *md;
565         HookModifierData *hmd;
566         
567         event= 0; // XXX pupmenu("Modify Hooks for Selected...%t|Reset Offset%x1|Recenter at Cursor%x2");
568         if (event==-1) return;
569         if (event==2 && !(v3d)) {
570                 // XXX error("Cannot perform this operation without a 3d view");
571                 return;
572         }
573         
574         for (base= FIRSTBASE; base; base= base->next) {
575                 if(TESTBASELIB(v3d, base)) {
576                         for (md = base->object->modifiers.first; md; md=md->next) {
577                                 if (md->type==eModifierType_Hook) {
578                                         ob = base->object;
579                                         hmd = (HookModifierData*) md;
580                                         
581                                         /*
582                                          * Copied from modifiers_cursorHookCenter and
583                                          * modifiers_clearHookOffset, should consolidate
584                                          * */
585                                         
586                                         if (event==1) {
587                                                 if(hmd->object) {
588                                                         invert_m4_m4(hmd->object->imat, hmd->object->obmat);
589                                                         mul_serie_m4(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
590                                                         
591                                                         changed= 1;
592                                                         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
593                                                 }
594                                         } else {
595                                                 float *curs = give_cursor(scene, v3d);
596                                                 float bmat[3][3], imat[3][3];
597                                                 
598                                                 where_is_object(scene, ob);
599                                         
600                                                 copy_m3_m4(bmat, ob->obmat);
601                                                 invert_m3_m3(imat, bmat);
602                                 
603                                                 curs= give_cursor(scene, v3d);
604                                                 hmd->cent[0]= curs[0]-ob->obmat[3][0];
605                                                 hmd->cent[1]= curs[1]-ob->obmat[3][1];
606                                                 hmd->cent[2]= curs[2]-ob->obmat[3][2];
607                                                 mul_m3_v3(imat, hmd->cent);
608                                                 
609                                                 changed= 1;
610                                                 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
611                                         } 
612                                 }
613                         }
614                 }
615         }
616         
617         if (changed) {
618         }       
619 }
620
621 static int object_add_hook_exec(bContext *C, wmOperator *op)
622 {
623         Scene *scene= CTX_data_scene(C);
624         View3D *v3d = CTX_wm_view3d(C);
625
626         int mode= RNA_enum_get(op->ptr, "type");
627
628         // XXX - todo, break up this function for different operators
629         // and detect if this finished correctly or not,
630         add_hook(scene, v3d, mode);
631
632         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
633         return OPERATOR_FINISHED;
634 }
635
636 void OBJECT_OT_hook_add(wmOperatorType *ot)
637 {
638         static EnumPropertyItem prop_new_hook_types[] = {
639                 {1, "NEW", 0, "New Object", "Create a new object and assign the verts to it."},
640                 {2, "SELECTED", 0, "Selection", "Add the hook to the selected object."},
641                 {0, NULL, 0, NULL, NULL}
642         };
643
644         /* identifiers */
645         ot->name= "Add Hook";
646         ot->description= "Add hook to selected verts.";
647         ot->idname= "OBJECT_OT_hook_add";
648
649         /* api callbacks */
650         ot->invoke= WM_menu_invoke;
651         ot->exec= object_add_hook_exec;
652 //      ot->poll= ED_operator_editmesh;
653
654         /* flags */
655         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
656
657         RNA_def_enum(ot->srna, "type", prop_new_hook_types, 0, "Type", "");
658 }
659