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