-- Bugfix #3524: theEditMesh structure was not being initialized correctly.
[blender-staging.git] / source / blender / blenkernel / intern / blender.c
1
2 /*  blender.c   jan 94     MIXED MODEL
3  * 
4  * common help functions and data
5  * 
6  * $Id$
7  *
8  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version. The Blender
14  * Foundation also sells licenses for use in proprietary software under
15  * the Blender License.  See http://www.blender.org/BL/ for information
16  * about this.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  *
27  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
28  * All rights reserved.
29  *
30  * The Original Code is: all of this file.
31  *
32  * Contributor(s): none yet.
33  *
34  * ***** END GPL/BL DUAL LICENSE BLOCK *****
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef WIN32 
42     #include <unistd.h> // for read close
43     #include <sys/param.h> // for MAXPATHLEN
44 #else
45     #include <io.h> // for open close read
46 #endif
47
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <fcntl.h> // for open
52
53 #include "MEM_guardedalloc.h"
54 #include "DNA_listBase.h"
55 #include "DNA_sdna_types.h"
56 #include "DNA_userdef_types.h"
57 #include "DNA_object_types.h"
58 #include "DNA_curve_types.h"
59
60 #include "BLI_blenlib.h"
61 #include "BLI_dynstr.h"
62
63 #include "IMB_imbuf_types.h"
64 #include "IMB_imbuf.h"
65
66 #include "DNA_mesh_types.h"
67 #include "DNA_screen_types.h"
68
69 #include "BKE_library.h"
70 #include "BKE_blender.h"
71 #include "BKE_displist.h"
72 #include "BKE_global.h"
73 #include "BKE_main.h"
74 #include "BKE_object.h"
75 #include "BKE_scene.h"
76 #include "BKE_curve.h"
77 #include "BKE_font.h"
78
79 #include "BLI_editVert.h"
80
81 #include "BLO_undofile.h"
82 #include "BLO_readfile.h" 
83 #include "BLO_writefile.h" 
84
85 #include "BKE_bad_level_calls.h" // for freeAllRad editNurb free_editMesh free_editText free_editArmature
86 #include "BKE_utildefines.h" // O_BINARY FALSE
87 #include "BIF_mainqueue.h" // mainqenter for onload script
88 #include "mydevice.h"
89 #include "nla.h"
90 #include "blendef.h"
91
92 Global G;
93 UserDef U;
94
95 char versionstr[48]= "";
96
97 /* ************************************************ */
98 /* pushpop facility: to store data temporally, FIFO! */
99
100 ListBase ppmain={0, 0};
101
102 typedef struct PushPop {
103         struct PushPop *next, *prev;
104         void *data;
105         int len;
106 } PushPop;
107
108 void pushdata(void *data, int len)
109 {
110         PushPop *pp;
111         
112         pp= MEM_mallocN(sizeof(PushPop), "pushpop");
113         BLI_addtail(&ppmain, pp);
114         pp->data= MEM_mallocN(len, "pushpop");
115         pp->len= len;
116         memcpy(pp->data, data, len);
117 }
118
119 void popfirst(void *data)
120 {
121         PushPop *pp;
122         
123         pp= ppmain.first;
124         if(pp) {
125                 memcpy(data, pp->data, pp->len);
126                 BLI_remlink(&ppmain, pp);
127                 MEM_freeN(pp->data);
128                 MEM_freeN(pp);
129         }
130         else printf("error in popfirst\n");
131 }
132
133 void poplast(void *data)
134 {
135         PushPop *pp;
136         
137         pp= ppmain.last;
138         if(pp) {
139                 memcpy(data, pp->data, pp->len);
140                 BLI_remlink(&ppmain, pp);
141                 MEM_freeN(pp->data);
142                 MEM_freeN(pp);
143         }
144         else printf("error in poplast\n");
145 }
146
147 void free_pushpop()
148 {
149         PushPop *pp;
150
151         pp= ppmain.first;
152         while(pp) {
153                 BLI_remlink(&ppmain, pp);
154                 MEM_freeN(pp->data);
155                 MEM_freeN(pp);
156         }       
157 }
158
159 void pushpop_test()
160 {
161         if(ppmain.first) printf("pushpop not empty\n");
162         free_pushpop();
163 }
164
165
166
167 /* ********** free ********** */
168
169 void free_blender(void)
170 {
171         free_main(G.main);
172         G.main= NULL;
173
174         IMB_freeImBufdata();            /* imbuf lib */
175 }
176
177 void duplicatelist(ListBase *list1, ListBase *list2)  /* copy from 2 to 1 */
178 {
179         struct Link *link1, *link2;
180         
181         list1->first= list1->last= 0;
182         
183         link2= list2->first;
184         while(link2) {
185
186                 link1= MEM_dupallocN(link2);
187                 BLI_addtail(list1, link1);
188                 
189                 link2= link2->next;
190         }       
191 }
192
193 static EditMesh theEditMesh;
194
195 void initglobals(void)
196 {
197         memset(&G, 0, sizeof(Global));
198         
199         memset(&theEditMesh, 0, sizeof(theEditMesh));
200         G.editMesh = &theEditMesh;
201
202         U.savetime= 1;
203
204         G.main= MEM_callocN(sizeof(Main), "initglobals");
205
206         strcpy(G.ima, "//");
207
208         G.version= BLENDER_VERSION;
209
210         G.order= 1;
211         G.order= (((char*)&G.order)[0])?L_ENDIAN:B_ENDIAN;
212
213         sprintf(versionstr, "www.blender.org %d", G.version);
214
215 #ifdef _WIN32   // FULLSCREEN
216         G.windowstate = G_WINDOWSTATE_USERDEF;
217 #endif
218
219         clear_workob(); /* object.c */
220
221         G.charstart = 0x0000;
222         G.charmin = 0x0000;
223         G.charmax = 0xffff;
224 }
225
226 /***/
227
228 static void clear_global(void) 
229 {
230         extern short winqueue_break;    /* screen.c */
231
232         freeAllRad();
233         free_main(G.main); /* free all lib data */
234         freefastshade();        /* othwerwise old lamp settings stay active */
235
236
237         /* prevent hanging vars */      
238         R.backbuf= 0;
239         
240         /* force all queues to be left */
241         winqueue_break= 1;
242         
243         if (G.obedit) {
244                 freeNurblist(&editNurb);
245                 free_editMesh(G.editMesh);
246                 free_editText();
247                 free_editArmature();
248         }
249
250         G.curscreen= NULL;
251         G.scene= NULL;
252         G.main= NULL;
253         
254         G.obedit= NULL;
255         G.saction= NULL;
256         G.buts= NULL;
257         G.v2d= NULL;
258         G.vd= NULL;
259         G.soops= NULL;
260         G.sima= NULL;
261         G.sipo= NULL;
262         
263         free_vertexpaint();
264         
265         G.f &= ~(G_WEIGHTPAINT + G_VERTEXPAINT + G_FACESELECT);
266 }
267
268 /* make sure path names are correct for OS */
269 static void clean_paths(Main *main)
270 {
271         Image *image= main->image.first;
272         bSound *sound= main->sound.first;
273         Scene *scene= main->scene.first;
274         Editing *ed;
275         Sequence *seq;
276         Strip *strip;
277         
278         
279         while(image) {
280                 BLI_clean(image->name);
281                 image= image->id.next;
282         }
283         
284         while(sound) {
285                 BLI_clean(sound->name);
286                 sound= sound->id.next;
287         }
288         
289         while(scene) {
290                 ed= scene->ed;
291                 if(ed) {
292                         seq= ed->seqbasep->first;
293                         while(seq) {
294                                 if(seq->plugin) {
295                                         BLI_clean(seq->plugin->name);
296                                 }
297                                 strip= seq->strip;
298                                 while(strip) {
299                                         BLI_clean(strip->dir);
300                                         strip= strip->next;
301                                 }
302                                 seq= seq->next;
303                         }
304                 }
305                 BLI_clean(scene->r.backbuf);
306                 BLI_clean(scene->r.pic);
307                 BLI_clean(scene->r.ftype);
308                 
309                 scene= scene->id.next;
310         }
311 }
312
313 static void setup_app_data(BlendFileData *bfd, char *filename) 
314 {
315         Object *ob;
316         bScreen *curscreen= NULL;
317         Scene *curscene= NULL;
318         char mode;
319         
320         /* 'u' = undo save, 'n' = no UI load */
321         if(bfd->main->screen.first==NULL) mode= 'u';
322         else if(G.fileflags & G_FILE_NO_UI) mode= 'n';
323         else mode= 0;
324         
325         clean_paths(bfd->main);
326         
327         /* no load screens? */
328         if(mode) {
329                 /* comes from readfile.c */
330                 extern void lib_link_screen_restore(Main *, Scene *);
331                 
332                 SWAP(ListBase, G.main->screen, bfd->main->screen);
333                 
334                 /* we re-use current screen */
335                 curscreen= G.curscreen;
336                 /* but use new Scene pointer */
337                 curscene= bfd->curscene;
338                 if(curscene==NULL) curscene= bfd->main->scene.first;
339                 /* and we enforce curscene to be in current screen */
340                 curscreen->scene= curscene;
341
342                 /* clear_global will free G.main, here we can still restore pointers */
343                 lib_link_screen_restore(bfd->main, curscene);
344         }
345         
346         clear_global();
347         
348         if(mode!='u') G.save_over = 1;
349         
350         G.main= bfd->main;
351         if (bfd->user) {
352                 
353                 /* only here free userdef themes... */
354                 BLI_freelistN(&U.themes);
355
356                 U= *bfd->user;
357                 MEM_freeN(bfd->user);
358                 
359         }
360         
361         /* case G_FILE_NO_UI or no screens in file */
362         if(mode) {
363                 G.curscreen= curscreen;
364                 G.scene= curscene;
365         }
366         else {
367                 G.winpos= bfd->winpos;
368                 G.displaymode= bfd->displaymode;
369                 G.fileflags= bfd->fileflags;
370                 G.curscreen= bfd->curscreen;
371                 G.scene= G.curscreen->scene;
372         }
373         /* this can happen when active scene was lib-linked, and doesnt exist anymore */
374         if(G.scene==NULL) {
375                 G.scene= G.main->scene.first;
376                 G.curscreen->scene= G.scene;
377         }
378
379         /* special cases, override loaded flags: */
380         if (G.f & G_DEBUG) bfd->globalf |= G_DEBUG;
381         else bfd->globalf &= ~G_DEBUG;
382         if (!(G.f & G_DOSCRIPTLINKS)) bfd->globalf &= ~G_DOSCRIPTLINKS;
383
384         G.f= bfd->globalf;
385
386         /* last stage of do_versions actually, update objects (like recalc poses) */
387         for(ob= G.main->object.first; ob; ob= ob->id.next) {
388                 if(ob->recalc) object_handle_update(ob);
389         }
390         
391         if (!G.background) {
392                 setscreen(G.curscreen);
393         }
394                 /* baseflags */
395         set_scene_bg(G.scene);
396
397         if (G.f & G_DOSCRIPTLINKS) {
398                 /* there's an onload scriptlink to execute in screenmain */
399                 mainqenter(ONLOAD_SCRIPT, 1);
400         }
401
402         strcpy(G.sce, filename);
403         strcpy(G.main->name, filename); /* is guaranteed current file */
404         
405         MEM_freeN(bfd);
406 }
407
408 /* returns:
409    0: no load file
410    1: OK
411    2: OK, and with new user settings
412 */
413
414 int BKE_read_file(char *dir, void *type_r) 
415 {
416         BlendReadError bre;
417         BlendFileData *bfd;
418         int retval= 1;
419         
420         if (!G.background)
421                 waitcursor(1);
422                 
423         bfd= BLO_read_from_file(dir, &bre);
424         if (bfd) {
425                 if(bfd->user) retval= 2;
426                 if (type_r)
427                         *((BlenFileType*)type_r)= bfd->type;
428                 
429                 setup_app_data(bfd, dir);
430         } else {
431                 error("Loading %s failed: %s", dir, BLO_bre_as_string(bre));
432         }
433         
434         if (!G.background)
435                 waitcursor(0);
436         
437         return (bfd?retval:0);
438 }
439
440 int BKE_read_file_from_memory(char* filebuf, int filelength, void *type_r)
441 {
442         BlendReadError bre;
443         BlendFileData *bfd;
444         
445         if (!G.background)
446                 waitcursor(1);
447                 
448         bfd= BLO_read_from_memory(filebuf, filelength, &bre);
449         if (bfd) {
450                 if (type_r)
451                         *((BlenFileType*)type_r)= bfd->type;
452                 
453                 setup_app_data(bfd, "<memory>");
454         } else {
455                 error("Loading failed: %s", BLO_bre_as_string(bre));
456         }
457         
458         if (!G.background)
459                 waitcursor(0);
460         
461         return (bfd?1:0);
462 }
463
464 int BKE_read_file_from_memfile(MemFile *memfile)
465 {
466         BlendReadError bre;
467         BlendFileData *bfd;
468         
469         if (!G.background)
470                 waitcursor(1);
471                 
472         bfd= BLO_read_from_memfile(memfile, &bre);
473         if (bfd) {
474                 setup_app_data(bfd, "<memory>");
475         } else {
476                 error("Loading failed: %s", BLO_bre_as_string(bre));
477         }
478         
479         if (!G.background)
480                 waitcursor(0);
481         
482         return (bfd?1:0);
483 }
484
485
486 /* ***************** GLOBAL UNDO *************** */
487
488 #define UNDO_DISK       0
489
490 #define MAXUNDONAME     64
491 typedef struct UndoElem {
492         struct UndoElem *next, *prev;
493         char str[FILE_MAXDIR+FILE_MAXFILE];
494         char name[MAXUNDONAME];
495         MemFile memfile;
496 } UndoElem;
497
498 #define MAXUNDO  32
499 static ListBase undobase={NULL, NULL};
500 static UndoElem *curundo= NULL;
501
502
503 static int read_undosave(UndoElem *uel)
504 {
505         char scestr[FILE_MAXDIR+FILE_MAXFILE];
506         int success=0, fileflags;
507         
508         strcpy(scestr, G.sce);  /* temporal store */
509         fileflags= G.fileflags;
510         G.fileflags |= G_FILE_NO_UI;
511
512         if(UNDO_DISK) 
513                 success= BKE_read_file(uel->str, NULL);
514         else
515                 success= BKE_read_file_from_memfile(&uel->memfile);
516         
517         /* restore */
518         strcpy(G.sce, scestr);
519         G.fileflags= fileflags;
520
521         return success;
522 }
523
524 /* name can be a dynamic string */
525 void BKE_write_undo(char *name)
526 {
527         int nr, success;
528         UndoElem *uel;
529         
530         if( (U.uiflag & USER_GLOBALUNDO)==0) return;
531
532         /* remove all undos after (also when curundo==NULL) */
533         while(undobase.last != curundo) {
534                 uel= undobase.last;
535                 BLI_remlink(&undobase, uel);
536                 BLO_free_memfile(&uel->memfile);
537                 MEM_freeN(uel);
538         }
539         
540         /* make new */
541         curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file");
542         strncpy(uel->name, name, MAXUNDONAME-1);
543         BLI_addtail(&undobase, uel);
544         
545         /* and limit amount to the maximum */
546         nr= 0;
547         uel= undobase.last;
548         while(uel) {
549                 nr++;
550                 if(nr==MAXUNDO) break;
551                 uel= uel->prev;
552         }
553         if(uel) {
554                 while(undobase.first!=uel) {
555                         UndoElem *first= undobase.first;
556                         BLI_remlink(&undobase, first);
557                         /* the merge is because of compression */
558                         BLO_merge_memfile(&first->memfile, &first->next->memfile);
559                         MEM_freeN(first);
560                 }
561         }
562
563
564         /* disk save version */
565         if(UNDO_DISK) {
566                 static int counter= 0;
567                 char *err, tstr[FILE_MAXDIR+FILE_MAXFILE];
568                 char numstr[32];
569                 
570                 /* calculate current filename */
571                 counter++;
572                 counter= counter % MAXUNDO;     
573         
574                 sprintf(numstr, "%d.blend", counter);
575                 BLI_make_file_string("/", tstr, U.tempdir, numstr);
576         
577                 success= BLO_write_file(tstr, G.fileflags, &err);
578                 
579                 strcpy(curundo->str, tstr);
580         }
581         else {
582                 MemFile *prevfile=NULL;
583                 char *err;
584                 
585                 if(curundo->prev) prevfile= &(curundo->prev->memfile);
586                 
587                 success= BLO_write_file_mem(prevfile, &curundo->memfile, G.fileflags, &err);
588                 
589         }
590 }
591
592 /* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */
593 void BKE_undo_step(int step)
594 {
595         
596         if(step==0) {
597                 read_undosave(curundo);
598         }
599         else if(step==1) {
600                 /* curundo should never be NULL, after restart or load file it should call undo_save */
601                 if(curundo==NULL || curundo->prev==NULL) error("No undo available");
602                 else {
603                         if(G.f & G_DEBUG) printf("undo %s\n", curundo->name);
604                         curundo= curundo->prev;
605                         read_undosave(curundo);
606                 }
607         }
608         else {
609                 
610                 /* curundo has to remain current situation! */
611                 
612                 if(curundo==NULL || curundo->next==NULL) error("No redo available");
613                 else {
614                         read_undosave(curundo->next);
615                         curundo= curundo->next;
616                         if(G.f & G_DEBUG) printf("redo %s\n", curundo->name);
617                 }
618         }
619 }
620
621 void BKE_reset_undo(void)
622 {
623         UndoElem *uel;
624         
625         uel= undobase.first;
626         while(uel) {
627                 BLO_free_memfile(&uel->memfile);
628                 uel= uel->next;
629         }
630         
631         BLI_freelistN(&undobase);
632         curundo= NULL;
633 }
634
635 /* based on index nr it does a restore */
636 void BKE_undo_number(int nr)
637 {
638         UndoElem *uel;
639         int a=1;
640         
641         for(uel= undobase.first; uel; uel= uel->next, a++) {
642                 if(a==nr) break;
643         }
644         curundo= uel;
645         BKE_undo_step(0);
646 }
647
648 char *BKE_undo_menu_string(void)
649 {
650         UndoElem *uel;
651         DynStr *ds= BLI_dynstr_new();
652         char *menu;
653         
654         BLI_dynstr_append(ds, "Global Undo History %t");
655         
656         for(uel= undobase.first; uel; uel= uel->next) {
657                 BLI_dynstr_append(ds, "|");
658                 BLI_dynstr_append(ds, uel->name);
659         }
660         
661         menu= BLI_dynstr_get_cstring(ds);
662         BLI_dynstr_free(ds);
663
664         return menu;
665 }
666
667         /* saves quit.blend */
668 void BKE_undo_save_quit(void)
669 {
670         UndoElem *uel;
671         MemFileChunk *chunk;
672         int file;
673         char str[FILE_MAXDIR+FILE_MAXFILE];
674         
675         if( (U.uiflag & USER_GLOBALUNDO)==0) return;
676         
677         uel= curundo;
678         if(uel==NULL) {
679                 printf("No undo buffer to save recovery file\n");
680                 return;
681         }
682         
683         /* no undo state to save */
684         if(undobase.first==undobase.last) return;
685                 
686         BLI_make_file_string("/", str, U.tempdir, "quit.blend");
687
688         file = open(str,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666);
689         if(file == -1) {
690                 printf("Unable to save %s\n", str);
691                 return;
692         }
693
694         chunk= uel->memfile.chunks.first;
695         while(chunk) {
696                 if( write(file, chunk->buf, chunk->size) != chunk->size) break;
697                 chunk= chunk->next;
698         }
699         
700         close(file);
701         
702         if(chunk) printf("Unable to save %s\n", str);
703         else printf("Saved session recovery to %s\n", str);
704 }
705