Merge -c 25001,25310,25311,25638,25746 from COLLADA branch into trunk.
[blender.git] / source / blender / editors / metaball / mball_edit.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  * The Original Code is: all of this file.
24  
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <string.h>
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BLI_blenlib.h"
40 #include "BLI_math.h"
41 #include "BLI_rand.h"
42
43 #include "DNA_meta_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_view3d_types.h"
47 #include "DNA_windowmanager_types.h"
48 #include "DNA_userdef_types.h"
49
50 #include "RNA_define.h"
51 #include "RNA_access.h"
52
53 #include "BKE_utildefines.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_object.h"
56 #include "BKE_context.h"
57
58 #include "ED_screen.h"
59 #include "ED_view3d.h"
60 #include "ED_transform.h"
61 #include "ED_util.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66 /* This function is used to free all MetaElems from MetaBall */
67 void free_editMball(Object *obedit)
68 {
69 }
70
71 /* This function is called, when MetaBall Object is
72  * switched from object mode to edit mode */
73 void make_editMball(Object *obedit)
74 {
75         MetaBall *mb = (MetaBall*)obedit->data;
76         MetaElem *ml;/*, *newml;*/
77
78         ml= mb->elems.first;
79         
80         while(ml) {
81                 if(ml->flag & SELECT) mb->lastelem = ml;
82                 ml= ml->next;
83         }
84
85         mb->editelems = &mb->elems;
86 }
87
88 /* This function is called, when MetaBall Object switched from
89  * edit mode to object mode. List od MetaElements is copied
90  * from object->data->edit_elems to to object->data->elems. */
91 void load_editMball(Object *obedit)
92 {
93         MetaBall *mb = (MetaBall*)obedit->data;
94         
95         mb->editelems= NULL;
96         mb->lastelem= NULL;
97 }
98
99 /* Add metaelem primitive to metaball object (which is in edit mode) */
100 MetaElem *add_metaball_primitive(bContext *C, int type, int newname)
101 {
102         Scene *scene= CTX_data_scene(C);
103         View3D *v3d= CTX_wm_view3d(C);
104         RegionView3D *rv3d = CTX_wm_region_view3d(C);
105         Object *obedit= CTX_data_edit_object(C);
106         MetaBall *mball = (MetaBall*)obedit->data;
107         MetaElem *ml;
108         float *curs, mat[3][3], cent[3], imat[3][3], cmat[3][3];
109
110         if(!obedit) return NULL;
111
112         /* Deselect all existing metaelems */
113         ml= mball->editelems->first;
114         while(ml) {
115                 ml->flag &= ~SELECT;
116                 ml= ml->next;
117         }
118
119         copy_m3_m4(mat, obedit->obmat);
120         if(v3d) {
121                 curs= give_cursor(scene, v3d);
122                 VECCOPY(cent, curs);
123         }
124         else
125                 cent[0]= cent[1]= cent[2]= 0.0f;
126         
127         cent[0]-= obedit->obmat[3][0];
128         cent[1]-= obedit->obmat[3][1];
129         cent[2]-= obedit->obmat[3][2];
130
131         if (rv3d) {
132                 if (!(newname) || U.flag & USER_ADD_VIEWALIGNED)
133                         copy_m3_m4(imat, rv3d->viewmat);
134                 else
135                         unit_m3(imat);
136                 mul_m3_v3(imat, cent);
137                 mul_m3_m3m3(cmat, imat, mat);
138                 invert_m3_m3(imat,cmat);
139                 mul_m3_v3(imat, cent);
140         }
141         else
142                 unit_m3(imat);
143
144         ml= MEM_callocN(sizeof(MetaElem), "metaelem");
145
146         ml->x= cent[0];
147         ml->y= cent[1];
148         ml->z= cent[2];
149         ml->quat[0]= 1.0;
150         ml->quat[1]= 0.0;
151         ml->quat[2]= 0.0;
152         ml->quat[3]= 0.0;
153         ml->rad= 2.0;
154         ml->s= 2.0;
155         ml->flag= SELECT | MB_SCALE_RAD;
156
157         switch(type) {
158         case MB_BALL:
159                 ml->type = MB_BALL;
160                 ml->expx= ml->expy= ml->expz= 1.0;
161                 break;
162         case MB_TUBE:
163                 ml->type = MB_TUBE;
164                 ml->expx= ml->expy= ml->expz= 1.0;
165                 break;
166         case MB_PLANE:
167                 ml->type = MB_PLANE;
168                 ml->expx= ml->expy= ml->expz= 1.0;
169                 break;
170         case MB_ELIPSOID:
171                 ml->type = MB_ELIPSOID;
172                 ml->expx= 1.2f;
173                 ml->expy= 0.8f;
174                 ml->expz= 1.0;
175                 break;
176         case MB_CUBE:
177                 ml->type = MB_CUBE;
178                 ml->expx= ml->expy= ml->expz= 1.0;
179                 break;
180         default:
181                 break;
182         }
183         
184         mball->lastelem= ml;
185         
186         return ml;
187 }
188
189 /***************************** Select/Deselect operator *****************************/
190
191 /* Select or deselect all MetaElements */
192 static int select_all_exec(bContext *C, wmOperator *op)
193 {
194         //Scene *scene= CTX_data_scene(C);
195         Object *obedit= CTX_data_edit_object(C);
196         MetaBall *mb = (MetaBall*)obedit->data;
197         MetaElem *ml;
198         int action = RNA_enum_get(op->ptr, "action");
199
200         ml= mb->editelems->first;
201         if(ml) {
202                 if (action == SEL_TOGGLE) {
203                         action = SEL_SELECT;
204                         while(ml) {
205                                 if(ml->flag & SELECT) {
206                                         action = SEL_DESELECT;
207                                         break;
208                                 }
209                                 ml= ml->next;
210                         }
211                 }
212
213                 ml= mb->editelems->first;
214                 while(ml) {
215                         switch (action) {
216                         case SEL_SELECT:
217                                 ml->flag |= SELECT;
218                                 break;
219                         case SEL_DESELECT:
220                                 ml->flag &= ~SELECT;
221                                 break;
222                         case SEL_INVERT:
223                                 ml->flag ^= SELECT;
224                                 break;
225                         }
226                         ml= ml->next;
227                 }
228                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
229         }
230
231         return OPERATOR_FINISHED;
232 }
233
234 void MBALL_OT_select_all(wmOperatorType *ot)
235 {
236         /* identifiers */
237         ot->name= "Select/Deselect All";
238     ot->description= "Change selection of all meta elements.";
239         ot->idname= "MBALL_OT_select_all";
240
241         /* callback functions */
242         ot->exec= select_all_exec;
243         ot->poll= ED_operator_editmball;
244
245         /* flags */
246         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
247
248         WM_operator_properties_select_all(ot);
249 }
250
251 /***************************** Select inverse operator *****************************/
252
253 /* Invert metaball selection */
254 static int select_inverse_metaelems_exec(bContext *C, wmOperator *op)
255 {
256         Object *obedit= CTX_data_edit_object(C);
257         MetaBall *mb = (MetaBall*)obedit->data;
258         MetaElem *ml;
259         
260         ml= mb->editelems->first;
261         if(ml) {
262                 while(ml) {
263                         if(ml->flag & SELECT)
264                                 ml->flag &= ~SELECT;
265                         else
266                                 ml->flag |= SELECT;
267                         ml= ml->next;
268                 }
269                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
270         }
271         
272         return OPERATOR_FINISHED;
273 }
274
275 void MBALL_OT_select_inverse_metaelems(wmOperatorType *ot)
276 {
277         /* identifiers */
278         ot->name= "Inverse";
279     ot->description= "Select inverse of (un)selected metaelements.";
280         ot->idname= "MBALL_OT_select_inverse_metaelems";
281
282         /* callback functions */
283         ot->exec= select_inverse_metaelems_exec;
284         ot->poll= ED_operator_editmball;
285
286         /* flags */
287         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
288 }
289
290 /***************************** Select random operator *****************************/
291
292 /* Random metaball selection */
293 static int select_random_metaelems_exec(bContext *C, wmOperator *op)
294 {
295         Object *obedit= CTX_data_edit_object(C);
296         MetaBall *mb = (MetaBall*)obedit->data;
297         MetaElem *ml;
298         float percent= RNA_float_get(op->ptr, "percent");
299         
300         if(percent == 0.0)
301                 return OPERATOR_CANCELLED;
302         
303         ml= mb->editelems->first;
304         BLI_srand( BLI_rand() );        /* Random seed */
305         
306         /* Stupid version of random selection. Should be improved. */
307         while(ml) {
308                 if(BLI_frand() < percent)
309                         ml->flag |= SELECT;
310                 else
311                         ml->flag &= ~SELECT;
312                 ml= ml->next;
313         }
314         
315         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
316         
317         return OPERATOR_FINISHED;
318 }
319
320
321 void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot)
322 {
323         /* identifiers */
324         ot->name= "Random...";
325     ot->description= "Randomly select metaelements.";
326         ot->idname= "MBALL_OT_select_random_metaelems";
327         
328         /* callback functions */
329         ot->exec= select_random_metaelems_exec;
330         ot->invoke= WM_operator_props_popup;
331         ot->poll= ED_operator_editmball;
332         
333         /* flags */
334         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
335         
336         /* properties */
337         RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "Percentage of metaelems to select randomly.", 0.0001f, 1.0f);
338 }
339
340 /***************************** Duplicate operator *****************************/
341
342 /* Duplicate selected MetaElements */
343 static int duplicate_metaelems_exec(bContext *C, wmOperator *op)
344 {
345         Object *obedit= CTX_data_edit_object(C);
346         MetaBall *mb = (MetaBall*)obedit->data;
347         MetaElem *ml, *newml;
348         
349         ml= mb->editelems->last;
350         if(ml) {
351                 while(ml) {
352                         if(ml->flag & SELECT) {
353                                 newml= MEM_dupallocN(ml);
354                                 BLI_addtail(mb->editelems, newml);
355                                 mb->lastelem= newml;
356                                 ml->flag &= ~SELECT;
357                         }
358                         ml= ml->prev;
359                 }
360                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
361                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
362         }
363
364         return OPERATOR_FINISHED;
365 }
366
367 static int duplicate_metaelems_invoke(bContext *C, wmOperator *op, wmEvent *event)
368 {
369         int retv= duplicate_metaelems_exec(C, op);
370         
371         if (retv == OPERATOR_FINISHED) {
372                 RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
373                 WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
374         }
375         
376         return retv;
377 }
378
379
380 void MBALL_OT_duplicate_metaelems(wmOperatorType *ot)
381 {
382         /* identifiers */
383         ot->name= "Duplicate";
384     ot->description= "Delete selected metaelement(s).";
385         ot->idname= "MBALL_OT_duplicate_metaelems";
386
387         /* callback functions */
388         ot->exec= duplicate_metaelems_exec;
389         ot->invoke= duplicate_metaelems_invoke;
390         ot->poll= ED_operator_editmball;
391
392         /* flags */
393         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
394         
395         /* to give to transform */
396         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
397 }
398
399 /***************************** Delete operator *****************************/
400
401 /* Delete all selected MetaElems (not MetaBall) */
402 static int delete_metaelems_exec(bContext *C, wmOperator *op)
403 {
404         Object *obedit= CTX_data_edit_object(C);
405         MetaBall *mb= (MetaBall*)obedit->data;
406         MetaElem *ml, *next;
407         
408         ml= mb->editelems->first;
409         if(ml) {
410                 while(ml) {
411                         next= ml->next;
412                         if(ml->flag & SELECT) {
413                                 if(mb->lastelem==ml) mb->lastelem= NULL;
414                                 BLI_remlink(mb->editelems, ml);
415                                 MEM_freeN(ml);
416                         }
417                         ml= next;
418                 }
419                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
420                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
421         }
422
423         return OPERATOR_FINISHED;
424 }
425
426 void MBALL_OT_delete_metaelems(wmOperatorType *ot)
427 {
428         /* identifiers */
429         ot->name= "Delete";
430     ot->description= "Delete selected metaelement(s).";
431         ot->idname= "MBALL_OT_delete_metaelems";
432
433         /* callback functions */
434         ot->exec= delete_metaelems_exec;
435         ot->poll= ED_operator_editmball;
436
437         /* flags */
438         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
439 }
440
441 /***************************** Hide operator *****************************/
442
443 /* Hide selected MetaElems */
444 static int hide_metaelems_exec(bContext *C, wmOperator *op)
445 {
446         Object *obedit= CTX_data_edit_object(C);
447         MetaBall *mb= (MetaBall*)obedit->data;
448         MetaElem *ml;
449         int hide_unselected= RNA_boolean_get(op->ptr, "unselected");
450
451         ml= mb->editelems->first;
452
453         if(ml) {
454                 /* Hide unselected metaelems */
455                 if(hide_unselected) {
456                         while(ml){
457                                 if(!(ml->flag & SELECT))
458                                         ml->flag |= MB_HIDE;
459                                 ml= ml->next;
460                         }
461                 /* Hide selected metaelems */   
462                 } else {
463                         while(ml){
464                                 if(ml->flag & SELECT)
465                                         ml->flag |= MB_HIDE;
466                                 ml= ml->next;
467                         }
468                 }
469                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
470                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
471         }
472
473         return OPERATOR_FINISHED;
474 }
475
476 void MBALL_OT_hide_metaelems(wmOperatorType *ot)
477 {
478         /* identifiers */
479         ot->name= "Hide";
480     ot->description= "Hide (un)selected metaelement(s).";
481         ot->idname= "MBALL_OT_hide_metaelems";
482
483         /* callback functions */
484         ot->exec= hide_metaelems_exec;
485         ot->poll= ED_operator_editmball;
486
487         /* flags */
488         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
489         
490         /* props */
491         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
492 }
493
494 /***************************** Unhide operator *****************************/
495
496 /* Unhide all edited MetaElems */
497 static int reveal_metaelems_exec(bContext *C, wmOperator *op)
498 {
499         Object *obedit= CTX_data_edit_object(C);
500         MetaBall *mb= (MetaBall*)obedit->data;
501         MetaElem *ml;
502
503         ml= mb->editelems->first;
504
505         if(ml) {
506                 while(ml) {
507                         ml->flag &= ~MB_HIDE;
508                         ml= ml->next;
509                 }
510                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
511                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
512         }
513         
514         return OPERATOR_FINISHED;
515 }
516
517 void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
518 {
519         /* identifiers */
520         ot->name= "Reveal";
521     ot->description= "Reveal all hidden metaelements.";
522         ot->idname= "MBALL_OT_reveal_metaelems";
523         
524         /* callback functions */
525         ot->exec= reveal_metaelems_exec;
526         ot->poll= ED_operator_editmball;
527         
528         /* flags */
529         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
530 }
531
532 /* Select MetaElement with mouse click (user can select radius circle or
533  * stiffness circle) */
534 int mouse_mball(bContext *C, short mval[2], int extend)
535 {
536         static MetaElem *startelem=NULL;
537         Object *obedit= CTX_data_edit_object(C);
538         ViewContext vc;
539         MetaBall *mb = (MetaBall*)obedit->data;
540         MetaElem *ml, *act=NULL;
541         int a, hits;
542         unsigned int buffer[4*MAXPICKBUF];
543         rcti rect;
544
545         view3d_set_viewcontext(C, &vc);
546
547         rect.xmin= mval[0]-12;
548         rect.xmax= mval[0]+12;
549         rect.ymin= mval[1]-12;
550         rect.ymax= mval[1]+12;
551
552         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
553
554         /* does startelem exist? */
555         ml= mb->editelems->first;
556         while(ml) {
557                 if(ml==startelem) break;
558                 ml= ml->next;
559         }
560
561         if(ml==NULL) startelem= mb->editelems->first;
562         
563         if(hits>0) {
564                 ml= startelem;
565                 while(ml) {
566                         for(a=0; a<hits; a++) {
567                                 /* index converted for gl stuff */
568                                 if(ml->selcol1==buffer[ 4 * a + 3 ]){
569                                         ml->flag |= MB_SCALE_RAD;
570                                         act= ml;
571                                 }
572                                 if(ml->selcol2==buffer[ 4 * a + 3 ]){
573                                         ml->flag &= ~MB_SCALE_RAD;
574                                         act= ml;
575                                 }
576                         }
577                         if(act) break;
578                         ml= ml->next;
579                         if(ml==NULL) ml= mb->editelems->first;
580                         if(ml==startelem) break;
581                 }
582                 
583                 /* When some metaelem was found, then it is neccessary to select or
584                  * deselet it. */
585                 if(act) {
586                         if(extend==0) {
587                                 /* Deselect all existing metaelems */
588                                 ml= mb->editelems->first;
589                                 while(ml) {
590                                         ml->flag &= ~SELECT;
591                                         ml= ml->next;
592                                 }
593                                 /* Select only metaelem clicked on */
594                                 act->flag |= SELECT;
595                         }
596                         else {
597                                 if(act->flag & SELECT)
598                                         act->flag &= ~SELECT;
599                                 else
600                                         act->flag |= SELECT;
601                         }
602                         mb->lastelem= act;
603                         
604                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
605
606                         return 1;
607                 }
608         }
609
610         return 0;
611 }
612
613
614 /*  ************* undo for MetaBalls ************* */
615
616 /* free all MetaElems from ListBase */
617 static void freeMetaElemlist(ListBase *lb)
618 {
619         MetaElem *ml, *next;
620
621         if(lb==NULL) return;
622
623         ml= lb->first;
624         while(ml){
625                 next= ml->next;
626                 BLI_remlink(lb, ml);
627                 MEM_freeN(ml);
628                 ml= next;
629         }
630
631         lb->first= lb->last= NULL;
632 }
633
634
635 static void undoMball_to_editMball(void *lbu, void *lbe)
636 {
637         ListBase *lb= lbu;
638         ListBase *editelems= lbe;
639         MetaElem *ml, *newml;
640         
641         freeMetaElemlist(editelems);
642
643         /* copy 'undo' MetaElems to 'edit' MetaElems */
644         ml= lb->first;
645         while(ml){
646                 newml= MEM_dupallocN(ml);
647                 BLI_addtail(editelems, newml);
648                 ml= ml->next;
649         }
650         
651 }
652
653 static void *editMball_to_undoMball(void *lbe)
654 {
655         ListBase *editelems= lbe;
656         ListBase *lb;
657         MetaElem *ml, *newml;
658
659         /* allocate memory for undo ListBase */
660         lb= MEM_callocN(sizeof(ListBase), "listbase undo");
661         lb->first= lb->last= NULL;
662         
663         /* copy contents of current ListBase to the undo ListBase */
664         ml= editelems->first;
665         while(ml){
666                 newml= MEM_dupallocN(ml);
667                 BLI_addtail(lb, newml);
668                 ml= ml->next;
669         }
670         
671         return lb;
672 }
673
674 /* free undo ListBase of MetaElems */
675 static void free_undoMball(void *lbv)
676 {
677         ListBase *lb= lbv;
678         
679         freeMetaElemlist(lb);
680         MEM_freeN(lb);
681 }
682
683 ListBase *metaball_get_editelems(Object *ob)
684 {
685         if(ob && ob->type==OB_MBALL) {
686                 struct MetaBall *mb= (struct MetaBall*)ob->data;
687                 return mb->editelems;
688         }
689         return NULL;
690 }
691
692
693 static void *get_data(bContext *C)
694 {
695         Object *obedit= CTX_data_edit_object(C);
696         return metaball_get_editelems(obedit);
697 }
698
699 /* this is undo system for MetaBalls */
700 void undo_push_mball(bContext *C, char *name)
701 {
702         undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
703 }
704