Another step in the undo evolution.
[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 HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 #ifdef WIN32
45 #include "BLI_winstuff.h"
46 #include <process.h> /* getpid */
47 #else
48 #include <unistd.h> /* getpid */
49 #endif
50 #include "MEM_guardedalloc.h"
51
52 #include "BMF_Api.h"
53 #ifdef INTERNATIONAL
54 #include "BIF_language.h"
55 #include "FTF_Api.h"
56 #endif
57
58 #include "BLI_blenlib.h"
59 #include "BLI_arithb.h"
60 #include "BLI_linklist.h"
61
62 #include "IMB_imbuf_types.h"
63 #include "IMB_imbuf.h"
64
65 #include "DNA_object_types.h"
66 #include "DNA_space_types.h"
67 #include "DNA_userdef_types.h"
68 #include "DNA_sound_types.h"
69
70 #include "BKE_blender.h"
71 #include "BKE_curve.h"
72 #include "BKE_displist.h"
73 #include "BKE_exotic.h"
74 #include "BKE_font.h"
75 #include "BKE_global.h"
76 #include "BKE_main.h"
77 #include "BKE_mball.h"
78 #include "BKE_packedFile.h"
79 #include "BKE_utildefines.h"
80
81 #include "BIF_fsmenu.h"
82 #include "BIF_gl.h"
83 #include "BIF_interface.h"
84 #include "BIF_usiblender.h"
85 #include "BIF_drawtext.h"
86 #include "BIF_editarmature.h"
87 #include "BIF_editlattice.h"
88 #include "BIF_editfont.h"
89 #include "BIF_editmesh.h"
90 #include "BIF_editsound.h"
91 #include "BIF_renderwin.h"
92 #include "BIF_resources.h"
93 #include "BIF_screen.h"
94 #include "BIF_space.h"
95 #include "BIF_toolbox.h"
96 #include "BIF_cursors.h"
97
98 #include "BSE_drawview.h"
99 #include "BSE_headerbuttons.h"
100 #include "BSE_editipo.h"
101 #include "BSE_editaction.h"
102 #include "BSE_filesel.h"
103 #include "BSE_edit.h"
104
105 #include "BLO_readfile.h"
106 #include "BLO_writefile.h"
107
108 #include "BDR_drawobject.h"
109 #include "BDR_editobject.h"
110 #include "BDR_editcurve.h"
111 #include "BDR_vpaint.h"
112
113 #include "BPY_extern.h"
114
115 #include "blendef.h"
116
117 #include "radio.h"
118 #include "render.h"
119 #include "datatoc.h"
120
121 #include "SYS_System.h"
122
123 #include "PIL_time.h"
124
125 /***/
126
127 void BIF_read_file(char *name)
128 {
129         extern short winqueue_break; /* editscreen.c */
130
131         //here?
132         //sound_end_all_sounds();
133
134         // first try to read exotic file formats...
135         if (BKE_read_exotic(name) == 0) { /* throws first error box */
136                 /* we didn't succeed, now try to read Blender file
137                    calls readfile, calls toolbox, throws one more,
138                    on failure calls the stream, and that is stubbed.... */
139                 BKE_read_file(name, NULL);
140         }
141
142         mainwindow_set_filename_to_title(G.main->name);
143         countall();
144         sound_initialize_sounds();
145
146         winqueue_break= 1;      /* leave queues everywhere */
147
148         BKE_reset_undo();
149         BKE_write_undo("original");     /* save current state */
150 }
151
152 int BIF_read_homefile(void)
153 {
154         char tstr[FILE_MAXDIR+FILE_MAXFILE], scestr[FILE_MAXDIR];
155         char *home= BLI_gethome();
156         int success;
157 #ifdef _WIN32   // FULLSCREEN
158         static int screenmode = -1;
159
160         screenmode = U.uiflag & USER_FLIPFULLSCREEN;
161 #endif
162
163         BLI_make_file_string(G.sce, tstr, home, ".B.blend");
164         strcpy(scestr, G.sce);  /* temporal store */
165
166         /* only here free userdef themes... */
167         BLI_freelistN(&U.themes);
168
169         if (BLI_exists(tstr)) {
170                 success = BKE_read_file(tstr, NULL);
171         } else {
172                 success = BKE_read_file_from_memory(datatoc_B_blend, datatoc_B_blend_size, NULL);
173         }
174         strcpy(G.sce, scestr);
175
176         BIF_InitTheme();        // sets default again
177
178         if (success) {
179                 mainwindow_set_filename_to_title(tstr);
180                 countall();
181                 G.save_over = 0;
182
183                 /*  disable autoplay in .B.blend... */
184                 G.fileflags &= ~G_FILE_AUTOPLAY;
185
186 #ifdef _WIN32   // FULLSCREEN
187                 /* choose window startmode */
188                 switch (G.windowstate){
189                         case G_WINDOWSTATE_USERDEF: /* use the usersetting */
190                                 break;
191                         case G_WINDOWSTATE_FULLSCREEN: /* force fullscreen */
192                                 U.uiflag |= USER_FLIPFULLSCREEN;
193                                 break;
194                         case G_WINDOWSTATE_BORDER: /* force with borders */
195                                 U.uiflag &= ~USER_FLIPFULLSCREEN;
196                 }
197
198                 if(screenmode != (U.uiflag & USER_FLIPFULLSCREEN)) {
199                         mainwindow_toggle_fullscreen ((U.uiflag & USER_FLIPFULLSCREEN));
200                         screenmode = (U.uiflag & USER_FLIPFULLSCREEN);
201                 }
202 #endif
203
204                 if (BLI_streq(U.tempdir, "/")) {
205                         char *tmp= getenv("TEMP");
206
207                         strcpy(U.tempdir, tmp?tmp:"/tmp/");
208                 }
209                 if (U.savetime <= 0) {
210                         U.savetime = 1;
211                         error("%s is buggy, please consider removing it.\n",
212                                 tstr);
213                 }
214                 if (G.main->versionfile <= 191) {
215                         strcpy(U.plugtexdir, U.textudir);
216                         strcpy(U.sounddir, "/");
217                 }
218
219                         /* patch to set Dupli Armature */
220                 if (G.main->versionfile < 220) {
221                         U.dupflag |= USER_DUP_ARM;
222                 }
223
224                         /* userdef new option */
225                 if (G.main->versionfile <= 222) {
226                         U.vrmlflag= USER_VRML_LAYERS;
227                 }
228
229                         /* added seam, normal color */
230                 if (G.main->versionfile <= 234) {
231                         bTheme *btheme;
232                         
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.edge_seam[3]==0) {
236                                         btheme->tv3d.edge_seam[0]= 230;
237                                         btheme->tv3d.edge_seam[1]= 150;
238                                         btheme->tv3d.edge_seam[2]= 50;
239                                         btheme->tv3d.edge_seam[3]= 255;
240                                 }
241                                 if(btheme->tv3d.normal[3]==0) {
242                                         btheme->tv3d.normal[0]= 0x22;
243                                         btheme->tv3d.normal[1]= 0xDD;
244                                         btheme->tv3d.normal[2]= 0xDD;
245                                         btheme->tv3d.normal[3]= 255;
246                                 }
247                         }
248                 }
249                 
250                 space_set_commmandline_options();
251
252                 if (U.undosteps==0) U.undosteps=32;
253                 BKE_reset_undo();
254                 BKE_write_undo("original");     /* save current state */
255
256                 reset_autosave();
257
258 #ifdef INTERNATIONAL
259                 read_languagefile();
260         
261                 if(U.transopts & USER_DOTRANSLATE)
262                         start_interface_font();
263                 else
264                         G.ui_international = FALSE;
265 #endif // INTERNATIONAL
266
267         }
268
269         return success;
270 }
271
272 static void get_autosave_location(char buf[FILE_MAXDIR+FILE_MAXFILE])
273 {
274         char pidstr[32];
275
276         sprintf(pidstr, "%d.blend", abs(getpid()));
277         BLI_make_file_string("/", buf, U.tempdir, pidstr);
278 }
279
280 void BIF_read_autosavefile(void)
281 {
282         char tstr[FILE_MAXDIR+FILE_MAXFILE], scestr[FILE_MAXDIR];
283         int save_over;
284
285         strcpy(scestr, G.sce);  /* temporal store */
286         
287         get_autosave_location(tstr);
288
289         save_over = G.save_over;
290         BKE_read_file(tstr, NULL);
291         G.save_over = save_over;
292         strcpy(G.sce, scestr);
293 }
294
295 /***/
296
297 static void readBlog(void)
298 {
299         char name[FILE_MAXDIR+FILE_MAXFILE];
300         LinkNode *l, *lines;
301
302         BLI_make_file_string("/", name, BLI_gethome(), ".Blog");
303         lines= BLI_read_file_as_lines(name);
304
305         if (lines && !BLI_streq(lines->link, "")) {
306                 strcpy(G.sce, lines->link);
307         } else {
308                 BLI_make_file_string("/", G.sce, BLI_gethome(), "untitled.blend");
309         }
310
311         BLI_free_file_lines(lines);
312
313 #ifdef WIN32
314         /* Add the drive names to the listing */
315         {
316                 __int64 tmp;
317                 char tmps[4];
318                 int i;
319                         
320                 tmp= GetLogicalDrives();
321                 
322                 for (i=2; i < 26; i++) {
323                         if ((tmp>>i) & 1) {
324                                 tmps[0]='a'+i;
325                                 tmps[1]=':';
326                                 tmps[2]='\\';
327                                 tmps[3]=0;
328                                 
329                                 fsmenu_insert_entry(tmps, 0);
330                         }
331                 }
332                 
333                 fsmenu_append_seperator();
334         }
335 #endif
336
337         BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
338         lines= BLI_read_file_as_lines(name);
339
340         for (l= lines; l; l= l->next) {
341                 char *line= l->link;
342                         
343                 if (!BLI_streq(line, "")) {
344                         fsmenu_insert_entry(line, 0);
345                 }
346         }
347
348         fsmenu_append_seperator();
349         BLI_free_file_lines(lines);
350 }
351
352
353 static void writeBlog(void)
354 {
355         char name[FILE_MAXDIR+FILE_MAXFILE];
356         FILE *fp;
357
358         BLI_make_file_string("/", name, BLI_gethome(), ".Blog");
359
360         fp= fopen(name, "w");
361         if (fp) {
362                 fprintf(fp, G.sce);
363                 fclose(fp);
364         }
365 }
366
367 static void do_history(char *name)
368 {
369         char tempname1[FILE_MAXDIR+FILE_MAXFILE], tempname2[FILE_MAXDIR+FILE_MAXFILE];
370         int hisnr= U.versions;
371         
372         if(U.versions==0) return;
373         if(strlen(name)<2) return;
374                 
375         while(  hisnr > 1) {
376                 sprintf(tempname1, "%s%d", name, hisnr-1);
377                 sprintf(tempname2, "%s%d", name, hisnr);
378         
379                 if(BLI_rename(tempname1, tempname2))
380                         error("Unable to make version backup");
381                         
382                 hisnr--;
383         }
384                 
385         /* is needed when hisnr==1 */
386         sprintf(tempname1, "%s%d", name, hisnr);
387         
388         if(BLI_rename(name, tempname1))
389                 error("Unable to make version backup");
390 }
391
392 void BIF_write_file(char *target)
393 {
394         Library *li;
395         char di[FILE_MAXDIR];
396         char *err;
397         
398         if (BLI_streq(target, "")) return;
399  
400         /*Send the OnSave event*/
401         if (G.f & G_SCENESCRIPT) {
402                 BPY_do_pyscript(&G.scene->id, SCRIPT_ONSAVE);
403         }
404
405         for (li= G.main->library.first; li; li= li->id.next) {
406                 if (BLI_streq(li->name, target)) {
407                         error("Cannot overwrite used library");
408                         return;
409                 }
410         }
411         
412         if (!BLO_has_bfile_extension(target)) {
413                 sprintf(di, "%s.blend", target);
414         } else {
415                 strcpy(di, target);
416         }
417
418         if (BLI_exists(di)) {
419                 if(!saveover(di))
420                         return; 
421         }
422         
423         waitcursor(1);
424         
425         if(G.obedit) {
426                 exit_editmode(0);       /* 0 = no free data */
427         }
428         if (G.fileflags & G_AUTOPACK) {
429                 packAll();
430         }
431
432         do_history(di);
433                 
434         if (BLO_write_file(di, G.fileflags, &err)) {
435                 strcpy(G.sce, di);
436                 strcpy(G.main->name, di);       /* is guaranteed current file */
437
438                 mainwindow_set_filename_to_title(G.main->name);
439
440                 G.save_over = 1;
441
442                 writeBlog();
443         } else {
444                 error("%s", err);
445         }
446
447         waitcursor(0);
448 }
449
450 void BIF_write_homefile(void)
451 {
452         char *err, tstr[FILE_MAXDIR+FILE_MAXFILE];
453         int write_flags;
454         
455         BLI_make_file_string("/", tstr, BLI_gethome(), ".B.blend");
456                 
457         /*  force save as regular blend file */
458         write_flags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_LOCK | G_FILE_SIGN);
459         BLO_write_file(tstr, write_flags, &err);
460 }
461
462 void BIF_write_autosave(void)
463 {
464         char *err, tstr[FILE_MAXDIR+FILE_MAXFILE];
465         int write_flags;
466         
467         get_autosave_location(tstr);
468
469                 /*  force save as regular blend file */
470         write_flags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_LOCK | G_FILE_SIGN);
471         BLO_write_file(tstr, write_flags, &err);
472 }
473
474 /* if global undo; remove tempsave, otherwise rename */
475 static void delete_autosave(void)
476 {
477         char tstr[FILE_MAXDIR+FILE_MAXFILE];
478         
479         get_autosave_location(tstr);
480
481         if (BLI_exists(tstr)) {
482                 char str[FILE_MAXDIR+FILE_MAXFILE];
483                 BLI_make_file_string("/", str, U.tempdir, "quit.blend");
484
485                 if(U.uiflag & USER_GLOBALUNDO) BLI_delete(tstr, 0, 0);
486                 else BLI_rename(tstr, str);
487         }
488 }
489
490 /***/
491
492 static void initbuttons(void)
493 {
494         uiDefFont(UI_HELVB, 
495                                 BMF_GetFont(BMF_kHelveticaBold14), 
496                                 BMF_GetFont(BMF_kHelveticaBold12), 
497                                 BMF_GetFont(BMF_kHelveticaBold10), 
498                                 BMF_GetFont(BMF_kHelveticaBold8));
499         uiDefFont(UI_HELV, 
500                                 BMF_GetFont(BMF_kHelvetica12), 
501                                 BMF_GetFont(BMF_kHelvetica12), 
502                                 BMF_GetFont(BMF_kHelvetica10), 
503                                 BMF_GetFont(BMF_kHelveticaBold8));
504         
505         BIF_resources_init();
506
507         glClearColor(.7, .7, .6, 0.0);
508         
509         G.font= BMF_GetFont(BMF_kHelvetica12);
510         G.fonts= BMF_GetFont(BMF_kHelvetica10);
511         G.fontss= BMF_GetFont(BMF_kHelveticaBold8);
512
513         clear_matcopybuf();
514 }
515
516
517 static void sound_init_listener(void)
518 {
519         G.listener = MEM_callocN(sizeof(bSoundListener), "soundlistener");
520         G.listener->gain = 1.0;
521         G.listener->dopplerfactor = 1.0;
522         G.listener->dopplervelocity = 1.0;
523 }
524
525 void BIF_init(void)
526 {
527
528         initscreen();   /* for (visuele) speed, this first, then setscreen */
529         initbuttons();
530         InitCursorData();
531         sound_init_listener();
532         
533         init_draw_rects();      /* drawobject.c */
534         BIF_read_homefile();
535         init_gl_stuff();        /* drawview.c, after homefile */
536         readBlog();
537         strcpy(G.lib, G.sce);
538
539 }
540
541 /***/
542
543 extern ListBase editNurb;
544 extern ListBase editelems;
545
546 void exit_usiblender(void)
547 {
548         freeAllRad();
549         BKE_freecubetable();
550
551         if (G.background == 0)
552                 sound_end_all_sounds();
553
554         if(G.obedit) {
555                 if(G.obedit->type==OB_FONT) {
556                         free_editText();
557                 }
558                 else if(G.obedit->type==OB_MBALL) BLI_freelistN(&editelems);
559                 free_editMesh();
560         }
561
562         free_editLatt();
563         free_editArmature();
564         free_posebuf();
565
566         free_blender(); /* blender.c, does entire library */
567         free_hashedgetab();
568         free_matcopybuf();
569         free_ipocopybuf();
570         freefastshade();
571         free_vertexpaint();
572         
573         /* editnurb can remain to exist outside editmode */
574         freeNurblist(&editNurb);
575
576         fsmenu_free();
577 #ifdef INTERNATIONAL
578         free_languagemenu();
579 #endif  
580         
581         RE_free_render_data();
582         RE_free_filt_mask();
583         
584         free_txt_data();
585
586         sound_exit_audio();
587         if(G.listener) MEM_freeN(G.listener);
588
589 #ifdef WITH_QUICKTIME
590         quicktime_exit();
591 #endif
592                 
593         BPY_end_python();
594
595         if (!G.background) {
596                 BIF_resources_free();
597         
598                 BIF_close_render_display();
599                 mainwindow_close();
600         }
601
602 #ifdef INTERNATIONAL
603         FTF_End();
604 #endif
605
606         if (G.undo_clear) G.undo_clear();
607         undo_clear_curve();
608         
609         BKE_undo_save_quit();   // saves quit.blend if global undo is on
610         BKE_reset_undo(); 
611         
612         BLI_freelistN(&U.themes);
613         
614         if(totblock!=0) {
615                 printf("Error Totblock: %d\n",totblock);
616                 MEM_printmemlist();
617         }
618         delete_autosave();
619         
620         printf("\nBlender quit\n");
621
622 #ifdef WIN32   
623         /* ask user to press enter when in debug mode */
624         if(G.f & G_DEBUG) {
625                 printf("press enter key to exit...\n\n");
626                 getchar();
627         }
628 #endif 
629
630
631         SYS_DeleteSystem(SYS_GetSystem());
632
633         exit(G.afbreek==1);
634 }