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