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