Added a NO_NOR_RECALC context flag. With Individual extrude, the normals are already...
[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->lay= 1;
181         ml->s= 2.0;
182         ml->flag= SELECT;
183
184         switch(dummy_argument) {
185                 case 1:
186                         ml->type = MB_BALL;
187                         ml->expx= ml->expy= ml->expz= 1.0;
188                         break;
189                 case 2:
190                         ml->type = MB_TUBE;
191                         ml->expx= ml->expy= ml->expz= 1.0;
192                         break;
193                 case 3:
194                         ml->type = MB_PLANE;
195                         ml->expx= ml->expy= ml->expz= 1.0;
196                         break;
197                 case 4:
198                         ml->type = MB_ELIPSOID;
199                         ml->expx= 1.2f;
200                         ml->expy= 0.8f;
201                         ml->expz= 1.0;
202                         break;
203                 case 5:
204                         ml->type = MB_CUBE;
205                         ml->expx= ml->expy= ml->expz= 1.0;
206                         break;
207                 default:
208                         break;
209         }
210         
211         lastelem= ml;
212         
213         allqueue(REDRAWALL, 0);
214         makeDispList(G.obedit);
215         BIF_undo_push("Add MetaElem");
216 }
217
218 void deselectall_mball()
219 {
220         MetaElem *ml;
221         int sel= 0;
222         
223         ml= editelems.first;
224         while(ml) {
225                 if(ml->flag & SELECT) break;
226                 ml= ml->next;
227         }
228
229         if(ml) sel= 1;
230
231         ml= editelems.first;
232         while(ml) {
233                 if(sel) ml->flag &= ~SELECT;
234                 else ml->flag |= SELECT;
235                 ml= ml->next;
236         }
237         allqueue(REDRAWVIEW3D, 0);
238 //      BIF_undo_push("Deselect MetaElem");
239 }
240
241 void mouse_mball()
242 {
243         static MetaElem *startelem=0;
244         MetaElem *ml, *act=0;
245         int a, hits;
246         unsigned int buffer[MAXPICKBUF];
247         
248         hits= selectprojektie(buffer, 0, 0, 0, 0);
249
250         /* does startelem exist? */
251         ml= editelems.first;
252         while(ml) {
253                 if(ml==startelem) break;
254                 ml= ml->next;
255         }
256         if(ml==0) startelem= editelems.first;
257         
258         if(hits>0) {
259                 ml= startelem;
260                 while(ml) {
261                         /* if(base->lay & G.vd->lay) { */
262                         
263                                 for(a=0; a<hits; a++) {
264                                         /* index converted for gl stuff */
265                                         if(ml->selcol==buffer[ 4 * a + 3 ]) act= ml;
266                                 }
267                         /* } */
268                         
269                         if(act) break;
270                         
271                         ml= ml->next;
272                         if(ml==0) ml= editelems.first;
273                         if(ml==startelem) break;
274                 }
275                 if(act) {
276                         if((G.qual & LR_SHIFTKEY)==0) {
277                                 deselectall_mball();
278                                 if(act->flag & SELECT) deselectall_mball();
279                                 act->flag |= SELECT;
280                         }
281                         else {
282                                 if(act->flag & SELECT) {
283                                         act->flag &= ~SELECT;
284                                 }
285                                 else act->flag |= SELECT;
286                         }
287                         lastelem= act;
288                         allqueue(REDRAWVIEW3D, 0);
289                         allqueue(REDRAWBUTSEDIT, 0);
290                 }
291         }
292         rightmouse_transform();
293 }
294
295 void adduplicate_mball()
296 {
297         MetaElem *ml, *newml;
298         
299         ml= editelems.last;
300         while(ml) {
301                 if(ml->flag & SELECT) {
302                         newml= MEM_dupallocN(ml);
303                         BLI_addtail(&editelems, newml);
304                         lastelem= newml;
305                         ml->flag &= ~SELECT;
306                 }
307                 ml= ml->prev;
308         }
309         
310         Transform(TFM_TRANSLATION, CTX_NO_PET);
311         allqueue(REDRAWBUTSEDIT, 0);
312 }
313
314 /* Delete all selected MetaElems (not MetaBall) */
315 void delete_mball()
316 {
317         MetaElem *ml, *next;
318         
319         if(okee("Erase selected")==0) return;
320         
321         ml= editelems.first;
322         while(ml) {
323                 next= ml->next;
324                 if(ml->flag & SELECT) {
325                         if(lastelem==ml) lastelem= 0;
326                         BLI_remlink(&editelems, ml);
327                         MEM_freeN(ml);
328                 }
329                 ml= next;
330         }
331         
332         makeDispList(G.obedit);
333         allqueue(REDRAWVIEW3D, 0);
334         allqueue(REDRAWBUTSEDIT, 0);
335
336         BIF_undo_push("Delete MetaElem");
337 }
338
339 /* free all MetaElems from ListBase */
340 void freeMetaElemlist(ListBase *lb)
341 {
342         MetaElem *ml, *next;
343
344         if(lb==NULL) return;
345
346         ml= lb->first;
347         while(ml){
348                 next= ml->next;
349                 BLI_remlink(lb, ml);
350                 MEM_freeN(ml);
351                 ml= next;
352         }
353
354         lb->first= lb->last= NULL;
355         
356 }
357
358 /*  ************* undo for MetaBalls ************* */
359
360 static void undoMball_to_editMball(void *lbv)
361 {
362         ListBase *lb= lbv;
363         MetaElem *ml, *newml;
364         unsigned int nr, lastmlnr= 0;
365
366         /* we try to restore lastelem, which used in for example in button window */
367         for(ml= editelems.first; ml; ml= ml->next, lastmlnr++)
368                 if(lastelem==ml) break;
369
370         freeMetaElemlist(&editelems);
371
372         /* copy 'undo' MetaElems to 'edit' MetaElems */
373         ml= lb->first;
374         while(ml){
375                 newml= MEM_dupallocN(ml);
376                 BLI_addtail(&editelems, newml);
377                 ml= ml->next;
378         }
379         
380         for(nr=0, lastelem= editelems.first; lastelem; lastelem= lastelem->next, nr++)
381                 if(nr==lastmlnr) break;
382         
383 }
384
385 static void *editMball_to_undoMball(void)
386 {
387         ListBase *lb;
388         MetaElem *ml, *newml;
389
390         /* allocate memory for undo ListBase */
391         lb= MEM_callocN(sizeof(ListBase), "listbase undo");
392         lb->first= lb->last= NULL;
393         
394         /* copy contents of current ListBase to the undo ListBase */
395         ml= editelems.first;
396         while(ml){
397                 newml= MEM_dupallocN(ml);
398                 BLI_addtail(lb, newml);
399                 ml= ml->next;
400         }
401         
402         return lb;
403 }
404
405 /* free undo ListBase of MetaElems */
406 static void free_undoMball(void *lbv)
407 {
408         ListBase *lb= lbv;
409         
410         freeMetaElemlist(lb);
411         MEM_freeN(lb);
412 }
413
414 /* this is undo system for MetaBalls */
415 void undo_push_mball(char *name)
416 {
417         undo_editmode_push(name, free_undoMball, undoMball_to_editMball, editMball_to_undoMball);
418 }
419
420 /* Hide selected/unselected MetaElems */
421 void hide_mball(char hide)
422 {
423         MetaElem *ml;
424
425         ml= editelems.first;
426
427         while(ml){
428                 if(hide){
429                         if(!(ml->flag & SELECT))
430                                 ml->flag |= MB_HIDE;
431                 }
432                 else{
433                         if(ml->flag & SELECT)
434                                 ml->flag |= MB_HIDE;
435                 }
436                 ml= ml->next;
437         }
438
439         makeDispList(G.obedit);
440         allqueue(REDRAWVIEW3D, 0);
441         allqueue(REDRAWBUTSEDIT, 0);
442
443         BIF_undo_push("Hide MetaElems");
444 }
445
446 /* Unhide all edited MetaElems */
447 void reveal_mball(void)
448 {
449         MetaElem *ml;
450
451         ml= editelems.first;
452
453         while(ml){
454                 ml->flag &= ~MB_HIDE;
455                 ml= ml->next;
456         }
457
458         makeDispList(G.obedit);
459         allqueue(REDRAWVIEW3D, 0);
460         allqueue(REDRAWBUTSEDIT, 0);
461
462         BIF_undo_push("Unhide MetaElems");
463 }