diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 3b7c3ae2d9f..81805a63f73 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -41,11 +41,13 @@ extern "C" { #endif struct ListBase; +struct MemFile; #define BLENDER_VERSION 234 int BKE_read_file(char *dir, void *type_r); int BKE_read_file_from_memory(char* filebuf, int filelength, void *type_r); +int BKE_read_file_from_memfile(struct MemFile *memfile); void duplicatelist(struct ListBase *list1, struct ListBase *list2); void free_blender(void); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index b9c45834840..205c417d79c 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -202,6 +202,8 @@ typedef struct Global { #define G_FILE_LOCK_BIT 7 #define G_FILE_SIGN_BIT 8 #define G_FILE_PUBLISH_BIT 9 +#define G_FILE_NO_UI_BIT 10 + #define G_AUTOPACK (1 << G_AUTOPACK_BIT) #define G_FILE_COMPRESS (1 << G_FILE_COMPRESS_BIT) @@ -213,6 +215,7 @@ typedef struct Global { #define G_FILE_LOCK (1 << G_FILE_LOCK_BIT) #define G_FILE_SIGN (1 << G_FILE_SIGN_BIT) #define G_FILE_PUBLISH (1 << G_FILE_PUBLISH_BIT) +#define G_FILE_NO_UI (1 << G_FILE_NO_UI_BIT) /* G.windowstate */ #define G_WINDOWSTATE_USERDEF 0 diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 02ad5f0c2fa..793a8f30c60 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -81,6 +81,7 @@ #include "BLI_editVert.h" +#include "BLO_undofile.h" #include "BLO_readfile.h" /* for BLO_read_file */ #include "BKE_bad_level_calls.h" // for freeAllRad editNurb free_editMesh free_editText free_editArmature @@ -223,7 +224,8 @@ void initglobals(void) /***/ -static void clear_global(void) { +static void clear_global(void) +{ extern short winqueue_break; /* screen.c */ freeAllRad(); @@ -261,8 +263,36 @@ static void clear_global(void) { G.f &= ~(G_WEIGHTPAINT + G_VERTEXPAINT + G_FACESELECT); } -static void setup_app_data(BlendFileData *bfd, char *filename) { +static void setup_app_data(BlendFileData *bfd, char *filename) +{ Object *ob; + bScreen *curscreen= NULL; + Scene *curscene= NULL; + char mode; + + /* 'u' = undo save, 'n' = no UI load */ + if(bfd->main->screen.first==NULL) mode= 'u'; + else if(G.fileflags & G_FILE_NO_UI) mode= 'n'; + else mode= 0; + + /* no load screens? */ + if(mode) { + /* comes from readfile.c */ + extern void lib_link_screen_restore(Main *, char, Scene *); + + SWAP(ListBase, G.main->screen, bfd->main->screen); + + /* we re-use current screen */ + curscreen= G.curscreen; + /* but use new Scene pointer */ + curscene= bfd->curscene; + if(curscene==NULL) curscene= bfd->main->scene.first; + /* and we enforce curscene to be in current screen */ + curscreen->scene= curscene; + + /* clear_global will free G.main, here we can still restore pointers */ + lib_link_screen_restore(bfd->main, mode, curscene); + } clear_global(); @@ -286,11 +316,19 @@ static void setup_app_data(BlendFileData *bfd, char *filename) { if(U.mixbufsize==0) U.mixbufsize= 2048; } - R.winpos= bfd->winpos; - R.displaymode= bfd->displaymode; - G.curscreen= bfd->curscreen; - G.fileflags= bfd->fileflags; - + /* case G_FILE_NO_UI or no screens in file */ + if(mode) { + G.curscreen= curscreen; + G.scene= curscene; + } + else { + R.winpos= bfd->winpos; + R.displaymode= bfd->displaymode; + G.fileflags= bfd->fileflags; + G.curscreen= bfd->curscreen; + G.scene= G.curscreen->scene; + } + /* special cases, override loaded flags: */ if (G.f & G_DEBUG) bfd->globalf |= G_DEBUG; else bfd->globalf &= ~G_DEBUG; @@ -298,7 +336,6 @@ static void setup_app_data(BlendFileData *bfd, char *filename) { else bfd->globalf &= ~G_SCENESCRIPT; G.f= bfd->globalf; - G.scene= G.curscreen->scene; /* few DispLists, but do text_to_curve */ // this should be removed!!! But first a better displist system (ton) @@ -330,7 +367,8 @@ static void setup_app_data(BlendFileData *bfd, char *filename) { MEM_freeN(bfd); } -int BKE_read_file(char *dir, void *type_r) { +int BKE_read_file(char *dir, void *type_r) +{ BlendReadError bre; BlendFileData *bfd; @@ -376,3 +414,25 @@ int BKE_read_file_from_memory(char* filebuf, int filelength, void *type_r) return (bfd?1:0); } + +int BKE_read_file_from_memfile(MemFile *memfile) +{ + BlendReadError bre; + BlendFileData *bfd; + + if (!G.background) + waitcursor(1); + + bfd= BLO_read_from_memfile(memfile, &bre); + if (bfd) { + setup_app_data(bfd, ""); + } else { + error("Loading failed: %s", BLO_bre_as_string(bre)); + } + + if (!G.background) + waitcursor(0); + + return (bfd?1:0); +} + diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 5b271daefdd..bd7cb626182 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -59,6 +59,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "DNA_oops_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -323,6 +324,19 @@ void unlink_object(Object *ob) if(v3d->localvd->persp>1) v3d->localvd->persp= 1; } } + else if(sl->spacetype==SPACE_IPO) { + SpaceIpo *sipo= (SpaceIpo *)sl; + if(sipo->from == (ID *)ob) sipo->from= NULL; + } + else if(sl->spacetype==SPACE_OOPS) { + SpaceOops *so= (SpaceOops *)sl; + Oops *oops; + oops= so->oops.first; + while(oops) { + if(oops->id==(ID *)ob) oops->id= NULL; + oops= oops->next; + } + } } sa= sa->next; diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 3093160139b..2c216f122cc 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -43,6 +43,7 @@ struct Main; struct UserDef; struct bScreen; struct Scene; +struct MemFile; typedef struct BlendHandle BlendHandle; @@ -113,7 +114,7 @@ BlendFileData* BLO_read_from_file (char *file, BlendReadError *error_r); * code indicating the cause of the failure. * @return The data of the file. */ -BlendFileData* BLO_read_from_memory (void *mem, int memsize, BlendReadError *error_r); +BlendFileData* BLO_read_from_memory(void *mem, int memsize, BlendReadError *error_r); /** @@ -124,6 +125,9 @@ BlendFileData* BLO_read_from_memory (void *mem, int memsize, BlendReadError *err * @return A static human readable string representation * of @a error. */ + +BlendFileData *BLO_read_from_memfile(struct MemFile *memfile, BlendReadError *error_r); + char* BLO_bre_as_string( BlendReadError error); diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h new file mode 100644 index 00000000000..225b6bc15f5 --- /dev/null +++ b/source/blender/blenloader/BLO_undofile.h @@ -0,0 +1,58 @@ +/* + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * external writefile function prototypes + */ + +#ifndef BLO_UNDOFILE_H +#define BLO_UNDOFILE_H + +typedef struct { + void *next, *prev; + + char *buf; + unsigned int ident, size; + +} MemFileChunk; + +typedef struct MemFile { + ListBase chunks; + unsigned int size; +} MemFile; + +/* actually only used writefile.c */ +extern void add_memfilechunk(MemFile *compare, MemFile *current, char *buf, unsigned int size); + +/* exports */ +extern void BLO_free_memfile(MemFile *memfile); +extern void BLO_merge_memfile(MemFile *first, MemFile *second); + +#endif + diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h index 1bbbf7ea4c9..cfa2fd7b0f6 100644 --- a/source/blender/blenloader/BLO_writefile.h +++ b/source/blender/blenloader/BLO_writefile.h @@ -34,8 +34,11 @@ #ifndef BLO_WRITEFILE_H #define BLO_WRITEFILE_H -int BLO_write_file(char *dir, int write_flags, char **error_r); -void BLO_write_runtime(char *file, char *exename); +struct MemFile; + +extern int BLO_write_file(char *dir, int write_flags, char **error_r); +extern int BLO_write_file_mem(struct MemFile *compare, struct MemFile *current, int write_flags, char **error_r); +extern void BLO_write_runtime(char *file, char *exename); #endif diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index a008142be66..fe39effdc01 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -61,6 +61,8 @@ #include "BKE_library.h" // for free_main #include "BLO_readfile.h" +#include "BLO_undofile.h" + #include "readfile.h" #include "BLO_readblenfile.h" @@ -113,7 +115,8 @@ static IDType idtypes[]= { }; static int nidtypes= sizeof(idtypes)/sizeof(idtypes[0]); -static IDType *idtype_from_name(char *str) { +static IDType *idtype_from_name(char *str) +{ int i= nidtypes; while (i--) @@ -122,7 +125,8 @@ static IDType *idtype_from_name(char *str) { return NULL; } -static IDType *idtype_from_code(int code) { +static IDType *idtype_from_code(int code) +{ int i= nidtypes; while (i--) @@ -132,7 +136,8 @@ static IDType *idtype_from_code(int code) { return NULL; } -static int bheadcode_is_idcode(int code) { +static int bheadcode_is_idcode(int code) +{ return idtype_from_code(code)?1:0; } @@ -141,13 +146,15 @@ static int idcode_is_linkable(int code) { return idt?(idt->flags&IDTYPE_FLAGS_ISLINKABLE):0; } -char *BLO_idcode_to_name(int code) { +char *BLO_idcode_to_name(int code) +{ IDType *idt= idtype_from_code(code); return idt?idt->name:NULL; } -int BLO_idcode_from_name(char *name) { +int BLO_idcode_from_name(char *name) +{ IDType *idt= idtype_from_name(name); return idt?idt->code:0; @@ -155,11 +162,13 @@ int BLO_idcode_from_name(char *name) { /* Access routines used by filesel. */ -BlendHandle *BLO_blendhandle_from_file(char *file) { +BlendHandle *BLO_blendhandle_from_file(char *file) +{ return (BlendHandle*) blo_openblenderfile(file); } -void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp) { +void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp) +{ FileData *fd= (FileData*) bh; BHead *bhead; @@ -188,7 +197,8 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp) { fprintf(fp, "]\n"); } -LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype) { +LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype) +{ FileData *fd= (FileData*) bh; LinkNode *names= NULL; BHead *bhead; @@ -205,7 +215,8 @@ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype) return names; } -LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) { +LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) +{ FileData *fd= (FileData*) bh; GHash *gathered= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); LinkNode *names= NULL; @@ -239,7 +250,8 @@ void BLO_blendhandle_close(BlendHandle *bh) { /**********/ -BlendFileData *BLO_read_from_file(char *file, BlendReadError *error_r) { +BlendFileData *BLO_read_from_file(char *file, BlendReadError *error_r) +{ BlendFileData *bfd = NULL; FileData *fd; @@ -256,7 +268,8 @@ BlendFileData *BLO_read_from_file(char *file, BlendReadError *error_r) { return bfd; } -BlendFileData *BLO_read_from_memory(void *mem, int memsize, BlendReadError *error_r) { +BlendFileData *BLO_read_from_memory(void *mem, int memsize, BlendReadError *error_r) +{ BlendFileData *bfd = NULL; FileData *fd; @@ -273,7 +286,26 @@ BlendFileData *BLO_read_from_memory(void *mem, int memsize, BlendReadError *erro return bfd; } -void BLO_blendfiledata_free(BlendFileData *bfd) { +BlendFileData *BLO_read_from_memfile(MemFile *memfile, BlendReadError *error_r) +{ + BlendFileData *bfd = NULL; + FileData *fd; + + fd = blo_openblendermemfile(memfile); + if (fd) { + bfd= blo_read_file_internal(fd, error_r); + if (bfd) { + bfd->type= BLENFILETYPE_BLEND; + strcpy(bfd->main->name, ""); + } + blo_freefiledata(fd); + } + + return bfd; +} + +void BLO_blendfiledata_free(BlendFileData *bfd) +{ if (bfd->main) { free_main(bfd->main); } @@ -285,7 +317,8 @@ void BLO_blendfiledata_free(BlendFileData *bfd) { MEM_freeN(bfd); } -char *BLO_bre_as_string(BlendReadError error) { +char *BLO_bre_as_string(BlendReadError error) +{ switch (error) { case BRE_NONE: return "No error"; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index d72921f1c03..498b84abb2c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -121,6 +121,7 @@ #include "BIF_butspace.h" // for do_versions, patching event codes #include "BLO_readfile.h" +#include "BLO_undofile.h" #include "readfile.h" #include "genfile.h" @@ -767,6 +768,54 @@ static int fd_read_from_memory(FileData *filedata, void *buffer, int size) return (readsize); } +static int fd_read_from_memfile(FileData *filedata, void *buffer, int size) +{ + static unsigned int seek= 1<<30; /* the current position */ + static unsigned int offset= 0; /* size of previous chunks */ + static MemFileChunk *chunk=NULL; + + if(size==0) return 0; + + if(seek != filedata->seek) { + chunk= filedata->memfile->chunks.first; + seek= 0; + + while(chunk) { + if(seek + chunk->size > filedata->seek) break; + seek+= chunk->size; + chunk= chunk->next; + } + offset= seek; + seek= filedata->seek; + } + + if(chunk) { + /* first check if it's on the end if current chunk */ + if( seek-offset == chunk->size) { + offset+= chunk->size; + chunk= chunk->next; + } + + /* debug, should never happen */ + if(chunk==NULL) { + printf("illegal read, chunk zero\n"); + return 0; + } + else if( (seek-offset)+size > chunk->size) { + size= chunk->size - (seek-offset); + printf("chunk too large, clipped to %d\n", size); + } + + memcpy(buffer, chunk->buf + (seek-offset), size); + filedata->seek += size; + seek+= size; + + return (size); + + } + return 0; +} + static FileData *filedata_new(void) { extern char DNAstr[]; /* DNA.c */ @@ -850,6 +899,34 @@ FileData *blo_openblendermemory(void *mem, int memsize) } } +FileData *blo_openblendermemfile(MemFile *memfile) +{ + if (!memfile) { + return NULL; + } else { + FileData *fd= filedata_new(); + fd->memfile= memfile; + + fd->read= fd_read_from_memfile; + fd->flags|= FD_FLAGS_NOT_MY_BUFFER; + + decode_blender_header(fd); + + if (fd->flags & FD_FLAGS_FILE_OK) { + if (!read_file_dna(fd)) { + blo_freefiledata(fd); + fd= NULL; + } + } else { + blo_freefiledata(fd); + fd= NULL; + } + + return fd; + } +} + + void blo_freefiledata(FileData *fd) { if (fd) { @@ -2437,6 +2514,8 @@ static void direct_link_scene(FileData *fd, Scene *sce) /* ************ READ SCREEN ***************** */ +/* note: file read without screens option G_FILE_NO_UI; + check lib pointers in call below */ static void lib_link_screen(FileData *fd, Main *main) { bScreen *sc; @@ -2478,8 +2557,8 @@ static void lib_link_screen(FileData *fd, Main *main) } else if(sl->spacetype==SPACE_BUTS) { SpaceButs *sbuts= (SpaceButs *)sl; - sbuts->rect= 0; - sbuts->lockpoin= 0; + sbuts->rect= NULL; + sbuts->lockpoin= NULL; if(main->versionfile<132) set_rects_butspace(sbuts); } else if(sl->spacetype==SPACE_FILE) { @@ -2540,6 +2619,130 @@ static void lib_link_screen(FileData *fd, Main *main) } } +static void *restore_pointer_by_name(Main *mainp, ID *id) +{ + ListBase *lb; + ID *idn=NULL; + + if(id) { + lb= wich_libbase(mainp, GS(id->name)); + idn= lb->first; + while(idn) { + if( strcmp(idn->name, id->name)==0) { + if(idn->us==0) idn->us++; + break; + } + idn= idn->next; + } + } + return idn; +} + +/* called from kernel/blender.c */ +void lib_link_screen_restore(Main *newmain, char mode, Scene *curscene) +{ + bScreen *sc; + ScrArea *sa; + + sc= newmain->screen.first; + while(sc) { + + if(mode=='u') sc->scene= restore_pointer_by_name(newmain, (ID *)sc->scene); + if(sc->scene==NULL || mode=='n') sc->scene= curscene; + + sa= sc->areabase.first; + while(sa) { + SpaceLink *sl; + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + + if(mode=='u') v3d->camera= restore_pointer_by_name(newmain, (ID *)v3d->camera); + if(v3d->camera==NULL || mode=='n') v3d->camera= sc->scene->camera; + + if(v3d->scenelock) v3d->lay= sc->scene->lay; + + if(v3d->bgpic) { + v3d->bgpic->ima= restore_pointer_by_name(newmain, (ID *)v3d->bgpic->ima); + v3d->bgpic->tex= restore_pointer_by_name(newmain, (ID *)v3d->bgpic->tex); + if(v3d->bgpic->rect) freeN(v3d->bgpic->rect); + v3d->bgpic->rect= NULL; + } + if(v3d->localvd) { + if(mode=='u') v3d->localvd->camera= restore_pointer_by_name(newmain, (ID *)v3d->localvd->camera); + if(v3d->localvd->camera==NULL || mode=='n') v3d->localvd->camera= sc->scene->camera; + } + } + else if(sl->spacetype==SPACE_IPO) { + SpaceIpo *sipo= (SpaceIpo *)sl; + sipo->from= restore_pointer_by_name(newmain, (ID *)sipo->from); + // not free sipo->ipokey, creates dependency with src/ + sipo->ipo= restore_pointer_by_name(newmain, (ID *)sipo->ipo); + if(sipo->editipo) MEM_freeN(sipo->editipo); + sipo->editipo= NULL; + } + else if(sl->spacetype==SPACE_BUTS) { + SpaceButs *sbuts= (SpaceButs *)sl; + sbuts->lockpoin= NULL; + if(sbuts->rect) MEM_freeN(sbuts->rect); + sbuts->rect= NULL; + } + else if(sl->spacetype==SPACE_FILE) { + SpaceFile *sfile= (SpaceFile *)sl; + + } + else if(sl->spacetype==SPACE_IMASEL) { + check_imasel_copy((SpaceImaSel *)sl); + } + else if(sl->spacetype==SPACE_ACTION) { + SpaceAction *saction= (SpaceAction *)sl; + saction->action = restore_pointer_by_name(newmain, (ID *)saction->action); + } + else if(sl->spacetype==SPACE_IMAGE) { + SpaceImage *sima= (SpaceImage *)sl; + + sima->image= restore_pointer_by_name(newmain, (ID *)sima->image); + } + else if(sl->spacetype==SPACE_NLA){ + /* SpaceNla *snla= (SpaceNla *)sl; */ + } + else if(sl->spacetype==SPACE_TEXT) { + SpaceText *st= (SpaceText *)sl; + + st->text= restore_pointer_by_name(newmain, (ID *)st->text); + } + else if(sl->spacetype==SPACE_SCRIPT) { + SpaceScript *sc= (SpaceScript *)sl; + + sc->script = NULL; + } + else if(sl->spacetype==SPACE_OOPS) { + SpaceOops *so= (SpaceOops *)sl; + Oops *oops; + + oops= so->oops.first; + while(oops) { + oops->id= restore_pointer_by_name(newmain, (ID *)oops->id); + oops= oops->next; + } + + so->lockpoin= NULL; + } + else if(sl->spacetype==SPACE_SOUND) { + SpaceSound *ssound= (SpaceSound *)sl; + + ssound->sound= restore_pointer_by_name(newmain, (ID *)ssound->sound); + } + } + sa= sa->next; + } + + sc= sc->id.next; + } + +} + static void direct_link_screen(FileData *fd, bScreen *sc) { ScrArea *sa; @@ -2881,12 +3084,17 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID static void link_global(FileData *fd, BlendFileData *bfd, FileGlobal *fg) { - // this is nonsense... will get rid of it once (ton) + // this is nonsense... make it struct once (ton) bfd->winpos= fg->winpos; bfd->fileflags= fg->fileflags; bfd->displaymode= fg->displaymode; bfd->globalf= fg->globalf; bfd->curscreen= newlibadr(fd, 0, fg->curscreen); + bfd->curscene= newlibadr(fd, 0, fg->curscene); + // this happens in files older than 2.35 + if(bfd->curscene==NULL) { + if(bfd->curscreen) bfd->curscene= bfd->curscreen->scene; + } } static void vcol_to_fcol(Mesh *me) @@ -4344,30 +4552,10 @@ BlendFileData *blo_read_file_internal(FileData *fd, BlendReadError *error_r) lib_link_all(fd, bfd->main); link_global(fd, bfd, fg); /* as last */ - if (!bfd->curscreen) - bfd->curscreen= bfd->main->screen.first; - - if (bfd->curscreen) { - bfd->curscene= bfd->curscreen->scene; - if (!bfd->curscene) { - bfd->curscene= bfd->main->scene.first; - bfd->curscreen->scene= bfd->curscene; - } - } + /* removed here: check for existance of curscreen/scene, moved to kernel setup_app */ MEM_freeN(fg); - /* require all files to have an active scene - * and screen. (implicitly: require all files - * to have at least one scene and one screen). - */ - if (!bfd->curscreen || !bfd->curscene) { - *error_r= (!bfd->curscreen)?BRE_NO_SCREEN:BRE_NO_SCENE; - - BLO_blendfiledata_free(bfd); - return NULL; - } - return bfd; } @@ -5202,7 +5390,8 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) /* reading runtime */ -BlendFileData *blo_read_blendafterruntime(int file, int actualsize, BlendReadError *error_r) { +BlendFileData *blo_read_blendafterruntime(int file, int actualsize, BlendReadError *error_r) +{ BlendFileData *bfd = NULL; FileData *fd = filedata_new(); fd->filedes = file; diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index a052b940c7c..e198752f130 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -34,6 +34,7 @@ #define READFILE_H struct OldNewMap; +struct MemFile; typedef struct FileData { // linked list of BHeadN's @@ -45,7 +46,9 @@ typedef struct FileData { int (*read)(struct FileData *filedata, void *buffer, int size); // variables needed for reading from memory / stream - char * buffer; + char *buffer; + // variables needed for reading from memfile (undo) + struct MemFile *memfile; // variables needed for reading from file int filedes; @@ -93,39 +96,18 @@ typedef struct BHeadN { void blo_join_main(ListBase *mainlist); void blo_split_main(ListBase *mainlist); - BlendFileData* -blo_read_file_internal( - FileData *fd, - BlendReadError *error_r); +BlendFileData *blo_read_file_internal( FileData *fd, BlendReadError *error_r); + +FileData *blo_openblenderfile( char *name); +FileData *blo_openblendermemory( void *buffer, int buffersize); +FileData *blo_openblendermemfile(struct MemFile *memfile); + +void blo_freefiledata( FileData *fd); - FileData* -blo_openblenderfile( - char *name); - - FileData* -blo_openblendermemory( - void *buffer, - int buffersize); - - void -blo_freefiledata( - FileData *fd); - - - BHead* -blo_firstbhead( - FileData *fd); - - BHead* -blo_nextbhead( - FileData *fd, - BHead *thisblock); - - BHead* -blo_prevbhead( - FileData *fd, - BHead *thisblock); +BHead *blo_firstbhead(FileData *fd); +BHead *blo_nextbhead(FileData *fd, BHead *thisblock); +BHead *blo_prevbhead(FileData *fd, BHead *thisblock); #endif diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ddab7f2b26d..6d84c120422 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -158,17 +158,22 @@ Important to know is that 'streaming' has been added to files, for Blender Publi #include "BLO_writefile.h" #include "BLO_readfile.h" +#include "BLO_undofile.h" #include "readfile.h" #include "genfile.h" + +/* ********* my write, buffered writing with minimum 50k chunks ************ */ + typedef struct { struct SDNA *sdna; int file; unsigned char *buf; - - int tot, count, error; + MemFile *compare, *current; + + int tot, count, error, memsize; } WriteData; static WriteData *writedata_new(int file) @@ -193,8 +198,16 @@ static WriteData *writedata_new(int file) static void writedata_do_write(WriteData *wd, void *mem, int memlen) { if (wd->error) return; - if (write(wd->file, mem, memlen) != memlen) - wd->error= 1; + + /* memory based save */ + if(wd->current) { + add_memfilechunk(NULL, wd->current, mem, memlen); + } + else { + if (write(wd->file, mem, memlen) != memlen) + wd->error= 1; + + } } static void writedata_free(WriteData *wd) @@ -215,16 +228,23 @@ int mywfile; * @param len Length of new chunk of data * @warning Talks to other functions with global parameters */ - static void -mywrite( - WriteData *wd, - void *adr, - int len) + +#define MYWRITE_FLUSH NULL + +static void mywrite( WriteData *wd, void *adr, int len) { if (wd->error) return; - wd->tot+= len; + if(adr==MYWRITE_FLUSH) { + if(wd->count) { + writedata_do_write(wd, wd->buf, wd->count); + wd->count= 0; + } + return; + } + wd->tot+= len; + if(len>50000) { if(wd->count) { writedata_do_write(wd, wd->buf, wd->count); @@ -239,6 +259,7 @@ mywrite( } memcpy(&wd->buf[wd->count], adr, len); wd->count+= len; + } /** @@ -247,13 +268,15 @@ mywrite( * @param write_flags Write parameters * @warning Talks to other functions with global parameters */ - static WriteData * -bgnwrite( - int file, - int write_flags) +static WriteData *bgnwrite(int file, MemFile *compare, MemFile *current, int write_flags) { WriteData *wd= writedata_new(file); + wd->compare= compare; + wd->current= current; + /* this inits comparing */ + add_memfilechunk(compare, NULL, NULL, 0); + return wd; } @@ -263,9 +286,7 @@ bgnwrite( * @return unknown global variable otherwise * @warning Talks to other functions with global parameters */ - static int -endwrite( - WriteData *wd) +static int endwrite(WriteData *wd) { int err; @@ -273,10 +294,10 @@ endwrite( writedata_do_write(wd, wd->buf, wd->count); wd->count= 0; } - + err= wd->error; writedata_free(wd); - +if(wd->current) printf("undo size %d\n", wd->current->size); return err; } @@ -654,6 +675,9 @@ static void write_objects(WriteData *wd, ListBase *idbase) } ob= ob->id.next; } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); } @@ -709,6 +733,9 @@ static void write_ipos(WriteData *wd, ListBase *idbase) ipo= ipo->id.next; } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); } static void write_keys(WriteData *wd, ListBase *idbase) @@ -733,6 +760,8 @@ static void write_keys(WriteData *wd, ListBase *idbase) key= key->id.next; } + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); } static void write_cameras(WriteData *wd, ListBase *idbase) @@ -816,6 +845,9 @@ static void write_curves(WriteData *wd, ListBase *idbase) } cu= cu->id.next; } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); } static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist) @@ -880,6 +912,8 @@ static void write_images(WriteData *wd, ListBase *idbase) } ima= ima->id.next; } + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); } static void write_textures(WriteData *wd, ListBase *idbase) @@ -899,6 +933,9 @@ static void write_textures(WriteData *wd, ListBase *idbase) } tex= tex->id.next; } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); } static void write_materials(WriteData *wd, ListBase *idbase) @@ -1088,6 +1125,8 @@ static void write_scenes(WriteData *wd, ListBase *scebase) sce= sce->id.next; } + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); } static void write_screens(WriteData *wd, ListBase *scrbase) @@ -1282,6 +1321,9 @@ static void write_armatures(WriteData *wd, ListBase *idbase) } arm=arm->id.next; } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); } static void write_actions(WriteData *wd, ListBase *idbase) @@ -1331,6 +1373,9 @@ static void write_texts(WriteData *wd, ListBase *idbase) } text= text->id.next; } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); } static void write_sounds(WriteData *wd, ListBase *idbase) @@ -1377,6 +1422,9 @@ static void write_sounds(WriteData *wd, ListBase *idbase) } sound= sound->id.next; } + + /* flush helps the compression for undo-save */ + mywrite(wd, MYWRITE_FLUSH, 0); } static void write_groups(WriteData *wd, ListBase *idbase) @@ -1423,6 +1471,7 @@ static void write_global(WriteData *wd) FileGlobal fg; fg.curscreen= G.curscreen; + fg.curscene= G.scene; fg.displaymode= R.displaymode; fg.winpos= R.winpos; fg.fileflags= G.fileflags; @@ -1431,8 +1480,10 @@ static void write_global(WriteData *wd) writestruct(wd, GLOB, "FileGlobal", 1, &fg); } -static int write_file_handle(int handle, int write_user_block, int write_flags) +/* if *mem there's filesave to memory */ +static int write_file_handle(int handle, MemFile *compare, MemFile *current, int write_user_block, int write_flags) { + BHead bhead; ListBase mainlist; char buf[13]; WriteData *wd; @@ -1443,21 +1494,18 @@ static int write_file_handle(int handle, int write_user_block, int write_flags) blo_split_main(&mainlist); - wd= bgnwrite(handle, write_flags); - + wd= bgnwrite(handle, compare, current, write_flags); + sprintf(buf, "BLENDER%c%c%.3d", (sizeof(void*)==8)?'-':'_', (G.order==B_ENDIAN)?'V':'v', G.version); mywrite(wd, buf, 12); write_renderinfo(wd); - - write_screens (wd, &G.main->screen); + + if(current==NULL) + write_screens (wd, &G.main->screen); // no UI save write_scenes (wd, &G.main->scene); - write_objects (wd, &G.main->object); - write_meshs (wd, &G.main->mesh); write_curves (wd, &G.main->curve); write_mballs (wd, &G.main->mball); - write_materials(wd, &G.main->mat); - write_textures (wd, &G.main->tex); write_images (wd, &G.main->image); write_cameras (wd, &G.main->camera); write_lamps (wd, &G.main->lamp); @@ -1472,6 +1520,10 @@ static int write_file_handle(int handle, int write_user_block, int write_flags) write_groups (wd, &G.main->group); write_armatures(wd, &G.main->armature); write_actions (wd, &G.main->action); + write_objects (wd, &G.main->object); + write_materials(wd, &G.main->mat); + write_textures (wd, &G.main->tex); + write_meshs (wd, &G.main->mesh); write_libraries(wd, G.main->next); write_global(wd); @@ -1482,11 +1534,10 @@ static int write_file_handle(int handle, int write_user_block, int write_flags) /* dna as last, because (to be implemented) test for which structs are written */ writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data); - data= ENDB; - mywrite(wd, &data, 4); - - data= 0; - mywrite(wd, &data, 4); + /* end of file */ + memset(&bhead, 0, sizeof(BHead)); + bhead.code= ENDB; + mywrite(wd, &bhead, sizeof(BHead)); blo_join_main(&mainlist); G.main= mainlist.first; @@ -1494,6 +1545,7 @@ static int write_file_handle(int handle, int write_user_block, int write_flags) return endwrite(wd); } +/* return: success (1) */ int BLO_write_file(char *dir, int write_flags, char **error_r) { char userfilename[FILE_MAXDIR+FILE_MAXFILE]; @@ -1515,7 +1567,7 @@ int BLO_write_file(char *dir, int write_flags, char **error_r) write_user_block= BLI_streq(dir, userfilename); - fout= write_file_handle(file, write_user_block, write_flags); + fout= write_file_handle(file, NULL,NULL, write_user_block, write_flags); close(file); if(!fout) { @@ -1533,6 +1585,18 @@ int BLO_write_file(char *dir, int write_flags, char **error_r) return 1; } +/* return: success (1) */ +int BLO_write_file_mem(MemFile *compare, MemFile *current, int write_flags, char **error_r) +{ + int err; + + err= write_file_handle(0, compare, current, 0, write_flags); + + if(err==0) return 1; + return 0; +} + + /* Runtime writing */ #ifdef WIN32 @@ -1632,7 +1696,7 @@ void BLO_write_runtime(char *file, char *exename) { outfd= open(gamename, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0777); if (outfd != -1) { - write_file_handle(outfd, 0, G.fileflags); + write_file_handle(outfd, NULL,NULL, 0, G.fileflags); if (write(outfd, " ", 1) != 1) { cause= "Unable to write to output file"; @@ -1712,7 +1776,7 @@ void BLO_write_runtime(char *file, char *exename) { datastart= lseek(outfd, 0, SEEK_CUR); - write_file_handle(outfd, 0, G.fileflags); + write_file_handle(outfd, NULL,NULL, 0, G.fileflags); if (!handle_write_msb_int(outfd, datastart) || (write(outfd, "BRUNTIME", 8)!=8)) { cause= "Unable to write to output file"; diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h index 40bf5e2a68f..b06f3f3e372 100644 --- a/source/blender/makesdna/DNA_fileglobal_types.h +++ b/source/blender/makesdna/DNA_fileglobal_types.h @@ -40,6 +40,7 @@ */ typedef struct FileGlobal { void *curscreen; + void *curscene; short displaymode, winpos; int fileflags; int globalf; diff --git a/source/blender/src/editscreen.c b/source/blender/src/editscreen.c index b8f26bddbef..b9aed992686 100644 --- a/source/blender/src/editscreen.c +++ b/source/blender/src/editscreen.c @@ -554,11 +554,14 @@ void markdirty_all() ScrArea *sa; for (sa= G.curscreen->areabase.first; sa; sa= sa->next) { - scrarea_queue_winredraw(sa); - sa->win_swap &= ~WIN_FRONT_OK; - - scrarea_queue_headredraw(sa); - sa->head_swap &= ~WIN_FRONT_OK; + if(sa->win) { + scrarea_queue_winredraw(sa); + sa->win_swap &= ~WIN_FRONT_OK; + } + if(sa->headwin) { + scrarea_queue_headredraw(sa); + sa->head_swap &= ~WIN_FRONT_OK; + } } } @@ -1870,6 +1873,7 @@ void setscreen(bScreen *sc) sa= sa->next; } } + else if(G.curscreen) markdirty_all(); /* at least redraw */ if (G.curscreen != sc) { mywinset(sc->mainwin); @@ -1916,7 +1920,7 @@ void setscreen(bScreen *sc) sa->cursor= CURSOR_STD; } - + G.scene= sc->scene; countall(); diff --git a/source/blender/src/header_info.c b/source/blender/src/header_info.c index 91dc0c29da6..6d22e5a0dae 100644 --- a/source/blender/src/header_info.c +++ b/source/blender/src/header_info.c @@ -883,12 +883,16 @@ static void do_info_filemenu(void *arg, int event) case 13: exit_usiblender(); break; + case 14: + G.fileflags ^= G_FILE_NO_UI; + break; case 31: /* save default settings */ BIF_write_homefile(); break; } allqueue(REDRAWINFO, 0); } + static uiBlock *info_filemenu(void *arg_unused) { uiBlock *block; @@ -904,6 +908,14 @@ static uiBlock *info_filemenu(void *arg_unused) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + if(G.fileflags & G_FILE_NO_UI) { + uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Load UI", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, ""); + } else { + uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Load UI", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, ""); + } + + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save|Ctrl W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save As...|F2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, ""); @@ -1290,7 +1302,7 @@ static uiBlock *info_gamemenu(void *arg_unused) if(G.fileflags & (1 << G_FILE_ENABLE_ALL_FRAMES_BIT)) { uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Enable All Frames", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_ENABLE_ALL_FRAMES_BIT, ""); } else { - uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Enable All Frames", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_ENABLE_ALL_FRAMES_BIT, ""); + uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Enable All Frames", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_ENABLE_ALL_FRAMES_BIT, ""); } if(G.fileflags & (1 << G_FILE_SHOW_FRAMERATE_BIT)) { diff --git a/source/blender/src/interface.c b/source/blender/src/interface.c index 29f8a805153..f7fa04982cc 100644 --- a/source/blender/src/interface.c +++ b/source/blender/src/interface.c @@ -3091,7 +3091,7 @@ static int ui_do_block(uiBlock *block, uiEvent *uevent) if(inside || uevent->event!=LEFTMOUSE) { butevent= ui_do_button(block, but, uevent); - if(but->type!=BLOCK) BIF_write_undo(but->str); + if(but->type!=BLOCK && but->type!=MENU) BIF_write_undo(but->str); if(butevent) addqueue(block->winq, UI_BUT_EVENT, (short)butevent); diff --git a/source/blender/src/oops.c b/source/blender/src/oops.c index 25934fe98a4..1646b6c8166 100644 --- a/source/blender/src/oops.c +++ b/source/blender/src/oops.c @@ -105,6 +105,7 @@ Oops *find_oops(ID *id) return oops; } +/* never even called! (ton) */ int test_oops(Oops *oops) { /* test if own ID block still exists */ diff --git a/source/blender/src/toets.c b/source/blender/src/toets.c index e2ccb8a3239..81270c9f846 100644 --- a/source/blender/src/toets.c +++ b/source/blender/src/toets.c @@ -888,7 +888,7 @@ int blenderqread(unsigned short event, short val) } else if(G.qual==(LR_ALTKEY|LR_CTRLKEY)) { int a; - int event= pupmenu("10 Timer%t|draw|draw+swap|displist"); + int event= pupmenu("10 Timer%t|draw|draw+swap|displist|undo"); if(event>0) { double stime= PIL_check_seconds_timer(); char tmpstr[128]; @@ -907,6 +907,10 @@ int blenderqread(unsigned short event, short val) makeDispList(OBACT); } } + else if(event==4) { + extern void BIF_write_undo(char *name); + BIF_write_undo("10 timer"); + } } time= (PIL_check_seconds_timer()-stime)*1000; @@ -914,6 +918,7 @@ int blenderqread(unsigned short event, short val) if(event==1) sprintf(tmpstr, "draw %%t|%d ms", time); if(event==2) sprintf(tmpstr, "d+sw %%t|%d ms", time); if(event==3) sprintf(tmpstr, "displist %%t|%d ms", time); + if(event==4) sprintf(tmpstr, "undo %%t|%d ms", time); waitcursor(0); pupmenu(tmpstr); diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c index b484d2d7d68..50e599b1427 100644 --- a/source/blender/src/usiblender.c +++ b/source/blender/src/usiblender.c @@ -122,15 +122,16 @@ #include "PIL_time.h" +// temporal, will go to include file +void BIF_reset_undo(void); +void BIF_write_undo(char *); + + /***/ void BIF_read_file(char *name) { extern short winqueue_break; /* editscreen.c */ - void BIF_reset_undo(void); - void BIF_write_undo(char *); - - BIF_reset_undo(); //here? //sound_end_all_sounds(); @@ -149,6 +150,7 @@ void BIF_read_file(char *name) winqueue_break= 1; /* leave queues everywhere */ + BIF_reset_undo(); BIF_write_undo("original"); /* save current state */ } @@ -232,6 +234,8 @@ int BIF_read_homefile(void) space_set_commmandline_options(); if (U.undosteps==0) U.undosteps=32; + BIF_reset_undo(); + BIF_write_undo("original"); /* save current state */ reset_autosave(); @@ -464,124 +468,6 @@ static void delete_autosave(void) } } -/***/ - -#define MAXUNDONAME 64 -typedef struct UndoElem { - struct UndoElem *next, *prev; - char str[FILE_MAXDIR+FILE_MAXFILE]; - char name[MAXUNDONAME]; -} UndoElem; - -#define MAXUNDO 32 -static ListBase undobase={NULL, NULL}; -static UndoElem *curundo= NULL; - -static void get_undosave_location(char buf[FILE_MAXDIR+FILE_MAXFILE], int num) -{ - char numstr[32]; - - sprintf(numstr, "%d.blend", num); - BLI_make_file_string("/", buf, U.tempdir, numstr); - -} - -static int read_undosave(char *tstr) -{ - char scestr[FILE_MAXDIR+FILE_MAXFILE]; - int success; - - strcpy(scestr, G.sce); /* temporal store */ - - success= BKE_read_file(tstr, NULL); - strcpy(G.sce, scestr); - - return success; -} - -/* name can be a dynamic string */ -void BIF_write_undo(char *name) -{ - static int counter= 0; - int nr; - char *err, tstr[FILE_MAXDIR+FILE_MAXFILE]; - UndoElem *uel; - - if( (U.uiflag & USER_GLOBALUNDO==0)) return; - - /* calculate current filename */ - counter++; - counter= counter % MAXUNDO; - get_undosave_location(tstr, counter); - - if(BLO_write_file(tstr, G.fileflags, &err)) { - - /* remove all undos after (also when curundo==NULL) */ - while(undobase.last != curundo) { - uel= undobase.last; - BLI_remlink(&undobase, uel); - MEM_freeN(uel); - } - - /* make new */ - curundo= uel= MEM_mallocN(sizeof(UndoElem), "undo file"); - strcpy(uel->str, tstr); - strncpy(uel->name, name, MAXUNDONAME-1); - BLI_addtail(&undobase, uel); - - /* and limit amount to the maximum */ - nr= 0; - uel= undobase.last; - while(uel) { - nr++; - if(nr==MAXUNDO) break; - uel= uel->prev; - } - if(uel) { - while(undobase.first!=uel) { - UndoElem *first= undobase.first; - BLI_remlink(&undobase, first); - MEM_freeN(first); - } - } - } - -} - -/* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */ -void BIF_undo_step(int step) -{ - - if(step==1) { - /* curundo should never be NULL, after restart or load file it should call undo_save */ - if(curundo==NULL || curundo->prev==NULL) error("No undo available"); - else { - printf("undo %s\n", curundo->name); - curundo= curundo->prev; - read_undosave(curundo->str); - } - } - else { - - /* curundo has to remain current situation! */ - - if(curundo==NULL || curundo->next==NULL) error("No redo available"); - else { - read_undosave(curundo->next->str); - curundo= curundo->next; - printf("redo %s\n", curundo->name); - } - } -} - -void BIF_reset_undo(void) -{ - - BLI_freelistN(&undobase); - curundo= NULL; -} - - /***/ static void initbuttons(void)