Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenloader/intern')
-rw-r--r--source/blender/blenloader/intern/readblenentry.c129
-rw-r--r--source/blender/blenloader/intern/readfile.c983
-rw-r--r--source/blender/blenloader/intern/readfile.h5
-rw-r--r--source/blender/blenloader/intern/versioning_260.c4
-rw-r--r--source/blender/blenloader/intern/versioning_270.c20
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c2
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c2
-rw-r--r--source/blender/blenloader/intern/writefile.c77
8 files changed, 840 insertions, 382 deletions
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 20ec27a1f4b..cd6df354ca7 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -72,6 +72,13 @@ void BLO_blendhandle_print_sizes(BlendHandle *, void *);
/* Access routines used by filesel. */
+/**
+ * Open a blendhandle from a file path.
+ *
+ * \param filepath The file path to open.
+ * \param reports Report errors in opening the file (can be NULL).
+ * \return A handle on success, or NULL on failure.
+ */
BlendHandle *BLO_blendhandle_from_file(const char *filepath, ReportList *reports)
{
BlendHandle *bh;
@@ -81,6 +88,13 @@ BlendHandle *BLO_blendhandle_from_file(const char *filepath, ReportList *reports
return bh;
}
+/**
+ * Open a blendhandle from memory.
+ *
+ * \param mem The data to load from.
+ * \param memsize The size of the data.
+ * \return A handle on success, or NULL on failure.
+ */
BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize)
{
BlendHandle *bh;
@@ -120,6 +134,14 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp)
fprintf(fp, "]\n");
}
+/**
+ * Gets the names of all the datablocks in a file of a certain type (e.g. all the scene names in a file).
+ *
+ * \param bh The blendhandle to access.
+ * \param ofblocktype The type of names to get.
+ * \param tot_names The length of the returned list.
+ * \return A BLI_linklist of strings. The string links should be freed with malloc.
+ */
LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names)
{
FileData *fd = (FileData *) bh;
@@ -142,6 +164,14 @@ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype,
return names;
}
+/**
+ * Gets the previews of all the datablocks in a file of a certain type (e.g. all the scene previews in a file).
+ *
+ * \param bh The blendhandle to access.
+ * \param ofblocktype The type of names to get.
+ * \param tot_prev The length of the returned list.
+ * \return A BLI_linklist of PreviewImage. The PreviewImage links should be freed with malloc.
+ */
LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *tot_prev)
{
FileData *fd = (FileData *) bh;
@@ -161,6 +191,9 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to
case ID_IM: /* fall through */
case ID_WO: /* fall through */
case ID_LA: /* fall through */
+ case ID_OB: /* fall through */
+ case ID_GR: /* fall through */
+ case ID_SCE: /* fall through */
new_prv = MEM_callocN(sizeof(PreviewImage), "newpreview");
BLI_linklist_prepend(&previews, new_prv);
tot++;
@@ -229,7 +262,13 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to
return previews;
}
-LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
+/**
+ * Gets the names of all the linkable datablock types available in a file. (e.g. "Scene", "Mesh", "Lamp", etc.).
+ *
+ * \param bh The blendhandle to access.
+ * \return A BLI_linklist of strings. The string links should be freed with malloc.
+ */
+LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
{
FileData *fd = (FileData *) bh;
GSet *gathered = BLI_gset_ptr_new("linkable_groups gh");
@@ -257,6 +296,11 @@ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
return names;
}
+/**
+ * Close and free a blendhandle. The handle becomes invalid after this call.
+ *
+ * \param bh The handle to close.
+ */
void BLO_blendhandle_close(BlendHandle *bh)
{
FileData *fd = (FileData *) bh;
@@ -266,6 +310,14 @@ void BLO_blendhandle_close(BlendHandle *bh)
/**********/
+/**
+ * Open a blender file from a pathname. The function returns NULL
+ * and sets a report in the list if it cannot open the file.
+ *
+ * \param filepath The path of the file to open.
+ * \param reports If the return value is NULL, errors indicating the cause of the failure.
+ * \return The data of the file.
+ */
BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports)
{
BlendFileData *bfd = NULL;
@@ -281,6 +333,15 @@ BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports)
return bfd;
}
+/**
+ * Open a blender file from memory. The function returns NULL
+ * and sets a report in the list if it cannot open the file.
+ *
+ * \param mem The file data.
+ * \param memsize The length of \a mem.
+ * \param reports If the return value is NULL, errors indicating the cause of the failure.
+ * \return The data of the file.
+ */
BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *reports)
{
BlendFileData *bfd = NULL;
@@ -296,11 +357,17 @@ BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *re
return bfd;
}
+/**
+ * Used for undo/redo, skips part of libraries reading (assuming their data are already loaded & valid).
+ *
+ * \param oldmain old main, from which we will keep libraries and other datablocks that should not have changed.
+ * \param filename current file, only for retrieving library data.
+ */
BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFile *memfile, ReportList *reports)
{
BlendFileData *bfd = NULL;
FileData *fd;
- ListBase mainlist;
+ ListBase old_mainlist;
fd = blo_openblendermemfile(memfile, reports);
if (fd) {
@@ -311,9 +378,9 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil
blo_clear_proxy_pointers_from_lib(oldmain);
/* separate libraries from old main */
- blo_split_main(&mainlist, oldmain);
+ blo_split_main(&old_mainlist, oldmain);
/* add the library pointers in oldmap lookup */
- blo_add_library_pointer_map(&mainlist, fd);
+ blo_add_library_pointer_map(&old_mainlist, fd);
/* makes lookup of existing images in old main */
blo_make_image_pointer_map(fd, oldmain);
@@ -337,25 +404,55 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil
/* ensures relinked sounds are not freed */
blo_end_sound_pointer_map(fd, oldmain);
- /* move libraries from old main to new main */
- if (bfd && mainlist.first != mainlist.last) {
-
- /* Library structs themselves */
- bfd->main->library = oldmain->library;
- BLI_listbase_clear(&oldmain->library);
-
- /* add the Library mainlist to the new main */
- BLI_remlink(&mainlist, oldmain);
- BLI_addhead(&mainlist, bfd->main);
+ /* Still in-use libraries have already been moved from oldmain to new mainlist,
+ * but oldmain itself shall *never* be 'transferred' to new mainlist! */
+ BLI_assert(old_mainlist.first == oldmain);
+
+ if (bfd && old_mainlist.first != old_mainlist.last) {
+ /* Even though directly used libs have been already moved to new main, indirect ones have not.
+ * This is a bit annoying, but we have no choice but to keep them all for now - means some now unused
+ * data may remain in memory, but think we'll have to live with it. */
+ Main *libmain;
+ Main *newmain = bfd->main;
+ ListBase new_mainlist = {newmain, newmain};
+
+ for (libmain = oldmain->next; libmain; libmain = libmain->next) {
+ /* Note that LIB_INDIRECT does not work with libraries themselves, so we use non-NULL parent
+ * to detect indirect-linked ones... */
+ if (libmain->curlib && (libmain->curlib->parent != NULL)) {
+ BLI_remlink(&old_mainlist, libmain);
+ BLI_addtail(&new_mainlist, libmain);
+ }
+#if 0
+ else {
+ printf("Dropped Main for lib: %s\n", libmain->curlib->id.name);
+ }
+#endif
+ }
+ /* In any case, we need to move all lib datablocks themselves - those are 'first level data',
+ * getting rid of them would imply updating spaces & co to prevent invalid pointers access. */
+ BLI_movelisttolist(&newmain->library, &oldmain->library);
+
+ blo_join_main(&new_mainlist);
}
- blo_join_main(&mainlist);
-
+
+ /* printf("Remaining mains/libs in oldmain: %d\n", BLI_listbase_count(&fd->old_mainlist) - 1); */
+
+ /* That way, libs (aka mains) we did not reuse in new undone/redone state
+ * will be cleared together with oldmain... */
+ blo_join_main(&old_mainlist);
+
blo_freefiledata(fd);
}
return bfd;
}
+/**
+ * Frees a BlendFileData structure and *all* the data associated with it (the userdef data, and the main libblock data).
+ *
+ * \param bfd The structure to free.
+ */
void BLO_blendfiledata_free(BlendFileData *bfd)
{
if (bfd->main) {
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index cc84a899856..6545a3b0e67 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -109,7 +109,7 @@
#include "BLI_threads.h"
#include "BLI_mempool.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -124,6 +124,7 @@
#include "BKE_global.h" // for G
#include "BKE_group.h"
#include "BKE_library.h" // for which_libbase
+#include "BKE_library_query.h"
#include "BKE_idcode.h"
#include "BKE_material.h"
#include "BKE_main.h" // for Main
@@ -313,6 +314,56 @@ void blo_do_versions_oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newad
oldnewmap_insert(onm, oldaddr, newaddr, nr);
}
+/**
+ * Do a full search (no state).
+ *
+ * \param lasthit: Use as a reference position to avoid a full search
+ * from either end of the array, giving more efficient lookups.
+ *
+ * \note This would seem an ideal case for hash or btree lookups.
+ * However the data is written in-order, using the \a lasthit will normally avoid calling this function.
+ * Creating a btree/hash structure adds overhead for the common-case to optimize the corner-case
+ * (since most entries will never be retrieved).
+ * So just keep full lookups as a fall-back.
+ */
+static int oldnewmap_lookup_entry_full(const OldNewMap *onm, const void *addr, int lasthit)
+{
+ const int nentries = onm->nentries;
+ const OldNew *entries = onm->entries;
+ int i;
+
+ /* search relative to lasthit where possible */
+ if (lasthit >= 0 && lasthit < nentries) {
+
+ /* search forwards */
+ i = lasthit;
+ while (++i != nentries) {
+ if (entries[i].old == addr) {
+ return i;
+ }
+ }
+
+ /* search backwards */
+ i = lasthit + 1;
+ while (i--) {
+ if (entries[i].old == addr) {
+ return i;
+ }
+ }
+ }
+ else {
+ /* search backwards (full) */
+ i = nentries;
+ while (i--) {
+ if (entries[i].old == addr) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+}
+
static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_users)
{
int i;
@@ -329,16 +380,14 @@ static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_
}
}
- for (i = 0; i < onm->nentries; i++) {
+ i = oldnewmap_lookup_entry_full(onm, addr, onm->lasthit);
+ if (i != -1) {
OldNew *entry = &onm->entries[i];
-
- if (entry->old == addr) {
- onm->lasthit = i;
-
- if (increase_users)
- entry->nr++;
- return entry->newp;
- }
+ BLI_assert(entry->old == addr);
+ onm->lasthit = i;
+ if (increase_users)
+ entry->nr++;
+ return entry->newp;
}
return NULL;
@@ -368,16 +417,13 @@ static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib)
}
else {
/* note, this can be a bottle neck when loading some files */
- unsigned int nentries = (unsigned int)onm->nentries;
- unsigned int i;
- OldNew *entry;
-
- for (i = 0, entry = onm->entries; i < nentries; i++, entry++) {
- if (entry->old == addr) {
- ID *id = entry->newp;
- if (id && (!lib || id->lib)) {
- return id;
- }
+ const int i = oldnewmap_lookup_entry_full(onm, addr, -1);
+ if (i != -1) {
+ OldNew *entry = &onm->entries[i];
+ ID *id = entry->newp;
+ BLI_assert(entry->old == addr);
+ if (id && (!lib || id->lib)) {
+ return id;
}
}
}
@@ -573,7 +619,9 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
m = BKE_main_new();
BLI_addtail(mainlist, m);
- lib = BKE_libblock_alloc(m, ID_LI, "lib");
+ /* Add library datablock itself to 'main' Main, since libraries are **never** linked data.
+ * Fixes bug where you could end with all ID_LI datablocks having the same name... */
+ lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib");
BLI_strncpy(lib->name, filepath, sizeof(lib->name));
BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath));
@@ -806,6 +854,12 @@ BHead *blo_nextbhead(FileData *fd, BHead *thisblock)
return(bhead);
}
+/* Warning! Caller's responsability to ensure given bhead **is** and ID one! */
+const char *bhead_id_name(const FileData *fd, const BHead *bhead)
+{
+ return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs);
+}
+
static void decode_blender_header(FileData *fd)
{
char header[SIZEOFBLENDERHEADER], num[4];
@@ -872,6 +926,41 @@ static int read_file_dna(FileData *fd)
return 0;
}
+static int *read_file_thumbnail(FileData *fd)
+{
+ BHead *bhead;
+ int *blend_thumb = NULL;
+
+ for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
+ if (bhead->code == TEST) {
+ const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
+ int *data = (int *)(bhead + 1);
+
+ if (bhead->len < (2 * sizeof(int))) {
+ break;
+ }
+
+ if (do_endian_swap) {
+ BLI_endian_switch_int32(&data[0]);
+ BLI_endian_switch_int32(&data[1]);
+ }
+
+ if (bhead->len < BLEN_THUMB_MEMSIZE_FILE(data[0], data[1])) {
+ break;
+ }
+
+ blend_thumb = data;
+ break;
+ }
+ else if (bhead->code != REND) {
+ /* Thumbnail is stored in TEST immediately after first REND... */
+ break;
+ }
+ }
+
+ return blend_thumb;
+}
+
static int fd_read_from_file(FileData *filedata, void *buffer, unsigned int size)
{
int readsize = read(filedata->filedes, buffer, size);
@@ -1035,6 +1124,33 @@ FileData *blo_openblenderfile(const char *filepath, ReportList *reports)
}
}
+/**
+ * Same as blo_openblenderfile(), but does not reads DNA data, only header. Use it for light access
+ * (e.g. thumbnail reading).
+ */
+static FileData *blo_openblenderfile_minimal(const char *filepath)
+{
+ gzFile gzfile;
+ errno = 0;
+ gzfile = BLI_gzopen(filepath, "rb");
+
+ if (gzfile != (gzFile)Z_NULL) {
+ FileData *fd = filedata_new();
+ fd->gzfiledes = gzfile;
+ fd->read = fd_read_gzip_from_file;
+
+ decode_blender_header(fd);
+
+ if (fd->flags & FD_FLAGS_FILE_OK) {
+ return fd;
+ }
+
+ blo_freefiledata(fd);
+ }
+
+ return NULL;
+}
+
static int fd_read_gzip_from_memory(FileData *filedata, void *buffer, unsigned int size)
{
int err;
@@ -1183,53 +1299,115 @@ void blo_freefiledata(FileData *fd)
/* ************ DIV ****************** */
+/**
+ * Check whether given path ends with a blend file compatible extension (.blend, .ble or .blend.gz).
+ *
+ * \param str The path to check.
+ * \return true is this path ends with a blender file extension.
+ */
bool BLO_has_bfile_extension(const char *str)
{
const char *ext_test[4] = {".blend", ".ble", ".blend.gz", NULL};
return BLI_testextensie_array(str, ext_test);
}
-bool BLO_is_a_library(const char *path, char *dir, char *group)
+/**
+ * Try to explode given path into its 'library components' (i.e. a .blend file, id type/group, and datablock itself).
+ *
+ * \param path the full path to explode.
+ * \param r_dir the string that'll contain path up to blend file itself ('library' path).
+ * \param r_group the string that'll contain 'group' part of the path, if any. May be NULL.
+ * \param r_name the string that'll contain data's name part of the path, if any. May be NULL.
+ * \return true if path contains a blend file.
+ */
+bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
{
- /* return ok when a blenderfile, in dir is the filename,
- * in group the type of libdata
- */
- int len;
- char *fd;
-
- /* if path leads to a directory we can be sure we're not in a library */
- if (BLI_is_dir(path)) return 0;
+ /* We might get some data names with slashes, so we have to go up in path until we find blend file itself,
+ * then we now next path item is group, and everything else is data name. */
+ char *slash = NULL, *prev_slash = NULL, c = '\0';
- strcpy(dir, path);
- len = strlen(dir);
- if (len < 7) return 0;
- if ((dir[len - 1] != '/') && (dir[len - 1] != '\\')) return 0;
-
- group[0] = '\0';
- dir[len - 1] = '\0';
+ r_dir[0] = '\0';
+ if (r_group) {
+ *r_group = NULL;
+ }
+ if (r_name) {
+ *r_name = NULL;
+ }
+
+ /* if path leads to an existing directory, we can be sure we're not (in) a library */
+ if (BLI_is_dir(path)) {
+ return false;
+ }
- /* Find the last slash */
- fd = (char *)BLI_last_slash(dir);
+ strcpy(r_dir, path);
+
+ while ((slash = (char *)BLI_last_slash(r_dir))) {
+ char tc = *slash;
+ *slash = '\0';
+ if (BLO_has_bfile_extension(r_dir)) {
+ break;
+ }
- if (fd == NULL) return 0;
- *fd = 0;
- if (BLO_has_bfile_extension(fd+1)) {
- /* the last part of the dir is a .blend file, no group follows */
- *fd = '/'; /* put back the removed slash separating the dir and the .blend file name */
+ if (prev_slash) {
+ *prev_slash = c;
+ }
+ prev_slash = slash;
+ c = tc;
+ }
+
+ if (!slash) {
+ return false;
+ }
+
+ if (slash[1] != '\0') {
+ BLI_assert(strlen(slash + 1) < BLO_GROUP_MAX);
+ if (r_group) {
+ *r_group = slash + 1;
+ }
+ }
+
+ if (prev_slash && (prev_slash[1] != '\0')) {
+ BLI_assert(strlen(prev_slash + 1) < MAX_ID_NAME - 2);
+ if (r_name) {
+ *r_name = prev_slash + 1;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Does a very light reading of given .blend file to extract its stored thumbnail.
+ *
+ * \param filepath The path of the file to extract thumbnail from.
+ * \return The raw thumbnail
+ * (MEM-allocated, as stored in file, use BKE_main_thumbnail_to_imbuf() to convert it to ImBuf image).
+ */
+BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
+{
+ FileData *fd;
+ BlendThumbnail *data;
+ int *fd_data;
+
+ fd = blo_openblenderfile_minimal(filepath);
+ fd_data = fd ? read_file_thumbnail(fd) : NULL;
+
+ if (fd_data) {
+ const size_t sz = BLEN_THUMB_MEMSIZE(fd_data[0], fd_data[1]);
+ data = MEM_mallocN(sz, __func__);
+
+ BLI_assert((sz - sizeof(*data)) == (BLEN_THUMB_MEMSIZE_FILE(fd_data[0], fd_data[1]) - (sizeof(*fd_data) * 2)));
+ data->width = fd_data[0];
+ data->height = fd_data[1];
+ memcpy(data->rect, &fd_data[2], sz - sizeof(*data));
}
else {
- const char * const gp = fd + 1; // in case we have a .blend file, gp points to the group
-
- /* Find the last slash */
- fd = (char *)BLI_last_slash(dir);
- if (!fd || !BLO_has_bfile_extension(fd+1)) return 0;
-
- /* now we know that we are in a blend file and it is safe to
- * assume that gp actually points to a group */
- if (!STREQ("Screen", gp))
- BLI_strncpy(group, gp, BLO_GROUP_MAX);
+ data = NULL;
}
- return 1;
+
+ blo_freefiledata(fd);
+
+ return data;
}
/* ************** OLD POINTERS ******************* */
@@ -1239,6 +1417,31 @@ static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
return oldnewmap_lookup_and_inc(fd->datamap, adr, true);
}
+/* This is a special version of newdataadr() which allows us to keep lasthit of
+ * map unchanged. In certain cases this makes file loading time significantly
+ * faster.
+ *
+ * Use this function in cases like restoring pointer from one list element to
+ * another list element, but keep lasthit value so we can continue restoring
+ * pointers efficiently.
+ *
+ * Example of this could be found in direct_link_fcurves() which restores the
+ * fcurve group pointer and keeps lasthit optimal for linking all further
+ * fcurves.
+ */
+static void *newdataadr_ex(FileData *fd, void *adr, bool increase_lasthit) /* only direct databocks */
+{
+ if (increase_lasthit) {
+ return newdataadr(fd, adr);
+ }
+ else {
+ int lasthit = fd->datamap->lasthit;
+ void *newadr = newdataadr(fd, adr);
+ fd->datamap->lasthit = lasthit;
+ return newadr;
+ }
+}
+
static void *newdataadr_no_us(FileData *fd, void *adr) /* only direct databocks */
{
return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
@@ -1597,9 +1800,9 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
/* undo file support: add all library pointers in lookup */
-void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd)
+void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
{
- Main *ptr = mainlist->first;
+ Main *ptr = old_mainlist->first;
ListBase *lbarray[MAX_LIBARRAY];
for (ptr = ptr->next; ptr; ptr = ptr->next) {
@@ -1610,6 +1813,8 @@ void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd)
oldnewmap_insert(fd->libmap, id, id, GS(id->name));
}
}
+
+ fd->old_mainlist = old_mainlist;
}
@@ -1655,17 +1860,25 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname)
return temp;
}
-static void link_list(FileData *fd, ListBase *lb) /* only direct data */
+typedef void (*link_list_cb)(FileData *fd, void *data);
+
+static void link_list_ex(FileData *fd, ListBase *lb, link_list_cb callback) /* only direct data */
{
Link *ln, *prev;
if (BLI_listbase_is_empty(lb)) return;
lb->first = newdataadr(fd, lb->first);
+ if (callback != NULL) {
+ callback(fd, lb->first);
+ }
ln = lb->first;
prev = NULL;
while (ln) {
ln->next = newdataadr(fd, ln->next);
+ if (ln->next != NULL && callback != NULL) {
+ callback(fd, ln->next);
+ }
ln->prev = prev;
prev = ln;
ln = ln->next;
@@ -1673,6 +1886,11 @@ static void link_list(FileData *fd, ListBase *lb) /* only direct data */
lb->last = prev;
}
+static void link_list(FileData *fd, ListBase *lb) /* only direct data */
+{
+ link_list_ex(fd, lb, NULL);
+}
+
static void link_glob_list(FileData *fd, ListBase *lb) /* for glob data */
{
Link *ln, *prev;
@@ -1882,6 +2100,25 @@ static void IDP_LibLinkProperty(IDProperty *UNUSED(prop), int UNUSED(switch_endi
{
}
+/* ************ READ IMAGE PREVIEW *************** */
+
+static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_prv)
+{
+ PreviewImage *prv = newdataadr(fd, old_prv);
+
+ if (prv) {
+ int i;
+ for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ if (prv->rect[i]) {
+ prv->rect[i] = newdataadr(fd, prv->rect[i]);
+ }
+ prv->gputexture[i] = NULL;
+ }
+ }
+
+ return prv;
+}
+
/* ************ READ ID *************** */
static void direct_link_id(FileData *fd, ID *id)
@@ -2004,25 +2241,6 @@ static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
return pf;
}
-/* ************ READ IMAGE PREVIEW *************** */
-
-static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_prv)
-{
- PreviewImage *prv = newdataadr(fd, old_prv);
-
- if (prv) {
- int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
- if (prv->rect[i]) {
- prv->rect[i] = newdataadr(fd, prv->rect[i]);
- }
- prv->gputexture[i] = NULL;
- }
- }
-
- return prv;
-}
-
/* ************ READ ANIMATION STUFF ***************** */
/* Legacy Data Support (for Version Patching) ----------------------------- */
@@ -2206,7 +2424,7 @@ static void direct_link_fcurves(FileData *fd, ListBase *list)
fcu->rna_path = newdataadr(fd, fcu->rna_path);
/* group */
- fcu->grp = newdataadr(fd, fcu->grp);
+ fcu->grp = newdataadr_ex(fd, fcu->grp, false);
/* clear disabled flag - allows disabled drivers to be tried again ([#32155]),
* but also means that another method for "reviving disabled F-Curves" exists
@@ -3706,35 +3924,34 @@ static const char *ptcache_data_struct[] = {
"", // BPHYS_DATA_TIMES:
"BoidData" // case BPHYS_DATA_BOIDS:
};
+
+static void direct_link_pointcache_cb(FileData *fd, void *data)
+{
+ PTCacheMem *pm = data;
+ PTCacheExtra *extra;
+ int i;
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ pm->data[i] = newdataadr(fd, pm->data[i]);
+
+ /* the cache saves non-struct data without DNA */
+ if (pm->data[i] && ptcache_data_struct[i][0]=='\0' && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) {
+ int tot = (BKE_ptcache_data_size (i) * pm->totpoint) / sizeof(int); /* data_size returns bytes */
+ int *poin = pm->data[i];
+
+ BLI_endian_switch_int32_array(poin, tot);
+ }
+ }
+
+ link_list(fd, &pm->extradata);
+
+ for (extra=pm->extradata.first; extra; extra=extra->next)
+ extra->data = newdataadr(fd, extra->data);
+}
+
static void direct_link_pointcache(FileData *fd, PointCache *cache)
{
if ((cache->flag & PTCACHE_DISK_CACHE)==0) {
- PTCacheMem *pm;
- PTCacheExtra *extra;
- int i;
-
- link_list(fd, &cache->mem_cache);
-
- pm = cache->mem_cache.first;
-
- for (; pm; pm=pm->next) {
- for (i=0; i<BPHYS_TOT_DATA; i++) {
- pm->data[i] = newdataadr(fd, pm->data[i]);
-
- /* the cache saves non-struct data without DNA */
- if (pm->data[i] && ptcache_data_struct[i][0]=='\0' && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) {
- int tot = (BKE_ptcache_data_size (i) * pm->totpoint) / sizeof(int); /* data_size returns bytes */
- int *poin = pm->data[i];
-
- BLI_endian_switch_int32_array(poin, tot);
- }
- }
-
- link_list(fd, &pm->extradata);
-
- for (extra=pm->extradata.first; extra; extra=extra->next)
- extra->data = newdataadr(fd, extra->data);
- }
+ link_list_ex(fd, &cache->mem_cache, direct_link_pointcache_cb);
}
else
BLI_listbase_clear(&cache->mem_cache);
@@ -3944,7 +4161,7 @@ static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase
if (psys->clmd) {
/* XXX - from reading existing code this seems correct but intended usage of
- * pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
+ * pointcache /w cloth should be added in 'ParticleSystem' - campbell */
psys->clmd->point_cache = psys->pointcache;
psys->clmd->ptcaches.first = psys->clmd->ptcaches.last= NULL;
psys->clmd->coll_parms->group = newlibadr(fd, id->lib, psys->clmd->coll_parms->group);
@@ -4012,8 +4229,6 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
psys->pdd = NULL;
psys->renderdata = NULL;
- direct_link_pointcache_list(fd, &psys->ptcaches, &psys->pointcache, 0);
-
if (psys->clmd) {
psys->clmd = newdataadr(fd, psys->clmd);
psys->clmd->clothObject = NULL;
@@ -4030,10 +4245,13 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
psys->hair_in_dm = psys->hair_out_dm = NULL;
psys->clmd->solver_result = NULL;
-
+ }
+
+ direct_link_pointcache_list(fd, &psys->ptcaches, &psys->pointcache, 0);
+ if (psys->clmd) {
psys->clmd->point_cache = psys->pointcache;
}
-
+
psys->tree = NULL;
psys->bvhtree = NULL;
}
@@ -4402,15 +4620,15 @@ static void direct_link_latt(FileData *fd, Lattice *lt)
/* ************ READ OBJECT ***************** */
-static void lib_link_modifiers__linkModifiers(void *userData, Object *ob,
- ID **idpoin)
+static void lib_link_modifiers__linkModifiers(
+ void *userData, Object *ob, ID **idpoin, int cd_flag)
{
FileData *fd = userData;
*idpoin = newlibadr(fd, ob->id.lib, *idpoin);
- /* hardcoded bad exception; non-object modifier data gets user count (texture, displace) */
- if (*idpoin && GS((*idpoin)->name)!=ID_OB)
+ if (*idpoin != NULL && (cd_flag & IDWALK_USER) != 0) {
(*idpoin)->us++;
+ }
}
static void lib_link_modifiers(FileData *fd, Object *ob)
{
@@ -5242,6 +5460,8 @@ static void direct_link_object(FileData *fd, Object *ob)
link_list(fd, &ob->lodlevels);
ob->currentlod = ob->lodlevels.first;
+
+ ob->preview = direct_link_preview_image(fd, ob->preview);
}
/* ************ READ SCENE ***************** */
@@ -5387,16 +5607,10 @@ static void lib_link_scene(FileData *fd, Main *main)
}
}
if (seq->clip) {
- seq->clip = newlibadr(fd, sce->id.lib, seq->clip);
- if (seq->clip) {
- seq->clip->id.us++;
- }
+ seq->clip = newlibadr_us(fd, sce->id.lib, seq->clip);
}
if (seq->mask) {
- seq->mask = newlibadr(fd, sce->id.lib, seq->mask);
- if (seq->mask) {
- seq->mask->id.us++;
- }
+ seq->mask = newlibadr_us(fd, sce->id.lib, seq->mask);
}
if (seq->scene_camera) {
seq->scene_camera = newlibadr(fd, sce->id.lib, seq->scene_camera);
@@ -5799,6 +6013,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
rbw->ltime = (float)rbw->pointcache->startframe;
}
}
+
+ sce->preview = direct_link_preview_image(fd, sce->preview);
}
/* ************ READ WM ***************** */
@@ -6334,6 +6550,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_FILE) {
SpaceFile *sfile = (SpaceFile *)sl;
sfile->op = NULL;
+ sfile->previews_timer = NULL;
}
else if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
@@ -6417,7 +6634,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
BLI_mempool_iternew(so->treestore, &iter);
while ((tselem = BLI_mempool_iterstep(&iter))) {
- tselem->id = restore_pointer_by_name(newmain, tselem->id, USER_IGNORE);
+ /* Do not try to restore pointers to drivers/sequence/etc., can crash in undo case! */
+ if (TSE_IS_REAL_ID(tselem)) {
+ tselem->id = restore_pointer_by_name(newmain, tselem->id, USER_IGNORE);
+ }
+ else {
+ tselem->id = NULL;
+ }
}
if (so->treehash) {
/* rebuild hash table, because it depends on ids too */
@@ -6863,6 +7086,7 @@ static bool direct_link_screen(FileData *fd, bScreen *sc)
sfile->files = NULL;
sfile->layout = NULL;
sfile->op = NULL;
+ sfile->previews_timer = NULL;
sfile->params = newdataadr(fd, sfile->params);
}
else if (sl->spacetype == SPACE_CLIP) {
@@ -6975,11 +7199,7 @@ static void lib_link_speaker(FileData *fd, Main *main)
if (spk->id.flag & LIB_NEED_LINK) {
if (spk->adt) lib_link_animdata(fd, &spk->id, spk->adt);
- spk->sound= newlibadr(fd, spk->id.lib, spk->sound);
- if (spk->sound) {
- spk->sound->id.us++;
- }
-
+ spk->sound = newlibadr_us(fd, spk->id.lib, spk->sound);
spk->id.flag -= LIB_NEED_LINK;
}
}
@@ -7045,6 +7265,8 @@ static void lib_link_sound(FileData *fd, Main *main)
static void direct_link_group(FileData *fd, Group *group)
{
link_list(fd, &group->gobject);
+
+ group->preview = direct_link_preview_image(fd, group->preview);
}
static void lib_link_group(FileData *fd, Main *main)
@@ -7630,14 +7852,66 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a
static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **r_id)
{
- /* this routine reads a libblock and its direct data. Use link functions
- * to connect it all
+ /* this routine reads a libblock and its direct data. Use link functions to connect it all
*/
ID *id;
ListBase *lb;
const char *allocname;
bool wrong_id = false;
-
+
+ /* In undo case, most libs and linked data should be kept as is from previous state (see BLO_read_from_memfile).
+ * However, some needed by the snapshot being read may have been removed in previous one, and would go missing.
+ * This leads e.g. to desappearing objects in some undo/redo case, see T34446.
+ * That means we have to carefully check whether current lib or libdata already exits in old main, if it does
+ * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */
+ if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) {
+ const char *idname = bhead_id_name(fd, bhead);
+
+ /* printf("Checking %s...\n", idname); */
+
+ if (bhead->code == ID_LI) {
+ Main *libmain = fd->old_mainlist->first;
+ /* Skip oldmain itself... */
+ for (libmain = libmain->next; libmain; libmain = libmain->next) {
+ /* printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); */
+ if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) {
+ Main *oldmain = fd->old_mainlist->first;
+ /* printf("FOUND!\n"); */
+ /* In case of a library, we need to re-add its main to fd->mainlist, because if we have later
+ * a missing ID_ID, we need to get the correct lib it is linked to!
+ * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() like it used to be... */
+ BLI_remlink(fd->old_mainlist, libmain);
+ BLI_remlink_safe(&oldmain->library, libmain->curlib);
+ BLI_addtail(fd->mainlist, libmain);
+ BLI_addtail(&main->library, libmain->curlib);
+
+ if (r_id) {
+ *r_id = NULL; /* Just in case... */
+ }
+ return blo_nextbhead(fd, bhead);
+ }
+ /* printf("nothing...\n"); */
+ }
+ }
+ else {
+ /* printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); */
+ if ((id = BKE_libblock_find_name_ex(main, GS(idname), idname + 2))) {
+ /* printf("FOUND!\n"); */
+ /* Even though we found our linked ID, there is no guarantee its address is still the same... */
+ if (id != bhead->old) {
+ oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name));
+ }
+
+ /* No need to do anything else for ID_ID, it's assumed already present in its lib's main... */
+ if (r_id) {
+ *r_id = NULL; /* Just in case... */
+ }
+ return blo_nextbhead(fd, bhead);
+ }
+ /* printf("nothing...\n"); */
+ }
+ }
+
/* read libblock */
id = read_struct(fd, bhead, "lib block");
if (r_id)
@@ -7663,7 +7937,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
if (id->flag & LIB_FAKEUSER) id->us= 1;
else id->us = 0;
id->icon_id = 0;
- id->flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA|LIB_DOIT);
+ id->flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA | LIB_DOIT | LIB_MISSING);
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_ID) {
@@ -8072,6 +8346,24 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bfd->type = BLENFILETYPE_BLEND;
BLI_strncpy(bfd->main->name, filepath, sizeof(bfd->main->name));
+ if (G.background) {
+ /* We only read & store .blend thumbnail in background mode
+ * (because we cannot re-generate it, no OpenGL available).
+ */
+ const int *data = read_file_thumbnail(fd);
+
+ if (data) {
+ const size_t sz = BLEN_THUMB_MEMSIZE(data[0], data[1]);
+ bfd->main->blen_thumb = MEM_mallocN(sz, __func__);
+
+ BLI_assert((sz - sizeof(*bfd->main->blen_thumb)) ==
+ (BLEN_THUMB_MEMSIZE_FILE(data[0], data[1]) - (sizeof(*data) * 2)));
+ bfd->main->blen_thumb->width = data[0];
+ bfd->main->blen_thumb->height = data[1];
+ memcpy(bfd->main->blen_thumb->rect, &data[2], sz - sizeof(*bfd->main->blen_thumb));
+ }
+ }
+
while (bhead) {
switch (bhead->code) {
case DATA:
@@ -8090,26 +8382,10 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = NULL;
break;
- case ID_LI:
- /* skip library datablocks in undo, this works together with
- * BLO_read_from_memfile, where the old main->library is restored
- * overwriting the libraries from the memory file. previously
- * it did not save ID_LI/ID_ID blocks in this case, but they are
- * needed to make quit.blend recover them correctly. */
- if (fd->memfile)
- bhead = blo_nextbhead(fd, bhead);
- else
- bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
- break;
case ID_ID:
- /* same as above */
- if (fd->memfile)
- bhead = blo_nextbhead(fd, bhead);
- else
- /* always adds to the most recently loaded
- * ID_LI block, see direct_link_library.
- * this is part of the file format definition. */
- bhead = read_libblock(fd, mainlist.last, bhead, LIB_READ+LIB_EXTERN, NULL);
+ /* Always adds to the most recently loaded ID_LI block, see direct_link_library.
+ * This is part of the file format definition. */
+ bhead = read_libblock(fd, mainlist.last, bhead, LIB_READ | LIB_EXTERN, NULL);
break;
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
@@ -8122,10 +8398,10 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
}
/* do before read_libraries, but skip undo case */
- if (fd->memfile==NULL)
+ if (fd->memfile == NULL) {
do_versions(fd, NULL, bfd->main);
-
- do_versions_userdef(fd, bfd);
+ do_versions_userdef(fd, bfd);
+ }
read_libraries(fd, &mainlist);
@@ -8138,6 +8414,8 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
link_global(fd, bfd); /* as last */
+ fd->mainlist = NULL; /* Safety, this is local variable, shall not be used afterward. */
+
return bfd;
}
@@ -8261,11 +8539,6 @@ static BHead *find_bhead_from_idname(FileData *fd, const char *idname)
#endif
}
-const char *bhead_id_name(const FileData *fd, const BHead *bhead)
-{
- return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs);
-}
-
static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
{
const char *idname= bhead_id_name(fd, bhead);
@@ -8351,7 +8624,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
}
}
-static void (*expand_doit)(void *, Main *, void *);
+static BLOExpandDoitCallback expand_doit;
// XXX deprecated - old animation system
static void expand_ipo(FileData *fd, Main *mainvar, Ipo *ipo)
@@ -8788,8 +9061,8 @@ static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm)
#endif
}
-static void expand_object_expandModifiers(void *userData, Object *UNUSED(ob),
- ID **idpoin)
+static void expand_object_expandModifiers(
+ void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
{
struct { FileData *fd; Main *mainvar; } *data= userData;
@@ -9126,11 +9399,23 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
expand_animdata(fd, mainvar, gpd->adt);
}
-void BLO_main_expander(void (*expand_doit_func)(void *, Main *, void *))
+/**
+ * Set the callback func used over all ID data found by \a BLO_expand_main func.
+ *
+ * \param expand_doit_func Called for each ID block it finds.
+ */
+void BLO_main_expander(BLOExpandDoitCallback expand_doit_func)
{
expand_doit = expand_doit_func;
}
+/**
+ * Loop over all ID data in Main to mark relations.
+ * Set (id->flag & LIB_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
+ *
+ * \param fdhandle usually filedata, or own handle.
+ * \param mainvar the Main database to expand.
+ */
void BLO_expand_main(void *fdhandle, Main *mainvar)
{
ListBase *lbarray[MAX_LIBARRAY];
@@ -9242,101 +9527,86 @@ static bool object_in_any_scene(Main *mainvar, Object *ob)
{
Scene *sce;
- for (sce= mainvar->scene.first; sce; sce= sce->id.next) {
- if (BKE_scene_base_find(sce, ob))
- return 1;
+ for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
+ if (BKE_scene_base_find(sce, ob)) {
+ return true;
+ }
}
- return 0;
+ return false;
}
-static void give_base_to_objects(Main *mainvar, Scene *sce, Library *lib, const short idcode, const bool is_link, const short active_lay)
+static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Library *lib, const short flag)
{
Object *ob;
Base *base;
- const bool is_group_append = (is_link == false && idcode == ID_GR);
+ const unsigned int active_lay = (flag & FILE_ACTIVELAY) ? BKE_screen_view3d_layer_active(v3d, scene) : 0;
+ const bool is_link = (flag & FILE_LINK) != 0;
+
+ BLI_assert(scene);
/* give all objects which are LIB_INDIRECT a base, or for a group when *lib has been set */
for (ob = mainvar->object.first; ob; ob = ob->id.next) {
- if (ob->id.flag & LIB_INDIRECT) {
- /* IF below is quite confusing!
- * if we are appending, but this object wasnt just added along with a group,
- * then this is already used indirectly in the scene somewhere else and we didnt just append it.
- *
- * (ob->id.flag & LIB_PRE_EXISTING)==0 means that this is a newly appended object - Campbell */
- if (is_group_append==0 || (ob->id.flag & LIB_PRE_EXISTING)==0) {
- bool do_it = false;
-
- if (ob->id.us == 0) {
- do_it = true;
- }
- else if (idcode==ID_GR) {
- if ((is_link == false) && (ob->id.lib == lib)) {
- if ((ob->flag & OB_FROMGROUP) && object_in_any_scene(mainvar, ob)==0) {
- do_it = true;
- }
- }
- }
- else {
- /* when appending, make sure any indirectly loaded objects
- * get a base else they cant be accessed at all [#27437] */
- if ((is_link == false) && (ob->id.lib == lib)) {
- /* we may be appending from a scene where we already
- * have a linked object which is not in any scene [#27616] */
- if ((ob->id.flag & LIB_PRE_EXISTING)==0) {
- if (object_in_any_scene(mainvar, ob)==0) {
- do_it = true;
- }
- }
- }
- }
-
- if (do_it) {
- base = MEM_callocN(sizeof(Base), "add_ext_base");
- BLI_addtail(&sce->base, base);
-
- if (active_lay) ob->lay = sce->lay;
-
- base->lay = ob->lay;
- base->object = ob;
- base->flag = ob->flag;
+ if ((ob->id.flag & LIB_INDIRECT) && (ob->id.flag & LIB_PRE_EXISTING) == 0) {
+ bool do_it = false;
- CLAMP_MIN(ob->id.us, 0);
- ob->id.us += 1;
-
- ob->id.flag -= LIB_INDIRECT;
- ob->id.flag |= LIB_EXTERN;
+ if (ob->id.us == 0) {
+ do_it = true;
+ }
+ else if (!is_link && (ob->id.lib == lib) && (object_in_any_scene(mainvar, ob) == 0)) {
+ /* When appending, make sure any indirectly loaded objects get a base, else they cant be accessed at all
+ * (see T27437). */
+ do_it = true;
+ }
+
+ if (do_it) {
+ base = MEM_callocN(sizeof(Base), __func__);
+ BLI_addtail(&scene->base, base);
+
+ if (active_lay) {
+ ob->lay = active_lay;
}
+
+ base->lay = ob->lay;
+ base->object = ob;
+ base->flag = ob->flag;
+
+ CLAMP_MIN(ob->id.us, 0);
+ ob->id.us += 1;
+
+ ob->id.flag &= ~LIB_INDIRECT;
+ ob->id.flag |= LIB_EXTERN;
}
}
}
}
-static void give_base_to_groups(Main *mainvar, Scene *scene)
+static void give_base_to_groups(
+ Main *mainvar, Scene *scene, View3D *v3d, Library *UNUSED(lib), const short UNUSED(flag))
{
Group *group;
-
+ Base *base;
+ Object *ob;
+ const unsigned int active_lay = BKE_screen_view3d_layer_active(v3d, scene);
+
/* give all objects which are tagged a base */
for (group = mainvar->group.first; group; group = group->id.next) {
if (group->id.flag & LIB_DOIT) {
- Base *base;
- Object *ob;
-
/* any indirect group should not have been tagged */
- BLI_assert((group->id.flag & LIB_INDIRECT)==0);
-
+ BLI_assert((group->id.flag & LIB_INDIRECT) == 0);
+
/* BKE_object_add(...) messes with the selection */
ob = BKE_object_add_only_object(mainvar, OB_EMPTY, group->id.name + 2);
ob->type = OB_EMPTY;
- ob->lay = scene->lay;
-
+ ob->lay = active_lay;
+
/* assign the base */
base = BKE_scene_base_add(scene, ob);
base->flag |= SELECT;
- base->object->flag= base->flag;
+ base->object->flag = base->flag;
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
scene->basact = base;
-
+
/* assign the group */
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
@@ -9345,11 +9615,30 @@ static void give_base_to_groups(Main *mainvar, Scene *scene)
}
}
+static ID *create_placeholder(Main *mainvar, const char *idname, const short flag)
+{
+ const short idcode = GS(idname);
+ ListBase *lb = which_libbase(mainvar, idcode);
+ ID *ph_id = BKE_libblock_alloc_notest(idcode);
+
+ memcpy(ph_id->name, idname, sizeof(ph_id->name));
+ BKE_libblock_init_empty(ph_id);
+ ph_id->lib = mainvar->curlib;
+ ph_id->flag = flag | LIB_MISSING;
+ ph_id->us = (flag & LIB_FAKEUSER) ? 1 : 0;
+ ph_id->icon_id = 0;
+
+ BLI_addtail(lb, ph_id);
+ id_sort_by_name(lb, ph_id);
+
+ return ph_id;
+}
+
/* returns true if the item was found
* but it may already have already been appended/linked */
-static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, const short idcode)
+static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name)
{
- BHead *bhead = find_bhead_from_code_name(fd, idcode, idname);
+ BHead *bhead = find_bhead_from_code_name(fd, idcode, name);
ID *id;
if (bhead) {
@@ -9385,8 +9674,10 @@ static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, cons
return id;
}
-/* simple reader for copy/paste buffers */
-void BLO_library_append_all(Main *mainl, BlendHandle *bh)
+/**
+ * Simple reader for copy/paste buffers.
+ */
+void BLO_library_link_all(Main *mainl, BlendHandle *bh)
{
FileData *fd = (FileData *)(bh);
BHead *bhead;
@@ -9406,33 +9697,33 @@ void BLO_library_append_all(Main *mainl, BlendHandle *bh)
}
}
-
-static ID *append_named_part_ex(const bContext *C, Main *mainl, FileData *fd, const char *idname, const int idcode, const int flag)
+static ID *link_named_part_ex(
+ Main *mainl, FileData *fd, const short idcode, const char *name, const short flag,
+ Scene *scene, View3D *v3d)
{
- ID *id= append_named_part(mainl, fd, idname, idcode);
+ ID *id = link_named_part(mainl, fd, idcode, name);
if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */
- Scene *scene = CTX_data_scene(C); /* can be NULL */
if (scene) {
Base *base;
Object *ob;
-
- base= MEM_callocN(sizeof(Base), "app_nam_part");
+
+ base = MEM_callocN(sizeof(Base), "app_nam_part");
BLI_addtail(&scene->base, base);
-
+
ob = (Object *)id;
-
+
/* link at active layer (view3d if available in context, else scene one */
- if ((flag & FILE_ACTIVELAY)) {
- View3D *v3d = CTX_wm_view3d(C);
+ if (flag & FILE_ACTIVELAY) {
ob->lay = BKE_screen_view3d_layer_active(v3d, scene);
}
-
+
ob->mode = OB_MODE_OBJECT;
base->lay = ob->lay;
base->object = ob;
+ base->flag = ob->flag;
ob->id.us++;
-
+
if (flag & FILE_AUTOSELECT) {
base->flag |= SELECT;
base->object->flag = base->flag;
@@ -9441,47 +9732,91 @@ static ID *append_named_part_ex(const bContext *C, Main *mainl, FileData *fd, co
}
}
else if (id && (GS(id->name) == ID_GR)) {
- /* tag as needing to be instanced */
+ /* tag as needing to be instantiated */
if (flag & FILE_GROUP_INSTANCE)
id->flag |= LIB_DOIT;
}
-
+
return id;
}
-ID *BLO_library_append_named_part(Main *mainl, BlendHandle **bh, const char *idname, const int idcode)
+/**
+ * Link a named datablock from an external blend file.
+ *
+ * \param mainl The main database to link from (not the active one).
+ * \param bh The blender file handle.
+ * \param idcode The kind of datablock to link.
+ * \param name The name of the datablock (without the 2 char ID prefix).
+ * \return the linked ID when found.
+ */
+ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name)
{
FileData *fd = (FileData*)(*bh);
- return append_named_part(mainl, fd, idname, idcode);
+ return link_named_part(mainl, fd, idcode, name);
}
-ID *BLO_library_append_named_part_ex(const bContext *C, Main *mainl, BlendHandle **bh, const char *idname, const int idcode, const short flag)
+/**
+ * Link a named datablock from an external blend file.
+ * Optionally instantiate the object/group in the scene when the flags are set.
+ *
+ * \param mainl The main database to link from (not the active one).
+ * \param bh The blender file handle.
+ * \param idcode The kind of datablock to link.
+ * \param name The name of the datablock (without the 2 char ID prefix).
+ * \param flag Options for linking, used for instantiating.
+ * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
+ * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL).
+ * \return the linked ID when found.
+ */
+ID *BLO_library_link_named_part_ex(
+ Main *mainl, BlendHandle **bh,
+ const short idcode, const char *name, const short flag,
+ Scene *scene, View3D *v3d)
{
FileData *fd = (FileData*)(*bh);
- return append_named_part_ex(C, mainl, fd, idname, idcode, flag);
+ return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d);
}
-static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **r_id)
+static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
{
- BHead *bhead = find_bhead_from_idname(fd, id->name);
+ BHead *bhead = NULL;
+
+ if (fd) {
+ bhead = find_bhead_from_idname(fd, id->name);
+ }
+
+ id->flag &= ~LIB_READ;
if (bhead) {
- id->flag &= ~LIB_READ;
id->flag |= LIB_NEED_EXPAND;
// printf("read lib block %s\n", id->name);
read_libblock(fd, mainvar, bhead, id->flag, r_id);
}
+ else {
+ blo_reportf_wrap(
+ reports, RPT_WARNING,
+ TIP_("LIB ERROR: %s: '%s' missing from '%s', parent '%s'"),
+ BKE_idcode_to_name(GS(id->name)),
+ id->name + 2,
+ mainvar->curlib->filepath,
+ library_parent_filepath(mainvar->curlib));
+
+ /* Generate a placeholder for this ID (simplified version of read_libblock actually...). */
+ if (r_id) {
+ *r_id = create_placeholder(mainvar, id->name, id->flag);
+ }
+ }
}
/* common routine to append/link something from a library */
-static Main *library_append_begin(Main *mainvar, FileData **fd, const char *filepath)
+static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepath)
{
Main *mainl;
(*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
- /* clear for group instancing tag */
+ /* clear for group instantiating tag */
BKE_main_id_tag_listbase(&(mainvar->group), false);
/* make mains */
@@ -9500,77 +9835,72 @@ static Main *library_append_begin(Main *mainvar, FileData **fd, const char *file
return mainl;
}
-Main *BLO_library_append_begin(Main *mainvar, BlendHandle **bh, const char *filepath)
+/**
+ * Initialize the BlendHandle for linking library data.
+ *
+ * \param mainvar The current main database, e.g. G.main or CTX_data_main(C).
+ * \param bh A blender file handle as returned by \a BLO_blendhandle_from_file or \a BLO_blendhandle_from_memory.
+ * \param filepath Used for relative linking, copied to the \a lib->name.
+ * \return the library Main, to be passed to \a BLO_library_append_named_part as \a mainl.
+ */
+Main *BLO_library_link_begin(Main *mainvar, BlendHandle **bh, const char *filepath)
{
FileData *fd = (FileData*)(*bh);
- return library_append_begin(mainvar, &fd, filepath);
+ return library_link_begin(mainvar, &fd, filepath);
}
-
-/* Context == NULL signifies not to do any scene manipulation */
-static void library_append_end(const bContext *C, Main *mainl, FileData **fd, int idcode, short flag)
+/* scene and v3d may be NULL. */
+static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene *scene, View3D *v3d)
{
Main *mainvar;
Library *curlib;
-
+
/* expander now is callback function */
BLO_main_expander(expand_doit_library);
-
+
/* make main consistent */
BLO_expand_main(*fd, mainl);
-
+
/* do this when expand found other libs */
read_libraries(*fd, (*fd)->mainlist);
-
+
curlib = mainl->curlib;
-
+
/* make the lib path relative if required */
if (flag & FILE_RELPATH) {
/* use the full path, this could have been read by other library even */
BLI_strncpy(curlib->name, curlib->filepath, sizeof(curlib->name));
-
+
/* uses current .blend file as reference */
BLI_path_rel(curlib->name, G.main->name);
}
-
+
blo_join_main((*fd)->mainlist);
mainvar = (*fd)->mainlist->first;
MEM_freeN((*fd)->mainlist);
mainl = NULL; /* blo_join_main free's mainl, cant use anymore */
-
+
lib_link_all(*fd, mainvar);
lib_verify_nodetree(mainvar, false);
fix_relpaths_library(G.main->name, mainvar); /* make all relative paths, relative to the open blend file */
-
- if (C) {
- Scene *scene = CTX_data_scene(C);
-
- /* give a base to loose objects. If group append, do it for objects too */
- if (scene) {
- const bool is_link = (flag & FILE_LINK) != 0;
- if (idcode == ID_SCE) {
- /* don't instance anything when linking in scenes, assume the scene its self instances the data */
- }
- else {
- give_base_to_objects(mainvar, scene, curlib, idcode, is_link, flag & FILE_ACTIVELAY);
-
- if (flag & FILE_GROUP_INSTANCE) {
- give_base_to_groups(mainvar, scene);
- }
- }
- }
- else {
- printf("library_append_end, scene is NULL (objects wont get bases)\n");
+
+ /* Give a base to loose objects. If group append, do it for objects too.
+ * Only directly linked objects & groups are instantiated by `BLO_library_link_named_part_ex()` & co,
+ * here we handle indirect ones and other possible edge-cases. */
+ if (scene) {
+ give_base_to_objects(mainvar, scene, v3d, curlib, flag);
+
+ if (flag & FILE_GROUP_INSTANCE) {
+ give_base_to_groups(mainvar, scene, v3d, curlib, flag);
}
}
+ else {
+ /* printf("library_append_end, scene is NULL (objects wont get bases)\n"); */
+ }
- /* clear group instancing tag */
+ /* clear group instantiating tag */
BKE_main_id_tag_listbase(&(mainvar->group), false);
-
- /* has been removed... erm, why? s..ton) */
- /* 20040907: looks like they are give base already in append_named_part(); -Nathan L */
- /* 20041208: put back. It only linked direct, not indirect objects (ton) */
-
+
/* patch to prevent switch_endian happens twice */
if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
blo_freefiledata(*fd);
@@ -9578,10 +9908,21 @@ static void library_append_end(const bContext *C, Main *mainl, FileData **fd, in
}
}
-void BLO_library_append_end(const bContext *C, struct Main *mainl, BlendHandle **bh, int idcode, short flag)
+/**
+ * Finalize linking from a given .blend file (library).
+ * Optionally instance the indirect object/group in the scene when the flags are set.
+ * \note Do not use \a bh after calling this function, it may frees it.
+ *
+ * \param mainl The main database to link from (not the active one).
+ * \param bh The blender file handle (WARNING! may be freed by this function!).
+ * \param flag Options for linking, used for instantiating.
+ * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
+ * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL).
+ */
+void BLO_library_link_end(Main *mainl, BlendHandle **bh, short flag, Scene *scene, View3D *v3d)
{
FileData *fd = (FileData*)(*bh);
- library_append_end(C, mainl, &fd, idcode, flag);
+ library_link_end(mainl, &fd, flag, scene, v3d);
*bh = (BlendHandle*)fd;
}
@@ -9709,6 +10050,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
}
else {
mainptr->curlib->filedata = NULL;
+ mainptr->curlib->id.flag |= LIB_MISSING;
}
if (fd == NULL) {
@@ -9718,37 +10060,29 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
}
if (fd) {
do_it = true;
- a = set_listbasepointers(mainptr, lbarray);
- while (a--) {
- ID *id = lbarray[a]->first;
-
- while (id) {
- ID *idn = id->next;
- if (id->flag & LIB_READ) {
- ID *realid = NULL;
- BLI_remlink(lbarray[a], id);
-
- append_id_part(fd, mainptr, id, &realid);
- if (!realid) {
- blo_reportf_wrap(
- fd->reports, RPT_WARNING,
- TIP_("LIB ERROR: %s: '%s' missing from '%s', parent '%s'"),
- BKE_idcode_to_name(GS(id->name)),
- id->name + 2,
- mainptr->curlib->filepath,
- library_parent_filepath(mainptr->curlib));
- }
-
- change_idid_adr(mainlist, basefd, id, realid);
-
- MEM_freeN(id);
- }
- id = idn;
+ }
+ a = set_listbasepointers(mainptr, lbarray);
+ while (a--) {
+ ID *id = lbarray[a]->first;
+
+ while (id) {
+ ID *idn = id->next;
+ if (id->flag & LIB_READ) {
+ ID *realid = NULL;
+ BLI_remlink(lbarray[a], id);
+
+ link_id_part(basefd->reports, fd, mainptr, id, &realid);
+
+ BLI_assert(realid != NULL);
+
+ change_idid_adr(mainlist, basefd, id, realid);
+
+ MEM_freeN(id);
}
+ id = idn;
}
-
- BLO_expand_main(fd, mainptr);
}
+ BLO_expand_main(fd, mainptr);
}
mainptr = mainptr->next;
@@ -9756,6 +10090,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
}
/* test if there are unread libblocks */
+ /* XXX This code block is kept for 2.77, until we are sure it never gets reached anymore. Can be removed later. */
for (mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
a = set_listbasepointers(mainptr, lbarray);
while (a--) {
@@ -9764,10 +10099,12 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
for (id = lbarray[a]->first; id; id = idn) {
idn = id->next;
if (id->flag & LIB_READ) {
+ BLI_assert(0);
BLI_remlink(lbarray[a], id);
blo_reportf_wrap(
basefd->reports, RPT_WARNING,
- TIP_("LIB ERROR: %s: '%s' unread lib block missing from '%s', parent '%s'"),
+ TIP_("LIB ERROR: %s: '%s' unread lib block missing from '%s', parent '%s' - "
+ "Please file a bug report if you see this message"),
BKE_idcode_to_name(GS(id->name)),
id->name + 2,
mainptr->curlib->filepath,
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index ed22daef9ec..f6c3b69c414 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -96,7 +96,8 @@ typedef struct FileData {
struct GHash *bhead_idname_hash;
ListBase *mainlist;
-
+ ListBase *old_mainlist; /* Used for undo. */
+
/* ick ick, used to return
* data through streamglue.
*/
@@ -139,7 +140,7 @@ void blo_make_sound_pointer_map(FileData *fd, Main *oldmain);
void blo_end_sound_pointer_map(FileData *fd, Main *oldmain);
void blo_make_packed_pointer_map(FileData *fd, Main *oldmain);
void blo_end_packed_pointer_map(FileData *fd, Main *oldmain);
-void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd);
+void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd);
void blo_freefiledata(FileData *fd);
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index c66b9d1fae9..947f945edcc 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -57,7 +57,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_anim.h"
#include "BKE_image.h"
@@ -343,7 +343,7 @@ static void do_versions_mesh_mloopcol_swap_2_62_1(Mesh *me)
if (layer->type == CD_MLOOPCOL) {
mloopcol = (MLoopCol *)layer->data;
for (i = 0; i < me->totloop; i++, mloopcol++) {
- SWAP(char, mloopcol->r, mloopcol->b);
+ SWAP(unsigned char, mloopcol->r, mloopcol->b);
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 571a8cc49e5..8cd82c617af 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -42,6 +42,7 @@
#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
+#include "DNA_object_force.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
@@ -654,7 +655,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
ParticleSystem *psys;
for (ob = main->object.first; ob; ob = ob->id.next) {
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- psys->recalc |= PSYS_RECALC_RESET;
+ if ((psys->pointcache->flag & PTCACHE_BAKED) == 0) {
+ psys->recalc |= PSYS_RECALC_RESET;
+ }
}
}
}
@@ -764,7 +767,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
SpaceImage *sima = (SpaceImage *) sl;
sima->iuser.flag |= IMA_SHOW_STEREO;
- sima->iuser.passtype = SCE_PASS_COMBINED;
break;
}
}
@@ -852,6 +854,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
#undef BRUSH_TORUS
}
+ if (!MAIN_VERSION_ATLEAST(main, 276, 2)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "custom_scale")) {
+ Object *ob;
+
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ if (ob->pose) {
+ bPoseChannel *pchan;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->custom_scale = 1.0f;
+ }
+ }
+ }
+ }
+ }
{
bScreen *screen;
for (screen = main->screen.first; screen; screen = screen->id.next) {
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 17b0f388af4..c32b3ac51cf 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -160,7 +160,7 @@ void BLO_update_defaults_startup_blend(Main *bmain)
br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Fill");
if (!br) {
- br = BKE_brush_add(bmain, "Fill");
+ br = BKE_brush_add(bmain, "Fill", OB_MODE_TEXTURE_PAINT);
br->imagepaint_tool = PAINT_TOOL_FILL;
br->ob_mode = OB_MODE_TEXTURE_PAINT;
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index dcfafc26e4f..12069fd80dd 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -648,7 +648,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
while (ob) {
if (ob->transflag & 1) {
ob->transflag -= 1;
- //ob->ipoflag |= OB_OFFS_OB;
}
ob = ob->id.next;
}
@@ -685,7 +684,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
ob = main->object.first;
while (ob) {
- //ob->ipoflag |= OB_OFFS_PARENT;
if (ob->dt == 0)
ob->dt = OB_SOLID;
ob = ob->id.next;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index f5d35e45fc0..d320274ef96 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -291,11 +291,10 @@ static void ww_handle_init(eWriteWrapType ww_type, WriteWrap *r_ww)
typedef struct {
struct SDNA *sdna;
- int file;
unsigned char *buf;
MemFile *compare, *current;
- int tot, count, error, memsize;
+ int tot, count, error;
/* Wrap writing, so we can use zlib or
* other compression types later, see: G_FILE_COMPRESS
@@ -588,6 +587,33 @@ void IDP_WriteProperty(IDProperty *prop, void *wd)
IDP_WriteProperty_OnlyData(prop, wd);
}
+static void write_previews(WriteData *wd, PreviewImage *prv)
+{
+ /* Never write previews when doing memsave (i.e. undo/redo)! */
+ if (prv && !wd->current) {
+ short w = prv->w[1];
+ short h = prv->h[1];
+ unsigned int *rect = prv->rect[1];
+
+ /* don't write out large previews if not requested */
+ if (!(U.flag & USER_SAVE_PREVIEWS)) {
+ prv->w[1] = 0;
+ prv->h[1] = 0;
+ prv->rect[1] = NULL;
+ }
+ writestruct(wd, DATA, "PreviewImage", 1, prv);
+ if (prv->rect[0]) writedata(wd, DATA, prv->w[0] * prv->h[0] * sizeof(unsigned int), prv->rect[0]);
+ if (prv->rect[1]) writedata(wd, DATA, prv->w[1] * prv->h[1] * sizeof(unsigned int), prv->rect[1]);
+
+ /* restore preview, we still want to keep it in memory even if not saved to file */
+ if (!(U.flag & USER_SAVE_PREVIEWS) ) {
+ prv->w[1] = w;
+ prv->h[1] = h;
+ prv->rect[1] = rect;
+ }
+ }
+}
+
static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers)
{
FModifier *fcm;
@@ -1698,6 +1724,9 @@ static void write_objects(WriteData *wd, ListBase *idbase)
writelist(wd, DATA, "LinkData", &ob->pc_ids);
writelist(wd, DATA, "LodLevel", &ob->lodlevels);
}
+
+ write_previews(wd, ob->preview);
+
ob= ob->id.next;
}
@@ -2049,7 +2078,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
/* now fill in polys to mfaces */
/* XXX This breaks writing desing, by using temp allocated memory, which will likely generate
- * doublons in stored 'old' addresses.
+ * duplicates in stored 'old' addresses.
* This is very bad, but do not see easy way to avoid this, aside from generating those data
* outside of save process itself.
* Maybe we can live with this, though?
@@ -2138,32 +2167,6 @@ static void write_lattices(WriteData *wd, ListBase *idbase)
}
}
-static void write_previews(WriteData *wd, PreviewImage *prv)
-{
- /* Never write previews in undo steps! */
- if (prv && !wd->current) {
- short w = prv->w[1];
- short h = prv->h[1];
- unsigned int *rect = prv->rect[1];
- /* don't write out large previews if not requested */
- if (!(U.flag & USER_SAVE_PREVIEWS)) {
- prv->w[1] = 0;
- prv->h[1] = 0;
- prv->rect[1] = NULL;
- }
- writestruct(wd, DATA, "PreviewImage", 1, prv);
- if (prv->rect[0]) writedata(wd, DATA, prv->w[0]*prv->h[0]*sizeof(unsigned int), prv->rect[0]);
- if (prv->rect[1]) writedata(wd, DATA, prv->w[1]*prv->h[1]*sizeof(unsigned int), prv->rect[1]);
-
- /* restore preview, we still want to keep it in memory even if not saved to file */
- if (!(U.flag & USER_SAVE_PREVIEWS) ) {
- prv->w[1] = w;
- prv->h[1] = h;
- prv->rect[1] = rect;
- }
- }
-}
-
static void write_images(WriteData *wd, ListBase *idbase)
{
Image *ima;
@@ -2572,6 +2575,8 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
}
+ write_previews(wd, sce->preview);
+
sce= sce->id.next;
}
/* flush helps the compression for undo-save */
@@ -3068,6 +3073,8 @@ static void write_groups(WriteData *wd, ListBase *idbase)
writestruct(wd, ID_GR, "Group", 1, group);
if (group->id.properties) IDP_WriteProperty(group->id.properties, wd);
+ write_previews(wd, group->preview);
+
go= group->gobject.first;
while (go) {
writestruct(wd, DATA, "GroupObject", 1, go);
@@ -3680,10 +3687,11 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
* second are an RGBA image (unsigned char)
* note, this uses 'TEST' since new types will segfault on file load for older blender versions.
*/
-static void write_thumb(WriteData *wd, const int *img)
+static void write_thumb(WriteData *wd, const BlendThumbnail *thumb)
{
- if (img)
- writedata(wd, TEST, (2 + img[0] * img[1]) * sizeof(int), img);
+ if (thumb) {
+ writedata(wd, TEST, BLEN_THUMB_MEMSIZE_FILE(thumb->width, thumb->height), thumb);
+ }
}
/* if MemFile * there's filesave to memory */
@@ -3691,7 +3699,7 @@ static int write_file_handle(
Main *mainvar,
WriteWrap *ww,
MemFile *compare, MemFile *current,
- int write_user_block, int write_flags, const int *thumb)
+ int write_user_block, int write_flags, const BlendThumbnail *thumb)
{
BHead bhead;
ListBase mainlist;
@@ -3823,7 +3831,8 @@ static bool do_history(const char *name, ReportList *reports)
}
/* return: success (1) */
-int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportList *reports, const int *thumb)
+int BLO_write_file(
+ Main *mainvar, const char *filepath, int write_flags, ReportList *reports, const BlendThumbnail *thumb)
{
char tempname[FILE_MAX+1];
int err, write_user_block;