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