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