- added support for MetaBall undo in edit mode (Ctrl-Z ... undo) (Ctrl-Y/Ctrl-Shift...
[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 #ifdef WIN32
40 #include "BLI_winstuff.h"
41 #endif
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_arithb.h"
46
47 #include "DNA_screen_types.h"
48 #include "DNA_meta_types.h"
49 #include "DNA_object_types.h"
50 #include "DNA_view3d_types.h"
51
52 #include "BKE_utildefines.h"
53 #include "BKE_displist.h"
54 #include "BKE_global.h"
55 #include "BKE_object.h"
56
57 #include "BIF_gl.h"
58 #include "BIF_graphics.h"
59 #include "BIF_screen.h"
60 #include "BIF_toolbox.h"
61 #include "BIF_space.h"
62 #include "BIF_editmode_undo.h"
63
64 #include "BDR_editobject.h"
65 #include "BDR_editmball.h"
66
67 #include "BSE_edit.h"
68 #include "BSE_view.h"
69
70 #include "render.h"
71 #include "blendef.h"
72 #include "mydevice.h"
73
74 extern short editbutflag;
75
76 ListBase editelems= {0, 0};
77 MetaElem *lastelem;
78
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 void load_editMball()
104 {
105         /* load mball in object */
106         MetaBall *mb;
107         MetaElem *ml, *newml;
108
109         if(G.obedit==0) return;
110         
111         mb= G.obedit->data;
112         BLI_freelistN(&(mb->elems));
113
114
115         ml= editelems.first;
116         while(ml) {
117                 newml= MEM_dupallocN(ml);
118                 BLI_addtail(&(mb->elems), newml);
119                 
120                 ml= ml->next;
121         }
122 }
123
124 void add_primitiveMball(int dummy_argument)
125 {
126         MetaElem *ml;
127         float *curs, mat[3][3], cent[3], imat[3][3], cmat[3][3];
128
129         if(G.scene->id.lib) return;
130
131         /* this function also comes from an info window */
132         if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
133         
134         check_editmode(OB_MBALL);
135
136         /* if no obedit: new object and enter editmode */
137         if(G.obedit==0) {
138                 add_object_draw(OB_MBALL);
139                 base_init_from_view3d(BASACT, G.vd);
140                 G.obedit= BASACT->object;
141                 
142                 where_is_object(G.obedit);
143
144                 make_editMball();
145                 setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
146         }
147         
148         /* deselect */
149         ml= editelems.first;
150         while(ml) {
151                 ml->flag &= ~SELECT;
152                 ml= ml->next;
153         }
154         
155         /* imat and centre and size */
156         Mat3CpyMat4(mat, G.obedit->obmat);
157
158         curs= give_cursor();
159         VECCOPY(cent, curs);
160         cent[0]-= G.obedit->obmat[3][0];
161         cent[1]-= G.obedit->obmat[3][1];
162         cent[2]-= G.obedit->obmat[3][2];
163
164         Mat3CpyMat4(imat, G.vd->viewmat);
165         Mat3MulVecfl(imat, cent);
166         Mat3MulMat3(cmat, imat, mat);
167         Mat3Inv(imat,cmat);
168         
169         Mat3MulVecfl(imat, cent);
170
171         ml= MEM_callocN(sizeof(MetaElem), "metaelem");
172         BLI_addtail(&editelems, ml);
173
174         ml->x= cent[0];
175         ml->y= cent[1];
176         ml->z= cent[2];
177         ml->rad= 2.0;
178         ml->lay= 1;
179         ml->s= 2.0;
180         ml->flag= SELECT;
181
182         switch(dummy_argument) {
183                 case 1:
184                         ml->type = MB_BALL;
185                         ml->expx= ml->expy= ml->expz= 1.0;
186                         break;
187                 case 2:
188                         ml->type = MB_TUBE;
189                         ml->expx= ml->expy= ml->expz= 1.0;
190                         break;
191                 case 3:
192                         ml->type = MB_PLANE;
193                         ml->expx= ml->expy= ml->expz= 1.0;
194                         break;
195                 case 4:
196                         ml->type = MB_ELIPSOID;
197                         ml->expx= 1.2f;
198                         ml->expy= 0.8f;
199                         ml->expz= 1.0;
200                         break;
201                 case 5:
202                         ml->type = MB_CUBE;
203                         ml->expx= ml->expy= ml->expz= 1.0;
204                         break;
205                 default:
206                         break;
207         }
208         
209         lastelem= ml;
210         
211         allqueue(REDRAWALL, 0);
212         makeDispList(G.obedit);
213         BIF_undo_push("Add MetaElem");
214 }
215
216 void deselectall_mball()
217 {
218         MetaElem *ml;
219         int sel= 0;
220         
221         ml= editelems.first;
222         while(ml) {
223                 if(ml->flag & SELECT) break;
224                 ml= ml->next;
225         }
226
227         if(ml) sel= 1;
228
229         ml= editelems.first;
230         while(ml) {
231                 if(sel) ml->flag &= ~SELECT;
232                 else ml->flag |= SELECT;
233                 ml= ml->next;
234         }
235         allqueue(REDRAWVIEW3D, 0);
236 //      BIF_undo_push("Deselect MetaElem");
237 }
238
239 void mouse_mball()
240 {
241         static MetaElem *startelem=0;
242         MetaElem *ml, *act=0;
243         int a, hits;
244         unsigned int buffer[MAXPICKBUF];
245         
246         hits= selectprojektie(buffer, 0, 0, 0, 0);
247
248         /* does startelem exist? */
249         ml= editelems.first;
250         while(ml) {
251                 if(ml==startelem) break;
252                 ml= ml->next;
253         }
254         if(ml==0) startelem= editelems.first;
255         
256         if(hits>0) {
257                 ml= startelem;
258                 while(ml) {
259                         /* if(base->lay & G.vd->lay) { */
260                         
261                                 for(a=0; a<hits; a++) {
262                                         /* index converted for gl stuff */
263                                         if(ml->selcol==buffer[ 4 * a + 3 ]) act= ml;
264                                 }
265                         /* } */
266                         
267                         if(act) break;
268                         
269                         ml= ml->next;
270                         if(ml==0) ml= editelems.first;
271                         if(ml==startelem) break;
272                 }
273                 if(act) {
274                         if((G.qual & LR_SHIFTKEY)==0) {
275                                 deselectall_mball();
276                                 if(act->flag & SELECT) deselectall_mball();
277                                 act->flag |= SELECT;
278                         }
279                         else {
280                                 if(act->flag & SELECT) {
281                                         act->flag &= ~SELECT;
282                                 }
283                                 else act->flag |= SELECT;
284                         }
285                         lastelem= act;
286                         allqueue(REDRAWVIEW3D, 0);
287                         allqueue(REDRAWBUTSEDIT, 0);
288                 }
289         }
290         rightmouse_transform();
291 }
292
293 void adduplicate_mball()
294 {
295         MetaElem *ml, *newml;
296         
297         ml= editelems.last;
298         while(ml) {
299                 if(ml->flag & SELECT) {
300                         newml= MEM_dupallocN(ml);
301                         BLI_addtail(&editelems, newml);
302                         lastelem= newml;
303                         ml->flag &= ~SELECT;
304                 }
305                 ml= ml->prev;
306         }
307         
308         transform('g');
309         allqueue(REDRAWBUTSEDIT, 0);
310 }
311
312 /* Delete all selected MetaElems (not MetaBall) */
313 void delete_mball()
314 {
315         MetaElem *ml, *next;
316         
317         if(okee("Erase selected")==0) return;
318         
319         ml= editelems.first;
320         while(ml) {
321                 next= ml->next;
322                 if(ml->flag & SELECT) {
323                         if(lastelem==ml) lastelem= 0;
324                         BLI_remlink(&editelems, ml);
325                         MEM_freeN(ml);
326                 }
327                 ml= next;
328         }
329         
330         makeDispList(G.obedit);
331         allqueue(REDRAWVIEW3D, 0);
332         allqueue(REDRAWBUTSEDIT, 0);
333
334         BIF_undo_push("Delete MetaElem");
335 }
336
337 /* free all MetaElems from ListBase */
338 void freeMetaElemlist(ListBase *lb)
339 {
340         MetaElem *ml, *next;
341
342         if(lb==NULL) return;
343
344         ml= lb->first;
345         while(ml){
346                 next= ml->next;
347                 BLI_remlink(lb, ml);
348                 MEM_freeN(ml);
349                 ml= next;
350         }
351
352         lb->first= lb->last= NULL;
353         
354 }
355
356 /*  ************* undo for MetaBalls ************* */
357
358 static void undoMball_to_editMball(void *lbv)
359 {
360         ListBase *lb= lbv;
361         MetaElem *ml, *newml;
362         unsigned int nr, lastmlnr= 0;
363
364         /* we try to restore lastelem, which used in for example in button window */
365         for(ml= editelems.first; ml; ml= ml->next, lastmlnr++)
366                 if(lastelem==ml) break;
367
368         freeMetaElemlist(&editelems);
369
370         /* copy 'undo' MetaElems to 'edit' MetaElems */
371         ml= lb->first;
372         while(ml){
373                 newml= MEM_dupallocN(ml);
374                 BLI_addtail(&editelems, newml);
375                 ml= ml->next;
376         }
377         
378         for(nr=0, lastelem= editelems.first; lastelem; lastelem= lastelem->next, nr++)
379                 if(nr==lastmlnr) break;
380         
381 }
382
383 static void *editMball_to_undoMball(void)
384 {
385         ListBase *lb;
386         MetaElem *ml, *newml;
387
388         /* allocate memory for undo ListBase */
389         lb= MEM_callocN(sizeof(ListBase), "listbase undo");
390         lb->first= lb->last= NULL;
391         
392         /* copy contents of current ListBase to the undo ListBase */
393         ml= editelems.first;
394         while(ml){
395                 newml= MEM_dupallocN(ml);
396                 BLI_addtail(lb, newml);
397                 ml= ml->next;
398         }
399         
400         return lb;
401 }
402
403 /* free undo ListBase of MetaElems */
404 static void free_undoMball(void *lbv)
405 {
406         ListBase *lb= lbv;
407         
408         freeMetaElemlist(lb);
409         MEM_freeN(lb);
410 }
411
412 /* this is undo system for MetaBalls */
413 void undo_push_mball(char *name)
414 {
415         undo_editmode_push(name, free_undoMball, undoMball_to_editMball, editMball_to_undoMball);
416 }