- It is possible to scale radius of MetaElem again.
[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_displist.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 void make_editMball()
78 {
79         MetaBall *mb;
80         MetaElem *ml, *newmb;
81
82         BLI_freelistN(&editelems);
83         lastelem= 0;
84         
85         mb= G.obedit->data;
86         ml= mb->elems.first;
87         
88         while(ml) {
89                 newmb= MEM_dupallocN(ml);
90                 BLI_addtail(&editelems, newmb);
91                 if(ml->flag & SELECT) lastelem= newmb;
92                 
93                 ml= ml->next;
94         }
95
96         allqueue(REDRAWBUTSEDIT, 0);
97
98         countall();
99 }
100
101 void load_editMball()
102 {
103         /* load mball in object */
104         MetaBall *mb;
105         MetaElem *ml, *newml;
106
107         if(G.obedit==0) return;
108         
109         mb= G.obedit->data;
110         BLI_freelistN(&(mb->elems));
111
112
113         ml= editelems.first;
114         while(ml) {
115                 newml= MEM_dupallocN(ml);
116                 BLI_addtail(&(mb->elems), newml);
117                 
118                 ml= ml->next;
119         }
120 }
121
122 void add_primitiveMball(int dummy_argument)
123 {
124         MetaElem *ml;
125         float *curs, mat[3][3], cent[3], imat[3][3], cmat[3][3];
126
127         if(G.scene->id.lib) return;
128
129         /* this function also comes from an info window */
130         if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
131         
132         check_editmode(OB_MBALL);
133
134         /* if no obedit: new object and enter editmode */
135         if(G.obedit==0) {
136                 add_object_draw(OB_MBALL);
137                 base_init_from_view3d(BASACT, G.vd);
138                 G.obedit= BASACT->object;
139                 
140                 where_is_object(G.obedit);
141
142                 make_editMball();
143                 setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
144         }
145         
146         /* deselect */
147         ml= editelems.first;
148         while(ml) {
149                 ml->flag &= ~SELECT;
150                 ml= ml->next;
151         }
152         
153         /* imat and centre and size */
154         Mat3CpyMat4(mat, G.obedit->obmat);
155
156         curs= give_cursor();
157         VECCOPY(cent, curs);
158         cent[0]-= G.obedit->obmat[3][0];
159         cent[1]-= G.obedit->obmat[3][1];
160         cent[2]-= G.obedit->obmat[3][2];
161
162         Mat3CpyMat4(imat, G.vd->viewmat);
163         Mat3MulVecfl(imat, cent);
164         Mat3MulMat3(cmat, imat, mat);
165         Mat3Inv(imat,cmat);
166         
167         Mat3MulVecfl(imat, cent);
168
169         ml= MEM_callocN(sizeof(MetaElem), "metaelem");
170         BLI_addtail(&editelems, ml);
171
172         ml->x= cent[0];
173         ml->y= cent[1];
174         ml->z= cent[2];
175         ml->quat[0]= 1.0;
176         ml->quat[1]= 0.0;
177         ml->quat[2]= 0.0;
178         ml->quat[3]= 0.0;
179         ml->rad= 2.0;
180         ml->s= 2.0;
181         ml->flag= SELECT | MB_SCALE_RAD;
182
183         switch(dummy_argument) {
184                 case 1:
185                         ml->type = MB_BALL;
186                         ml->expx= ml->expy= ml->expz= 1.0;
187                         break;
188                 case 2:
189                         ml->type = MB_TUBE;
190                         ml->expx= ml->expy= ml->expz= 1.0;
191                         break;
192                 case 3:
193                         ml->type = MB_PLANE;
194                         ml->expx= ml->expy= ml->expz= 1.0;
195                         break;
196                 case 4:
197                         ml->type = MB_ELIPSOID;
198                         ml->expx= 1.2f;
199                         ml->expy= 0.8f;
200                         ml->expz= 1.0;
201                         break;
202                 case 5:
203                         ml->type = MB_CUBE;
204                         ml->expx= ml->expy= ml->expz= 1.0;
205                         break;
206                 default:
207                         break;
208         }
209         
210         lastelem= ml;
211         
212         allqueue(REDRAWALL, 0);
213         makeDispList(G.obedit);
214         BIF_undo_push("Add MetaElem");
215 }
216
217 void deselectall_mball()
218 {
219         MetaElem *ml;
220         int sel= 0;
221         
222         ml= editelems.first;
223         while(ml) {
224                 if(ml->flag & SELECT) break;
225                 ml= ml->next;
226         }
227
228         if(ml) sel= 1;
229
230         ml= editelems.first;
231         while(ml) {
232                 if(sel) ml->flag &= ~SELECT;
233                 else ml->flag |= SELECT;
234                 ml= ml->next;
235         }
236         allqueue(REDRAWVIEW3D, 0);
237 //      BIF_undo_push("Deselect MetaElem");
238 }
239
240 void mouse_mball()
241 {
242         static MetaElem *startelem=0;
243         MetaElem *ml, *act=0;
244         int a, hits;
245         unsigned int buffer[MAXPICKBUF];
246         
247         hits= selectprojektie(buffer, 0, 0, 0, 0);
248
249         /* does startelem exist? */
250         ml= editelems.first;
251         while(ml) {
252                 if(ml==startelem) break;
253                 ml= ml->next;
254         }
255         if(ml==0) startelem= editelems.first;
256         
257         if(hits>0) {
258                 ml= startelem;
259                 while(ml) {
260                         
261                         for(a=0; a<hits; a++) {
262                                 /* index converted for gl stuff */
263                                 if(ml->selcol1==buffer[ 4 * a + 3 ]){
264                                         ml->flag |= MB_SCALE_RAD;
265                                         act= ml;
266                                 }
267                                 if(ml->selcol2==buffer[ 4 * a + 3 ]){
268                                         ml->flag &= ~MB_SCALE_RAD;
269                                         act= ml;
270                                 }
271
272                         }
273                         
274                         if(act) break;
275                         
276                         ml= ml->next;
277                         if(ml==0) ml= editelems.first;
278                         if(ml==startelem) break;
279                 }
280                 if(act) {
281                         if((G.qual & LR_SHIFTKEY)==0) {
282                                 deselectall_mball();
283                                 if(act->flag & SELECT) deselectall_mball();
284                                 act->flag |= SELECT;
285                         }
286                         else {
287                                 if(act->flag & SELECT) {
288                                         act->flag &= ~SELECT;
289                                 }
290                                 else act->flag |= SELECT;
291                         }
292                         lastelem= act;
293                         allqueue(REDRAWVIEW3D, 0);
294                         allqueue(REDRAWBUTSEDIT, 0);
295                 }
296         }
297         rightmouse_transform();
298 }
299
300 void adduplicate_mball()
301 {
302         MetaElem *ml, *newml;
303         
304         ml= editelems.last;
305         while(ml) {
306                 if(ml->flag & SELECT) {
307                         newml= MEM_dupallocN(ml);
308                         BLI_addtail(&editelems, newml);
309                         lastelem= newml;
310                         ml->flag &= ~SELECT;
311                 }
312                 ml= ml->prev;
313         }
314         
315         Transform(TFM_TRANSLATION, CTX_NO_PET);
316         allqueue(REDRAWBUTSEDIT, 0);
317 }
318
319 /* Delete all selected MetaElems (not MetaBall) */
320 void delete_mball()
321 {
322         MetaElem *ml, *next;
323         
324         if(okee("Erase selected")==0) return;
325         
326         ml= editelems.first;
327         while(ml) {
328                 next= ml->next;
329                 if(ml->flag & SELECT) {
330                         if(lastelem==ml) lastelem= 0;
331                         BLI_remlink(&editelems, ml);
332                         MEM_freeN(ml);
333                 }
334                 ml= next;
335         }
336         
337         makeDispList(G.obedit);
338         allqueue(REDRAWVIEW3D, 0);
339         allqueue(REDRAWBUTSEDIT, 0);
340
341         BIF_undo_push("Delete MetaElem");
342 }
343
344 /* free all MetaElems from ListBase */
345 void freeMetaElemlist(ListBase *lb)
346 {
347         MetaElem *ml, *next;
348
349         if(lb==NULL) return;
350
351         ml= lb->first;
352         while(ml){
353                 next= ml->next;
354                 BLI_remlink(lb, ml);
355                 MEM_freeN(ml);
356                 ml= next;
357         }
358
359         lb->first= lb->last= NULL;
360         
361 }
362
363 /*  ************* undo for MetaBalls ************* */
364
365 static void undoMball_to_editMball(void *lbv)
366 {
367         ListBase *lb= lbv;
368         MetaElem *ml, *newml;
369         unsigned int nr, lastmlnr= 0;
370
371         /* we try to restore lastelem, which used in for example in button window */
372         for(ml= editelems.first; ml; ml= ml->next, lastmlnr++)
373                 if(lastelem==ml) break;
374
375         freeMetaElemlist(&editelems);
376
377         /* copy 'undo' MetaElems to 'edit' MetaElems */
378         ml= lb->first;
379         while(ml){
380                 newml= MEM_dupallocN(ml);
381                 BLI_addtail(&editelems, newml);
382                 ml= ml->next;
383         }
384         
385         for(nr=0, lastelem= editelems.first; lastelem; lastelem= lastelem->next, nr++)
386                 if(nr==lastmlnr) break;
387         
388 }
389
390 static void *editMball_to_undoMball(void)
391 {
392         ListBase *lb;
393         MetaElem *ml, *newml;
394
395         /* allocate memory for undo ListBase */
396         lb= MEM_callocN(sizeof(ListBase), "listbase undo");
397         lb->first= lb->last= NULL;
398         
399         /* copy contents of current ListBase to the undo ListBase */
400         ml= editelems.first;
401         while(ml){
402                 newml= MEM_dupallocN(ml);
403                 BLI_addtail(lb, newml);
404                 ml= ml->next;
405         }
406         
407         return lb;
408 }
409
410 /* free undo ListBase of MetaElems */
411 static void free_undoMball(void *lbv)
412 {
413         ListBase *lb= lbv;
414         
415         freeMetaElemlist(lb);
416         MEM_freeN(lb);
417 }
418
419 /* this is undo system for MetaBalls */
420 void undo_push_mball(char *name)
421 {
422         undo_editmode_push(name, free_undoMball, undoMball_to_editMball, editMball_to_undoMball);
423 }
424
425 /* Hide selected/unselected MetaElems */
426 void hide_mball(char hide)
427 {
428         MetaElem *ml;
429
430         ml= editelems.first;
431
432         while(ml){
433                 if(hide){
434                         if(!(ml->flag & SELECT))
435                                 ml->flag |= MB_HIDE;
436                 }
437                 else{
438                         if(ml->flag & SELECT)
439                                 ml->flag |= MB_HIDE;
440                 }
441                 ml= ml->next;
442         }
443
444         makeDispList(G.obedit);
445         allqueue(REDRAWVIEW3D, 0);
446         allqueue(REDRAWBUTSEDIT, 0);
447
448         BIF_undo_push("Hide MetaElems");
449 }
450
451 /* Unhide all edited MetaElems */
452 void reveal_mball(void)
453 {
454         MetaElem *ml;
455
456         ml= editelems.first;
457
458         while(ml){
459                 ml->flag &= ~MB_HIDE;
460                 ml= ml->next;
461         }
462
463         makeDispList(G.obedit);
464         allqueue(REDRAWVIEW3D, 0);
465         allqueue(REDRAWBUTSEDIT, 0);
466
467         BIF_undo_push("Unhide MetaElems");
468 }