Sculpt: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r24152...
[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_arithb.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         Mat3CpyMat4(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                         Mat3CpyMat4(imat, rv3d->viewmat);
134                 else
135                         Mat3One(imat);
136                 Mat3MulVecfl(imat, cent);
137                 Mat3MulMat3(cmat, imat, mat);
138                 Mat3Inv(imat,cmat);
139                 Mat3MulVecfl(imat, cent);
140         }
141         else
142                 Mat3One(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_deselect_all_metaelems_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 any_sel= 0;
199         
200         /* Is any metaelem selected? */
201         ml= mb->editelems->first;
202         if(ml) {
203                 while(ml) {
204                         if(ml->flag & SELECT) break;
205                         ml= ml->next;
206                 }
207                 if(ml) any_sel= 1;
208
209                 ml= mb->editelems->first;
210                 while(ml) {
211                         if(any_sel) ml->flag &= ~SELECT;
212                         else ml->flag |= SELECT;
213                         ml= ml->next;
214                 }
215                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
216                 //DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
217         }
218
219         return OPERATOR_FINISHED;
220 }
221
222 void MBALL_OT_select_deselect_all_metaelems(wmOperatorType *ot)
223 {
224         /* identifiers */
225         ot->name= "Select/Deselect All";
226     ot->description= "(de)select all metaelements.";
227         ot->idname= "MBALL_OT_select_deselect_all_metaelems";
228
229         /* callback functions */
230         ot->exec= select_deselect_all_metaelems_exec;
231         ot->poll= ED_operator_editmball;
232
233         /* flags */
234         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
235 }
236
237 /***************************** Select inverse operator *****************************/
238
239 /* Invert metaball selection */
240 static int select_inverse_metaelems_exec(bContext *C, wmOperator *op)
241 {
242         Object *obedit= CTX_data_edit_object(C);
243         MetaBall *mb = (MetaBall*)obedit->data;
244         MetaElem *ml;
245         
246         ml= mb->editelems->first;
247         if(ml) {
248                 while(ml) {
249                         if(ml->flag & SELECT)
250                                 ml->flag &= ~SELECT;
251                         else
252                                 ml->flag |= SELECT;
253                         ml= ml->next;
254                 }
255                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
256         }
257         
258         return OPERATOR_FINISHED;
259 }
260
261 void MBALL_OT_select_inverse_metaelems(wmOperatorType *ot)
262 {
263         /* identifiers */
264         ot->name= "Inverse";
265     ot->description= "Select inverse of (un)selected metaelements.";
266         ot->idname= "MBALL_OT_select_inverse_metaelems";
267
268         /* callback functions */
269         ot->exec= select_inverse_metaelems_exec;
270         ot->poll= ED_operator_editmball;
271
272         /* flags */
273         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
274 }
275
276 /***************************** Select random operator *****************************/
277
278 /* Random metaball selection */
279 static int select_random_metaelems_exec(bContext *C, wmOperator *op)
280 {
281         Object *obedit= CTX_data_edit_object(C);
282         MetaBall *mb = (MetaBall*)obedit->data;
283         MetaElem *ml;
284         float percent= RNA_float_get(op->ptr, "percent");
285         
286         if(percent == 0.0)
287                 return OPERATOR_CANCELLED;
288         
289         ml= mb->editelems->first;
290         BLI_srand( BLI_rand() );        /* Random seed */
291         
292         /* Stupid version of random selection. Should be improved. */
293         while(ml) {
294                 if(BLI_frand() < percent)
295                         ml->flag |= SELECT;
296                 else
297                         ml->flag &= ~SELECT;
298                 ml= ml->next;
299         }
300         
301         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
302         
303         return OPERATOR_FINISHED;
304 }
305
306
307 void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot)
308 {
309         /* identifiers */
310         ot->name= "Random...";
311     ot->description= "Randomly select metaelements.";
312         ot->idname= "MBALL_OT_select_random_metaelems";
313         
314         /* callback functions */
315         ot->exec= select_random_metaelems_exec;
316         ot->invoke= WM_operator_props_popup;
317         ot->poll= ED_operator_editmball;
318         
319         /* flags */
320         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
321         
322         /* properties */
323         RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "Percentage of metaelems to select randomly.", 0.0001f, 1.0f);
324 }
325
326 /***************************** Duplicate operator *****************************/
327
328 /* Duplicate selected MetaElements */
329 static int duplicate_metaelems_exec(bContext *C, wmOperator *op)
330 {
331         Object *obedit= CTX_data_edit_object(C);
332         MetaBall *mb = (MetaBall*)obedit->data;
333         MetaElem *ml, *newml;
334         
335         ml= mb->editelems->last;
336         if(ml) {
337                 while(ml) {
338                         if(ml->flag & SELECT) {
339                                 newml= MEM_dupallocN(ml);
340                                 BLI_addtail(mb->editelems, newml);
341                                 mb->lastelem= newml;
342                                 ml->flag &= ~SELECT;
343                         }
344                         ml= ml->prev;
345                 }
346                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
347                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
348         }
349
350         return OPERATOR_FINISHED;
351 }
352
353 static int duplicate_metaelems_invoke(bContext *C, wmOperator *op, wmEvent *event)
354 {
355         int retv= duplicate_metaelems_exec(C, op);
356         
357         if (retv == OPERATOR_FINISHED) {
358                 RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
359                 WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
360         }
361         
362         return retv;
363 }
364
365
366 void MBALL_OT_duplicate_metaelems(wmOperatorType *ot)
367 {
368         /* identifiers */
369         ot->name= "Duplicate";
370     ot->description= "Delete selected metaelement(s).";
371         ot->idname= "MBALL_OT_duplicate_metaelems";
372
373         /* callback functions */
374         ot->exec= duplicate_metaelems_exec;
375         ot->invoke= duplicate_metaelems_invoke;
376         ot->poll= ED_operator_editmball;
377
378         /* flags */
379         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
380         
381         /* to give to transform */
382         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
383 }
384
385 /***************************** Delete operator *****************************/
386
387 /* Delete all selected MetaElems (not MetaBall) */
388 static int delete_metaelems_exec(bContext *C, wmOperator *op)
389 {
390         Object *obedit= CTX_data_edit_object(C);
391         MetaBall *mb= (MetaBall*)obedit->data;
392         MetaElem *ml, *next;
393         
394         ml= mb->editelems->first;
395         if(ml) {
396                 while(ml) {
397                         next= ml->next;
398                         if(ml->flag & SELECT) {
399                                 if(mb->lastelem==ml) mb->lastelem= NULL;
400                                 BLI_remlink(mb->editelems, ml);
401                                 MEM_freeN(ml);
402                         }
403                         ml= next;
404                 }
405                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
406                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
407         }
408
409         return OPERATOR_FINISHED;
410 }
411
412 void MBALL_OT_delete_metaelems(wmOperatorType *ot)
413 {
414         /* identifiers */
415         ot->name= "Delete";
416     ot->description= "Delete selected metaelement(s).";
417         ot->idname= "MBALL_OT_delete_metaelems";
418
419         /* callback functions */
420         ot->exec= delete_metaelems_exec;
421         ot->poll= ED_operator_editmball;
422
423         /* flags */
424         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
425 }
426
427 /***************************** Hide operator *****************************/
428
429 /* Hide selected MetaElems */
430 static int hide_metaelems_exec(bContext *C, wmOperator *op)
431 {
432         Object *obedit= CTX_data_edit_object(C);
433         MetaBall *mb= (MetaBall*)obedit->data;
434         MetaElem *ml;
435         int hide_unselected= RNA_boolean_get(op->ptr, "unselected");
436
437         ml= mb->editelems->first;
438
439         if(ml) {
440                 /* Hide unselected metaelems */
441                 if(hide_unselected) {
442                         while(ml){
443                                 if(!(ml->flag & SELECT))
444                                         ml->flag |= MB_HIDE;
445                                 ml= ml->next;
446                         }
447                 /* Hide selected metaelems */   
448                 } else {
449                         while(ml){
450                                 if(ml->flag & SELECT)
451                                         ml->flag |= MB_HIDE;
452                                 ml= ml->next;
453                         }
454                 }
455                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
456                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
457         }
458
459         return OPERATOR_FINISHED;
460 }
461
462 void MBALL_OT_hide_metaelems(wmOperatorType *ot)
463 {
464         /* identifiers */
465         ot->name= "Hide";
466     ot->description= "Hide (un)selected metaelement(s).";
467         ot->idname= "MBALL_OT_hide_metaelems";
468
469         /* callback functions */
470         ot->exec= hide_metaelems_exec;
471         ot->poll= ED_operator_editmball;
472
473         /* flags */
474         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
475         
476         /* props */
477         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
478 }
479
480 /***************************** Unhide operator *****************************/
481
482 /* Unhide all edited MetaElems */
483 static int reveal_metaelems_exec(bContext *C, wmOperator *op)
484 {
485         Object *obedit= CTX_data_edit_object(C);
486         MetaBall *mb= (MetaBall*)obedit->data;
487         MetaElem *ml;
488
489         ml= mb->editelems->first;
490
491         if(ml) {
492                 while(ml) {
493                         ml->flag &= ~MB_HIDE;
494                         ml= ml->next;
495                 }
496                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, mb);
497                 DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
498         }
499         
500         return OPERATOR_FINISHED;
501 }
502
503 void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
504 {
505         /* identifiers */
506         ot->name= "Reveal";
507     ot->description= "Reveal all hidden metaelements.";
508         ot->idname= "MBALL_OT_reveal_metaelems";
509         
510         /* callback functions */
511         ot->exec= reveal_metaelems_exec;
512         ot->poll= ED_operator_editmball;
513         
514         /* flags */
515         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
516 }
517
518 /* Select MetaElement with mouse click (user can select radius circle or
519  * stiffness circle) */
520 void mouse_mball(bContext *C, short mval[2], int extend)
521 {
522         static MetaElem *startelem=NULL;
523         Object *obedit= CTX_data_edit_object(C);
524         ViewContext vc;
525         MetaBall *mb = (MetaBall*)obedit->data;
526         MetaElem *ml, *act=NULL;
527         int a, hits;
528         unsigned int buffer[4*MAXPICKBUF];
529         rcti rect;
530
531         view3d_set_viewcontext(C, &vc);
532
533         rect.xmin= mval[0]-12;
534         rect.xmax= mval[0]+12;
535         rect.ymin= mval[1]-12;
536         rect.ymax= mval[1]+12;
537
538         hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
539
540         /* does startelem exist? */
541         ml= mb->editelems->first;
542         while(ml) {
543                 if(ml==startelem) break;
544                 ml= ml->next;
545         }
546
547         if(ml==NULL) startelem= mb->editelems->first;
548         
549         if(hits>0) {
550                 ml= startelem;
551                 while(ml) {
552                         for(a=0; a<hits; a++) {
553                                 /* index converted for gl stuff */
554                                 if(ml->selcol1==buffer[ 4 * a + 3 ]){
555                                         ml->flag |= MB_SCALE_RAD;
556                                         act= ml;
557                                 }
558                                 if(ml->selcol2==buffer[ 4 * a + 3 ]){
559                                         ml->flag &= ~MB_SCALE_RAD;
560                                         act= ml;
561                                 }
562                         }
563                         if(act) break;
564                         ml= ml->next;
565                         if(ml==NULL) ml= mb->editelems->first;
566                         if(ml==startelem) break;
567                 }
568                 
569                 /* When some metaelem was found, then it is neccessary to select or
570                  * deselet it. */
571                 if(act) {
572                         if(extend==0) {
573                                 /* Deselect all existing metaelems */
574                                 ml= mb->editelems->first;
575                                 while(ml) {
576                                         ml->flag &= ~SELECT;
577                                         ml= ml->next;
578                                 }
579                                 /* Select only metaelem clicked on */
580                                 act->flag |= SELECT;
581                         }
582                         else {
583                                 if(act->flag & SELECT)
584                                         act->flag &= ~SELECT;
585                                 else
586                                         act->flag |= SELECT;
587                         }
588                         mb->lastelem= act;
589                         
590                         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, mb);
591                 }
592         }
593 }
594
595
596 /*  ************* undo for MetaBalls ************* */
597
598 /* free all MetaElems from ListBase */
599 static void freeMetaElemlist(ListBase *lb)
600 {
601         MetaElem *ml, *next;
602
603         if(lb==NULL) return;
604
605         ml= lb->first;
606         while(ml){
607                 next= ml->next;
608                 BLI_remlink(lb, ml);
609                 MEM_freeN(ml);
610                 ml= next;
611         }
612
613         lb->first= lb->last= NULL;
614 }
615
616
617 static void undoMball_to_editMball(void *lbu, void *lbe)
618 {
619         ListBase *lb= lbu;
620         ListBase *editelems= lbe;
621         MetaElem *ml, *newml;
622         
623         freeMetaElemlist(editelems);
624
625         /* copy 'undo' MetaElems to 'edit' MetaElems */
626         ml= lb->first;
627         while(ml){
628                 newml= MEM_dupallocN(ml);
629                 BLI_addtail(editelems, newml);
630                 ml= ml->next;
631         }
632         
633 }
634
635 static void *editMball_to_undoMball(void *lbe)
636 {
637         ListBase *editelems= lbe;
638         ListBase *lb;
639         MetaElem *ml, *newml;
640
641         /* allocate memory for undo ListBase */
642         lb= MEM_callocN(sizeof(ListBase), "listbase undo");
643         lb->first= lb->last= NULL;
644         
645         /* copy contents of current ListBase to the undo ListBase */
646         ml= editelems->first;
647         while(ml){
648                 newml= MEM_dupallocN(ml);
649                 BLI_addtail(lb, newml);
650                 ml= ml->next;
651         }
652         
653         return lb;
654 }
655
656 /* free undo ListBase of MetaElems */
657 static void free_undoMball(void *lbv)
658 {
659         ListBase *lb= lbv;
660         
661         freeMetaElemlist(lb);
662         MEM_freeN(lb);
663 }
664
665 ListBase *metaball_get_editelems(Object *ob)
666 {
667         if(ob && ob->type==OB_MBALL) {
668                 struct MetaBall *mb= (struct MetaBall*)ob->data;
669                 return mb->editelems;
670         }
671         return NULL;
672 }
673
674
675 static void *get_data(bContext *C)
676 {
677         Object *obedit= CTX_data_edit_object(C);
678         return metaball_get_editelems(obedit);
679 }
680
681 /* this is undo system for MetaBalls */
682 void undo_push_mball(bContext *C, char *name)
683 {
684         undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
685 }
686