bug fix:
[blender.git] / source / blender / src / editmball.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <string.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_arithb.h"
43
44 #include "DNA_screen_types.h"
45 #include "DNA_meta_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_view3d_types.h"
49
50 #include "BKE_utildefines.h"
51 #include "BKE_depsgraph.h"
52 #include "BKE_global.h"
53 #include "BKE_object.h"
54
55 #include "BIF_gl.h"
56 #include "BIF_graphics.h"
57 #include "BIF_screen.h"
58 #include "BIF_toolbox.h"
59 #include "BIF_space.h"
60 #include "BIF_editmode_undo.h"
61 #include "BIF_transform.h"
62
63 #include "BDR_editobject.h"
64 #include "BDR_editmball.h"
65
66 #include "BSE_edit.h"
67 #include "BSE_view.h"
68
69 #include "blendef.h"
70 #include "mydevice.h"
71
72 extern short editbutflag;
73
74 ListBase editelems= {0, 0};
75 MetaElem *lastelem;
76
77 /* this function is called, when MetaBall Object is
78  * switched from object mode to edit mode */
79 void make_editMball()
80 {
81         MetaBall *mb;
82         MetaElem *ml, *newmb;
83
84         BLI_freelistN(&editelems);
85         lastelem= 0;
86         
87         mb= G.obedit->data;
88         ml= mb->elems.first;
89         
90         while(ml) {
91                 newmb= MEM_dupallocN(ml);
92                 BLI_addtail(&editelems, newmb);
93                 if(ml->flag & SELECT) lastelem= newmb;
94                 
95                 ml= ml->next;
96         }
97
98         allqueue(REDRAWBUTSEDIT, 0);
99
100         countall();
101 }
102
103 /* this function is called, when MetaBall Object switched from
104  * edit mode to object mode. List od MetaElements is copied
105  * from editelems to to object->data structure (mb->elems) */
106 void load_editMball()
107 {
108         /* load mball in object */
109         MetaBall *mb;
110         MetaElem *ml, *newml;
111
112         if(G.obedit==NULL) return;
113         
114         mb= G.obedit->data;
115         BLI_freelistN(&(mb->elems));
116
117
118         ml= editelems.first;
119         while(ml) {
120                 newml= MEM_dupallocN(ml);
121                 BLI_addtail(&(mb->elems), newml);
122                 
123                 ml= ml->next;
124         }
125 }
126
127 /* add new MetaElement primitive */
128 void add_primitiveMball(int dummy_argument)
129 {
130         MetaElem *ml;
131         float *curs, mat[3][3], cent[3], imat[3][3], cmat[3][3];
132
133         if(G.scene->id.lib) return;
134
135         /* this function also comes from an info window */
136         if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
137         
138         check_editmode(OB_MBALL);
139
140         /* if no obedit: new object and enter editmode */
141         if(G.obedit==NULL) {
142                 add_object_draw(OB_MBALL);
143                 base_init_from_view3d(BASACT, G.vd);
144                 G.obedit= BASACT->object;
145                 
146                 where_is_object(G.obedit);  // need now, for imat
147                 
148                 make_editMball();
149                 setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
150         }
151         
152         /* deselect */
153         ml= editelems.first;
154         while(ml) {
155                 ml->flag &= ~SELECT;
156                 ml= ml->next;
157         }
158         
159         /* imat and centre and size */
160         Mat3CpyMat4(mat, G.obedit->obmat);
161
162         curs= give_cursor();
163         VECCOPY(cent, curs);
164         cent[0]-= G.obedit->obmat[3][0];
165         cent[1]-= G.obedit->obmat[3][1];
166         cent[2]-= G.obedit->obmat[3][2];
167
168         Mat3CpyMat4(imat, G.vd->viewmat);
169         Mat3MulVecfl(imat, cent);
170         Mat3MulMat3(cmat, imat, mat);
171         Mat3Inv(imat,cmat);
172         
173         Mat3MulVecfl(imat, cent);
174
175         ml= MEM_callocN(sizeof(MetaElem), "metaelem");
176         BLI_addtail(&editelems, ml);
177
178         ml->x= cent[0];
179         ml->y= cent[1];
180         ml->z= cent[2];
181         ml->quat[0]= 1.0;
182         ml->quat[1]= 0.0;
183         ml->quat[2]= 0.0;
184         ml->quat[3]= 0.0;
185         ml->rad= 2.0;
186         ml->s= 2.0;
187         ml->flag= SELECT | MB_SCALE_RAD;
188
189         switch(dummy_argument) {
190         case 1:
191                 ml->type = MB_BALL;
192                 ml->expx= ml->expy= ml->expz= 1.0;
193                 break;
194         case 2:
195                 ml->type = MB_TUBE;
196                 ml->expx= ml->expy= ml->expz= 1.0;
197                 break;
198         case 3:
199                 ml->type = MB_PLANE;
200                 ml->expx= ml->expy= ml->expz= 1.0;
201                 break;
202         case 4:
203                 ml->type = MB_ELIPSOID;
204                 ml->expx= 1.2f;
205                 ml->expy= 0.8f;
206                 ml->expz= 1.0;
207                 break;
208         case 5:
209                 ml->type = MB_CUBE;
210                 ml->expx= ml->expy= ml->expz= 1.0;
211                 break;
212         default:
213                 break;
214         }
215         
216         lastelem= ml;
217         
218         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);  // added ball can influence others
219
220         countall();     
221         allqueue(REDRAWALL, 0);
222         BIF_undo_push("Add MetaElem");
223 }
224
225 /* deselect all MetaElements */
226 void deselectall_mball()
227 {
228         MetaElem *ml;
229         int sel= 0;
230         
231         ml= editelems.first;
232         while(ml) {
233                 if(ml->flag & SELECT) break;
234                 ml= ml->next;
235         }
236
237         if(ml) sel= 1;
238
239         ml= editelems.first;
240         while(ml) {
241                 if(sel) ml->flag &= ~SELECT;
242                 else ml->flag |= SELECT;
243                 ml= ml->next;
244         }
245
246         allqueue(REDRAWVIEW3D, 0);
247         countall();
248         BIF_undo_push("Deselect MetaElem");
249 }
250
251 /* select MetaElement with mouse click (user can select radius circle or
252  * stiffness circle) */
253 void mouse_mball()
254 {
255         static MetaElem *startelem=0;
256         MetaElem *ml, *act=0;
257         int a, hits;
258         unsigned int buffer[MAXPICKBUF];
259         
260         hits= view3d_opengl_select(buffer, MAXPICKBUF, 0, 0, 0, 0);
261
262         /* does startelem exist? */
263         ml= editelems.first;
264         while(ml) {
265                 if(ml==startelem) break;
266                 ml= ml->next;
267         }
268         if(ml==NULL) startelem= editelems.first;
269         
270         if(hits>0) {
271                 ml= startelem;
272                 while(ml) {
273                         
274                         for(a=0; a<hits; a++) {
275                                 /* index converted for gl stuff */
276                                 if(ml->selcol1==buffer[ 4 * a + 3 ]){
277                                         ml->flag |= MB_SCALE_RAD;
278                                         act= ml;
279                                 }
280                                 if(ml->selcol2==buffer[ 4 * a + 3 ]){
281                                         ml->flag &= ~MB_SCALE_RAD;
282                                         act= ml;
283                                 }
284
285                         }
286                         
287                         if(act) break;
288                         
289                         ml= ml->next;
290                         if(ml==NULL) ml= editelems.first;
291                         if(ml==startelem) break;
292                 }
293                 if(act) {
294                         if((G.qual & LR_SHIFTKEY)==0) {
295                                 deselectall_mball();
296                                 if(act->flag & SELECT) deselectall_mball();
297                                 act->flag |= SELECT;
298                         }
299                         else {
300                                 if(act->flag & SELECT) {
301                                         act->flag &= ~SELECT;
302                                 }
303                                 else act->flag |= SELECT;
304                         }
305                         lastelem= act;
306                         allqueue(REDRAWVIEW3D, 0);
307                         allqueue(REDRAWBUTSEDIT, 0);
308                 }
309         }
310
311         allqueue(REDRAWBUTSOBJECT, 0);
312         countall();
313         rightmouse_transform();
314 }
315
316 /* duplicate selected MetaElements */
317 void adduplicate_mball()
318 {
319         MetaElem *ml, *newml;
320         
321         ml= editelems.last;
322         while(ml) {
323                 if(ml->flag & SELECT) {
324                         newml= MEM_dupallocN(ml);
325                         BLI_addtail(&editelems, newml);
326                         lastelem= newml;
327                         ml->flag &= ~SELECT;
328                 }
329                 ml= ml->prev;
330         }
331         
332         BIF_TransformSetUndo("Add Duplicate");
333         countall();
334         initTransform(TFM_TRANSLATION, CTX_NO_PET);
335         Transform();
336         allqueue(REDRAWBUTSEDIT, 0);
337 }
338
339 /* Delete all selected MetaElems (not MetaBall) */
340 void delete_mball()
341 {
342         MetaElem *ml, *next;
343         
344         if(okee("Erase selected")==0) return;
345         
346         ml= editelems.first;
347         while(ml) {
348                 next= ml->next;
349                 if(ml->flag & SELECT) {
350                         if(lastelem==ml) lastelem= 0;
351                         BLI_remlink(&editelems, ml);
352                         MEM_freeN(ml);
353                 }
354                 ml= next;
355         }
356         
357         DAG_scene_sort(G.scene);
358         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
359         allqueue(REDRAWVIEW3D, 0);
360         allqueue(REDRAWBUTSEDIT, 0);
361         countall();
362         BIF_undo_push("Delete MetaElem");
363 }
364
365 /* free all MetaElems from ListBase */
366 void freeMetaElemlist(ListBase *lb)
367 {
368         MetaElem *ml, *next;
369
370         if(lb==NULL) return;
371
372         ml= lb->first;
373         while(ml){
374                 next= ml->next;
375                 BLI_remlink(lb, ml);
376                 MEM_freeN(ml);
377                 ml= next;
378         }
379
380         lb->first= lb->last= NULL;
381         
382 }
383
384 /*  ************* undo for MetaBalls ************* */
385
386 static void undoMball_to_editMball(void *lbv)
387 {
388         ListBase *lb= lbv;
389         MetaElem *ml, *newml;
390         unsigned int nr, lastmlnr= 0;
391
392         /* we try to restore lastelem, which used in for example in button window */
393         for(ml= editelems.first; ml; ml= ml->next, lastmlnr++)
394                 if(lastelem==ml) break;
395
396         freeMetaElemlist(&editelems);
397
398         /* copy 'undo' MetaElems to 'edit' MetaElems */
399         ml= lb->first;
400         while(ml){
401                 newml= MEM_dupallocN(ml);
402                 BLI_addtail(&editelems, newml);
403                 ml= ml->next;
404         }
405         
406         for(nr=0, lastelem= editelems.first; lastelem; lastelem= lastelem->next, nr++)
407                 if(nr==lastmlnr) break;
408         
409         countall();
410 }
411
412 static void *editMball_to_undoMball(void)
413 {
414         ListBase *lb;
415         MetaElem *ml, *newml;
416
417         /* allocate memory for undo ListBase */
418         lb= MEM_callocN(sizeof(ListBase), "listbase undo");
419         lb->first= lb->last= NULL;
420         
421         /* copy contents of current ListBase to the undo ListBase */
422         ml= editelems.first;
423         while(ml){
424                 newml= MEM_dupallocN(ml);
425                 BLI_addtail(lb, newml);
426                 ml= ml->next;
427         }
428         
429         return lb;
430 }
431
432 /* free undo ListBase of MetaElems */
433 static void free_undoMball(void *lbv)
434 {
435         ListBase *lb= lbv;
436         
437         freeMetaElemlist(lb);
438         MEM_freeN(lb);
439 }
440
441 /* this is undo system for MetaBalls */
442 void undo_push_mball(char *name)
443 {
444         undo_editmode_push(name, free_undoMball, undoMball_to_editMball, editMball_to_undoMball);
445 }
446
447 /* Hide selected/unselected MetaElems */
448 void hide_mball(char hide)
449 {
450         MetaElem *ml;
451
452         ml= editelems.first;
453
454         while(ml){
455                 if(hide){
456                         if(!(ml->flag & SELECT))
457                                 ml->flag |= MB_HIDE;
458                 }
459                 else{
460                         if(ml->flag & SELECT)
461                                 ml->flag |= MB_HIDE;
462                 }
463                 ml= ml->next;
464         }
465
466         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
467         allqueue(REDRAWVIEW3D, 0);
468         allqueue(REDRAWBUTSEDIT, 0);
469         countall();
470         BIF_undo_push("Hide MetaElems");
471 }
472
473 /* Unhide all edited MetaElems */
474 void reveal_mball(void)
475 {
476         MetaElem *ml;
477
478         ml= editelems.first;
479
480         while(ml){
481                 ml->flag &= ~MB_HIDE;
482                 ml= ml->next;
483         }
484
485         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
486         allqueue(REDRAWVIEW3D, 0);
487         allqueue(REDRAWBUTSEDIT, 0);
488         countall();
489         BIF_undo_push("Unhide MetaElems");
490 }
491