Replaced old fly mode for a fly mode that works in all 3 view types - ortho, perspect...
[blender-staging.git] / source / blender / src / usiblender.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         /* placed up here because of crappy
34          * winsock stuff.
35          */
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39
40 #ifdef WIN32
41 #include <shlobj.h> /* SHGetSpecialFolderPath, has to be done before BLI_winstuff for some reasons... */
42 #include "BLI_winstuff.h"
43 #include <process.h> /* getpid */
44 #else
45 #include <unistd.h> /* getpid */
46 #endif
47 #include "MEM_guardedalloc.h"
48 #include "MEM_CacheLimiterC-Api.h"
49
50 #include "BMF_Api.h"
51 #ifdef INTERNATIONAL
52 #include "BIF_language.h"
53 #include "FTF_Api.h"
54 #endif
55
56 #include "BLI_blenlib.h"
57 #include "BLI_arithb.h"
58 #include "BLI_linklist.h"
59
60 #include "IMB_imbuf_types.h"
61 #include "IMB_imbuf.h"
62
63 #include "DNA_object_types.h"
64 #include "DNA_space_types.h"
65 #include "DNA_userdef_types.h"
66 #include "DNA_sound_types.h"
67 #include "DNA_scene_types.h"
68
69 #include "BKE_blender.h"
70 #include "BKE_curve.h"
71 #include "BKE_displist.h"
72 #include "BKE_exotic.h"
73 #include "BKE_font.h"
74 #include "BKE_global.h"
75 #include "BKE_main.h"
76 #include "BKE_mball.h"
77 #include "BKE_packedFile.h"
78 #include "BKE_utildefines.h"
79
80 #include "BLI_vfontdata.h"
81
82 #include "BIF_fsmenu.h"
83 #include "BIF_gl.h"
84 #include "BIF_interface.h"
85 #include "BIF_usiblender.h"
86 #include "BIF_drawtext.h"
87 #include "BIF_editarmature.h"
88 #include "BIF_editlattice.h"
89 #include "BIF_editfont.h"
90 #include "BIF_editmesh.h"
91 #include "BIF_editmode_undo.h"
92 #include "BIF_editsound.h"
93 #include "BIF_poseobject.h"
94 #include "BIF_previewrender.h"
95 #include "BIF_renderwin.h"
96 #include "BIF_resources.h"
97 #include "BIF_screen.h"
98 #include "BIF_space.h"
99 #include "BIF_toolbox.h"
100 #include "BIF_cursors.h"
101
102 #include "BSE_drawview.h"
103 #include "BSE_edit.h"
104 #include "BSE_editipo.h"
105 #include "BSE_filesel.h"
106 #include "BSE_headerbuttons.h"
107 #include "BSE_node.h"
108
109 #include "BLO_readfile.h"
110 #include "BLO_writefile.h"
111
112 #include "BDR_drawobject.h"
113 #include "BDR_editobject.h"
114 #include "BDR_editcurve.h"
115 #include "BDR_vpaint.h"
116
117 #include "BPY_extern.h"
118
119 #include "blendef.h"
120
121 #include "RE_pipeline.h"                /* RE_ free stuff */
122
123 #include "radio.h"
124 #include "datatoc.h"
125
126 #include "SYS_System.h"
127
128 #include "PIL_time.h"
129
130 /***/
131
132 /* define for setting colors in theme below */
133 #define SETCOL(col, r, g, b, a)  col[0]=r; col[1]=g; col[2]= b; col[3]= a;
134
135 /* patching UserDef struct, set globals for UI stuff */
136 static void init_userdef_file(void)
137 {
138         
139         BIF_InitTheme();        // sets default again
140         
141         mainwindow_set_filename_to_title("");   // empty string re-initializes title to "Blender"
142         countall();
143         G.save_over = 0;        // start with save preference untitled.blend
144         
145         /*  disable autoplay in .B.blend... */
146         G.fileflags &= ~G_FILE_AUTOPLAY;
147         
148         /* the UserDef struct is not corrected with do_versions() .... ugh! */
149         if(U.wheellinescroll == 0) U.wheellinescroll = 3;
150         if(U.menuthreshold1==0) {
151                 U.menuthreshold1= 5;
152                 U.menuthreshold2= 2;
153         }
154         if(U.tb_leftmouse==0) {
155                 U.tb_leftmouse= 5;
156                 U.tb_rightmouse= 5;
157         }
158         if(U.mixbufsize==0) U.mixbufsize= 2048;
159         if (BLI_streq(U.tempdir, "/")) {
160                 char *tmp= getenv("TEMP");
161                 
162                 strcpy(U.tempdir, tmp?tmp:"/tmp/");
163         }
164         if (U.savetime <= 0) {
165                 U.savetime = 1;
166                 error(".B.blend is buggy, please consider removing it.\n");
167         }
168         /* transform widget settings */
169         if(U.tw_hotspot==0) {
170                 U.tw_hotspot= 14;
171                 U.tw_size= 20;                  // percentage of window size
172                 U.tw_handlesize= 16;    // percentage of widget radius
173         }
174         
175         if (G.main->versionfile <= 191) {
176                 strcpy(U.plugtexdir, U.textudir);
177                 strcpy(U.sounddir, "/");
178         }
179         
180         /* patch to set Dupli Armature */
181         if (G.main->versionfile < 220) {
182                 U.dupflag |= USER_DUP_ARM;
183         }
184         
185         /* userdef new option */
186         if (G.main->versionfile <= 222) {
187                 U.vrmlflag= USER_VRML_LAYERS;
188         }
189         
190         /* added seam, normal color, undo */
191         if (G.main->versionfile <= 234) {
192                 bTheme *btheme;
193                 
194                 U.uiflag |= USER_GLOBALUNDO;
195                 
196                 for(btheme= U.themes.first; btheme; btheme= btheme->next) {
197                         /* check for alpha==0 is safe, then color was never set */
198                         if(btheme->tv3d.edge_seam[3]==0) {
199                                 SETCOL(btheme->tv3d.edge_seam, 230, 150, 50, 255);
200                         }
201                         if(btheme->tv3d.normal[3]==0) {
202                                 SETCOL(btheme->tv3d.normal, 0x22, 0xDD, 0xDD, 255);
203                         }
204                         if(btheme->tv3d.face_dot[3]==0) {
205                                 SETCOL(btheme->tv3d.face_dot, 255, 138, 48, 255);
206                                 btheme->tv3d.facedot_size= 4;
207                         }
208                 }
209         }
210         if (G.main->versionfile <= 235) {
211                 /* illegal combo... */
212                 if (U.flag & USER_LMOUSESELECT) 
213                         U.flag &= ~USER_TWOBUTTONMOUSE;
214         }
215         if (G.main->versionfile <= 236) {
216                 bTheme *btheme;
217                 /* new space type */
218                 for(btheme= U.themes.first; btheme; btheme= btheme->next) {
219                         /* check for alpha==0 is safe, then color was never set */
220                         if(btheme->ttime.back[3]==0) {
221                                 btheme->ttime = btheme->tsnd;   // copy from sound
222                         }
223                         if(btheme->text.syntaxn[3]==0) {
224                                 SETCOL(btheme->text.syntaxn,    0, 0, 200, 255);        /* Numbers  Blue*/
225                                 SETCOL(btheme->text.syntaxl,    100, 0, 0, 255);        /* Strings  red */
226                                 SETCOL(btheme->text.syntaxc,    0, 100, 50, 255);       /* Comments greenish */
227                                 SETCOL(btheme->text.syntaxv,    95, 95, 0, 255);        /* Special */
228                                 SETCOL(btheme->text.syntaxb,    128, 0, 80, 255);       /* Builtin, red-purple */
229                         }
230                 }
231         }
232         if (G.main->versionfile <= 237) {
233                 bTheme *btheme;
234                 /* bone colors */
235                 for(btheme= U.themes.first; btheme; btheme= btheme->next) {
236                         /* check for alpha==0 is safe, then color was never set */
237                         if(btheme->tv3d.bone_solid[3]==0) {
238                                 SETCOL(btheme->tv3d.bone_solid, 200, 200, 200, 255);
239                                 SETCOL(btheme->tv3d.bone_pose, 80, 200, 255, 80);
240                         }
241                 }
242         }
243         if (G.main->versionfile <= 238) {
244                 bTheme *btheme;
245                 /* bone colors */
246                 for(btheme= U.themes.first; btheme; btheme= btheme->next) {
247                         /* check for alpha==0 is safe, then color was never set */
248                         if(btheme->tnla.strip[3]==0) {
249                                 SETCOL(btheme->tnla.strip_select,       0xff, 0xff, 0xaa, 255);
250                                 SETCOL(btheme->tnla.strip, 0xe4, 0x9c, 0xc6, 255);
251                         }
252                 }
253         }
254         if (G.main->versionfile <= 239) {
255                 bTheme *btheme;
256                 
257                 for(btheme= U.themes.first; btheme; btheme= btheme->next) {
258                         /* Lamp theme, check for alpha==0 is safe, then color was never set */
259                         if(btheme->tv3d.lamp[3]==0) {
260                                 SETCOL(btheme->tv3d.lamp,       0, 0, 0, 40);
261 /* TEMPORAL, remove me! (ton) */                                
262                                 U.uiflag |= USER_PLAINMENUS;
263                         }
264                         
265                         /* check for text field selection highlight, set it to text editor highlight by default */
266                         if(btheme->tui.textfield_hi[3]==0) {
267                                 SETCOL(btheme->tui.textfield_hi,        
268                                         btheme->text.shade2[0], 
269                                         btheme->text.shade2[1], 
270                                         btheme->text.shade2[2],
271                                         255);
272                         }
273                 }
274                 if(U.obcenter_dia==0) U.obcenter_dia= 6;
275         }
276         if (G.main->versionfile <= 241) {
277                 bTheme *btheme;
278                 for(btheme= U.themes.first; btheme; btheme= btheme->next) {
279                         /* Node editor theme, check for alpha==0 is safe, then color was never set */
280                         if(btheme->tnode.syntaxn[3]==0) {
281                                 /* re-uses syntax color storage */
282                                 btheme->tnode= btheme->tv3d;
283                                 SETCOL(btheme->tnode.edge_select, 255, 255, 255, 255);
284                                 SETCOL(btheme->tnode.syntaxl, 150, 150, 150, 255);      /* TH_NODE, backdrop */
285                                 SETCOL(btheme->tnode.syntaxn, 95, 110, 145, 255);       /* in/output */
286                                 SETCOL(btheme->tnode.syntaxb, 135, 125, 120, 255);      /* operator */
287                                 SETCOL(btheme->tnode.syntaxv, 120, 120, 120, 255);      /* generator */
288                                 SETCOL(btheme->tnode.syntaxc, 120, 145, 120, 255);      /* group */
289                         }
290                         if(btheme->tv3d.group[3]==0) {
291                                 SETCOL(btheme->tv3d.group, 0x10, 0x40, 0x10, 255);
292                                 SETCOL(btheme->tv3d.group_active, 0x66, 0xFF, 0x66, 255);
293                         }
294                 }
295                 
296                 /* set defaults for 3D View rotating axis indicator */ 
297                 /* since size can't be set to 0, this indicates it's not saved in .B.blend */
298                 if (U.rvisize == 0) {
299                         U.rvisize = 15;
300                         U.rvibright = 8;
301                         U.uiflag |= USER_SHOW_ROTVIEWICON;
302                 }
303                 
304         }
305         
306         if (U.undosteps==0) U.undosteps=32;
307         
308         /* GL Texture Garbage Collection (variable abused above!) */
309         if (U.textimeout == 0) {
310                 U.texcollectrate = 60;
311                 U.textimeout = 120;
312         }
313         if (U.memcachelimit <= 0) {
314                 U.memcachelimit = 32;
315         }
316         if (U.frameserverport == 0) {
317                 U.frameserverport = 8080;
318         }
319
320         MEM_CacheLimiter_set_maximum(U.memcachelimit * 1024 * 1024);
321         
322         reset_autosave();
323         
324 #ifdef INTERNATIONAL
325         read_languagefile();
326         
327         refresh_interface_font();
328 #endif // INTERNATIONAL
329
330 }
331
332 void BIF_read_file(char *name)
333 {
334         extern short winqueue_break; /* editscreen.c */
335
336         //here?
337         //sound_end_all_sounds();
338
339         // first try to read exotic file formats...
340         if (BKE_read_exotic(name) == 0) { /* throws first error box */
341                 /* we didn't succeed, now try to read Blender file
342                    calls readfile, calls toolbox, throws one more,
343                    on failure calls the stream, and that is stubbed.... */
344                 int retval= BKE_read_file(name, NULL);
345
346                 mainwindow_set_filename_to_title(G.main->name);
347                 countall();
348                 sound_initialize_sounds();
349
350                 winqueue_break= 1;      /* leave queues everywhere */
351
352                 if(retval==2) init_userdef_file();      // in case a userdef is read from regular .blend
353                 
354                 undo_editmode_clear();
355                 BKE_reset_undo();
356                 BKE_write_undo("original");     /* save current state */
357                 refresh_interface_font();
358         }
359         else BIF_undo_push("Import file");
360 }
361
362 /* only here settings for fullscreen */
363 int BIF_read_homefile(void)
364 {
365         char tstr[FILE_MAXDIR+FILE_MAXFILE], scestr[FILE_MAXDIR];
366         char *home= BLI_gethome();
367         int success;
368         struct TmpFont *tf;
369         
370         BLI_clean(home);
371
372         tf= G.ttfdata.first;
373         while(tf)
374         {
375                 freePackedFile(tf->pf);
376                 tf->pf = NULL;
377                 tf->vfont = NULL;
378                 tf= tf->next;
379         }
380         BLI_freelistN(&G.ttfdata);
381         
382 #if 0
383 //#ifdef _WIN32 // FULLSCREEN
384         static int screenmode = -1;
385         
386         screenmode = U.uiflag & USER_FLIPFULLSCREEN;
387 #endif
388         
389         BLI_make_file_string(G.sce, tstr, home, ".B.blend");
390         strcpy(scestr, G.sce);  /* temporal store */
391         
392         /* prevent loading no UI */
393         G.fileflags &= ~G_FILE_NO_UI;
394         
395         if (BLI_exists(tstr)) {
396                 success = BKE_read_file(tstr, NULL);
397         } else {
398                 success = BKE_read_file_from_memory(datatoc_B_blend, datatoc_B_blend_size, NULL);
399         }
400
401         BLI_clean(scestr);
402         strcpy(G.sce, scestr);
403         
404 #if 0
405 //#ifdef _WIN32 // FULLSCREEN
406         /* choose window startmode */
407         switch (G.windowstate){
408                 case G_WINDOWSTATE_USERDEF: /* use the usersetting */
409                         break;
410                 case G_WINDOWSTATE_FULLSCREEN: /* force fullscreen */
411                         U.uiflag |= USER_FLIPFULLSCREEN;
412                         break;
413                 case G_WINDOWSTATE_BORDER: /* force with borders */
414                         U.uiflag &= ~USER_FLIPFULLSCREEN;
415         }
416         
417         if(screenmode != (U.uiflag & USER_FLIPFULLSCREEN)) {
418                 mainwindow_toggle_fullscreen ((U.uiflag & USER_FLIPFULLSCREEN));
419                 screenmode = (U.uiflag & USER_FLIPFULLSCREEN);
420         }
421 #endif
422         
423         space_set_commmandline_options();
424         
425         init_userdef_file();
426
427         undo_editmode_clear();
428         BKE_reset_undo();
429         BKE_write_undo("original");     /* save current state */
430         
431         return success;
432 }
433
434
435 static void get_autosave_location(char buf[FILE_MAXDIR+FILE_MAXFILE])
436 {
437         char pidstr[32];
438
439         sprintf(pidstr, "%d.blend", abs(getpid()));
440         BLI_make_file_string("/", buf, U.tempdir, pidstr);
441 }
442
443 void BIF_read_autosavefile(void)
444 {
445         char tstr[FILE_MAXDIR+FILE_MAXFILE], scestr[FILE_MAXDIR];
446         int save_over;
447
448         strcpy(scestr, G.sce);  /* temporal store */
449         
450         get_autosave_location(tstr);
451
452         save_over = G.save_over;
453         BKE_read_file(tstr, NULL);
454         G.save_over = save_over;
455         strcpy(G.sce, scestr);
456 }
457
458 /* free strings of open recent files */
459 static void free_openrecent(void)
460 {
461         struct RecentFile *recent;
462
463         for(recent = G.recent_files.first; recent; recent=recent->next)
464                 MEM_freeN(recent->filename);
465
466         BLI_freelistN(&(G.recent_files));
467 }
468
469 static void readBlog(void)
470 {
471         char name[FILE_MAXDIR+FILE_MAXFILE], filename[FILE_MAXFILE];
472         LinkNode *l, *lines;
473         struct RecentFile *recent;
474         char *line;
475         int num;
476
477         BLI_make_file_string("/", name, BLI_gethome(), ".Blog");
478         lines= BLI_read_file_as_lines(name);
479
480         G.recent_files.first = G.recent_files.last = NULL;
481
482         /* read list of recent opend files from .Blog to memory */
483         for (l= lines, num= 0; l && (num<10); l= l->next, num++) {
484                 line = l->link;
485                 if (!BLI_streq(line, "")) {
486                         if (num==0) strcpy(G.sce, line);
487                         recent = (RecentFile*)MEM_mallocN(sizeof(RecentFile),"RecentFile");
488                         BLI_addtail(&(G.recent_files), recent);
489                         recent->filename = (char*)MEM_mallocN(sizeof(char)*(strlen(line)+1), "name of file");
490                         recent->filename[0] = '\0';
491                         strcpy(recent->filename, line);
492                 }
493         }
494
495         if(G.sce[0] == 0)
496                 BLI_make_file_string("/", G.sce, BLI_gethome(), "untitled.blend");
497         
498         BLI_free_file_lines(lines);
499
500 #ifdef WIN32
501         /* Add the drive names to the listing */
502         {
503                 __int64 tmp;
504                 char folder[MAX_PATH];
505                 char tmps[4];
506                 int i;
507                         
508                 tmp= GetLogicalDrives();
509                 
510                 for (i=2; i < 26; i++) {
511                         if ((tmp>>i) & 1) {
512                                 tmps[0]='a'+i;
513                                 tmps[1]=':';
514                                 tmps[2]='\\';
515                                 tmps[3]=0;
516                                 
517                                 fsmenu_insert_entry(tmps, 0);
518                         }
519                 }
520
521                 /* Adding Desktop and My Documents */
522                 fsmenu_append_seperator();
523                 SHGetFolderPath(0, CSIDL_PERSONAL,NULL, 0, folder);
524                 fsmenu_insert_entry(folder, 0);
525                 SHGetFolderPath(0, CSIDL_DESKTOPDIRECTORY,NULL, 0, folder);
526                 fsmenu_insert_entry(folder, 0);
527
528                 fsmenu_append_seperator();
529         }
530 #endif
531
532         BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
533         lines= BLI_read_file_as_lines(name);
534
535         for (l= lines; l; l= l->next) {
536                 char *line= l->link;
537                         
538                 if (!BLI_streq(line, "")) {
539                         fsmenu_insert_entry(line, 0);
540                 }
541         }
542
543         fsmenu_append_seperator();
544         
545         /* add last saved file */
546         BLI_split_dirfile(G.sce, name, filename);
547         
548         fsmenu_insert_entry(name, 0);
549         
550         BLI_free_file_lines(lines);
551 }
552
553
554 static void writeBlog(void)
555 {
556         struct RecentFile *recent, *next_recent;
557         char name[FILE_MAXDIR+FILE_MAXFILE];
558         FILE *fp;
559         int i;
560
561         BLI_make_file_string("/", name, BLI_gethome(), ".Blog");
562
563         recent = G.recent_files.first;
564         /* refresh .Blog of recent opened files, when current file was changed */
565         if(!(recent) || (strcmp(recent->filename, G.sce)!=0)) {
566                 fp= fopen(name, "w");
567                 if (fp) {
568                         /* add current file to the beginning of list */
569                         recent = (RecentFile*)MEM_mallocN(sizeof(RecentFile),"RecentFile");
570                         recent->filename = (char*)MEM_mallocN(sizeof(char)*(strlen(G.sce)+1), "name of file");
571                         recent->filename[0] = '\0';
572                         strcpy(recent->filename, G.sce);
573                         BLI_addhead(&(G.recent_files), recent);
574                         /* write current file to .Blog */
575                         fprintf(fp, "%s\n", recent->filename);
576                         recent = recent->next;
577                         i=1;
578                         /* write rest of recent opened files to .Blog */
579                         while((i<10) && (recent)){
580                                 /* this prevents to have duplicities in list */
581                                 if (strcmp(recent->filename, G.sce)!=0) {
582                                         fprintf(fp, "%s\n", recent->filename);
583                                         recent = recent->next;
584                                 }
585                                 else {
586                                         next_recent = recent->next;
587                                         MEM_freeN(recent->filename);
588                                         BLI_freelinkN(&(G.recent_files), recent);
589                                         recent = next_recent;
590                                 }
591                                 i++;
592                         }
593                 }
594                 fclose(fp);
595         }
596 }
597
598 static void do_history(char *name)
599 {
600         char tempname1[FILE_MAXDIR+FILE_MAXFILE], tempname2[FILE_MAXDIR+FILE_MAXFILE];
601         int hisnr= U.versions;
602         
603         if(U.versions==0) return;
604         if(strlen(name)<2) return;
605                 
606         while(  hisnr > 1) {
607                 sprintf(tempname1, "%s%d", name, hisnr-1);
608                 sprintf(tempname2, "%s%d", name, hisnr);
609         
610                 if(BLI_rename(tempname1, tempname2))
611                         error("Unable to make version backup");
612                         
613                 hisnr--;
614         }
615                 
616         /* is needed when hisnr==1 */
617         sprintf(tempname1, "%s%d", name, hisnr);
618         
619         if(BLI_rename(name, tempname1))
620                 error("Unable to make version backup");
621 }
622
623 void BIF_write_file(char *target)
624 {
625         Library *li;
626         int writeflags;
627         char di[FILE_MAXDIR];
628         char *err;
629         
630         if (BLI_streq(target, "")) return;
631  
632         /* send the OnSave event */
633         if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript(&G.scene->id, SCRIPT_ONSAVE);
634
635         for (li= G.main->library.first; li; li= li->id.next) {
636                 if (BLI_streq(li->name, target)) {
637                         error("Cannot overwrite used library");
638                         return;
639                 }
640         }
641         
642         if (!BLO_has_bfile_extension(target)) {
643                 sprintf(di, "%s.blend", target);
644         } else {
645                 strcpy(di, target);
646         }
647
648         if (BLI_exists(di)) {
649                 if(!saveover(di))
650                         return; 
651         }
652         
653         if(G.obedit) {
654                 exit_editmode(0);       /* 0 = no free data */
655         }
656         if (G.fileflags & G_AUTOPACK) {
657                 packAll();
658         }
659         
660         waitcursor(1);  // exit_editmode sets cursor too
661
662         do_history(di);
663         
664         /* we use the UserDef to define compression flag */
665         writeflags= G.fileflags & ~G_FILE_COMPRESS;
666         if(U.flag & USER_FILECOMPRESS)
667                 writeflags |= G_FILE_COMPRESS;
668         
669         if (BLO_write_file(di, writeflags, &err)) {
670                 strcpy(G.sce, di);
671                 strcpy(G.main->name, di);       /* is guaranteed current file */
672
673                 mainwindow_set_filename_to_title(G.main->name);
674
675                 G.save_over = 1;
676
677                 writeBlog();
678         } else {
679                 error("%s", err);
680         }
681
682         waitcursor(0);
683 }
684
685 void BIF_write_homefile(void)
686 {
687         char *err, tstr[FILE_MAXDIR+FILE_MAXFILE];
688         int write_flags;
689         
690         BLI_make_file_string("/", tstr, BLI_gethome(), ".B.blend");
691                 
692         /*  force save as regular blend file */
693         write_flags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_LOCK | G_FILE_SIGN);
694         BLO_write_file(tstr, write_flags, &err);
695 }
696
697 void BIF_write_autosave(void)
698 {
699         char *err, tstr[FILE_MAXDIR+FILE_MAXFILE];
700         int write_flags;
701         
702         get_autosave_location(tstr);
703
704                 /*  force save as regular blend file */
705         write_flags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_LOCK | G_FILE_SIGN);
706         BLO_write_file(tstr, write_flags, &err);
707 }
708
709 /* if global undo; remove tempsave, otherwise rename */
710 static void delete_autosave(void)
711 {
712         char tstr[FILE_MAXDIR+FILE_MAXFILE];
713         
714         get_autosave_location(tstr);
715
716         if (BLI_exists(tstr)) {
717                 char str[FILE_MAXDIR+FILE_MAXFILE];
718                 BLI_make_file_string("/", str, U.tempdir, "quit.blend");
719
720                 if(U.uiflag & USER_GLOBALUNDO) BLI_delete(tstr, 0, 0);
721                 else BLI_rename(tstr, str);
722         }
723 }
724
725 /***/
726
727 static void initbuttons(void)
728 {
729         uiDefFont(UI_HELVB, 
730                                 BMF_GetFont(BMF_kHelveticaBold14), 
731                                 BMF_GetFont(BMF_kHelveticaBold12), 
732                                 BMF_GetFont(BMF_kHelveticaBold10), 
733                                 BMF_GetFont(BMF_kHelveticaBold8));
734         uiDefFont(UI_HELV, 
735                                 BMF_GetFont(BMF_kHelvetica12), 
736                                 BMF_GetFont(BMF_kHelvetica12), 
737                                 BMF_GetFont(BMF_kHelvetica10), 
738                                 BMF_GetFont(BMF_kHelveticaBold8));
739         
740         BIF_resources_init();
741
742         glClearColor(.7f, .7f, .6f, 0.0);
743         
744         G.font= BMF_GetFont(BMF_kHelvetica12);
745         G.fonts= BMF_GetFont(BMF_kHelvetica10);
746         G.fontss= BMF_GetFont(BMF_kHelveticaBold8);
747
748         clear_matcopybuf();
749         
750         glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
751 }
752
753
754 static void sound_init_listener(void)
755 {
756         G.listener = MEM_callocN(sizeof(bSoundListener), "soundlistener");
757         G.listener->gain = 1.0;
758         G.listener->dopplerfactor = 1.0;
759         G.listener->dopplervelocity = 340.29f;
760 }
761
762 void BIF_init(void)
763 {
764
765         initscreen();   /* for (visuele) speed, this first, then setscreen */
766         initbuttons();
767         InitCursorData();
768         sound_init_listener();
769         init_node_butfuncs();
770         
771         BIF_preview_init_dbase();
772         BIF_read_homefile();
773         
774         init_gl_stuff();        /* drawview.c, after homefile */
775         readBlog();
776         strcpy(G.lib, G.sce);
777
778 }
779
780 /***/
781
782 extern ListBase editNurb;
783 extern ListBase editelems;
784
785 void exit_usiblender(void)
786 {
787         struct TmpFont *tf;
788         tf= G.ttfdata.first;
789         while(tf)
790         {
791                 freePackedFile(tf->pf);
792                 tf->pf= NULL;
793                 tf->vfont= NULL;
794                 tf= tf->next;
795         }
796         BLI_freelistN(&G.ttfdata);
797         free_openrecent();
798
799         freeAllRad();
800         BKE_freecubetable();
801
802         if (G.background == 0)
803                 sound_end_all_sounds();
804
805         if(G.obedit) {
806                 if(G.obedit->type==OB_FONT) {
807                         free_editText();
808                 }
809                 else if(G.obedit->type==OB_MBALL) BLI_freelistN(&editelems);
810                 free_editMesh(G.editMesh);
811         }
812
813         free_editLatt();
814         free_editArmature();
815         free_posebuf();
816
817         /* before free_blender so py's gc happens while library still exists */
818         /* needed at least for a rare sigsegv that can happen in pydrivers */
819         BPY_end_python();
820
821         fastshade_free_render();        /* shaded view */
822         free_blender();                         /* blender.c, does entire library */
823         free_matcopybuf();
824         free_ipocopybuf();
825         free_vertexpaint();
826         
827         /* editnurb can remain to exist outside editmode */
828         freeNurblist(&editNurb);
829
830         fsmenu_free();
831 #ifdef INTERNATIONAL
832         free_languagemenu();
833 #endif  
834         
835         RE_FreeAllRender();
836         
837         free_txt_data();
838
839         sound_exit_audio();
840         if(G.listener) MEM_freeN(G.listener);
841
842         libtiff_exit();
843
844 #ifdef WITH_QUICKTIME
845         quicktime_exit();
846 #endif
847
848         if (!G.background) {
849                 BIF_resources_free();
850         
851                 BIF_close_render_display();
852                 mainwindow_close();
853         }
854
855 #ifdef INTERNATIONAL
856         FTF_End();
857 #endif
858
859         if (copybuf) MEM_freeN(copybuf);
860         if (copybufinfo) MEM_freeN(copybufinfo);
861
862         /* undo free stuff */
863         undo_editmode_clear();
864         
865         BKE_undo_save_quit();   // saves quit.blend if global undo is on
866         BKE_reset_undo(); 
867         
868         BLI_freelistN(&U.themes);
869         BIF_preview_free_dbase();
870                 
871         if(totblock!=0) {
872                 printf("Error Totblock: %d\n",totblock);
873                 MEM_printmemlist();
874         }
875         delete_autosave();
876         
877         printf("\nBlender quit\n");
878
879 #ifdef WIN32   
880         /* ask user to press enter when in debug mode */
881         if(G.f & G_DEBUG) {
882                 printf("press enter key to exit...\n\n");
883                 getchar();
884         }
885 #endif 
886
887
888         SYS_DeleteSystem(SYS_GetSystem());
889
890         exit(G.afbreek==1);
891 }