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:
authorMartin Poirier <theeth@yahoo.com>2007-11-07 01:29:20 +0300
committerMartin Poirier <theeth@yahoo.com>2007-11-07 01:29:20 +0300
commit0de103c1cdf1e4c40cfad4e233a42a6d1165953d (patch)
treea57039fa592cf0f5af3738a9624d0b0ccbf20ec0 /source/blender/blenloader
Filling in branch from trunk
Diffstat (limited to 'source/blender/blenloader')
-rw-r--r--source/blender/blenloader/BLO_genfile.h38
-rw-r--r--source/blender/blenloader/BLO_readfile.h250
-rw-r--r--source/blender/blenloader/BLO_soundfile.h44
-rw-r--r--source/blender/blenloader/BLO_sys_types.h102
-rw-r--r--source/blender/blenloader/BLO_undofile.h58
-rw-r--r--source/blender/blenloader/BLO_writefile.h44
-rw-r--r--source/blender/blenloader/CMakeLists.txt46
-rw-r--r--source/blender/blenloader/Makefile37
-rw-r--r--source/blender/blenloader/SConscript18
-rw-r--r--source/blender/blenloader/intern/Makefile76
-rw-r--r--source/blender/blenloader/intern/genfile.c1102
-rw-r--r--source/blender/blenloader/intern/genfile.h49
-rw-r--r--source/blender/blenloader/intern/readblenentry.c456
-rw-r--r--source/blender/blenloader/intern/readfile.c8134
-rw-r--r--source/blender/blenloader/intern/readfile.h127
-rw-r--r--source/blender/blenloader/intern/undofile.c146
-rw-r--r--source/blender/blenloader/intern/writefile.c2202
17 files changed, 12929 insertions, 0 deletions
diff --git a/source/blender/blenloader/BLO_genfile.h b/source/blender/blenloader/BLO_genfile.h
new file mode 100644
index 00000000000..6549bafe89b
--- /dev/null
+++ b/source/blender/blenloader/BLO_genfile.h
@@ -0,0 +1,38 @@
+/*
+ * $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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * external genfile function prototypes
+ */
+
+#ifndef BLO_GENFILE_H
+#define BLO_GENFILE_H
+
+#endif
+
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
new file mode 100644
index 00000000000..09edfe90d02
--- /dev/null
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -0,0 +1,250 @@
+/*
+ * $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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * external readfile function prototypes
+ */
+#ifndef BLO_READFILE_H
+#define BLO_READFILE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct SpaceFile;
+struct SpaceImaSel;
+struct FileList;
+struct LinkNode;
+struct Main;
+struct UserDef;
+struct bScreen;
+struct Scene;
+struct MemFile;
+struct direntry;
+
+typedef struct BlendHandle BlendHandle;
+
+typedef enum BlenFileType {
+ BLENFILETYPE_BLEND= 1,
+ BLENFILETYPE_PUB= 2,
+ BLENFILETYPE_RUNTIME= 3
+} BlenFileType;
+
+typedef enum {
+ BRE_NONE,
+
+ BRE_UNABLE_TO_OPEN,
+ BRE_UNABLE_TO_READ,
+
+ BRE_OUT_OF_MEMORY,
+ BRE_INTERNAL_ERROR,
+
+ BRE_NOT_A_BLEND,
+ BRE_NOT_A_PUBFILE,
+ BRE_INCOMPLETE,
+ BRE_CORRUPT,
+
+ BRE_TOO_NEW,
+ BRE_NOT_ALLOWED,
+
+ BRE_NO_SCREEN,
+ BRE_NO_SCENE,
+
+ BRE_INVALID
+} BlendReadError;
+
+typedef struct BlendFileData {
+ struct Main* main;
+ struct UserDef* user;
+
+ int winpos;
+ int fileflags;
+ int displaymode;
+ int globalf;
+
+ struct bScreen* curscreen;
+ struct Scene* curscene;
+
+ BlenFileType type;
+} BlendFileData;
+
+ /**
+ * Open a blender file from a pathname. The function
+ * returns NULL and sets the @a error_r argument if
+ * it cannot open the file.
+ *
+ * @param file The path of the file to open.
+ * @param error_r If the return value is NULL, an error
+ * code indicating the cause of the failure.
+ * @return The data of the file.
+ */
+BlendFileData* BLO_read_from_file (char *file, BlendReadError *error_r);
+
+ /**
+ * Open a blender file from memory. The function
+ * returns NULL and sets the @a error_r argument if
+ * it cannot open the file.
+ *
+ * @param mem The file data.
+ * @param memsize The length of @a mem.
+ * @param error_r If the return value is NULL, an error
+ * 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);
+
+/**
+ * file name is current file, only for retrieving library data */
+
+BlendFileData *BLO_read_from_memfile(const char *filename, struct MemFile *memfile, BlendReadError *error_r);
+
+/**
+ * Convert a BlendReadError to a human readable string.
+ * The string is static and does not need to be free'd.
+ *
+ * @param error The error to return a string for.
+ * @return A static human readable string representation
+ * of @a error.
+ */
+
+ char*
+BLO_bre_as_string(
+ BlendReadError error);
+
+/**
+ * Free's 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);
+
+/**
+ * Convert an idcode into a name.
+ *
+ * @param code The code to convert.
+ * @return A static string representing the name of
+ * the code.
+ */
+ char*
+BLO_idcode_to_name(
+ int code);
+
+/**
+ * Convert a name into an idcode (ie. ID_SCE)
+ *
+ * @param name The name to convert.
+ * @return The code for the name, or 0 if invalid.
+ */
+ int
+BLO_idcode_from_name(
+ char *name);
+
+/**
+ * Open a blendhandle from a file path.
+ *
+ * @param file The file path to open.
+ * @return A handle on success, or NULL on failure.
+ */
+ BlendHandle*
+BLO_blendhandle_from_file(
+ char *file);
+
+/**
+ * Gets the names of all the datablocks in a file
+ * of a certain type (ie. All the scene names in
+ * a file).
+ *
+ * @param bh The blendhandle to access.
+ * @param ofblocktype The type of names to get.
+ * @return A BLI_linklist of strings. The string links
+ * should be freed with malloc.
+ */
+ struct LinkNode*
+BLO_blendhandle_get_datablock_names(
+ BlendHandle *bh,
+ int ofblocktype);
+
+/**
+ * Gets the previews of all the datablocks in a file
+ * of a certain type (ie. All the scene names in
+ * a file).
+ *
+ * @param bh The blendhandle to access.
+ * @param ofblocktype The type of names to get.
+ * @return A BLI_linklist of PreviewImage. The PreviewImage links
+ * should be freed with malloc.
+ */
+ struct LinkNode*
+BLO_blendhandle_get_previews(
+ BlendHandle *bh,
+ int ofblocktype);
+
+/**
+ * Gets the names of all the datablock groups in a
+ * file. (ie. file contains Scene, Mesh, and Lamp
+ * datablocks).
+ *
+ * @param bh The blendhandle to access.
+ * @return A BLI_linklist of strings. The string links
+ * should be freed with malloc.
+ */
+ struct LinkNode*
+BLO_blendhandle_get_linkable_groups(
+ BlendHandle *bh);
+
+/**
+ * Close and free a blendhandle. The handle
+ * becomes invalid after this call.
+ *
+ * @param bh The handle to close.
+ */
+ void
+BLO_blendhandle_close(
+ BlendHandle *bh);
+
+ /***/
+
+char *BLO_gethome(void);
+int BLO_has_bfile_extension(char *str);
+void BLO_library_append(struct SpaceFile *sfile, char *dir, int idcode);
+void BLO_library_append_(BlendHandle **libfiledata, struct direntry* filelist, int totfile, char *dir, char* file, short flag, int idcode);
+void BLO_script_library_append(BlendHandle *bh, char *dir, char *name, int idcode, short flag, struct Scene *scene);
+
+BlendFileData* blo_read_blendafterruntime(int file, int actualsize, BlendReadError *error_r);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenloader/BLO_soundfile.h b/source/blender/blenloader/BLO_soundfile.h
new file mode 100644
index 00000000000..3a8ff3fcb99
--- /dev/null
+++ b/source/blender/blenloader/BLO_soundfile.h
@@ -0,0 +1,44 @@
+/**
+ * $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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BLO_SOUNDFILE_H
+#define BLO_SOUNDFILE_H
+
+#include "DNA_sound_types.h"
+#include "DNA_packedFile_types.h"
+
+struct bSound;
+struct PackedFile;
+
+//void sound_read_wav_data(bSound * sound, PackedFile * pf);
+
+#endif
+
diff --git a/source/blender/blenloader/BLO_sys_types.h b/source/blender/blenloader/BLO_sys_types.h
new file mode 100644
index 00000000000..38dde20500e
--- /dev/null
+++ b/source/blender/blenloader/BLO_sys_types.h
@@ -0,0 +1,102 @@
+/**
+ * $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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * A platform-independent definition of [u]intXX_t
+ * Plus the accompanying header include for htonl/ntohl
+ *
+ * This file includes <sys/types.h> to define [u]intXX_t types, where
+ * XX can be 8, 16, 32 or 64. Unfortunately, not all systems have this
+ * file.
+ * - Windows uses __intXX compiler-builtin types. These are signed,
+ * so we have to flip the signs.
+ * For these rogue platforms, we make the typedefs ourselves.
+ *
+ */
+
+#ifndef BLO_SYS_TYPES_H
+#define BLO_SYS_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef FREE_WINDOWS
+typedef unsigned char uint8_t;
+typedef unsigned int uint32_t;
+#endif
+
+#if defined(_WIN32) && !defined(FREE_WINDOWS)
+
+/* The __intXX are built-in types of the visual complier! So we don't
+ * need to include anything else here. */
+
+typedef signed __int8 int8_t;
+typedef signed __int16 int16_t;
+typedef signed __int32 int32_t;
+typedef signed __int64 int64_t;
+
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+
+#elif defined(__linux__)
+
+ /* Linux-i386, Linux-Alpha, Linux-ppc */
+#include <stdint.h>
+
+#elif defined (__APPLE__)
+
+#include <inttypes.h>
+
+#else
+
+ /* FreeBSD, Irix, Solaris */
+#include <sys/types.h>
+
+#endif /* ifdef platform for types */
+
+#ifdef _WIN32
+#define htonl(x) correctByteOrder(x)
+#define ntohl(x) correctByteOrder(x)
+#elif defined (__FreeBSD__) || defined (__OpenBSD__)
+#include <sys/param.h>
+#elif defined (__APPLE__)
+#include <sys/types.h>
+#else /* irix sun linux */
+#include <netinet/in.h>
+#endif /* ifdef platform for htonl/ntohl */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* eof */
+
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
new file mode 100644
index 00000000000..cfa2fd7b0f6
--- /dev/null
+++ b/source/blender/blenloader/BLO_writefile.h
@@ -0,0 +1,44 @@
+/*
+ * $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) 2001-2002 by NaN Holding BV.
+ * 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_WRITEFILE_H
+#define BLO_WRITEFILE_H
+
+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/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
new file mode 100644
index 00000000000..3e21c1dc318
--- /dev/null
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -0,0 +1,46 @@
+# $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) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/*.c)
+
+SET(INC
+ . ../../../intern/guardedalloc ../blenlib ../blenkernel
+ ../makesdna ../readblenfile ../include
+ ../python ../../kernel/gen_messaging
+ ../render/extern/include
+ ${ZLIB_INC}
+)
+
+IF(WITH_VERSE)
+ ADD_DEFINITIONS(-DWITH_VERSE)
+ SET(INC ${INC} ${VERSE_INC})
+ENDIF(WITH_VERSE)
+
+BLENDERLIB(bf_blenloader "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_blenloader', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [70, 30] )
diff --git a/source/blender/blenloader/Makefile b/source/blender/blenloader/Makefile
new file mode 100644
index 00000000000..0d7cd16453e
--- /dev/null
+++ b/source/blender/blenloader/Makefile
@@ -0,0 +1,37 @@
+#
+# $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) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/blenloader
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/blenloader/SConscript b/source/blender/blenloader/SConscript
new file mode 100644
index 00000000000..fb36b15e3e7
--- /dev/null
+++ b/source/blender/blenloader/SConscript
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('intern/*.c')
+
+incs = '. #/intern/guardedalloc ../blenlib ../blenkernel'
+incs += ' ../makesdna ../readblenfile ../include'
+incs += ' ../python ../../kernel/gen_messaging'
+incs += ' ../render/extern/include'
+
+incs += ' ' + env['BF_ZLIB_INC']
+
+defs = ''
+if env['WITH_BF_VERSE']:
+ defs += ' WITH_VERSE'
+ incs += ' ' + env['BF_VERSE_INCLUDE']
+
+env.BlenderLib ( 'bf_blenloader', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [70, 30] )
diff --git a/source/blender/blenloader/intern/Makefile b/source/blender/blenloader/intern/Makefile
new file mode 100644
index 00000000000..4fcb0e8db47
--- /dev/null
+++ b/source/blender/blenloader/intern/Makefile
@@ -0,0 +1,76 @@
+#
+# $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) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = blenloader
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+# CFLAGS += $(LEVEL_2_C_WARNINGS)
+
+# OpenGL and Python
+CPPFLAGS += $(OGL_CPPFLAGS)
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+# zlib
+ifeq ($(OS),$(findstring $(OS), "solaris windows"))
+ CPPFLAGS += -I$(NAN_ZLIB)/include
+endif
+
+ifeq ($(WITH_VERSE), true)
+ CPPFLAGS += -DWITH_VERSE
+ CPPFLAGS += -I$(NAN_VERSE)/include
+endif
+
+# streaming write function
+CPPFLAGS += -I../../writestreamglue
+CPPFLAGS += -I../../readstreamglue
+
+# initiate a streaming read pipe
+CPPFLAGS += -I../../readblenfile
+
+# This mod uses the GEN, DNA, BLI and BKE modules
+CPPFLAGS += -I../../../kernel/gen_messaging
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../blenlib
+# path to the guarded memory allocator
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../render/extern/include/
+CPPFLAGS += -I../../python
+
+# we still refer to /include a bit...
+CPPFLAGS += -I../../include
+
+# path to our own external headerfiles
+CPPFLAGS += -I..
diff --git a/source/blender/blenloader/intern/genfile.c b/source/blender/blenloader/intern/genfile.c
new file mode 100644
index 00000000000..b21185e84a0
--- /dev/null
+++ b/source/blender/blenloader/intern/genfile.c
@@ -0,0 +1,1102 @@
+/* genfile.c
+ *
+ * Functions for struct-dna, the genetic file dot c!
+ *
+ * $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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * DNA handling
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h> // for read close
+#else
+#include <io.h> // for open close read
+#endif
+
+#include <string.h> // strncmp
+#include <stdio.h> // for printf
+#include <stdlib.h> // for atoi
+#include <fcntl.h> // for open O_RDONLY
+
+#include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN
+#include "BLI_blenlib.h" // for BLI_filesize
+
+#include "BKE_utildefines.h" // for O_BINARY TRUE MIN2
+
+#include "DNA_sdna_types.h" // for SDNA ;-)
+
+#include "BLO_writefile.h"
+#include "BLO_genfile.h"
+
+#include "genfile.h"
+
+/* gcc 4.1 on mingw was complaining that __int64 was alredy defined
+actually is saw the line below as typedef long long long long...
+Anyhow, since its alredy defined, its safe to do an ifndef here- Cambpell*/
+#ifdef FREE_WINDOWS
+#ifndef __int64
+typedef long long __int64;
+#endif
+#endif
+
+/*
+ * - please note: no builtin security to detect input of double structs
+ * - if you want a struct not to be in DNA file: add two hash marks above it (#<enter>#<enter>)
+
+Structure DNA data is added to each blender file and to each executable, this to detect
+in .blend files new veriables in structs, changed array sizes, etc. It's also used for
+converting endian and pointer size (32-64 bits)
+As an extra, Python uses a call to detect run-time the contents of a blender struct.
+
+Create a structDNA: only needed when one of the input include (.h) files change.
+File Syntax:
+ SDNA (4 bytes) (magic number)
+ NAME (4 bytes)
+ <nr> (4 bytes) amount of names (int)
+ <string>
+ <string>
+ ...
+ ...
+ TYPE (4 bytes)
+ <nr> amount of types (int)
+ <string>
+ <string>
+ ...
+ ...
+ TLEN (4 bytes)
+ <len> (short) the lengths of types
+ <len>
+ ...
+ ...
+ STRC (4 bytes)
+ <nr> amount of structs (int)
+ <typenr><nr_of_elems> <typenr><namenr> <typenr><namenr> ...
+
+!!Remember to read/write integer and short aligned!!
+
+ While writing a file, the names of a struct is indicated with a type number,
+ to be found with: type= findstruct_nr(SDNA *, char *)
+ The value of 'type' corresponds with the the index within the structs array
+
+ For the moment: the complete DNA file is included in a .blend file. For
+ the future we can think of smarter methods, like only included the used
+ structs. Only needed to keep a file short though...
+
+ALLOWED AND TESTED CHANGES IN STRUCTS:
+ - type change (a char to float will be divided by 255)
+ - location within a struct (everthing can be randomly mixed up)
+ - struct within struct (within struct etc), this is recursive
+ - adding new elements, will be default initialized zero
+ - remving elements
+ - change of array sizes
+ - change of a pointer type: when the name doesn't change the contents is copied
+
+NOT YET:
+ - array (vec[3]) to float struct (vec3f)
+
+DONE:
+ - endian compatibility
+ - pointer conversion (32-64 bits)
+
+IMPORTANT:
+ - do not use #defines in structs for array lenghts, this cannot be read by the dna functions
+ - do not use uint, but unsigned int instead, ushort and ulong are allowed
+ - only use a long in Blender if you want this to be the size of a pointer. so it is
+ 32 bits or 64 bits, dependant at the cpu architecture
+ - chars are always unsigned
+ - aligment of variables has to be done in such a way, that any system does
+ not create 'padding' (gaps) in structures. So make sure that:
+ - short: 2 aligned
+ - int: 4 aligned
+ - float: 4 aligned
+ - double: 8 aligned
+ - long: 8 aligned
+ - struct: 8 aligned
+ - the sdna functions have several error prints builtin, always check blender running from a console.
+
+*/
+
+/* local */
+static int le_int(int temp);
+static short le_short(short temp);
+
+/* ************************* ENDIAN STUFF ********************** */
+
+static short le_short(short temp)
+{
+ short new;
+ char *rt=(char *)&temp, *rtn=(char *)&new;
+
+ rtn[0]= rt[1];
+ rtn[1]= rt[0];
+
+ return new;
+}
+
+
+static int le_int(int temp)
+{
+ int new;
+ char *rt=(char *)&temp, *rtn=(char *)&new;
+
+ rtn[0]= rt[3];
+ rtn[1]= rt[2];
+ rtn[2]= rt[1];
+ rtn[3]= rt[0];
+
+ return new;
+}
+
+
+/* ************************* MAKE DNA ********************** */
+
+/* allowed duplicate code from makesdna.c */
+static int arraysize(char *astr, int len)
+{
+ int a, mul=1;
+ char str[100], *cp=0;
+
+ memcpy(str, astr, len+1);
+
+ for(a=0; a<len; a++) {
+ if( str[a]== '[' ) {
+ cp= &(str[a+1]);
+ }
+ else if( str[a]==']' && cp) {
+ str[a]= 0;
+ mul*= atoi(cp);
+ }
+ }
+
+ return mul;
+}
+
+/* ************************* END MAKE DNA ********************** */
+
+/* ************************* DIV ********************** */
+
+void dna_freestructDNA(struct SDNA *sdna)
+{
+ MEM_freeN(sdna->data);
+ MEM_freeN(sdna->names);
+ MEM_freeN(sdna->types);
+ MEM_freeN(sdna->structs);
+
+ MEM_freeN(sdna);
+}
+
+static int elementsize(struct SDNA *sdna, short type, short name)
+/* call with numbers from struct-array */
+{
+ int mul, namelen, len;
+ char *cp;
+
+ cp= sdna->names[name];
+ len= 0;
+
+ namelen= strlen(cp);
+ /* is it a pointer or function pointer? */
+ if(cp[0]=='*' || cp[1]=='*') {
+ /* has the naam an extra length? (array) */
+ mul= 1;
+ if( cp[namelen-1]==']') mul= arraysize(cp, namelen);
+
+ len= sdna->pointerlen*mul;
+ }
+ else if( sdna->typelens[type] ) {
+ /* has the naam an extra length? (array) */
+ mul= 1;
+ if( cp[namelen-1]==']') mul= arraysize(cp, namelen);
+
+ len= mul*sdna->typelens[type];
+
+ }
+
+ return len;
+}
+
+#if 0
+static void printstruct(struct SDNA *sdna, short strnr)
+{
+ /* is for debug */
+ int b, nr;
+ short *sp;
+
+ sp= sdna->structs[strnr];
+
+ printf("struct %s\n", sdna->types[ sp[0] ]);
+ nr= sp[1];
+ sp+= 2;
+
+ for(b=0; b< nr; b++, sp+= 2) {
+ printf(" %s %s\n", sdna->types[sp[0]], sdna->names[sp[1]]);
+ }
+}
+#endif
+
+static short *findstruct_name(struct SDNA *sdna, char *str)
+{
+ int a;
+ short *sp=0;
+
+
+ for(a=0; a<sdna->nr_structs; a++) {
+
+ sp= sdna->structs[a];
+
+ if(strcmp( sdna->types[ sp[0] ], str )==0) return sp;
+ }
+
+ return 0;
+}
+
+int dna_findstruct_nr(struct SDNA *sdna, char *str)
+{
+ short *sp=0;
+ int a;
+
+ if(sdna->lastfind<sdna->nr_structs) {
+ sp= sdna->structs[sdna->lastfind];
+ if(strcmp( sdna->types[ sp[0] ], str )==0) return sdna->lastfind;
+ }
+
+ for(a=0; a<sdna->nr_structs; a++) {
+
+ sp= sdna->structs[a];
+
+ if(strcmp( sdna->types[ sp[0] ], str )==0) {
+ sdna->lastfind= a;
+ return a;
+ }
+ }
+
+ return -1;
+}
+
+/* ************************* END DIV ********************** */
+
+/* ************************* READ DNA ********************** */
+
+static void init_structDNA(struct SDNA *sdna, int do_endian_swap)
+/* in sdna->data the data, now we convert that to something understandable */
+{
+ int *data, *verg;
+ long nr;
+ short *sp;
+ char str[8], *cp;
+
+ verg= (int *)str;
+ data= (int *)sdna->data;
+
+ strcpy(str, "SDNA");
+ if( *data == *verg ) {
+
+ data++;
+
+ /* load names array */
+ strcpy(str, "NAME");
+ if( *data == *verg ) {
+ data++;
+
+ if(do_endian_swap) sdna->nr_names= le_int(*data);
+ else sdna->nr_names= *data;
+
+ data++;
+ sdna->names= MEM_callocN( sizeof(void *)*sdna->nr_names, "sdnanames");
+ }
+ else {
+ printf("NAME error in SDNA file\n");
+ return;
+ }
+
+ nr= 0;
+ cp= (char *)data;
+ while(nr<sdna->nr_names) {
+ sdna->names[nr]= cp;
+ while( *cp) cp++;
+ cp++;
+ nr++;
+ }
+ nr= (long)cp; /* prevent BUS error */
+ nr= (nr+3) & ~3;
+ cp= (char *)nr;
+
+ /* load type names array */
+ data= (int *)cp;
+ strcpy(str, "TYPE");
+ if( *data == *verg ) {
+ data++;
+
+ if(do_endian_swap) sdna->nr_types= le_int(*data);
+ else sdna->nr_types= *data;
+
+ data++;
+ sdna->types= MEM_callocN( sizeof(void *)*sdna->nr_types, "sdnatypes");
+ }
+ else {
+ printf("TYPE error in SDNA file\n");
+ return;
+ }
+
+ nr= 0;
+ cp= (char *)data;
+ while(nr<sdna->nr_types) {
+ sdna->types[nr]= cp;
+
+ /* this is a patch, to change struct names without a confict with SDNA */
+ /* be careful to use it, in this case for a system-struct (opengl/X) */
+
+ if( *cp == 'b') {
+ /* struct Screen was already used by X, 'bScreen' replaces the old IrisGL 'Screen' struct */
+ if( strcmp("bScreen", cp)==0 ) sdna->types[nr]= cp+1;
+ }
+
+ while( *cp) cp++;
+ cp++;
+ nr++;
+ }
+ nr= (long)cp; /* prevent BUS error */
+ nr= (nr+3) & ~3;
+ cp= (char *)nr;
+
+ /* load typelen array */
+ data= (int *)cp;
+ strcpy(str, "TLEN");
+ if( *data == *verg ) {
+ data++;
+ sp= (short *)data;
+ sdna->typelens= sp;
+
+ if(do_endian_swap) {
+ short a, *spo= sp;
+
+ a= sdna->nr_types;
+ while(a--) {
+ spo[0]= le_short(spo[0]);
+ spo++;
+ }
+ }
+
+ sp+= sdna->nr_types;
+ }
+ else {
+ printf("TLEN error in SDNA file\n");
+ return;
+ }
+ if(sdna->nr_types & 1) sp++; /* prevent BUS error */
+
+ /* load struct array */
+ data= (int *)sp;
+ strcpy(str, "STRC");
+ if( *data == *verg ) {
+ data++;
+
+ if(do_endian_swap) sdna->nr_structs= le_int(*data);
+ else sdna->nr_structs= *data;
+
+ data++;
+ sdna->structs= MEM_callocN( sizeof(void *)*sdna->nr_structs, "sdnastrcs");
+ }
+ else {
+ printf("STRC error in SDNA file\n");
+ return;
+ }
+
+ nr= 0;
+ sp= (short *)data;
+ while(nr<sdna->nr_structs) {
+ sdna->structs[nr]= sp;
+
+ if(do_endian_swap) {
+ short a;
+
+ sp[0]= le_short(sp[0]);
+ sp[1]= le_short(sp[1]);
+
+ a= sp[1];
+ sp+= 2;
+ while(a--) {
+ sp[0]= le_short(sp[0]);
+ sp[1]= le_short(sp[1]);
+ sp+= 2;
+ }
+ }
+ else {
+ sp+= 2*sp[1]+2;
+ }
+
+ nr++;
+ }
+
+ /* finally pointerlen: use struct ListBase to test it, never change the size of it! */
+ sp= findstruct_name(sdna, "ListBase");
+ /* weird; i have no memory of that... I think I used sizeof(void *) before... (ton) */
+
+ sdna->pointerlen= sdna->typelens[ sp[0] ]/2;
+
+ if(sp[1]!=2 || (sdna->pointerlen!=4 && sdna->pointerlen!=8)) {
+ printf("ListBase struct error! Needs it to calculate pointerize.\n");
+ exit(0);
+ /* well, at least sizeof(ListBase) is error proof! (ton) */
+ }
+
+ }
+}
+
+struct SDNA *dna_sdna_from_data(void *data, int datalen, int do_endian_swap)
+{
+ struct SDNA *sdna= MEM_mallocN(sizeof(*sdna), "sdna");
+
+ sdna->lastfind= 0;
+
+ sdna->datalen= datalen;
+ sdna->data= MEM_mallocN(datalen, "sdna_data");
+ memcpy(sdna->data, data, datalen);
+
+ init_structDNA(sdna, do_endian_swap);
+
+ return sdna;
+}
+
+/* ******************** END READ DNA ********************** */
+
+/* ******************* HANDLE DNA ***************** */
+
+static void recurs_test_compflags(struct SDNA *sdna, char *compflags, int structnr)
+{
+ int a, b, typenr, elems;
+ short *sp;
+ char *cp;
+
+ /* check all structs, test if it's inside another struct */
+ sp= sdna->structs[structnr];
+ typenr= sp[0];
+
+ for(a=0; a<sdna->nr_structs; a++) {
+ if(a!=structnr && compflags[a]==1) {
+ sp= sdna->structs[a];
+ elems= sp[1];
+ sp+= 2;
+ for(b=0; b<elems; b++, sp+=2) {
+ if(sp[0]==typenr) {
+ cp= sdna->names[ sp[1] ];
+ if(cp[0]!= '*') {
+ compflags[a]= 2;
+ recurs_test_compflags(sdna, compflags, a);
+ }
+ }
+ }
+ }
+ }
+
+}
+
+ /* Unsure of exact function - compares the sdna argument to
+ * newsdna and sets up the information necessary to convert
+ * data written with a dna of oldsdna to inmemory data with a
+ * structure defined by the newsdna sdna (I think). -zr
+ */
+
+/* well, the function below is just a lookup table to speed
+ * up reading files. doh! -ton
+ */
+
+
+char *dna_get_structDNA_compareflags(struct SDNA *sdna, struct SDNA *newsdna)
+{
+ /* flag: 0: doesn't exist anymore (or not yet)
+ * 1: is equal
+ * 2: is different
+ */
+ int a, b;
+ short *spold, *spcur;
+ char *str1, *str2;
+ char *compflags;
+
+ if(sdna->nr_structs==0) {
+ printf("error: file without SDNA\n");
+ return NULL;
+ }
+
+ compflags= MEM_callocN(sdna->nr_structs, "compflags");
+
+ /* we check all structs in 'sdna' and compare them with
+ * the structs in 'newsdna'
+ */
+
+ for(a=0; a<sdna->nr_structs; a++) {
+ spold= sdna->structs[a];
+
+ /* search for type in cur */
+ spcur= findstruct_name(newsdna, sdna->types[spold[0]]);
+
+ if(spcur) {
+ compflags[a]= 2;
+
+ /* compare length and amount of elems */
+ if( spcur[1] == spold[1]) {
+ if( newsdna->typelens[spcur[0]] == sdna->typelens[spold[0]] ) {
+
+ /* same length, same amount of elems, now per type and name */
+ b= spold[1];
+ spold+= 2;
+ spcur+= 2;
+ while(b > 0) {
+ str1= newsdna->types[spcur[0]];
+ str2= sdna->types[spold[0]];
+ if(strcmp(str1, str2)!=0) break;
+
+ str1= newsdna->names[spcur[1]];
+ str2= sdna->names[spold[1]];
+ if(strcmp(str1, str2)!=0) break;
+
+ /* same type and same name, now pointersize */
+ if(str1[0]=='*') {
+ if(sdna->pointerlen!=newsdna->pointerlen) break;
+ }
+
+ b--;
+ spold+= 2;
+ spcur+= 2;
+ }
+ if(b==0) compflags[a]= 1;
+
+ }
+ }
+
+ }
+ }
+
+ /* first struct in util.h is struct Link, this is skipped in compflags (als # 0).
+ * was a bug, and this way dirty patched! Solve this later....
+ */
+ compflags[0]= 1;
+
+ /* Because structs can be inside structs, we recursively
+ * set flags when a struct is altered
+ */
+ for(a=0; a<sdna->nr_structs; a++) {
+ if(compflags[a]==2) recurs_test_compflags(sdna, compflags, a);
+ }
+
+/*
+ for(a=0; a<sdna->nr_structs; a++) {
+ if(compflags[a]==2) {
+ spold= sdna->structs[a];
+ printf("changed: %s\n", sdna->types[ spold[0] ]);
+ }
+ }
+*/
+
+ return compflags;
+}
+
+static void cast_elem(char *ctype, char *otype, char *name, char *curdata, char *olddata)
+{
+ double val = 0.0;
+ int arrlen, curlen=1, oldlen=1, ctypenr, otypenr;
+
+ arrlen= arraysize(name, strlen(name));
+
+ /* define otypenr */
+ if(strcmp(otype, "char")==0) otypenr= 0;
+ else if((strcmp(otype, "uchar")==0)||(strcmp(otype, "unsigned char")==0)) otypenr= 1;
+ else if(strcmp(otype, "short")==0) otypenr= 2;
+ else if((strcmp(otype, "ushort")==0)||(strcmp(otype, "unsigned short")==0)) otypenr= 3;
+ else if(strcmp(otype, "int")==0) otypenr= 4;
+ else if(strcmp(otype, "long")==0) otypenr= 5;
+ else if((strcmp(otype, "ulong")==0)||(strcmp(otype, "unsigned long")==0)) otypenr= 6;
+ else if(strcmp(otype, "float")==0) otypenr= 7;
+ else if(strcmp(otype, "double")==0) otypenr= 8;
+ else return;
+
+ /* define ctypenr */
+ if(strcmp(ctype, "char")==0) ctypenr= 0;
+ else if((strcmp(ctype, "uchar")==0)||(strcmp(ctype, "unsigned char")==0)) ctypenr= 1;
+ else if(strcmp(ctype, "short")==0) ctypenr= 2;
+ else if((strcmp(ctype, "ushort")==0)||(strcmp(ctype, "unsigned short")==0)) ctypenr= 3;
+ else if(strcmp(ctype, "int")==0) ctypenr= 4;
+ else if(strcmp(ctype, "long")==0) ctypenr= 5;
+ else if((strcmp(ctype, "ulong")==0)||(strcmp(ctype, "unsigned long")==0)) ctypenr= 6;
+ else if(strcmp(ctype, "float")==0) ctypenr= 7;
+ else if(strcmp(ctype, "double")==0) ctypenr= 8;
+ else return;
+
+ /* define lengths */
+ if(otypenr < 2) oldlen= 1;
+ else if(otypenr < 4) oldlen= 2;
+ else if(otypenr < 8) oldlen= 4;
+ else oldlen= 8;
+
+ if(ctypenr < 2) curlen= 1;
+ else if(ctypenr < 4) curlen= 2;
+ else if(ctypenr < 8) curlen= 4;
+ else curlen= 8;
+
+ while(arrlen>0) {
+ switch(otypenr) {
+ case 0:
+ val= *olddata; break;
+ case 1:
+ val= *( (unsigned char *)olddata); break;
+ case 2:
+ val= *( (short *)olddata); break;
+ case 3:
+ val= *( (unsigned short *)olddata); break;
+ case 4:
+ val= *( (int *)olddata); break;
+ case 5:
+ val= *( (int *)olddata); break;
+ case 6:
+ val= *( (unsigned int *)olddata); break;
+ case 7:
+ val= *( (float *)olddata); break;
+ case 8:
+ val= *( (double *)olddata); break;
+ }
+
+ switch(ctypenr) {
+ case 0:
+ *curdata= val; break;
+ case 1:
+ *( (unsigned char *)curdata)= val; break;
+ case 2:
+ *( (short *)curdata)= val; break;
+ case 3:
+ *( (unsigned short *)curdata)= val; break;
+ case 4:
+ *( (int *)curdata)= val; break;
+ case 5:
+ *( (int *)curdata)= val; break;
+ case 6:
+ *( (unsigned int *)curdata)= val; break;
+ case 7:
+ if(otypenr<2) val/= 255;
+ *( (float *)curdata)= val; break;
+ case 8:
+ if(otypenr<2) val/= 255;
+ *( (double *)curdata)= val; break;
+ }
+
+ olddata+= oldlen;
+ curdata+= curlen;
+ arrlen--;
+ }
+}
+
+static void cast_pointer(int curlen, int oldlen, char *name, char *curdata, char *olddata)
+{
+#ifdef WIN32
+ __int64 lval;
+#else
+ long long lval;
+#endif
+ int arrlen;
+
+ arrlen= arraysize(name, strlen(name));
+
+ while(arrlen>0) {
+
+ if(curlen==oldlen) {
+ memcpy(curdata, olddata, curlen);
+ }
+ else if(curlen==4 && oldlen==8) {
+#ifdef WIN32
+ lval= *( (__int64 *)olddata );
+#else
+ lval= *( (long long *)olddata );
+#endif
+ *((int *)curdata) = lval>>3; /* is of course gambling! */
+ }
+ else if(curlen==8 && oldlen==4) {
+#ifdef WIN32
+ *( (__int64 *)curdata ) = *((int *)olddata);
+#else
+ *( (long long *)curdata ) = *((int *)olddata);
+#endif
+ }
+ else {
+ /* for debug */
+ printf("errpr: illegal pointersize! \n");
+ }
+
+ olddata+= oldlen;
+ curdata+= curlen;
+ arrlen--;
+
+ }
+}
+
+static int elem_strcmp(char *name, char *oname)
+{
+ int a=0;
+
+ /* strcmp without array part */
+
+ while(TRUE) {
+ if(name[a] != oname[a]) return 1;
+ if(name[a]=='[') break;
+ if(name[a]==0) break;
+ a++;
+ }
+ if(name[a] != oname[a]) return 1;
+ return 0;
+}
+
+static char *find_elem(struct SDNA *sdna, char *type, char *name, short *old, char *olddata, short **sppo)
+{
+ int a, elemcount, len;
+ char *otype, *oname;
+
+ /* without arraypart, so names can differ: return old namenr and type */
+
+ /* in old is the old struct */
+ elemcount= old[1];
+ old+= 2;
+ for(a=0; a<elemcount; a++, old+=2) {
+
+ otype= sdna->types[old[0]];
+ oname= sdna->names[old[1]];
+
+ len= elementsize(sdna, old[0], old[1]);
+
+ if( elem_strcmp(name, oname)==0 ) { /* naam equal */
+ if( strcmp(type, otype)==0 ) { /* type equal */
+ if(sppo) *sppo= old;
+ return olddata;
+ }
+
+ return 0;
+ }
+
+ olddata+= len;
+ }
+ return 0;
+}
+
+static void reconstruct_elem(struct SDNA *newsdna, struct SDNA *oldsdna, char *type, char *name, char *curdata, short *old, char *olddata)
+{
+ /* rules: test for NAME:
+ - name equal:
+ - cast type
+ - name partially equal (array differs)
+ - type equal: memcpy
+ - types casten
+ (nzc 2-4-2001 I want the 'unsigned' bit to be parsed as well. Where
+ can I force this?)
+ */
+ int a, elemcount, len, array, oldsize, cursize, mul;
+ char *otype, *oname, *cp;
+
+ /* is 'name' an array? */
+ cp= name;
+ array= 0;
+ while( *cp && *cp!='[') {
+ cp++; array++;
+ }
+ if( *cp!= '[' ) array= 0;
+
+ /* in old is the old struct */
+ elemcount= old[1];
+ old+= 2;
+ for(a=0; a<elemcount; a++, old+=2) {
+ otype= oldsdna->types[old[0]];
+ oname= oldsdna->names[old[1]];
+ len= elementsize(oldsdna, old[0], old[1]);
+
+ if( strcmp(name, oname)==0 ) { /* name equal */
+
+ if( name[0]=='*') { /* pointer afhandelen */
+ cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata);
+ }
+ else if( strcmp(type, otype)==0 ) { /* type equal */
+ memcpy(curdata, olddata, len);
+ }
+ else cast_elem(type, otype, name, curdata, olddata);
+
+ return;
+ }
+ else if(array) { /* name is an array */
+
+ if(oname[array]=='[' && strncmp(name, oname, array)==0 ) { /* basis equal */
+
+ cursize= arraysize(name, strlen(name));
+ oldsize= arraysize(oname, strlen(oname));
+
+ if( name[0]=='*') { /* handle pointer */
+ if(cursize>oldsize) cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, oname, curdata, olddata);
+ else cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata);
+ }
+ else if(name[0]=='*' || strcmp(type, otype)==0 ) { /* type equal */
+ mul= len/oldsize;
+ mul*= MIN2(cursize, oldsize);
+ memcpy(curdata, olddata, mul);
+ }
+ else {
+ if(cursize>oldsize) cast_elem(type, otype, oname, curdata, olddata);
+ else cast_elem(type, otype, name, curdata, olddata);
+ }
+ return;
+ }
+ }
+ olddata+= len;
+ }
+}
+
+static void reconstruct_struct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, char *data, int curSDNAnr, char *cur)
+{
+ /* Recursive!
+ * Per element from cur_struct, read data from old_struct.
+ * If element is a struct, call recursive.
+ */
+ int a, elemcount, elen, eleno, mul, mulo, firststructtypenr;
+ short *spo, *spc, *sppo;
+ char *name, *nameo, *type, *cpo, *cpc;
+
+ if(oldSDNAnr== -1) return;
+ if(curSDNAnr== -1) return;
+
+ if( compflags[oldSDNAnr]==1 ) { /* if recursive: test for equal */
+
+ spo= oldsdna->structs[oldSDNAnr];
+ elen= oldsdna->typelens[ spo[0] ];
+ memcpy( cur, data, elen);
+
+ return;
+ }
+
+ firststructtypenr= *(newsdna->structs[0]);
+
+ spo= oldsdna->structs[oldSDNAnr];
+ spc= newsdna->structs[curSDNAnr];
+
+ elemcount= spc[1];
+
+ spc+= 2;
+ cpc= cur;
+ for(a=0; a<elemcount; a++, spc+=2) {
+ type= newsdna->types[spc[0]];
+ name= newsdna->names[spc[1]];
+
+ elen= elementsize(newsdna, spc[0], spc[1]);
+
+ /* test: is type a struct? */
+ if(spc[0]>=firststructtypenr && name[0]!='*') {
+
+ /* where does the old struct data start (and is there an old one?) */
+ cpo= find_elem(oldsdna, type, name, spo, data, &sppo);
+
+ if(cpo) {
+ oldSDNAnr= dna_findstruct_nr(oldsdna, type);
+ curSDNAnr= dna_findstruct_nr(newsdna, type);
+
+ /* array! */
+ mul= arraysize(name, strlen(name));
+ nameo= oldsdna->names[sppo[1]];
+ mulo= arraysize(nameo, strlen(nameo));
+
+ eleno= elementsize(oldsdna, sppo[0], sppo[1]);
+
+ elen/= mul;
+ eleno/= mulo;
+
+ while(mul--) {
+ reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
+ cpo+= eleno;
+ cpc+= elen;
+
+ /* new struct array larger than old */
+ mulo--;
+ if(mulo<=0) break;
+ }
+ }
+ else cpc+= elen;
+ }
+ else {
+
+ reconstruct_elem(newsdna, oldsdna, type, name, cpc, spo, data);
+ cpc+= elen;
+
+ }
+ }
+}
+
+void dna_switch_endian_struct(struct SDNA *oldsdna, int oldSDNAnr, char *data)
+{
+ /* Recursive!
+ * If element is a struct, call recursive.
+ */
+ int a, mul, elemcount, elen, elena, firststructtypenr;
+ short *spo, *spc, skip;
+ char *name, *type, *cpo, *cur, cval;
+
+ if(oldSDNAnr== -1) return;
+ firststructtypenr= *(oldsdna->structs[0]);
+
+ spo= spc= oldsdna->structs[oldSDNAnr];
+
+ elemcount= spo[1];
+
+ spc+= 2;
+ cur= data;
+
+ for(a=0; a<elemcount; a++, spc+=2) {
+ type= oldsdna->types[spc[0]];
+ name= oldsdna->names[spc[1]];
+
+ /* elementsize = including arraysize */
+ elen= elementsize(oldsdna, spc[0], spc[1]);
+
+ /* test: is type a struct? */
+ if(spc[0]>=firststructtypenr && name[0]!='*') {
+ /* where does the old data start (is there one?) */
+ cpo= find_elem(oldsdna, type, name, spo, data, 0);
+ if(cpo) {
+ oldSDNAnr= dna_findstruct_nr(oldsdna, type);
+
+ mul= arraysize(name, strlen(name));
+ elena= elen/mul;
+
+ while(mul--) {
+ dna_switch_endian_struct(oldsdna, oldSDNAnr, cpo);
+ cpo += elena;
+ }
+ }
+ }
+ else {
+
+ if( name[0]=='*' ) {
+ if(oldsdna->pointerlen==8) {
+
+ mul= arraysize(name, strlen(name));
+ cpo= cur;
+ while(mul--) {
+ cval= cpo[0]; cpo[0]= cpo[7]; cpo[7]= cval;
+ cval= cpo[1]; cpo[1]= cpo[6]; cpo[6]= cval;
+ cval= cpo[2]; cpo[2]= cpo[5]; cpo[5]= cval;
+ cval= cpo[3]; cpo[3]= cpo[4]; cpo[4]= cval;
+
+ cpo+= 8;
+ }
+
+ }
+ }
+ else {
+
+ if( spc[0]==2 || spc[0]==3 ) { /* short-ushort */
+
+ /* exception: variable called blocktype/ipowin: derived from ID_ */
+ skip= 0;
+ if(name[0]=='b' && name[1]=='l') {
+ if(strcmp(name, "blocktype")==0) skip= 1;
+ }
+ else if(name[0]=='i' && name[1]=='p') {
+ if(strcmp(name, "ipowin")==0) skip= 1;
+ }
+
+ if(skip==0) {
+ mul= arraysize(name, strlen(name));
+ cpo= cur;
+ while(mul--) {
+ cval= cpo[0];
+ cpo[0]= cpo[1];
+ cpo[1]= cval;
+ cpo+= 2;
+ }
+ }
+ }
+ else if(spc[0]>3 && spc[0]<8) { /* int-long-ulong-float */
+
+ mul= arraysize(name, strlen(name));
+ cpo= cur;
+ while(mul--) {
+ cval= cpo[0];
+ cpo[0]= cpo[3];
+ cpo[3]= cval;
+ cval= cpo[1];
+ cpo[1]= cpo[2];
+ cpo[2]= cval;
+ cpo+= 4;
+ }
+ }
+ }
+ }
+ cur+= elen;
+ }
+}
+
+void *dna_reconstruct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data)
+{
+ int a, curSDNAnr, curlen=0, oldlen;
+ short *spo, *spc;
+ char *cur, *type, *cpc, *cpo;
+
+ /* oldSDNAnr == structnr, we're looking for the corresponding 'cur' number */
+ spo= oldsdna->structs[oldSDNAnr];
+ type= oldsdna->types[ spo[0] ];
+ oldlen= oldsdna->typelens[ spo[0] ];
+ curSDNAnr= dna_findstruct_nr(newsdna, type);
+
+ /* init data and alloc */
+ if(curSDNAnr >= 0) {
+ spc= newsdna->structs[curSDNAnr];
+ curlen= newsdna->typelens[ spc[0] ];
+ }
+ if(curlen==0) {
+ return NULL;
+ }
+
+ cur= MEM_callocN( blocks*curlen, "reconstruct");
+ cpc= cur;
+ cpo= data;
+ for(a=0; a<blocks; a++) {
+ reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
+ cpc+= curlen;
+ cpo+= oldlen;
+ }
+
+ return cur;
+}
+
+int dna_elem_offset(struct SDNA *sdna, char *stype, char *vartype, char *name)
+{
+
+ int SDNAnr= dna_findstruct_nr(sdna, stype);
+ short *spo= sdna->structs[SDNAnr];
+ char *cp= find_elem(sdna, vartype, name, spo, NULL, NULL);
+ return (int)((long)cp);
+}
+
+
+
diff --git a/source/blender/blenloader/intern/genfile.h b/source/blender/blenloader/intern/genfile.h
new file mode 100644
index 00000000000..f027c14ac7a
--- /dev/null
+++ b/source/blender/blenloader/intern/genfile.h
@@ -0,0 +1,49 @@
+/*
+ * $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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * blenloader genfile private function prototypes
+ */
+
+#ifndef GENFILE_H
+#define GENFILE_H
+
+struct SDNA;
+
+int dna_findstruct_nr(struct SDNA *sdna, char *str);
+char *dna_get_structDNA_compareflags(struct SDNA *sdna, struct SDNA *newsdna);
+void dna_switch_endian_struct(struct SDNA *oldsdna, int oldSDNAnr, char *data);
+void *dna_reconstruct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data);
+int dna_elem_offset(struct SDNA *sdna, char *stype, char *vartype, char *name);
+
+struct SDNA *dna_sdna_from_data(void *data, int datalen, int do_endian_swap);
+void dna_freestructDNA(struct SDNA *sdna);
+
+#endif
+
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
new file mode 100644
index 00000000000..ef287428a19
--- /dev/null
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -0,0 +1,456 @@
+/**
+ * $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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * .blend file reading entry point
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+
+#include "DNA_sdna_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_ID.h"
+#include "DNA_material_types.h"
+
+#include "BKE_utildefines.h" // for ENDB
+
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_library.h" // for free_main
+
+#include "BLO_readfile.h"
+#include "BLO_undofile.h"
+
+#include "readfile.h"
+#include "genfile.h"
+
+#include "BLO_readblenfile.h"
+
+ /**
+ * IDType stuff, I plan to move this
+ * out into its own file + prefix, and
+ * make sure all IDType handling goes through
+ * these routines.
+ */
+
+typedef struct {
+ unsigned short code;
+ char *name;
+
+ int flags;
+#define IDTYPE_FLAGS_ISLINKABLE (1<<0)
+} IDType;
+
+static IDType idtypes[]= {
+ { ID_AC, "Action", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_AR, "Armature", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_BR, "Brush", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_CA, "Camera", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_CU, "Curve", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_GR, "Group", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_ID, "ID", 0},
+ { ID_IM, "Image", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_IP, "Ipo", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_KE, "Key", 0},
+ { ID_LA, "Lamp", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_LF, "Life", 0},
+ { ID_LI, "Library", 0},
+ { ID_LT, "Lattice", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_MA, "Material", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_MB, "Metaball", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_ME, "Mesh", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_NT, "NodeTree", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_OB, "Object", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_SCE, "Scene", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_SCR, "Screen", 0},
+ { ID_SEQ, "Sequence", 0},
+ { ID_SE, "Sector", 0},
+ { ID_SO, "Sound", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_TE, "Texture", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_TXT, "Text", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_VF, "VFont", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_WO, "World", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_WV, "Wave", 0},
+};
+static int nidtypes= sizeof(idtypes)/sizeof(idtypes[0]);
+
+/* local prototypes --------------------- */
+void BLO_blendhandle_print_sizes(BlendHandle *, void *);
+
+
+static IDType *idtype_from_name(char *str)
+{
+ int i= nidtypes;
+
+ while (i--)
+ if (BLI_streq(str, idtypes[i].name))
+ return &idtypes[i];
+
+ return NULL;
+}
+static IDType *idtype_from_code(int code)
+{
+ int i= nidtypes;
+
+ while (i--)
+ if (code==idtypes[i].code)
+ return &idtypes[i];
+
+ return NULL;
+}
+
+static int bheadcode_is_idcode(int code)
+{
+ return idtype_from_code(code)?1:0;
+}
+
+static int idcode_is_linkable(int code) {
+ IDType *idt= idtype_from_code(code);
+ return idt?(idt->flags&IDTYPE_FLAGS_ISLINKABLE):0;
+}
+
+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)
+{
+ IDType *idt= idtype_from_name(name);
+
+ return idt?idt->code:0;
+}
+
+ /* Access routines used by filesel. */
+
+BlendHandle *BLO_blendhandle_from_file(char *file)
+{
+ BlendReadError err;
+
+ return (BlendHandle*) blo_openblenderfile(file, &err);
+}
+
+void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp)
+{
+ FileData *fd= (FileData*) bh;
+ BHead *bhead;
+
+ fprintf(fp, "[\n");
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==ENDB)
+ break;
+ else {
+ short *sp= fd->filesdna->structs[bhead->SDNAnr];
+ char *name= fd->filesdna->types[ sp[0] ];
+ char buf[4];
+
+ buf[0]= (bhead->code>>24)&0xFF;
+ buf[1]= (bhead->code>>16)&0xFF;
+ buf[2]= (bhead->code>>8)&0xFF;
+ buf[3]= (bhead->code>>0)&0xFF;
+
+ buf[0]= buf[0]?buf[0]:' ';
+ buf[1]= buf[1]?buf[1]:' ';
+ buf[2]= buf[2]?buf[2]:' ';
+ buf[3]= buf[3]?buf[3]:' ';
+
+ fprintf(fp, "['%.4s', '%s', %d, %ld ], \n", buf, name, bhead->nr, (long)bhead->len+sizeof(BHead));
+ }
+ }
+ fprintf(fp, "]\n");
+}
+
+LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype)
+{
+ FileData *fd= (FileData*) bh;
+ LinkNode *names= NULL;
+ BHead *bhead;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==ofblocktype) {
+ char *idname= bhead_id_name(fd, bhead);
+
+ BLI_linklist_prepend(&names, strdup(idname+2));
+ } else if (bhead->code==ENDB)
+ break;
+ }
+
+ return names;
+}
+
+LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype)
+{
+ FileData *fd= (FileData*) bh;
+ LinkNode *previews= NULL;
+ BHead *bhead;
+ int looking=0;
+ int npreviews = 0;
+ PreviewImage* prv = NULL;
+ PreviewImage* new_prv = NULL;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==ofblocktype) {
+ ID *id= (ID*) (bhead+1);
+ if ( (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) {
+ new_prv = MEM_callocN(sizeof(PreviewImage), "newpreview");
+ BLI_linklist_prepend(&previews, new_prv);
+ looking = 1;
+ }
+ } else if (bhead->code==DATA) {
+ if (looking) {
+ if (bhead->SDNAnr == dna_findstruct_nr(fd->filesdna, "PreviewImage") ) {
+ prv = (PreviewImage*) (bhead+1);
+ npreviews = 0;
+ memcpy(new_prv, prv, sizeof(PreviewImage));
+ if (prv->rect[0]) {
+ unsigned int *rect = NULL;
+ int rectlen = 0;
+ new_prv->rect[0] = MEM_callocN(new_prv->w[0]*new_prv->h[0]*sizeof(unsigned int), "prvrect");
+ bhead= blo_nextbhead(fd, bhead);
+ rect = (unsigned int*)(bhead+1);
+ rectlen = new_prv->w[0]*new_prv->h[0]*sizeof(unsigned int);
+ memcpy(new_prv->rect[0], rect, bhead->len);
+ } else {
+ new_prv->rect[0] = NULL;
+ }
+
+ if (prv->rect[1]) {
+ unsigned int *rect = NULL;
+ int rectlen = 0;
+ new_prv->rect[1] = MEM_callocN(new_prv->w[1]*new_prv->h[1]*sizeof(unsigned int), "prvrect");
+ bhead= blo_nextbhead(fd, bhead);
+ rect = (unsigned int*)(bhead+1);
+ rectlen = new_prv->w[1]*new_prv->h[1]*sizeof(unsigned int);
+ memcpy(new_prv->rect[1], rect, bhead->len);
+ } else {
+ new_prv->rect[1] = NULL;
+ }
+ }
+ }
+ } else if (bhead->code==ENDB) {
+ break;
+ } else if (bhead->code==DATA) {
+ /* DATA blocks between IDBlock and Preview */
+ } else {
+ looking = 0;
+ new_prv = NULL;
+ prv = NULL;
+ }
+
+ }
+
+ return previews;
+}
+
+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;
+ BHead *bhead;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==ENDB) {
+ break;
+ } else if (bheadcode_is_idcode(bhead->code)) {
+ if (idcode_is_linkable(bhead->code)) {
+ char *str= BLO_idcode_to_name(bhead->code);
+
+ if (!BLI_ghash_haskey(gathered, str)) {
+ BLI_linklist_prepend(&names, strdup(str));
+ BLI_ghash_insert(gathered, str, NULL);
+ }
+ }
+ }
+ }
+
+ BLI_ghash_free(gathered, NULL, NULL);
+
+ return names;
+}
+
+void BLO_blendhandle_close(BlendHandle *bh) {
+ FileData *fd= (FileData*) bh;
+
+ blo_freefiledata(fd);
+}
+
+ /**********/
+
+BlendFileData *BLO_read_from_file(char *file, BlendReadError *error_r)
+{
+ BlendFileData *bfd = NULL;
+ FileData *fd;
+
+ fd = blo_openblenderfile(file, error_r);
+ if (fd) {
+ bfd= blo_read_file_internal(fd, error_r);
+ if (bfd) {
+ bfd->type= BLENFILETYPE_BLEND;
+ strncpy(bfd->main->name, file, sizeof(bfd->main->name)-1);
+ }
+ blo_freefiledata(fd);
+ }
+
+ return bfd;
+}
+
+BlendFileData *BLO_read_from_memory(void *mem, int memsize, BlendReadError *error_r)
+{
+ BlendFileData *bfd = NULL;
+ FileData *fd;
+
+ fd = blo_openblendermemory(mem, memsize, error_r);
+ 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;
+}
+
+BlendFileData *BLO_read_from_memfile(const char *filename, MemFile *memfile, BlendReadError *error_r)
+{
+ BlendFileData *bfd = NULL;
+ FileData *fd;
+ ListBase mainlist;
+
+ fd = blo_openblendermemfile(memfile, error_r);
+ if (fd) {
+ strcpy(fd->filename, filename);
+
+ /* separate libraries from G.main */
+ blo_split_main(&mainlist, G.main);
+ /* add the library pointers in oldmap lookup */
+ blo_add_library_pointer_map(&mainlist, fd);
+
+ /* makes lookup of existing images in G.main */
+ blo_make_image_pointer_map(fd);
+
+ bfd= blo_read_file_internal(fd, error_r);
+ if (bfd) {
+ bfd->type= BLENFILETYPE_BLEND;
+ strcpy(bfd->main->name, "");
+ }
+
+ /* ensures relinked images are not freed */
+ blo_end_image_pointer_map(fd);
+
+ /* move libraries from G.main to new main */
+ if(bfd && mainlist.first!=mainlist.last) {
+
+ /* Library structs themselves */
+ bfd->main->library= G.main->library;
+ G.main->library.first= G.main->library.last= NULL;
+
+ /* add the Library mainlist to the new main */
+ BLI_remlink(&mainlist, G.main);
+ BLI_addhead(&mainlist, bfd->main);
+ }
+ blo_join_main(&mainlist);
+
+ blo_freefiledata(fd);
+ }
+
+ return bfd;
+}
+
+void BLO_blendfiledata_free(BlendFileData *bfd)
+{
+ if (bfd->main) {
+ free_main(bfd->main);
+ }
+
+ if (bfd->user) {
+ MEM_freeN(bfd->user);
+ }
+
+ MEM_freeN(bfd);
+}
+
+char *BLO_bre_as_string(BlendReadError error)
+{
+ switch (error) {
+ case BRE_NONE:
+ return "No error";
+
+ case BRE_UNABLE_TO_OPEN:
+ return "Unable to open";
+ case BRE_UNABLE_TO_READ:
+ return "Unable to read";
+
+ case BRE_OUT_OF_MEMORY:
+ return "Out of memory";
+ case BRE_INTERNAL_ERROR:
+ return "<internal error>";
+
+ case BRE_NOT_A_BLEND:
+ return "File is not a Blender file";
+ case BRE_NOT_A_PUBFILE:
+ return "File is not a compressed, locked or signed Blender file";
+ case BRE_INCOMPLETE:
+ return "File incomplete";
+ case BRE_CORRUPT:
+ return "File corrupt";
+
+ case BRE_TOO_NEW:
+ return "File needs newer Blender version, please upgrade";
+ case BRE_NOT_ALLOWED:
+ return "File is locked";
+
+ case BRE_NO_SCREEN:
+ return "File has no screen";
+ case BRE_NO_SCENE:
+ return "File has no scene";
+
+ default:
+ case BRE_INVALID:
+ return "<invalid read error>";
+ }
+}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
new file mode 100644
index 00000000000..384a6d93480
--- /dev/null
+++ b/source/blender/blenloader/intern/readfile.c
@@ -0,0 +1,8134 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL 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.
+ *
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "zlib.h"
+
+#ifdef WIN32
+#include "winsock2.h"
+#include "BLI_winstuff.h"
+#endif
+
+#include <stdio.h> // for printf fopen fwrite fclose sprintf FILE
+#include <stdlib.h> // for getenv atoi
+#include <fcntl.h> // for open
+#include <string.h> // for strrchr strncmp strstr
+#include <math.h> // for fabs
+
+#ifndef WIN32
+ #include <unistd.h> // for read close
+ #include <sys/param.h> // for MAXPATHLEN
+#else
+ #include <io.h> // for open close read
+#endif
+
+#include "nla.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_ID.h"
+#include "DNA_actuator_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_color_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_fileglobal_types.h"
+#include "DNA_group_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_image_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h" // NT
+#include "DNA_oops_types.h"
+#include "DNA_object_force.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_property_types.h"
+#include "DNA_text_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_sdna_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_world_types.h"
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_storage_types.h" // for relname flags
+
+#include "BDR_sculptmode.h"
+
+#include "BKE_bad_level_calls.h" // for reopen_text build_seqar (from WHILE_SEQ) set_rects_butspace check_imasel_copy
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_colortools.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_effect.h" // for give_parteff
+#include "BKE_global.h" // for G
+#include "BKE_group.h"
+#include "BKE_image.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h" // for wich_libbase
+#include "BKE_main.h" // for Main
+#include "BKE_mesh.h" // for ME_ defines (patching)
+#include "BKE_modifier.h"
+#include "BKE_node.h" // for tree type defines
+#include "BKE_object.h"
+#include "BKE_property.h" // for get_property
+#include "BKE_sca.h" // for init_actuator
+#include "BKE_scene.h"
+#include "BKE_softbody.h" // sbNew()
+#include "BKE_texture.h" // for open_plugin_tex
+#include "BKE_utildefines.h" // SWITCH_INT DATA ENDB DNA1 O_BINARY GLOB USER TEST REND
+#include "BKE_idprop.h"
+
+#include "BIF_butspace.h" // badlevel, for do_versions, patching event codes
+#include "BIF_filelist.h" // badlevel too, where to move this? - elubie
+#include "BIF_previewrender.h" // bedlelvel, for struct RenderInfo
+#include "BLO_readfile.h"
+#include "BLO_undofile.h"
+#include "BLO_readblenfile.h" // streaming read pipe, for BLO_readblenfile BLO_readblenfilememory
+
+#include "multires.h"
+
+#include "readfile.h"
+
+#include "genfile.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include <errno.h>
+
+/*
+ Remark: still a weak point is the newadress() function, that doesnt solve reading from
+ multiple files at the same time
+
+ (added remark: oh, i thought that was solved? will look at that... (ton)
+
+READ
+- Existing Library (Main) push or free
+- allocate new Main
+- load file
+- read SDNA
+- for each LibBlock
+ - read LibBlock
+ - if a Library
+ - make a new Main
+ - attach ID's to it
+ - else
+ - read associated 'direct data'
+ - link direct data (internal and to LibBlock)
+- read FileGlobal
+- read USER data, only when indicated (file is ~/.B.blend)
+- free file
+- per Library (per Main)
+ - read file
+ - read SDNA
+ - find LibBlocks and attach IDs to Main
+ - if external LibBlock
+ - search all Main's
+ - or it's already read,
+ - or not read yet
+ - or make new Main
+ - per LibBlock
+ - read recursive
+ - read associated direct data
+ - link direct data (internal and to LibBlock)
+ - free file
+- per Library with unread LibBlocks
+ - read file
+ - read SDNA
+ - per LibBlock
+ - read recursive
+ - read associated direct data
+ - link direct data (internal and to LibBlock)
+ - free file
+- join all Mains
+- link all LibBlocks and indirect pointers to libblocks
+- initialize FileGlobal and copy pointers to Global
+*/
+
+/* also occurs in library.c */
+/* GS reads the memory pointed at in a specific ordering. There are,
+ * however two definitions for it. I have jotted them down here, both,
+ * but I think the first one is actually used. The thing is that
+ * big-endian systems might read this the wrong way round. OTOH, we
+ * constructed the IDs that are read out with this macro explicitly as
+ * well. I expect we'll sort it out soon... */
+
+/* from blendef: */
+#define GS(a) (*((short *)(a)))
+
+/* from misc_util: flip the bytes from x */
+/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */
+
+// only used here in readfile.c
+#define SWITCH_LONGINT(a) { \
+ char s_i, *p_i; \
+ p_i= (char *)&(a); \
+ s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \
+ s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \
+ s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \
+ s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; }
+
+/***/
+
+typedef struct OldNew {
+ void *old, *newp;
+ int nr;
+} OldNew;
+
+typedef struct OldNewMap {
+ OldNew *entries;
+ int nentries, entriessize;
+ int sorted;
+ int lasthit;
+} OldNewMap;
+
+
+/* local prototypes */
+static void *read_struct(FileData *fd, BHead *bh, char *blockname);
+
+
+static OldNewMap *oldnewmap_new(void)
+{
+ OldNewMap *onm= MEM_callocN(sizeof(*onm), "OldNewMap");
+
+ onm->entriessize= 1024;
+ onm->entries= MEM_mallocN(sizeof(*onm->entries)*onm->entriessize, "OldNewMap.entries");
+
+ return onm;
+}
+
+static int verg_oldnewmap(const void *v1, const void *v2)
+{
+ const struct OldNew *x1=v1, *x2=v2;
+
+ if( x1->old > x2->old) return 1;
+ else if( x1->old < x2->old) return -1;
+ return 0;
+}
+
+
+static void oldnewmap_sort(FileData *fd)
+{
+ qsort(fd->libmap->entries, fd->libmap->nentries, sizeof(OldNew), verg_oldnewmap);
+ fd->libmap->sorted= 1;
+}
+
+/* nr is zero for data, and ID code for libdata */
+static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr)
+{
+ OldNew *entry;
+
+ if(oldaddr==NULL || newaddr==NULL) return;
+
+ if (onm->nentries==onm->entriessize) {
+ int osize= onm->entriessize;
+ OldNew *oentries= onm->entries;
+
+ onm->entriessize*= 2;
+ onm->entries= MEM_mallocN(sizeof(*onm->entries)*onm->entriessize, "OldNewMap.entries");
+
+ memcpy(onm->entries, oentries, sizeof(*oentries)*osize);
+ MEM_freeN(oentries);
+ }
+
+ entry= &onm->entries[onm->nentries++];
+ entry->old= oldaddr;
+ entry->newp= newaddr;
+ entry->nr= nr;
+}
+
+static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr)
+{
+ int i;
+
+ if (onm->lasthit<onm->nentries-1) {
+ OldNew *entry= &onm->entries[++onm->lasthit];
+
+ if (entry->old==addr) {
+ entry->nr++;
+ return entry->newp;
+ }
+ }
+
+ for (i=0; i<onm->nentries; i++) {
+ OldNew *entry= &onm->entries[i];
+
+ if (entry->old==addr) {
+ onm->lasthit= i;
+
+ entry->nr++;
+ return entry->newp;
+ }
+ }
+
+ return NULL;
+}
+
+/* for libdata, nr has ID code, no increment */
+static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib)
+{
+ int i;
+
+ if(addr==NULL) return NULL;
+
+ /* lasthit works fine for non-libdata, linking there is done in same sequence as writing */
+ if(onm->sorted) {
+ OldNew entry_s, *entry;
+
+ entry_s.old= addr;
+
+ entry= bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap);
+ if(entry) {
+ ID *id= entry->newp;
+
+ if (id && (!lib || id->lib)) {
+ return entry->newp;
+ }
+ }
+ }
+
+ for (i=0; i<onm->nentries; i++) {
+ OldNew *entry= &onm->entries[i];
+
+ if (entry->old==addr) {
+ ID *id= entry->newp;
+
+ if (id && (!lib || id->lib)) {
+ return entry->newp;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void oldnewmap_free_unused(OldNewMap *onm)
+{
+ int i;
+
+ for (i=0; i<onm->nentries; i++) {
+ OldNew *entry= &onm->entries[i];
+ if (entry->nr==0) {
+ MEM_freeN(entry->newp);
+ entry->newp= NULL;
+ }
+ }
+}
+
+static void oldnewmap_clear(OldNewMap *onm)
+{
+ onm->nentries= 0;
+ onm->lasthit= 0;
+}
+
+static void oldnewmap_free(OldNewMap *onm)
+{
+ MEM_freeN(onm->entries);
+ MEM_freeN(onm);
+}
+
+/***/
+
+static void read_libraries(FileData *basefd, ListBase *mainlist);
+
+/* ************ help functions ***************** */
+
+static void add_main_to_main(Main *mainvar, Main *from)
+{
+ ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY];
+ int a;
+
+ a= set_listbasepointers(mainvar, lbarray);
+ a= set_listbasepointers(from, fromarray);
+ while(a--) {
+ addlisttolist(lbarray[a], fromarray[a]);
+ }
+}
+
+void blo_join_main(ListBase *mainlist)
+{
+ Main *tojoin, *mainl;
+
+
+ mainl= mainlist->first;
+ while ((tojoin= mainl->next)) {
+ add_main_to_main(mainl, tojoin);
+ BLI_remlink(mainlist, tojoin);
+ MEM_freeN(tojoin);
+ }
+}
+
+static void split_libdata(ListBase *lb, Main *first)
+{
+ ListBase *lbn;
+ ID *id, *idnext;
+ Main *mainvar;
+
+ id= lb->first;
+ while(id) {
+ idnext= id->next;
+ if(id->lib) {
+ mainvar= first;
+ while(mainvar) {
+ if(mainvar->curlib==id->lib) {
+ lbn= wich_libbase(mainvar, GS(id->name));
+ BLI_remlink(lb, id);
+ BLI_addtail(lbn, id);
+ break;
+ }
+ mainvar= mainvar->next;
+ }
+ if(mainvar==0) printf("error split_libdata\n");
+ }
+ id= idnext;
+ }
+}
+
+void blo_split_main(ListBase *mainlist, Main *main)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ Library *lib;
+ int i;
+
+ mainlist->first= mainlist->last= main;
+ main->next= NULL;
+
+ if(main->library.first==NULL)
+ return;
+
+ for (lib= main->library.first; lib; lib= lib->id.next) {
+ Main *libmain= MEM_callocN(sizeof(Main), "libmain");
+ libmain->curlib= lib;
+ BLI_addtail(mainlist, libmain);
+ }
+
+ i= set_listbasepointers(main, lbarray);
+ while(i--)
+ split_libdata(lbarray[i], main->next);
+}
+
+/* removes things like /blah/blah/../../blah/ etc, then writes in *name the full path */
+static void cleanup_path(const char *relabase, char *name)
+{
+ char filename[FILE_MAXFILE];
+
+ BLI_splitdirstring(name, filename);
+ BLI_cleanup_dir(relabase, name);
+ strcat(name, filename);
+}
+
+static Main *blo_find_main(ListBase *mainlist, const char *name, const char *relabase)
+{
+ Main *m;
+ Library *lib;
+ char name1[FILE_MAXDIR+FILE_MAXFILE];
+
+ strncpy(name1, name, sizeof(name1)-1);
+ cleanup_path(relabase, name1);
+// printf("blo_find_main: original in %s\n", name);
+// printf("blo_find_main: converted to %s\n", name1);
+
+ for (m= mainlist->first; m; m= m->next) {
+ char *libname= (m->curlib)?m->curlib->filename:m->name;
+
+ if (BLI_streq(name1, libname)) {
+ if(G.f & G_DEBUG) printf("blo_find_main: found library %s\n", libname);
+ return m;
+ }
+ }
+
+ m= MEM_callocN(sizeof(Main), "find_main");
+ BLI_addtail(mainlist, m);
+
+ lib= alloc_libblock(&m->library, ID_LI, "lib");
+ strncpy(lib->name, name, sizeof(lib->name)-1);
+ BLI_strncpy(lib->filename, name1, sizeof(lib->filename));
+
+ m->curlib= lib;
+
+ if(G.f & G_DEBUG) printf("blo_find_main: added new lib %s\n", name);
+ return m;
+}
+
+
+/* ************ FILE PARSING ****************** */
+
+static void switch_endian_bh4(BHead4 *bhead)
+{
+ /* the ID_.. codes */
+ if((bhead->code & 0xFFFF)==0) bhead->code >>=16;
+
+ if (bhead->code != ENDB) {
+ SWITCH_INT(bhead->len);
+ SWITCH_INT(bhead->SDNAnr);
+ SWITCH_INT(bhead->nr);
+ }
+}
+
+static void switch_endian_bh8(BHead8 *bhead)
+{
+ /* the ID_.. codes */
+ if((bhead->code & 0xFFFF)==0) bhead->code >>=16;
+
+ if (bhead->code != ENDB) {
+ SWITCH_INT(bhead->len);
+ SWITCH_INT(bhead->SDNAnr);
+ SWITCH_INT(bhead->nr);
+ }
+}
+
+static void bh4_from_bh8(BHead *bhead, BHead8 *bhead8, int do_endian_swap)
+{
+ BHead4 *bhead4 = (BHead4 *) bhead;
+#if defined(WIN32) && !defined(FREE_WINDOWS)
+ __int64 old;
+#else
+ long long old;
+#endif
+
+ bhead4->code= bhead8->code;
+ bhead4->len= bhead8->len;
+
+ if (bhead4->code != ENDB) {
+
+ // why is this here ??
+ if (do_endian_swap) {
+ SWITCH_LONGINT(bhead8->old);
+ }
+
+ /* this patch is to avoid a long long being read from not-eight aligned positions
+ is necessary on any modern 64bit architecture) */
+ memcpy(&old, &bhead8->old, 8);
+ bhead4->old = (int) (old >> 3);
+
+ bhead4->SDNAnr= bhead8->SDNAnr;
+ bhead4->nr= bhead8->nr;
+ }
+}
+
+static void bh8_from_bh4(BHead *bhead, BHead4 *bhead4)
+{
+ BHead8 *bhead8 = (BHead8 *) bhead;
+
+ bhead8->code= bhead4->code;
+ bhead8->len= bhead4->len;
+
+ if (bhead8->code != ENDB) {
+ bhead8->old= bhead4->old;
+ bhead8->SDNAnr= bhead4->SDNAnr;
+ bhead8->nr= bhead4->nr;
+ }
+}
+
+static BHeadN *get_bhead(FileData *fd)
+{
+ BHead8 bhead8;
+ BHead4 bhead4;
+ BHead bhead;
+ BHeadN *new_bhead = 0;
+ int readsize;
+
+ if (fd) {
+ if ( ! fd->eof) {
+
+ // First read the bhead structure.
+ // Depending on the platform the file was written on this can
+ // be a big or little endian BHead4 or BHead8 structure.
+
+ // As usual 'ENDB' (the last *partial* bhead of the file)
+ // needs some special handling. We don't want to EOF just yet.
+
+ if (fd->flags & FD_FLAGS_FILE_POINTSIZE_IS_4) {
+ bhead4.code = DATA;
+ readsize = fd->read(fd, &bhead4, sizeof(bhead4));
+
+ if (readsize == sizeof(bhead4) || bhead4.code == ENDB) {
+ if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ switch_endian_bh4(&bhead4);
+ }
+
+ if (fd->flags & FD_FLAGS_POINTSIZE_DIFFERS) {
+ bh8_from_bh4(&bhead, &bhead4);
+ } else {
+ memcpy(&bhead, &bhead4, sizeof(bhead));
+ }
+ } else {
+ fd->eof = 1;
+ bhead.len= 0;
+ }
+ } else {
+ bhead8.code = DATA;
+ readsize = fd->read(fd, &bhead8, sizeof(bhead8));
+
+ if (readsize == sizeof(bhead8) || bhead8.code == ENDB) {
+ if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ switch_endian_bh8(&bhead8);
+ }
+
+ if (fd->flags & FD_FLAGS_POINTSIZE_DIFFERS) {
+ bh4_from_bh8(&bhead, &bhead8, (fd->flags & FD_FLAGS_SWITCH_ENDIAN));
+ } else {
+ memcpy(&bhead, &bhead8, sizeof(bhead));
+ }
+ } else {
+ fd->eof = 1;
+ bhead.len= 0;
+ }
+ }
+
+ /* make sure people are not trying to pass bad blend files */
+ if (bhead.len < 0) fd->eof = 1;
+
+ // bhead now contains the (converted) bhead structure. Now read
+ // the associated data and put everything in a BHeadN (creative naming !)
+
+ if ( ! fd->eof) {
+ new_bhead = MEM_mallocN(sizeof(BHeadN) + bhead.len, "new_bhead");
+ if (new_bhead) {
+ new_bhead->next = new_bhead->prev = 0;
+ new_bhead->bhead = bhead;
+
+ readsize = fd->read(fd, new_bhead + 1, bhead.len);
+
+ if (readsize != bhead.len) {
+ fd->eof = 1;
+ MEM_freeN(new_bhead);
+ new_bhead = 0;
+ }
+ } else {
+ fd->eof = 1;
+ }
+ }
+ }
+ }
+
+ // We've read a new block. Now add it to the list
+ // of blocks.
+
+ if (new_bhead) {
+ BLI_addtail(&fd->listbase, new_bhead);
+ }
+
+ return(new_bhead);
+}
+
+BHead *blo_firstbhead(FileData *fd)
+{
+ BHeadN *new_bhead;
+ BHead *bhead = 0;
+
+ // Rewind the file
+ // Read in a new block if necessary
+
+ new_bhead = fd->listbase.first;
+ if (new_bhead == 0) {
+ new_bhead = get_bhead(fd);
+ }
+
+ if (new_bhead) {
+ bhead = &new_bhead->bhead;
+ }
+
+ return(bhead);
+}
+
+BHead *blo_prevbhead(FileData *fd, BHead *thisblock)
+{
+ BHeadN *bheadn= (BHeadN *) (((char *) thisblock) - (int) (&((BHeadN*)0)->bhead));
+ BHeadN *prev= bheadn->prev;
+
+ return prev?&prev->bhead:NULL;
+}
+
+BHead *blo_nextbhead(FileData *fd, BHead *thisblock)
+{
+ BHeadN *new_bhead = 0;
+ BHead *bhead = 0;
+
+ if (thisblock) {
+ // bhead is actually a sub part of BHeadN
+ // We calculate the BHeadN pointer from the BHead pointer below
+ new_bhead = (BHeadN *) (((char *) thisblock) - (int) (&((BHeadN*)0)->bhead));
+
+ // get the next BHeadN. If it doesn't exist we read in the next one
+ new_bhead = new_bhead->next;
+ if (new_bhead == 0) {
+ new_bhead = get_bhead(fd);
+ }
+ }
+
+ if (new_bhead) {
+ // here we do the reverse:
+ // go from the BHeadN pointer to the BHead pointer
+ bhead = &new_bhead->bhead;
+ }
+
+ return(bhead);
+}
+
+#if 0
+static void get_blender_subversion(FileData *fd)
+{
+ BHead *bhead;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==GLOB) {
+ FileGlobal *fg= read_struct(fd, bhead, "Global");
+ fd->filesubversion= fg->subversion;
+ fd->fileminversion= fg->minversion;
+ fd->fileminsubversion= fg->minsubversion;
+ MEM_freeN(fg);
+ return;
+ }
+ else if (bhead->code==ENDB)
+ break;
+ }
+}
+#endif
+
+static void decode_blender_header(FileData *fd)
+{
+ char header[SIZEOFBLENDERHEADER], num[4];
+ int readsize;
+
+ // read in the header data
+ readsize = fd->read(fd, header, sizeof(header));
+
+ if (readsize == sizeof(header)) {
+ if(strncmp(header, "BLENDER", 7) == 0) {
+ int remove_this_endian_test= 1;
+
+ fd->flags |= FD_FLAGS_FILE_OK;
+
+ // what size are pointers in the file ?
+ if(header[7]=='_') {
+ fd->flags |= FD_FLAGS_FILE_POINTSIZE_IS_4;
+ if (sizeof(void *) != 4) {
+ fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS;
+ }
+ } else {
+ if (sizeof(void *) != 8) {
+ fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS;
+ }
+ }
+
+ // is the file saved in a different endian
+ // than we need ?
+ if (((((char*)&remove_this_endian_test)[0]==1)?L_ENDIAN:B_ENDIAN) != ((header[8]=='v')?L_ENDIAN:B_ENDIAN)) {
+ fd->flags |= FD_FLAGS_SWITCH_ENDIAN;
+ }
+
+ // get the version number
+
+ memcpy(num, header+9, 3);
+ num[3] = 0;
+ fd->fileversion = atoi(num);
+ }
+ }
+}
+
+static int read_file_dna(FileData *fd)
+{
+ BHead *bhead;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==DNA1) {
+ int do_endian_swap= (fd->flags&FD_FLAGS_SWITCH_ENDIAN)?1:0;
+
+ fd->filesdna= dna_sdna_from_data(&bhead[1], bhead->len, do_endian_swap);
+ if (fd->filesdna) {
+
+ fd->compflags= dna_get_structDNA_compareflags(fd->filesdna, fd->memsdna);
+ /* used to retrieve ID names from (bhead+1) */
+ fd->id_name_offs= dna_elem_offset(fd->filesdna, "ID", "char", "name[]");
+ }
+
+ return 1;
+ } else if (bhead->code==ENDB)
+ break;
+ }
+
+ return 0;
+}
+
+static int fd_read_from_file(FileData *filedata, void *buffer, int size)
+{
+ int readsize = read(filedata->filedes, buffer, size);
+
+ if (readsize < 0) {
+ readsize = EOF;
+ } else {
+ filedata->seek += readsize;
+ }
+
+ return (readsize);
+}
+
+static int fd_read_gzip_from_file(FileData *filedata, void *buffer, int size)
+{
+ int readsize = gzread(filedata->gzfiledes, buffer, size);
+
+ if (readsize < 0) {
+ readsize = EOF;
+ } else {
+ filedata->seek += readsize;
+ }
+
+ return (readsize);
+}
+
+static int fd_read_from_memory(FileData *filedata, void *buffer, int size)
+{
+ // don't read more bytes then there are available in the buffer
+ int readsize = MIN2(size, filedata->buffersize - filedata->seek);
+
+ memcpy(buffer, filedata->buffer + filedata->seek, readsize);
+ filedata->seek += readsize;
+
+ 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 != (unsigned int)filedata->seek) {
+ chunk= filedata->memfile->chunks.first;
+ seek= 0;
+
+ while(chunk) {
+ if(seek + chunk->size > (unsigned) 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 unsigned char DNAstr[]; /* DNA.c */
+ extern int DNAlen;
+ FileData *fd = MEM_callocN(sizeof(FileData), "FileData");
+
+ fd->filedes = -1;
+ fd->gzfiledes = NULL;
+
+ /* XXX, this doesn't need to be done all the time,
+ * but it keeps us reentrant, remove once we have
+ * a lib that provides a nice lock. - zr
+ */
+ fd->memsdna = dna_sdna_from_data(DNAstr, DNAlen, 0);
+
+ fd->datamap = oldnewmap_new();
+ fd->globmap = oldnewmap_new();
+ fd->libmap = oldnewmap_new();
+
+ return fd;
+}
+
+static FileData *blo_decode_and_check(FileData *fd, BlendReadError *error_r)
+{
+ decode_blender_header(fd);
+
+ if (fd->flags & FD_FLAGS_FILE_OK) {
+ if (!read_file_dna(fd)) {
+ *error_r = BRE_INCOMPLETE;
+ blo_freefiledata(fd);
+ fd= NULL;
+ }
+ }
+ else {
+ *error_r = BRE_NOT_A_BLEND;
+ blo_freefiledata(fd);
+ fd= NULL;
+ }
+
+ return fd;
+}
+
+/* cannot be called with relative paths anymore! */
+/* on each new library added, it now checks for the current FileData and expands relativeness */
+FileData *blo_openblenderfile(char *name, BlendReadError *error_r)
+{
+ gzFile gzfile;
+
+ gzfile= gzopen(name, "rb");
+
+ if (NULL == gzfile) {
+ *error_r = BRE_UNABLE_TO_OPEN;
+ return NULL;
+ } else {
+ FileData *fd = filedata_new();
+ fd->gzfiledes = gzfile;
+ BLI_strncpy(fd->filename, name, sizeof(fd->filename)); // now only in use by library append
+ fd->read = fd_read_gzip_from_file;
+
+ return blo_decode_and_check(fd, error_r);
+ }
+}
+
+FileData *blo_openblendermemory(void *mem, int memsize, BlendReadError *error_r)
+{
+ if (!mem || memsize<SIZEOFBLENDERHEADER) {
+ *error_r = mem?BRE_UNABLE_TO_READ:BRE_UNABLE_TO_OPEN;
+ return NULL;
+ } else {
+ FileData *fd= filedata_new();
+ fd->buffer= mem;
+ fd->buffersize= memsize;
+ fd->read= fd_read_from_memory;
+ fd->flags|= FD_FLAGS_NOT_MY_BUFFER;
+
+ return blo_decode_and_check(fd, error_r);
+ }
+}
+
+FileData *blo_openblendermemfile(MemFile *memfile, BlendReadError *error_r)
+{
+ if (!memfile) {
+ *error_r = BRE_UNABLE_TO_OPEN;
+ return NULL;
+ } else {
+ FileData *fd= filedata_new();
+ fd->memfile= memfile;
+
+ fd->read= fd_read_from_memfile;
+ fd->flags|= FD_FLAGS_NOT_MY_BUFFER;
+
+ return blo_decode_and_check(fd, error_r);
+ }
+}
+
+
+void blo_freefiledata(FileData *fd)
+{
+ if (fd) {
+
+ if (fd->filedes != -1) {
+ close(fd->filedes);
+ }
+
+ if (fd->gzfiledes != NULL)
+ {
+ gzclose(fd->gzfiledes);
+ }
+
+ if (fd->buffer && !(fd->flags & FD_FLAGS_NOT_MY_BUFFER)) {
+ MEM_freeN(fd->buffer);
+ fd->buffer = 0;
+ }
+
+ // Free all BHeadN data blocks
+ BLI_freelistN(&fd->listbase);
+
+ if (fd->memsdna)
+ dna_freestructDNA(fd->memsdna);
+ if (fd->filesdna)
+ dna_freestructDNA(fd->filesdna);
+ if (fd->compflags)
+ MEM_freeN(fd->compflags);
+
+ if (fd->datamap)
+ oldnewmap_free(fd->datamap);
+ if (fd->globmap)
+ oldnewmap_free(fd->globmap);
+ if (fd->imamap)
+ oldnewmap_free(fd->imamap);
+ if (fd->libmap && !(fd->flags & FD_FLAGS_NOT_MY_LIBMAP))
+ oldnewmap_free(fd->libmap);
+
+ MEM_freeN(fd);
+ }
+}
+
+/* ************ DIV ****************** */
+
+int BLO_has_bfile_extension(char *str)
+{
+ return (BLI_testextensie(str, ".ble") || BLI_testextensie(str, ".blend")||BLI_testextensie(str, ".blend.gz"));
+}
+
+/* ************** OLD POINTERS ******************* */
+
+static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
+{
+ return oldnewmap_lookup_and_inc(fd->datamap, adr);
+}
+
+static void *newglobadr(FileData *fd, void *adr) /* direct datablocks with global linking */
+{
+ return oldnewmap_lookup_and_inc(fd->globmap, adr);
+}
+
+static void *newimaadr(FileData *fd, void *adr) /* used to restore image data after undo */
+{
+ if(fd->imamap && adr)
+ return oldnewmap_lookup_and_inc(fd->imamap, adr);
+ return NULL;
+}
+
+
+static void *newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
+{
+ return oldnewmap_liblookup(fd->libmap, adr, lib);
+}
+
+static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */
+{
+ ID *id= newlibadr(fd, lib, adr);
+
+ if(id)
+ id->us++;
+
+ return id;
+}
+
+static void change_idid_adr_fd(FileData *fd, void *old, void *new)
+{
+ int i;
+
+ for (i=0; i<fd->libmap->nentries; i++) {
+ OldNew *entry= &fd->libmap->entries[i];
+
+ if (old==entry->newp && entry->nr==ID_ID) {
+ entry->newp= new;
+ if(new) entry->nr= GS( ((ID *)new)->name );
+ break;
+ }
+ }
+}
+
+static void change_idid_adr(ListBase *mainlist, FileData *basefd, void *old, void *new)
+{
+ Main *mainptr;
+
+ for(mainptr= mainlist->first; mainptr; mainptr= mainptr->next) {
+ FileData *fd;
+
+ if(mainptr->curlib) fd= mainptr->curlib->filedata;
+ else fd= basefd;
+
+ if(fd) {
+ change_idid_adr_fd(fd, old, new);
+ }
+ }
+}
+
+/* assumed; G.main still exists */
+void blo_make_image_pointer_map(FileData *fd)
+{
+ Image *ima= G.main->image.first;
+ Scene *sce= G.main->scene.first;
+
+ fd->imamap= oldnewmap_new();
+
+ for(;ima; ima= ima->id.next) {
+ Link *ibuf= ima->ibufs.first;
+ for(; ibuf; ibuf= ibuf->next)
+ oldnewmap_insert(fd->imamap, ibuf, ibuf, 0);
+ }
+ for(; sce; sce= sce->id.next) {
+ if(sce->nodetree) {
+ bNode *node;
+ for(node= sce->nodetree->nodes.first; node; node= node->next)
+ oldnewmap_insert(fd->imamap, node->preview, node->preview, 0);
+ }
+ }
+}
+
+/* set G.main image ibufs to zero if it has been restored */
+/* this works because freeing G.main only happens after this call */
+void blo_end_image_pointer_map(FileData *fd)
+{
+ OldNew *entry= fd->imamap->entries;
+ Image *ima= G.main->image.first;
+ Scene *sce= G.main->scene.first;
+ int i;
+
+ /* used entries were restored, so we put them to zero */
+ for (i=0; i<fd->imamap->nentries; i++, entry++) {
+ if (entry->nr>0)
+ entry->newp= NULL;
+ }
+
+ for(;ima; ima= ima->id.next) {
+ Link *ibuf, *next;
+
+ /* this mirrors direct_link_image */
+ for(ibuf= ima->ibufs.first; ibuf; ibuf= next) {
+ next= ibuf->next;
+ if(NULL==newimaadr(fd, ibuf)) { /* so was restored */
+ BLI_remlink(&ima->ibufs, ibuf);
+ ima->bindcode= 0;
+ }
+ }
+ }
+ for(; sce; sce= sce->id.next) {
+ if(sce->nodetree) {
+ bNode *node;
+ for(node= sce->nodetree->nodes.first; node; node= node->next)
+ node->preview= newimaadr(fd, node->preview);
+ }
+ }
+}
+
+/* undo file support: add all library pointers in lookup */
+void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd)
+{
+ Main *ptr= mainlist->first;
+ ListBase *lbarray[MAX_LIBARRAY];
+
+ for(ptr= ptr->next; ptr; ptr= ptr->next) {
+ int i= set_listbasepointers(ptr, lbarray);
+ while(i--) {
+ ID *id;
+ for(id= lbarray[i]->first; id; id= id->next)
+ oldnewmap_insert(fd->libmap, id, id, GS(id->name));
+ }
+ }
+}
+
+
+/* ********** END OLD POINTERS ****************** */
+/* ********** READ FILE ****************** */
+
+static void switch_endian_structs(struct SDNA *filesdna, BHead *bhead)
+{
+ int blocksize, nblocks;
+ char *data;
+
+ data= (char *)(bhead+1);
+ blocksize= filesdna->typelens[ filesdna->structs[bhead->SDNAnr][0] ];
+
+ nblocks= bhead->nr;
+ while(nblocks--) {
+ dna_switch_endian_struct(filesdna, bhead->SDNAnr, data);
+
+ data+= blocksize;
+ }
+}
+
+static void *read_struct(FileData *fd, BHead *bh, char *blockname)
+{
+ void *temp= NULL;
+
+ if (bh->len) {
+ /* switch is based on file dna */
+ if (bh->SDNAnr && (fd->flags & FD_FLAGS_SWITCH_ENDIAN))
+ switch_endian_structs(fd->filesdna, bh);
+
+ if (fd->compflags[bh->SDNAnr]) { /* flag==0: doesn't exist anymore */
+ if(fd->compflags[bh->SDNAnr]==2) {
+ temp= dna_reconstruct(fd->memsdna, fd->filesdna, fd->compflags, bh->SDNAnr, bh->nr, (bh+1));
+ } else {
+ temp= MEM_mallocN(bh->len, blockname);
+ memcpy(temp, (bh+1), bh->len);
+ }
+ }
+ }
+
+ return temp;
+}
+
+static void link_list(FileData *fd, ListBase *lb) /* only direct data */
+{
+ Link *ln, *prev;
+
+ if(lb->first==NULL) return;
+
+ lb->first= newdataadr(fd, lb->first);
+ ln= lb->first;
+ prev= NULL;
+ while(ln) {
+ ln->next= newdataadr(fd, ln->next);
+ ln->prev= prev;
+ prev= ln;
+ ln= ln->next;
+ }
+ lb->last= prev;
+}
+
+static void link_glob_list(FileData *fd, ListBase *lb) /* for glob data */
+{
+ Link *ln, *prev;
+ void *poin;
+
+ if(lb->first==0) return;
+ poin= newdataadr(fd, lb->first);
+ if(lb->first) {
+ oldnewmap_insert(fd->globmap, lb->first, poin, 0);
+ }
+ lb->first= poin;
+
+ ln= lb->first;
+ prev= 0;
+ while(ln) {
+ poin= newdataadr(fd, ln->next);
+ if(ln->next) {
+ oldnewmap_insert(fd->globmap, ln->next, poin, 0);
+ }
+ ln->next= poin;
+ ln->prev= prev;
+ prev= ln;
+ ln= ln->next;
+ }
+ lb->last= prev;
+}
+
+static void test_pointer_array(FileData *fd, void **mat)
+{
+#if defined(WIN32) && !defined(FREE_WINDOWS)
+ __int64 *lpoin, *lmat;
+#else
+ long long *lpoin, *lmat;
+#endif
+ int len, *ipoin, *imat;
+
+ /* manually convert the pointer array in
+ * the old dna format to a pointer array in
+ * the new dna format.
+ */
+ if(*mat) {
+ len= MEM_allocN_len(*mat)/fd->filesdna->pointerlen;
+
+ if(fd->filesdna->pointerlen==8 && fd->memsdna->pointerlen==4) {
+ ipoin=imat= MEM_mallocN( len*4, "newmatar");
+ lpoin= *mat;
+
+ while(len-- > 0) {
+ if((fd->flags & FD_FLAGS_SWITCH_ENDIAN))
+ SWITCH_LONGINT(*lpoin);
+ *ipoin= (int) ((*lpoin) >> 3);
+ ipoin++;
+ lpoin++;
+ }
+ MEM_freeN(*mat);
+ *mat= imat;
+ }
+
+ if(fd->filesdna->pointerlen==4 && fd->memsdna->pointerlen==8) {
+ lpoin=lmat= MEM_mallocN( len*8, "newmatar");
+ ipoin= *mat;
+
+ while(len-- > 0) {
+ *lpoin= *ipoin;
+ ipoin++;
+ lpoin++;
+ }
+ MEM_freeN(*mat);
+ *mat= lmat;
+ }
+ }
+}
+
+/* ************ READ ID Properties *************** */
+
+void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, void *fd);
+void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, void *fd);
+
+void IDP_DirectLinkArray(IDProperty *prop, int switch_endian, void *fd)
+{
+ int i;
+
+ /*since we didn't save the extra buffer, set totallen to len.*/
+ prop->totallen = prop->len;
+ prop->data.pointer = newdataadr(fd, prop->data.pointer);
+
+ if (switch_endian) {
+ for (i=0; i<prop->len; i++) {
+ SWITCH_INT(((int*)prop->data.pointer)[i]);
+ }
+ }
+}
+
+void IDP_DirectLinkString(IDProperty *prop, int switch_endian, void *fd)
+{
+ /*since we didn't save the extra string buffer, set totallen to len.*/
+ prop->totallen = prop->len;
+ prop->data.pointer = newdataadr(fd, prop->data.pointer);
+}
+
+void IDP_DirectLinkGroup(IDProperty *prop, int switch_endian, void *fd)
+{
+ ListBase *lb = &prop->data.group;
+ IDProperty *loop;
+
+ link_list(fd, lb);
+
+ /*Link child id properties now*/
+ for (loop=prop->data.group.first; loop; loop=loop->next) {
+ IDP_DirectLinkProperty(loop, switch_endian, fd);
+ }
+}
+
+void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, void *fd)
+{
+ switch (prop->type) {
+ case IDP_GROUP:
+ IDP_DirectLinkGroup(prop, switch_endian, fd);
+ break;
+ case IDP_STRING:
+ IDP_DirectLinkString(prop, switch_endian, fd);
+ break;
+ case IDP_ARRAY:
+ IDP_DirectLinkArray(prop, switch_endian, fd);
+ break;
+ }
+}
+
+/*stub function*/
+void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, void *fd)
+{
+}
+
+/* ************ READ Brush *************** */
+/* library brush linking after fileread */
+static void lib_link_brush(FileData *fd, Main *main)
+{
+ Brush *brush;
+ MTex *mtex;
+ int a;
+
+ /* only link ID pointers */
+ for(brush= main->brush.first; brush; brush= brush->id.next) {
+ if(brush->id.flag & LIB_NEEDLINK) {
+ brush->id.flag -= LIB_NEEDLINK;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= brush->mtex[a];
+ if(mtex)
+ mtex->tex= newlibadr_us(fd, brush->id.lib, mtex->tex);
+ }
+ }
+ }
+}
+
+static void direct_link_brush(FileData *fd, Brush *brush)
+{
+ /* brush itself has been read */
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++)
+ brush->mtex[a]= newdataadr(fd, brush->mtex[a]);
+}
+
+/* ************ READ CurveMapping *************** */
+
+/* cuma itself has been read! */
+static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap)
+{
+ int a;
+
+ /* flag seems to be able to hang? Maybe old files... not bad to clear anyway */
+ cumap->flag &= ~CUMA_PREMULLED;
+
+ for(a=0; a<CM_TOT; a++) {
+ cumap->cm[a].curve= newdataadr(fd, cumap->cm[a].curve);
+ cumap->cm[a].table= NULL;
+ }
+}
+
+/* ************ READ NODE TREE *************** */
+
+/* singe node tree (also used for material/scene trees), ntree is not NULL */
+static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
+{
+ bNode *node;
+
+ for(node= ntree->nodes.first; node; node= node->next)
+ node->id= newlibadr_us(fd, id->lib, node->id);
+}
+
+/* library ntree linking after fileread */
+static void lib_link_nodetree(FileData *fd, Main *main)
+{
+ bNodeTree *ntree;
+
+ /* only link ID pointers */
+ for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) {
+ if(ntree->id.flag & LIB_NEEDLINK) {
+ ntree->id.flag -= LIB_NEEDLINK;
+ lib_link_ntree(fd, &ntree->id, ntree);
+ }
+ }
+}
+
+/* verify types for nodes and groups, all data has to be read */
+static void lib_verify_nodetree(Main *main)
+{
+ Scene *sce;
+ Material *ma;
+ bNodeTree *ntree;
+
+ /* now create the own typeinfo structs an verify nodes */
+ /* here we still assume no groups in groups */
+ for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) {
+ ntreeVerifyTypes(ntree); /* internal nodes, no groups! */
+ ntreeMakeOwnType(ntree); /* for group usage */
+ }
+
+ /* now verify all types in material trees, groups are set OK now */
+ for(ma= main->mat.first; ma; ma= ma->id.next) {
+ if(ma->nodetree)
+ ntreeVerifyTypes(ma->nodetree);
+ }
+ /* and scene trees */
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ if(sce->nodetree)
+ ntreeVerifyTypes(sce->nodetree);
+ }
+}
+
+
+
+/* ntree itself has been read! */
+static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
+{
+ /* note: writing and reading goes in sync, for speed */
+ bNode *node;
+ bNodeSocket *sock;
+ bNodeLink *link;
+
+ ntree->init= 0; /* to set callbacks and force setting types */
+ ntree->owntype= NULL;
+ ntree->timecursor= NULL;
+
+ link_list(fd, &ntree->nodes);
+ for(node= ntree->nodes.first; node; node= node->next) {
+ node->storage= newdataadr(fd, node->storage);
+ if(node->storage) {
+
+ /* could be handlerized at some point */
+ if(ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
+ direct_link_curvemapping(fd, node->storage);
+ else if(ntree->type==NTREE_COMPOSIT) {
+ if( ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB))
+ direct_link_curvemapping(fd, node->storage);
+ else if(ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
+ ((ImageUser *)node->storage)->ok= 1;
+ }
+ }
+ link_list(fd, &node->inputs);
+ link_list(fd, &node->outputs);
+ }
+ link_list(fd, &ntree->links);
+
+ /* and we connect the rest */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ node->preview= newimaadr(fd, node->preview);
+ node->lasty= 0;
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ sock->link= newdataadr(fd, sock->link);
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ sock->ns.data= NULL;
+ }
+ for(link= ntree->links.first; link; link= link->next) {
+ link->fromnode= newdataadr(fd, link->fromnode);
+ link->tonode= newdataadr(fd, link->tonode);
+ link->fromsock= newdataadr(fd, link->fromsock);
+ link->tosock= newdataadr(fd, link->tosock);
+ }
+
+ /* type verification is in lib-link */
+}
+
+/* ************ READ PACKEDFILE *************** */
+
+static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
+{
+ PackedFile *pf= newdataadr(fd, oldpf);
+
+ if (pf) {
+ pf->data= newdataadr(fd, pf->data);
+ }
+
+ 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 < PREVIEW_MIPMAPS; ++i) {
+ if (prv->rect[i]) {
+ prv->rect[i] = newdataadr(fd, prv->rect[i]);
+ }
+ }
+ }
+
+ return prv;
+}
+
+/* ************ READ SCRIPTLINK *************** */
+
+static void lib_link_scriptlink(FileData *fd, ID *id, ScriptLink *slink)
+{
+ int i;
+
+ for(i=0; i<slink->totscript; i++) {
+ slink->scripts[i]= newlibadr(fd, id->lib, slink->scripts[i]);
+ }
+}
+
+static void direct_link_scriptlink(FileData *fd, ScriptLink *slink)
+{
+ slink->scripts= newdataadr(fd, slink->scripts);
+ test_pointer_array(fd, (void **)&slink->scripts);
+
+ slink->flag= newdataadr(fd, slink->flag);
+
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ int a;
+
+ for(a=0; a<slink->totscript; a++) {
+ SWITCH_SHORT(slink->flag[a]);
+ }
+ }
+}
+
+/* ************ READ ARMATURE ***************** */
+
+static void lib_link_nlastrips(FileData *fd, ID *id, ListBase *striplist)
+{
+ bActionStrip *strip;
+ bActionModifier *amod;
+
+ for (strip=striplist->first; strip; strip=strip->next){
+ strip->object = newlibadr(fd, id->lib, strip->object);
+ strip->act = newlibadr_us(fd, id->lib, strip->act);
+ strip->ipo = newlibadr(fd, id->lib, strip->ipo);
+ for(amod= strip->modifiers.first; amod; amod= amod->next)
+ amod->ob= newlibadr(fd, id->lib, amod->ob);
+ }
+}
+
+static void lib_link_constraint_channels(FileData *fd, ID *id, ListBase *chanbase)
+{
+ bConstraintChannel *chan;
+
+ for (chan=chanbase->first; chan; chan=chan->next){
+ chan->ipo = newlibadr_us(fd, id->lib, chan->ipo);
+ }
+}
+
+static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
+{
+ bConstraint *con;
+
+ for (con = conlist->first; con; con=con->next) {
+ /* patch for error introduced by changing constraints (dunno how) */
+ /* if con->data type changes, dna cannot resolve the pointer! (ton) */
+ if(con->data==NULL) {
+ con->type= CONSTRAINT_TYPE_NULL;
+ }
+
+ switch (con->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data= (bPythonConstraint*)con->data;
+ bConstraintTarget *ct;
+
+ for (ct= data->targets.first; ct; ct= ct->next)
+ ct->tar = newlibadr(fd, id->lib, ct->tar);
+
+ data->text = newlibadr(fd, id->lib, data->text);
+ //IDP_LibLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+ break;
+ case CONSTRAINT_TYPE_ACTION:
+ {
+ bActionConstraint *data;
+ data= ((bActionConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ data->act = newlibadr(fd, id->lib, data->act);
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCLIKE:
+ {
+ bLocateLikeConstraint *data;
+ data= ((bLocateLikeConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data;
+ data= ((bRotateLikeConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_SIZELIKE:
+ {
+ bSizeLikeConstraint *data;
+ data= ((bSizeLikeConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ {
+ bKinematicConstraint *data;
+ data = ((bKinematicConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ data->poletar = newlibadr(fd, id->lib, data->poletar);
+ }
+ break;
+ case CONSTRAINT_TYPE_TRACKTO:
+ {
+ bTrackToConstraint *data;
+ data = ((bTrackToConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_MINMAX:
+ {
+ bMinMaxConstraint *data;
+ data = ((bMinMaxConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCKTRACK:
+ {
+ bLockTrackConstraint *data;
+ data= ((bLockTrackConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_FOLLOWPATH:
+ {
+ bFollowPathConstraint *data;
+ data= ((bFollowPathConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ {
+ bStretchToConstraint *data;
+ data= ((bStretchToConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_RIGIDBODYJOINT:
+ {
+ bRigidBodyJointConstraint *data;
+ data= ((bRigidBodyJointConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_CLAMPTO:
+ {
+ bClampToConstraint *data;
+ data= ((bClampToConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_CHILDOF:
+ {
+ bChildOfConstraint *data;
+ data= ((bChildOfConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ {
+ bTransformConstraint *data;
+ data= ((bTransformConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_NULL:
+ break;
+ }
+ }
+}
+
+static void direct_link_constraints(FileData *fd, ListBase *lb)
+{
+ bConstraint *cons;
+
+ link_list(fd, lb);
+ for (cons=lb->first; cons; cons=cons->next) {
+ cons->data = newdataadr(fd, cons->data);
+ if (cons->type == CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data= cons->data;
+ link_list(fd, &data->targets);
+ data->prop = newdataadr(fd, data->prop);
+ IDP_DirectLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+ }
+}
+
+static void lib_link_pose(FileData *fd, Object *ob, bPose *pose)
+{
+ bPoseChannel *pchan;
+ bArmature *arm= ob->data;
+ int rebuild;
+
+ if (!pose || !arm)
+ return;
+
+ /* always rebuild to match proxy or lib changes */
+ rebuild= ob->proxy || (ob->id.lib==NULL && arm->id.lib);
+
+ for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
+ lib_link_constraints(fd, (ID *)ob, &pchan->constraints);
+
+ /* hurms... loop in a loop, but yah... later... (ton) */
+ pchan->bone= get_named_bone(arm, pchan->name);
+
+ pchan->custom= newlibadr(fd, arm->id.lib, pchan->custom);
+ if(pchan->bone==NULL)
+ rebuild= 1;
+ else if(ob->id.lib==NULL && arm->id.lib) {
+ /* local pose selection copied to armature, bit hackish */
+ pchan->bone->flag &= ~(BONE_SELECTED|BONE_ACTIVE);
+ pchan->bone->flag |= pchan->selectflag;
+ }
+ }
+
+ if(rebuild) {
+ ob->recalc= OB_RECALC;
+ pose->flag |= POSE_RECALC;
+ }
+}
+
+static void lib_link_armature(FileData *fd, Main *main)
+{
+ bArmature *arm;
+
+ arm= main->armature.first;
+
+ while(arm) {
+ if(arm->id.flag & LIB_NEEDLINK) {
+ arm->id.flag -= LIB_NEEDLINK;
+ }
+ arm= arm->id.next;
+ }
+}
+
+static void lib_link_action(FileData *fd, Main *main)
+{
+ bAction *act;
+ bActionChannel *chan;
+
+ act= main->action.first;
+ while(act) {
+ if(act->id.flag & LIB_NEEDLINK) {
+ act->id.flag -= LIB_NEEDLINK;
+
+ for (chan=act->chanbase.first; chan; chan=chan->next) {
+ chan->ipo= newlibadr_us(fd, act->id.lib, chan->ipo);
+ lib_link_constraint_channels(fd, &act->id, &chan->constraintChannels);
+ }
+
+ }
+ act= act->id.next;
+ }
+}
+
+static void direct_link_bones(FileData *fd, Bone* bone)
+{
+ Bone *child;
+
+ bone->parent= newdataadr(fd, bone->parent);
+
+ link_list(fd, &bone->childbase);
+
+ for (child=bone->childbase.first; child; child=child->next) {
+ direct_link_bones(fd, child);
+ }
+}
+
+
+static void direct_link_action(FileData *fd, bAction *act)
+{
+ bActionChannel *achan;
+
+ link_list(fd, &act->chanbase);
+
+ for (achan = act->chanbase.first; achan; achan=achan->next)
+ link_list(fd, &achan->constraintChannels);
+
+}
+
+static void direct_link_armature(FileData *fd, bArmature *arm)
+{
+ Bone *bone;
+
+ link_list(fd, &arm->bonebase);
+
+ bone=arm->bonebase.first;
+ while (bone) {
+ direct_link_bones(fd, bone);
+ bone=bone->next;
+ }
+}
+
+/* ************ READ CAMERA ***************** */
+
+static void lib_link_camera(FileData *fd, Main *main)
+{
+ Camera *ca;
+
+ ca= main->camera.first;
+ while(ca) {
+ if(ca->id.flag & LIB_NEEDLINK) {
+
+ ca->ipo= newlibadr_us(fd, ca->id.lib, ca->ipo);
+
+ ca->dof_ob= newlibadr_us(fd, ca->id.lib, ca->dof_ob);
+
+ lib_link_scriptlink(fd, &ca->id, &ca->scriptlink);
+
+ ca->id.flag -= LIB_NEEDLINK;
+ }
+ ca= ca->id.next;
+ }
+}
+
+static void direct_link_camera(FileData *fd, Camera *ca)
+{
+ direct_link_scriptlink(fd, &ca->scriptlink);
+}
+
+
+/* ************ READ LAMP ***************** */
+
+static void lib_link_lamp(FileData *fd, Main *main)
+{
+ Lamp *la;
+ MTex *mtex;
+ int a;
+
+ la= main->lamp.first;
+ while(la) {
+ if(la->id.flag & LIB_NEEDLINK) {
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= la->mtex[a];
+ if(mtex) {
+ mtex->tex= newlibadr_us(fd, la->id.lib, mtex->tex);
+ mtex->object= newlibadr(fd, la->id.lib, mtex->object);
+ }
+ }
+
+ la->ipo= newlibadr_us(fd, la->id.lib, la->ipo);
+
+ lib_link_scriptlink(fd, &la->id, &la->scriptlink);
+
+ la->id.flag -= LIB_NEEDLINK;
+ }
+ la= la->id.next;
+ }
+}
+
+static void direct_link_lamp(FileData *fd, Lamp *la)
+{
+ int a;
+
+ direct_link_scriptlink(fd, &la->scriptlink);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ la->mtex[a]= newdataadr(fd, la->mtex[a]);
+ }
+
+ la->curfalloff= newdataadr(fd, la->curfalloff);
+ if(la->curfalloff)
+ direct_link_curvemapping(fd, la->curfalloff);
+
+ la->preview = direct_link_preview_image(fd, la->preview);
+}
+
+/* ************ READ keys ***************** */
+
+static void lib_link_key(FileData *fd, Main *main)
+{
+ Key *key;
+
+ key= main->key.first;
+ while(key) {
+ if(key->id.flag & LIB_NEEDLINK) {
+
+ key->ipo= newlibadr_us(fd, key->id.lib, key->ipo);
+ key->from= newlibadr(fd, key->id.lib, key->from);
+
+ key->id.flag -= LIB_NEEDLINK;
+ }
+ key= key->id.next;
+ }
+}
+
+static void switch_endian_keyblock(Key *key, KeyBlock *kb)
+{
+ int elemsize, a, b;
+ char *data, *poin, *cp;
+
+ elemsize= key->elemsize;
+ data= kb->data;
+
+ for(a=0; a<kb->totelem; a++) {
+
+ cp= key->elemstr;
+ poin= data;
+
+ while( cp[0] ) { /* cp[0]==amount */
+
+ switch(cp[1]) { /* cp[1]= type */
+ case IPO_FLOAT:
+ case IPO_BPOINT:
+ case IPO_BEZTRIPLE:
+ b= cp[0];
+ while(b--) {
+ SWITCH_INT((*poin));
+ poin+= 4;
+ }
+ break;
+ }
+
+ cp+= 2;
+
+ }
+ data+= elemsize;
+ }
+}
+
+static void direct_link_key(FileData *fd, Key *key)
+{
+ KeyBlock *kb;
+
+ link_list(fd, &(key->block));
+
+ key->refkey= newdataadr(fd, key->refkey);
+
+ kb= key->block.first;
+ while(kb) {
+
+ kb->data= newdataadr(fd, kb->data);
+
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN)
+ switch_endian_keyblock(key, kb);
+
+ kb= kb->next;
+ }
+}
+
+/* ************ READ mball ***************** */
+
+static void lib_link_mball(FileData *fd, Main *main)
+{
+ MetaBall *mb;
+ int a;
+
+ mb= main->mball.first;
+ while(mb) {
+ if(mb->id.flag & LIB_NEEDLINK) {
+
+ for(a=0; a<mb->totcol; a++) mb->mat[a]= newlibadr_us(fd, mb->id.lib, mb->mat[a]);
+
+ mb->ipo= newlibadr_us(fd, mb->id.lib, mb->ipo);
+
+ mb->id.flag -= LIB_NEEDLINK;
+ }
+ mb= mb->id.next;
+ }
+}
+
+static void direct_link_mball(FileData *fd, MetaBall *mb)
+{
+ mb->mat= newdataadr(fd, mb->mat);
+ test_pointer_array(fd, (void **)&mb->mat);
+
+ link_list(fd, &(mb->elems));
+
+ mb->disp.first= mb->disp.last= 0;
+
+ mb->bb= 0;
+}
+
+/* ************ READ WORLD ***************** */
+
+static void lib_link_world(FileData *fd, Main *main)
+{
+ World *wrld;
+ MTex *mtex;
+ int a;
+
+ wrld= main->world.first;
+ while(wrld) {
+ if(wrld->id.flag & LIB_NEEDLINK) {
+
+ wrld->ipo= newlibadr_us(fd, wrld->id.lib, wrld->ipo);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= wrld->mtex[a];
+ if(mtex) {
+ mtex->tex= newlibadr_us(fd, wrld->id.lib, mtex->tex);
+ mtex->object= newlibadr(fd, wrld->id.lib, mtex->object);
+ }
+ }
+
+ lib_link_scriptlink(fd, &wrld->id, &wrld->scriptlink);
+
+ wrld->id.flag -= LIB_NEEDLINK;
+ }
+ wrld= wrld->id.next;
+ }
+}
+
+static void direct_link_world(FileData *fd, World *wrld)
+{
+ int a;
+
+ direct_link_scriptlink(fd, &wrld->scriptlink);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ wrld->mtex[a]= newdataadr(fd, wrld->mtex[a]);
+ }
+ wrld->preview = direct_link_preview_image(fd, wrld->preview);
+}
+
+
+/* ************ READ IPO ***************** */
+
+static void lib_link_ipo(FileData *fd, Main *main)
+{
+ Ipo *ipo;
+
+ ipo= main->ipo.first;
+ while(ipo) {
+ if(ipo->id.flag & LIB_NEEDLINK) {
+ IpoCurve *icu;
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->driver)
+ icu->driver->ob= newlibadr(fd, ipo->id.lib, icu->driver->ob);
+ }
+ ipo->id.flag -= LIB_NEEDLINK;
+ }
+ ipo= ipo->id.next;
+ }
+}
+
+static void direct_link_ipo(FileData *fd, Ipo *ipo)
+{
+ IpoCurve *icu;
+
+ link_list(fd, &(ipo->curve));
+ icu= ipo->curve.first;
+ while(icu) {
+ icu->bezt= newdataadr(fd, icu->bezt);
+ icu->bp= newdataadr(fd, icu->bp);
+ icu->driver= newdataadr(fd, icu->driver);
+ icu= icu->next;
+ }
+}
+
+/* ************ READ VFONT ***************** */
+
+static void lib_link_vfont(FileData *fd, Main *main)
+{
+ VFont *vf;
+
+ vf= main->vfont.first;
+ while(vf) {
+ if(vf->id.flag & LIB_NEEDLINK) {
+ vf->id.flag -= LIB_NEEDLINK;
+ }
+ vf= vf->id.next;
+ }
+}
+
+static void direct_link_vfont(FileData *fd, VFont *vf)
+{
+ vf->data= NULL;
+ vf->packedfile= direct_link_packedfile(fd, vf->packedfile);
+}
+
+/* ************ READ TEXT ****************** */
+
+static void lib_link_text(FileData *fd, Main *main)
+{
+ Text *text;
+
+ text= main->text.first;
+ while(text) {
+ if(text->id.flag & LIB_NEEDLINK) {
+ text->id.flag -= LIB_NEEDLINK;
+ }
+ text= text->id.next;
+ }
+}
+
+static void direct_link_text(FileData *fd, Text *text)
+{
+ TextLine *ln;
+
+ text->name= newdataadr(fd, text->name);
+
+ text->undo_pos= -1;
+ text->undo_len= TXT_INIT_UNDO;
+ text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
+
+ text->compiled= NULL;
+
+/*
+ if(text->flags & TXT_ISEXT) {
+ reopen_text(text);
+ } else {
+*/
+
+ link_list(fd, &text->lines);
+
+ text->curl= newdataadr(fd, text->curl);
+ text->sell= newdataadr(fd, text->sell);
+
+ ln= text->lines.first;
+ while(ln) {
+ ln->line= newdataadr(fd, ln->line);
+ ln->format= NULL;
+
+ if (ln->len != (int) strlen(ln->line)) {
+ printf("Error loading text, line lengths differ\n");
+ ln->len = strlen(ln->line);
+ }
+
+ ln= ln->next;
+ }
+
+ text->flags = (text->flags|TXT_ISTMP) & ~TXT_ISEXT;
+
+ text->id.us= 1;
+}
+
+/* ************ READ IMAGE ***************** */
+
+static void lib_link_image(FileData *fd, Main *main)
+{
+ Image *ima;
+
+ ima= main->image.first;
+ while (ima) {
+ if(ima->id.flag & LIB_NEEDLINK) {
+ if (ima->id.properties) IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ ima->id.flag -= LIB_NEEDLINK;
+ }
+ ima= ima->id.next;
+ }
+}
+
+static void link_ibuf_list(FileData *fd, ListBase *lb)
+{
+ Link *ln, *prev;
+
+ if(lb->first==NULL) return;
+
+ lb->first= newimaadr(fd, lb->first);
+ ln= lb->first;
+ prev= NULL;
+ while(ln) {
+ ln->next= newimaadr(fd, ln->next);
+ ln->prev= prev;
+ prev= ln;
+ ln= ln->next;
+ }
+ lb->last= prev;
+}
+
+static void direct_link_image(FileData *fd, Image *ima)
+{
+ /* for undo system, pointers could be restored */
+ if(fd->imamap)
+ link_ibuf_list(fd, &ima->ibufs);
+ else
+ ima->ibufs.first= ima->ibufs.last= NULL;
+
+ /* if not restored, we keep the binded opengl index */
+ if(ima->ibufs.first==NULL)
+ ima->bindcode= 0;
+
+ ima->anim= NULL;
+ ima->rr= NULL;
+ ima->repbind= NULL;
+
+ ima->packedfile = direct_link_packedfile(fd, ima->packedfile);
+ ima->preview = direct_link_preview_image(fd, ima->preview);
+ ima->ok= 1;
+}
+
+
+/* ************ READ CURVE ***************** */
+
+static void lib_link_curve(FileData *fd, Main *main)
+{
+ Curve *cu;
+ int a;
+
+ cu= main->curve.first;
+ while(cu) {
+ if(cu->id.flag & LIB_NEEDLINK) {
+
+ for(a=0; a<cu->totcol; a++) cu->mat[a]= newlibadr_us(fd, cu->id.lib, cu->mat[a]);
+
+ cu->bevobj= newlibadr(fd, cu->id.lib, cu->bevobj);
+ cu->taperobj= newlibadr(fd, cu->id.lib, cu->taperobj);
+ cu->textoncurve= newlibadr(fd, cu->id.lib, cu->textoncurve);
+ cu->vfont= newlibadr_us(fd, cu->id.lib, cu->vfont);
+ cu->vfontb= newlibadr_us(fd, cu->id.lib, cu->vfontb);
+ cu->vfonti= newlibadr_us(fd, cu->id.lib, cu->vfonti);
+ cu->vfontbi= newlibadr_us(fd, cu->id.lib, cu->vfontbi);
+
+ cu->ipo= newlibadr_us(fd, cu->id.lib, cu->ipo);
+ cu->key= newlibadr_us(fd, cu->id.lib, cu->key);
+
+ cu->id.flag -= LIB_NEEDLINK;
+ }
+ cu= cu->id.next;
+ }
+}
+
+
+static void switch_endian_knots(Nurb *nu)
+{
+ int len;
+
+ if(nu->knotsu) {
+ len= KNOTSU(nu);
+ while(len--) {
+ SWITCH_INT(nu->knotsu[len]);
+ }
+ }
+ if(nu->knotsv) {
+ len= KNOTSV(nu);
+ while(len--) {
+ SWITCH_INT(nu->knotsv[len]);
+ }
+ }
+}
+
+static void direct_link_curve(FileData *fd, Curve *cu)
+{
+ Nurb *nu;
+ TextBox *tb;
+
+ cu->mat= newdataadr(fd, cu->mat);
+ test_pointer_array(fd, (void **)&cu->mat);
+ cu->str= newdataadr(fd, cu->str);
+ cu->strinfo= newdataadr(fd, cu->strinfo);
+ cu->tb= newdataadr(fd, cu->tb);
+
+ if(cu->vfont==0) link_list(fd, &(cu->nurb));
+ else {
+ cu->nurb.first=cu->nurb.last= 0;
+
+ tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "TextBoxread");
+ if (cu->tb) {
+ memcpy(tb, cu->tb, cu->totbox*sizeof(TextBox));
+ MEM_freeN(cu->tb);
+ cu->tb= tb;
+ } else {
+ cu->totbox = 1;
+ cu->actbox = 1;
+ cu->tb = tb;
+ cu->tb[0].w = cu->linewidth;
+ }
+ if (cu->wordspace == 0.0) cu->wordspace = 1.0;
+ }
+
+ cu->bev.first=cu->bev.last= 0;
+ cu->disp.first=cu->disp.last= 0;
+ cu->path= 0;
+
+ nu= cu->nurb.first;
+ while(nu) {
+ nu->bezt= newdataadr(fd, nu->bezt);
+ nu->bp= newdataadr(fd, nu->bp);
+ nu->knotsu= newdataadr(fd, nu->knotsu);
+ nu->knotsv= newdataadr(fd, nu->knotsv);
+ if (cu->vfont==0) nu->charidx= nu->mat_nr;
+
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ switch_endian_knots(nu);
+ }
+
+ nu= nu->next;
+ }
+ cu->bb= NULL;
+}
+
+/* ************ READ TEX ***************** */
+
+static void lib_link_texture(FileData *fd, Main *main)
+{
+ Tex *tex;
+
+ tex= main->tex.first;
+ while(tex) {
+ if(tex->id.flag & LIB_NEEDLINK) {
+
+ tex->ima= newlibadr_us(fd, tex->id.lib, tex->ima);
+ tex->ipo= newlibadr_us(fd, tex->id.lib, tex->ipo);
+ if(tex->env) tex->env->object= newlibadr(fd, tex->id.lib, tex->env->object);
+
+ tex->id.flag -= LIB_NEEDLINK;
+ }
+ tex= tex->id.next;
+ }
+}
+
+static void direct_link_texture(FileData *fd, Tex *tex)
+{
+ tex->plugin= newdataadr(fd, tex->plugin);
+ if(tex->plugin) {
+ tex->plugin->handle= 0;
+ open_plugin_tex(tex->plugin);
+ /* initialize data for this instance, if an initialization
+ * function exists.
+ */
+ if (tex->plugin->instance_init)
+ tex->plugin->instance_init((void *) tex->plugin->data);
+ }
+ tex->coba= newdataadr(fd, tex->coba);
+ tex->env= newdataadr(fd, tex->env);
+ if(tex->env) {
+ tex->env->ima= NULL;
+ memset(tex->env->cube, 0, 6*sizeof(void *));
+ tex->env->ok= 0;
+ }
+ tex->preview = direct_link_preview_image(fd, tex->preview);
+
+ tex->iuser.ok= 1;
+}
+
+
+
+/* ************ READ MATERIAL ***************** */
+
+static void lib_link_material(FileData *fd, Main *main)
+{
+ Material *ma;
+ MTex *mtex;
+ int a;
+
+ ma= main->mat.first;
+ while(ma) {
+ if(ma->id.flag & LIB_NEEDLINK) {
+ /*Link ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ if (ma->id.properties) IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ ma->ipo= newlibadr_us(fd, ma->id.lib, ma->ipo);
+ ma->group= newlibadr_us(fd, ma->id.lib, ma->group);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= ma->mtex[a];
+ if(mtex) {
+ mtex->tex= newlibadr_us(fd, ma->id.lib, mtex->tex);
+ mtex->object= newlibadr(fd, ma->id.lib, mtex->object);
+ }
+ }
+ lib_link_scriptlink(fd, &ma->id, &ma->scriptlink);
+
+ if(ma->nodetree)
+ lib_link_ntree(fd, &ma->id, ma->nodetree);
+
+ ma->id.flag -= LIB_NEEDLINK;
+ }
+ ma= ma->id.next;
+ }
+}
+
+static void direct_link_material(FileData *fd, Material *ma)
+{
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ ma->mtex[a]= newdataadr(fd, ma->mtex[a]);
+ }
+
+ ma->ramp_col= newdataadr(fd, ma->ramp_col);
+ ma->ramp_spec= newdataadr(fd, ma->ramp_spec);
+
+ direct_link_scriptlink(fd, &ma->scriptlink);
+
+ ma->nodetree= newdataadr(fd, ma->nodetree);
+ if(ma->nodetree)
+ direct_link_nodetree(fd, ma->nodetree);
+
+ ma->preview = direct_link_preview_image(fd, ma->preview);
+}
+
+/* ************ READ MESH ***************** */
+
+static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface)
+{
+ MTFace *tf= mtface;
+ int i;
+
+ for (i=0; i<totface; i++, tf++) {
+ tf->tpage= newlibadr(fd, me->id.lib, tf->tpage);
+ if(tf->tpage && tf->tpage->id.us==0)
+ tf->tpage->id.us= 1;
+ }
+}
+
+static void lib_link_customdata_mtface(FileData *fd, Mesh *me, CustomData *fdata, int totface)
+{
+ int i;
+ for(i=0; i<fdata->totlayer; i++) {
+ CustomDataLayer *layer = &fdata->layers[i];
+
+ if(layer->type == CD_MTFACE)
+ lib_link_mtface(fd, me, layer->data, totface);
+ }
+
+}
+
+static void lib_link_mesh(FileData *fd, Main *main)
+{
+ Mesh *me;
+
+ me= main->mesh.first;
+ while(me) {
+ if(me->id.flag & LIB_NEEDLINK) {
+ int i;
+
+ /*Link ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ if (me->id.properties) IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ /* this check added for python created meshes */
+ if(me->mat) {
+ for(i=0; i<me->totcol; i++) {
+ me->mat[i]= newlibadr_us(fd, me->id.lib, me->mat[i]);
+ }
+ }
+ else me->totcol= 0;
+
+ me->ipo= newlibadr_us(fd, me->id.lib, me->ipo);
+ me->key= newlibadr_us(fd, me->id.lib, me->key);
+ me->texcomesh= newlibadr_us(fd, me->id.lib, me->texcomesh);
+
+ lib_link_customdata_mtface(fd, me, &me->fdata, me->totface);
+ if(me->mr && me->mr->levels.first)
+ lib_link_customdata_mtface(fd, me, &me->mr->fdata,
+ ((MultiresLevel*)me->mr->levels.first)->totface);
+
+ me->id.flag -= LIB_NEEDLINK;
+ }
+ me= me->id.next;
+ }
+}
+
+static void direct_link_dverts(FileData *fd, int count, MDeformVert *mdverts)
+{
+ int i;
+
+ if (!mdverts)
+ return;
+
+ for (i=0; i<count; i++) {
+ mdverts[i].dw=newdataadr(fd, mdverts[i].dw);
+ if (!mdverts[i].dw)
+ mdverts[i].totweight=0;
+ }
+}
+
+static void direct_link_customdata(FileData *fd, CustomData *data, int count)
+{
+ int i = 0;
+
+ data->layers= newdataadr(fd, data->layers);
+
+ while (i < data->totlayer) {
+ CustomDataLayer *layer = &data->layers[i];
+
+ if (CustomData_verify_versions(data, i)) {
+ layer->data = newdataadr(fd, layer->data);
+ i++;
+ }
+ }
+}
+
+static void direct_link_mesh(FileData *fd, Mesh *mesh)
+{
+ mesh->mat= newdataadr(fd, mesh->mat);
+ test_pointer_array(fd, (void **)&mesh->mat);
+
+ mesh->mvert= newdataadr(fd, mesh->mvert);
+ mesh->medge= newdataadr(fd, mesh->medge);
+ mesh->mface= newdataadr(fd, mesh->mface);
+ mesh->tface= newdataadr(fd, mesh->tface);
+ mesh->mtface= newdataadr(fd, mesh->mtface);
+ mesh->mcol= newdataadr(fd, mesh->mcol);
+ mesh->msticky= newdataadr(fd, mesh->msticky);
+ mesh->dvert= newdataadr(fd, mesh->dvert);
+
+ /* Partial-mesh visibility (do this before using totvert, totface, or totedge!) */
+ mesh->pv= newdataadr(fd, mesh->pv);
+ if(mesh->pv) {
+ mesh->pv->vert_map= newdataadr(fd, mesh->pv->vert_map);
+ mesh->pv->edge_map= newdataadr(fd, mesh->pv->edge_map);
+ mesh->pv->old_faces= newdataadr(fd, mesh->pv->old_faces);
+ mesh->pv->old_edges= newdataadr(fd, mesh->pv->old_edges);
+ }
+
+ /* normally direct_link_dverts should be called in direct_link_customdata,
+ but for backwards compat in do_versions to work we do it here */
+ direct_link_dverts(fd, mesh->pv ? mesh->pv->totvert : mesh->totvert, mesh->dvert);
+
+ direct_link_customdata(fd, &mesh->vdata, mesh->pv ? mesh->pv->totvert : mesh->totvert);
+ direct_link_customdata(fd, &mesh->edata, mesh->pv ? mesh->pv->totedge : mesh->totedge);
+ direct_link_customdata(fd, &mesh->fdata, mesh->pv ? mesh->pv->totface : mesh->totface);
+
+ mesh->bb= NULL;
+ mesh->mselect = NULL;
+
+ /* Multires data */
+ mesh->mr= newdataadr(fd, mesh->mr);
+ if(mesh->mr) {
+ MultiresLevel *lvl;
+
+ link_list(fd, &mesh->mr->levels);
+ lvl= mesh->mr->levels.first;
+
+ direct_link_customdata(fd, &mesh->mr->vdata, lvl->totvert);
+ direct_link_dverts(fd, lvl->totvert, CustomData_get(&mesh->mr->vdata, 0, CD_MDEFORMVERT));
+ direct_link_customdata(fd, &mesh->mr->fdata, lvl->totface);
+
+ if(mesh->mr->edge_flags)
+ mesh->mr->edge_flags= newdataadr(fd, mesh->mr->edge_flags);
+ if(mesh->mr->edge_creases)
+ mesh->mr->edge_creases= newdataadr(fd, mesh->mr->edge_creases);
+
+ if(!mesh->mr->edge_flags)
+ mesh->mr->edge_flags= MEM_callocN(sizeof(short)*lvl->totedge, "Multires Edge Flags");
+ if(!mesh->mr->edge_creases)
+ mesh->mr->edge_creases= MEM_callocN(sizeof(char)*lvl->totedge, "Multires Edge Creases");
+
+ mesh->mr->verts = newdataadr(fd, mesh->mr->verts);
+
+ for(; lvl; lvl= lvl->next) {
+ lvl->verts= newdataadr(fd, lvl->verts);
+ lvl->faces= newdataadr(fd, lvl->faces);
+ lvl->edges= newdataadr(fd, lvl->edges);
+ lvl->colfaces= newdataadr(fd, lvl->colfaces);
+ lvl->edge_boundary_states= NULL;
+ lvl->vert_face_map = lvl->vert_edge_map = NULL;
+ lvl->map_mem= NULL;
+ }
+ }
+
+ if((fd->flags & FD_FLAGS_SWITCH_ENDIAN) && mesh->tface) {
+ TFace *tf= mesh->tface;
+ int i;
+
+ for (i=0; i< (mesh->pv ? mesh->pv->totface : mesh->totface); i++, tf++) {
+ SWITCH_INT(tf->col[0]);
+ SWITCH_INT(tf->col[1]);
+ SWITCH_INT(tf->col[2]);
+ SWITCH_INT(tf->col[3]);
+ }
+ }
+}
+
+/* ************ READ LATTICE ***************** */
+
+static void lib_link_latt(FileData *fd, Main *main)
+{
+ Lattice *lt;
+
+ lt= main->latt.first;
+ while(lt) {
+ if(lt->id.flag & LIB_NEEDLINK) {
+
+ lt->ipo= newlibadr_us(fd, lt->id.lib, lt->ipo);
+ lt->key= newlibadr_us(fd, lt->id.lib, lt->key);
+
+ lt->id.flag -= LIB_NEEDLINK;
+ }
+ lt= lt->id.next;
+ }
+}
+
+static void direct_link_latt(FileData *fd, Lattice *lt)
+{
+ lt->def= newdataadr(fd, lt->def);
+
+ lt->dvert= newdataadr(fd, lt->dvert);
+ direct_link_dverts(fd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert);
+}
+
+
+/* ************ READ OBJECT ***************** */
+
+static void lib_link_modifiers__linkModifiers(void *userData, Object *ob,
+ ID **idpoin)
+{
+ 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)
+ (*idpoin)->us++;
+}
+static void lib_link_modifiers(FileData *fd, Object *ob)
+{
+ modifiers_foreachIDLink(ob, lib_link_modifiers__linkModifiers, fd);
+}
+
+static void lib_link_object(FileData *fd, Main *main)
+{
+ Object *ob;
+ PartEff *paf;
+ bSensor *sens;
+ bController *cont;
+ bActuator *act;
+ void *poin;
+ int warn=0, a;
+
+ ob= main->object.first;
+ while(ob) {
+ if(ob->id.flag & LIB_NEEDLINK) {
+ if (ob->id.properties) IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ ob->parent= newlibadr(fd, ob->id.lib, ob->parent);
+ ob->track= newlibadr(fd, ob->id.lib, ob->track);
+ ob->ipo= newlibadr_us(fd, ob->id.lib, ob->ipo);
+ ob->action = newlibadr_us(fd, ob->id.lib, ob->action);
+ ob->dup_group= newlibadr_us(fd, ob->id.lib, ob->dup_group);
+
+ ob->proxy= newlibadr_us(fd, ob->id.lib, ob->proxy);
+ if(ob->proxy) {
+ /* paranoia check, actually a proxy_from pointer should never be written... */
+ if(ob->proxy->id.lib==NULL) {
+ ob->proxy->proxy_from= NULL;
+ ob->proxy= NULL;
+ }
+ else {
+ /* this triggers object_update to always use a copy */
+ ob->proxy->proxy_from= ob;
+ /* force proxy updates after load/undo, a bit weak */
+ ob->recalc= ob->proxy->recalc= OB_RECALC;
+ }
+ }
+ ob->proxy_group= newlibadr(fd, ob->id.lib, ob->proxy_group);
+
+ poin= ob->data;
+ ob->data= newlibadr_us(fd, ob->id.lib, ob->data);
+
+ if(ob->data==NULL && poin!=NULL) {
+ ob->type= OB_EMPTY;
+ warn= 1;
+ if(ob->id.lib) printf("Can't find obdata of %s lib %s\n", ob->id.name+2, ob->id.lib->name);
+ else printf("Object %s lost data.", ob->id.name+2);
+
+ if(ob->pose) {
+ free_pose_channels(ob->pose);
+ MEM_freeN(ob->pose);
+ ob->pose= NULL;
+ ob->flag &= ~OB_POSEMODE;
+ }
+ }
+ for(a=0; a<ob->totcol; a++) ob->mat[a]= newlibadr_us(fd, ob->id.lib, ob->mat[a]);
+
+ ob->id.flag -= LIB_NEEDLINK;
+ /* if id.us==0 a new base will be created later on */
+
+ /* WARNING! Also check expand_object(), should reflect the stuff below. */
+ lib_link_pose(fd, ob, ob->pose);
+ lib_link_constraints(fd, &ob->id, &ob->constraints);
+ lib_link_nlastrips(fd, &ob->id, &ob->nlastrips);
+ lib_link_constraint_channels(fd, &ob->id, &ob->constraintChannels);
+
+ for(paf= ob->effect.first; paf; paf= paf->next) {
+ if(paf->type==EFF_PARTICLE) {
+ paf->group= newlibadr_us(fd, ob->id.lib, paf->group);
+ }
+ }
+
+ sens= ob->sensors.first;
+ while(sens) {
+ if(ob->id.lib==NULL) { // done in expand_main
+ for(a=0; a<sens->totlinks; a++) {
+ sens->links[a]= newglobadr(fd, sens->links[a]);
+ }
+ }
+ if(sens->type==SENS_TOUCH) {
+ bTouchSensor *ts= sens->data;
+ ts->ma= newlibadr(fd, ob->id.lib, ts->ma);
+ }
+ else if(sens->type==SENS_MESSAGE) {
+ bMessageSensor *ms= sens->data;
+ ms->fromObject=
+ newlibadr(fd, ob->id.lib, ms->fromObject);
+ }
+ sens= sens->next;
+ }
+
+ cont= ob->controllers.first;
+ while(cont) {
+ if(ob->id.lib==NULL) { // done in expand_main
+ for(a=0; a<cont->totlinks; a++) {
+ cont->links[a]= newglobadr(fd, cont->links[a]);
+ }
+ }
+ if(cont->type==CONT_PYTHON) {
+ bPythonCont *pc= cont->data;
+ pc->text= newlibadr(fd, ob->id.lib, pc->text);
+ }
+ cont->slinks= NULL;
+ cont->totslinks= 0;
+
+ cont= cont->next;
+ }
+
+ act= ob->actuators.first;
+ while(act) {
+ if(act->type==ACT_SOUND) {
+ bSoundActuator *sa= act->data;
+ sa->sound= newlibadr_us(fd, ob->id.lib, sa->sound);
+ }
+ else if(act->type==ACT_CD) {
+ /* bCDActuator *cda= act->data; */
+ }
+ else if(act->type==ACT_GAME) {
+ /* bGameActuator *ga= act->data; */
+ }
+ else if(act->type==ACT_CAMERA) {
+ bCameraActuator *ca= act->data;
+ ca->ob= newlibadr(fd, ob->id.lib, ca->ob);
+ }
+ /* leave this one, it's obsolete but necessary to read for conversion */
+ else if(act->type==ACT_ADD_OBJECT) {
+ bAddObjectActuator *eoa= act->data;
+ if(eoa) eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
+ }
+ else if(act->type==ACT_EDIT_OBJECT) {
+ bEditObjectActuator *eoa= act->data;
+ if(eoa==NULL) {
+ init_actuator(act);
+ }
+ else {
+ eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
+ eoa->me= newlibadr(fd, ob->id.lib, eoa->me);
+ }
+ }
+ else if(act->type==ACT_SCENE) {
+ bSceneActuator *sa= act->data;
+ sa->camera= newlibadr(fd, ob->id.lib, sa->camera);
+ sa->scene= newlibadr(fd, ob->id.lib, sa->scene);
+ }
+ else if(act->type==ACT_ACTION) {
+ bActionActuator *aa= act->data;
+ aa->act= newlibadr(fd, ob->id.lib, aa->act);
+ }
+ else if(act->type==ACT_PROPERTY) {
+ bPropertyActuator *pa= act->data;
+ pa->ob= newlibadr(fd, ob->id.lib, pa->ob);
+ }
+ else if(act->type==ACT_MESSAGE) {
+ bMessageActuator *ma= act->data;
+ ma->toObject= newlibadr(fd, ob->id.lib, ma->toObject);
+ }
+ act= act->next;
+ }
+
+ if(ob->fluidsimSettings) {
+ ob->fluidsimSettings->ipo = newlibadr_us(fd, ob->id.lib, ob->fluidsimSettings->ipo);
+ }
+
+ lib_link_scriptlink(fd, &ob->id, &ob->scriptlink);
+ lib_link_modifiers(fd, ob);
+ }
+ ob= ob->id.next;
+ }
+
+ if(warn) error("WARNING IN CONSOLE");
+}
+
+
+static void direct_link_pose(FileData *fd, bPose *pose) {
+
+ bPoseChannel *pchan;
+
+ if (!pose)
+ return;
+
+ link_list(fd, &pose->chanbase);
+
+ for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
+ pchan->bone= NULL;
+ pchan->parent= newdataadr(fd, pchan->parent);
+ pchan->child= newdataadr(fd, pchan->child);
+ direct_link_constraints(fd, &pchan->constraints);
+ pchan->iktree.first= pchan->iktree.last= NULL;
+ pchan->path= NULL;
+ }
+
+}
+
+static void direct_link_modifiers(FileData *fd, ListBase *lb)
+{
+ ModifierData *md;
+
+ link_list(fd, lb);
+
+ for (md=lb->first; md; md=md->next) {
+ md->error = NULL;
+
+ /* if modifiers disappear, or for upward compatibility */
+ if(NULL==modifierType_getInfo(md->type))
+ md->type= eModifierType_None;
+
+ if (md->type==eModifierType_Subsurf) {
+ SubsurfModifierData *smd = (SubsurfModifierData*) md;
+
+ smd->emCache = smd->mCache = 0;
+ } else if (md->type==eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ hmd->indexar= newdataadr(fd, hmd->indexar);
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ int a;
+ for(a=0; a<hmd->totindex; a++) {
+ SWITCH_INT(hmd->indexar[a]);
+ }
+ }
+ }
+ else if (md->type==eModifierType_MeshDeform) {
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+
+ mmd->bindweights= newdataadr(fd, mmd->bindweights);
+ mmd->bindcos= newdataadr(fd, mmd->bindcos);
+
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ int a;
+
+ for(a=0; a<mmd->totcagevert*mmd->totvert; a++)
+ SWITCH_INT(mmd->bindweights[a])
+ for(a=0; a<mmd->totcagevert*3; a++)
+ SWITCH_INT(mmd->bindcos[a])
+ }
+ }
+ }
+}
+
+static void direct_link_nlastrips(FileData *fd, ListBase *strips)
+{
+ bActionStrip *strip;
+
+ link_list(fd, strips);
+
+ for(strip= strips->first; strip; strip= strip->next)
+ link_list(fd, &strip->modifiers);
+}
+
+static void direct_link_object(FileData *fd, Object *ob)
+{
+ PartEff *paf;
+ bProperty *prop;
+ bSensor *sens;
+ bController *cont;
+ bActuator *act;
+ int a;
+
+ /* weak weak... this was only meant as draw flag, now is used in give_base too */
+ ob->flag &= ~OB_FROMGROUP;
+
+ ob->disp.first=ob->disp.last= NULL;
+
+ ob->pose= newdataadr(fd, ob->pose);
+ direct_link_pose(fd, ob->pose);
+
+ link_list(fd, &ob->defbase);
+ direct_link_nlastrips(fd, &ob->nlastrips);
+ link_list(fd, &ob->constraintChannels);
+
+ direct_link_scriptlink(fd, &ob->scriptlink);
+
+ ob->mat= newdataadr(fd, ob->mat);
+ test_pointer_array(fd, (void **)&ob->mat);
+
+ /* do it here, below old data gets converted */
+ direct_link_modifiers(fd, &ob->modifiers);
+
+ link_list(fd, &ob->effect);
+ paf= ob->effect.first;
+ while(paf) {
+ if(paf->type==EFF_PARTICLE) {
+ paf->keys= NULL;
+ }
+ if(paf->type==EFF_WAVE) {
+ WaveEff *wav = (WaveEff*) paf;
+ PartEff *next = paf->next;
+ WaveModifierData *wmd = (WaveModifierData*) modifier_new(eModifierType_Wave);
+
+ wmd->damp = wav->damp;
+ wmd->flag = wav->flag;
+ wmd->height = wav->height;
+ wmd->lifetime = wav->lifetime;
+ wmd->narrow = wav->narrow;
+ wmd->speed = wav->speed;
+ wmd->startx = wav->startx;
+ wmd->starty = wav->startx;
+ wmd->timeoffs = wav->timeoffs;
+ wmd->width = wav->width;
+
+ BLI_addtail(&ob->modifiers, wmd);
+
+ BLI_remlink(&ob->effect, paf);
+ MEM_freeN(paf);
+
+ paf = next;
+ continue;
+ }
+ if(paf->type==EFF_BUILD) {
+ BuildEff *baf = (BuildEff*) paf;
+ PartEff *next = paf->next;
+ BuildModifierData *bmd = (BuildModifierData*) modifier_new(eModifierType_Build);
+
+ bmd->start = baf->sfra;
+ bmd->length = baf->len;
+ bmd->randomize = 0;
+ bmd->seed = 1;
+
+ BLI_addtail(&ob->modifiers, bmd);
+
+ BLI_remlink(&ob->effect, paf);
+ MEM_freeN(paf);
+
+ paf = next;
+ continue;
+ }
+ paf= paf->next;
+ }
+
+ ob->pd= newdataadr(fd, ob->pd);
+ ob->soft= newdataadr(fd, ob->soft);
+ if(ob->soft) {
+ SoftBody *sb= ob->soft;
+
+ sb->bpoint= NULL; // init pointers so it gets rebuilt nicely
+ sb->bspring= NULL;
+ sb->scratch= NULL;
+
+
+ sb->keys= newdataadr(fd, sb->keys);
+ test_pointer_array(fd, (void **)&sb->keys);
+ if(sb->keys) {
+ for(a=0; a<sb->totkey; a++) {
+ sb->keys[a]= newdataadr(fd, sb->keys[a]);
+ }
+ }
+ }
+ ob->fluidsimSettings= newdataadr(fd, ob->fluidsimSettings); /* NT */
+ if(ob->fluidsimSettings) {
+ // reinit mesh pointers
+ ob->fluidsimSettings->orgMesh = NULL; //ob->data;
+ ob->fluidsimSettings->meshSurface = NULL;
+ ob->fluidsimSettings->meshBB = NULL;
+ ob->fluidsimSettings->meshSurfNormals = NULL;
+ }
+
+ link_list(fd, &ob->prop);
+ prop= ob->prop.first;
+ while(prop) {
+ prop->poin= newdataadr(fd, prop->poin);
+ if(prop->poin==0) prop->poin= &prop->data;
+ prop= prop->next;
+ }
+
+ link_list(fd, &ob->sensors);
+ sens= ob->sensors.first;
+ while(sens) {
+ sens->data= newdataadr(fd, sens->data);
+ sens->links= newdataadr(fd, sens->links);
+ test_pointer_array(fd, (void **)&sens->links);
+ sens= sens->next;
+ }
+
+ direct_link_constraints(fd, &ob->constraints);
+
+ link_glob_list(fd, &ob->controllers);
+ cont= ob->controllers.first;
+ while(cont) {
+ cont->data= newdataadr(fd, cont->data);
+ cont->links= newdataadr(fd, cont->links);
+ test_pointer_array(fd, (void **)&cont->links);
+ cont= cont->next;
+ }
+
+ link_glob_list(fd, &ob->actuators);
+ act= ob->actuators.first;
+ while(act) {
+ act->data= newdataadr(fd, act->data);
+ act= act->next;
+ }
+
+ link_list(fd, &ob->hooks);
+ while (ob->hooks.first) {
+ ObHook *hook = ob->hooks.first;
+ HookModifierData *hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
+
+ hook->indexar= newdataadr(fd, hook->indexar);
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ int a;
+ for(a=0; a<hook->totindex; a++) {
+ SWITCH_INT(hook->indexar[a]);
+ }
+ }
+
+ /* Do conversion here because if we have loaded
+ * a hook we need to make sure it gets converted
+ * and free'd, regardless of version.
+ */
+ VECCOPY(hmd->cent, hook->cent);
+ hmd->falloff = hook->falloff;
+ hmd->force = hook->force;
+ hmd->indexar = hook->indexar;
+ hmd->object = hook->parent;
+ memcpy(hmd->parentinv, hook->parentinv, sizeof(hmd->parentinv));
+ hmd->totindex = hook->totindex;
+
+ BLI_addhead(&ob->modifiers, hmd);
+ BLI_remlink(&ob->hooks, hook);
+
+ MEM_freeN(hook);
+ }
+
+ ob->bb= NULL;
+ ob->derivedDeform= NULL;
+ ob->derivedFinal= NULL;
+}
+
+/* ************ READ SCENE ***************** */
+
+static void lib_link_scene(FileData *fd, Main *main)
+{
+ Scene *sce;
+ Base *base, *next;
+ Editing *ed;
+ Sequence *seq;
+ SceneRenderLayer *srl;
+ int a;
+
+ sce= main->scene.first;
+ while(sce) {
+ if(sce->id.flag & LIB_NEEDLINK) {
+ /*Link ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ if (sce->id.properties) IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ sce->camera= newlibadr(fd, sce->id.lib, sce->camera);
+ sce->world= newlibadr_us(fd, sce->id.lib, sce->world);
+ sce->set= newlibadr(fd, sce->id.lib, sce->set);
+ sce->ima= newlibadr_us(fd, sce->id.lib, sce->ima);
+ sce->toolsettings->imapaint.brush=
+ newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.brush);
+
+ /* Sculptdata textures */
+ for(a=0; a<MAX_MTEX; ++a) {
+ MTex *mtex= sce->sculptdata.mtex[a];
+ if(mtex)
+ mtex->tex= newlibadr_us(fd, sce->id.lib, mtex->tex);
+ }
+
+ for(base= sce->base.first; base; base= next) {
+ next= base->next;
+
+ /* base->object= newlibadr_us(fd, sce->id.lib, base->object); */
+ base->object= newlibadr_us(fd, sce->id.lib, base->object);
+
+ /* when save during radiotool, needs cleared */
+ base->flag &= ~OB_RADIO;
+
+ if(base->object==NULL) {
+ printf("LIB ERROR: base removed\n");
+ BLI_remlink(&sce->base, base);
+ if(base==sce->basact) sce->basact= 0;
+ MEM_freeN(base);
+ }
+ }
+
+ ed= sce->ed;
+ if(ed) {
+ WHILE_SEQ(&ed->seqbase) {
+ if(seq->ipo) seq->ipo= newlibadr_us(fd, sce->id.lib, seq->ipo);
+ if(seq->scene) seq->scene= newlibadr(fd, sce->id.lib, seq->scene);
+ if(seq->sound) {
+ seq->sound= newlibadr(fd, sce->id.lib, seq->sound);
+ if (seq->sound) {
+ seq->sound->id.us++;
+ seq->sound->flags |= SOUND_FLAGS_SEQUENCE;
+ }
+ }
+ seq->anim= 0;
+ seq->hdaudio = 0;
+ }
+ END_SEQ
+ }
+
+ lib_link_scriptlink(fd, &sce->id, &sce->scriptlink);
+
+ if(sce->nodetree)
+ lib_link_ntree(fd, &sce->id, sce->nodetree);
+
+ for(srl= sce->r.layers.first; srl; srl= srl->next) {
+ srl->mat_override= newlibadr_us(fd, sce->id.lib, srl->mat_override);
+ srl->light_override= newlibadr_us(fd, sce->id.lib, srl->light_override);
+ }
+
+ sce->id.flag -= LIB_NEEDLINK;
+ }
+
+ sce= sce->id.next;
+ }
+}
+
+static void link_recurs_seq(FileData *fd, ListBase *lb)
+{
+ Sequence *seq;
+
+ link_list(fd, lb);
+ seq= lb->first;
+ while(seq) {
+ if(seq->seqbase.first) link_recurs_seq(fd, &seq->seqbase);
+ seq= seq->next;
+ }
+}
+
+static void direct_link_scene(FileData *fd, Scene *sce)
+{
+ Editing *ed;
+ Sequence *seq;
+ MetaStack *ms;
+ StripElem *se;
+ int a;
+
+ sce->theDag = NULL;
+ sce->dagisvalid = 0;
+ /* set users to one by default, not in lib-link, this will increase it for compo nodes */
+ sce->id.us= 1;
+
+ link_list(fd, &(sce->base));
+
+ sce->basact= newdataadr(fd, sce->basact);
+
+ sce->radio= newdataadr(fd, sce->radio);
+
+ sce->toolsettings= newdataadr(fd, sce->toolsettings);
+
+ sce->sculptdata.session= NULL;
+ /* SculptData textures */
+ for(a=0; a<MAX_MTEX; ++a)
+ sce->sculptdata.mtex[a]= newdataadr(fd,sce->sculptdata.mtex[a]);
+
+ if(sce->ed) {
+ ListBase *old_seqbasep= &((Editing *)sce->ed)->seqbase;
+
+ ed= sce->ed= newdataadr(fd, sce->ed);
+
+ /* recursive link sequences, lb will be correctly initialized */
+ link_recurs_seq(fd, &ed->seqbase);
+
+ WHILE_SEQ(&ed->seqbase) {
+ seq->seq1= newdataadr(fd, seq->seq1);
+ seq->seq2= newdataadr(fd, seq->seq2);
+ seq->seq3= newdataadr(fd, seq->seq3);
+ /* a patch: after introduction of effects with 3 input strips */
+ if(seq->seq3==0) seq->seq3= seq->seq2;
+
+ seq->curelem= 0;
+
+ seq->plugin= newdataadr(fd, seq->plugin);
+ seq->effectdata= newdataadr(fd, seq->effectdata);
+
+ if (seq->type & SEQ_EFFECT) {
+ seq->flag |= SEQ_EFFECT_NOT_LOADED;
+ }
+
+ seq->strip= newdataadr(fd, seq->strip);
+ if(seq->strip && seq->strip->done==0) {
+ seq->strip->done= 1;
+
+ /* standard: strips from effects/metas are not written, but are mallocced */
+
+ if(seq->type==SEQ_IMAGE) {
+ seq->strip->stripdata= newdataadr(fd, seq->strip->stripdata);
+ se= seq->strip->stripdata;
+ if(se) {
+ for(a=0; a<seq->strip->len; a++, se++) {
+ se->ok= 1;
+ se->ibuf= 0;
+ }
+ }
+ }
+ else if(seq->type==SEQ_MOVIE) {
+ /* only first stripelem is in file */
+ se= newdataadr(fd, seq->strip->stripdata);
+
+ if(se) {
+ seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+ *seq->strip->stripdata= *se;
+ MEM_freeN(se);
+
+ se= seq->strip->stripdata;
+
+ for(a=0; a<seq->strip->len; a++, se++) {
+ se->ok= 1;
+ se->ibuf= 0;
+ se->nr= a + 1;
+ }
+ }
+ }
+ else if(seq->type==SEQ_RAM_SOUND
+ || seq->type == SEQ_HD_SOUND) {
+ /* only first stripelem is in file */
+ se= newdataadr(fd, seq->strip->stripdata);
+
+ if(se) {
+ seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+ *seq->strip->stripdata= *se;
+ MEM_freeN(se);
+
+ se= seq->strip->stripdata;
+
+ for(a=0; a<seq->strip->len; a++, se++) {
+ se->ok= 2; /* why? */
+ se->ibuf= 0;
+ se->nr= a + 1;
+ }
+ }
+ }
+ else if(seq->len>0)
+ seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+
+ }
+ }
+ END_SEQ
+
+ /* link metastack, slight abuse of structs here, have to restore pointer to internal part in struct */
+ {
+ Sequence temp;
+ char *poin;
+ long offset;
+
+ offset= ((long)&(temp.seqbase)) - ((long)&temp);
+
+ /* root pointer */
+ if(ed->seqbasep == old_seqbasep) {
+ ed->seqbasep= &ed->seqbase;
+ }
+ else {
+
+ poin= (char *)ed->seqbasep;
+ poin -= offset;
+
+ poin= newdataadr(fd, poin);
+ if(poin) ed->seqbasep= (ListBase *)(poin+offset);
+ else ed->seqbasep= &ed->seqbase;
+ }
+ /* stack */
+ link_list(fd, &(ed->metastack));
+
+ for(ms= ed->metastack.first; ms; ms= ms->next) {
+ ms->parseq= newdataadr(fd, ms->parseq);
+
+ if(ms->oldbasep == old_seqbasep)
+ ms->oldbasep= &ed->seqbase;
+ else {
+ poin= (char *)ms->oldbasep;
+ poin -= offset;
+ poin= newdataadr(fd, poin);
+ if(poin) ms->oldbasep= (ListBase *)(poin+offset);
+ else ms->oldbasep= &ed->seqbase;
+ }
+ }
+ }
+ }
+
+ direct_link_scriptlink(fd, &sce->scriptlink);
+
+ sce->r.avicodecdata = newdataadr(fd, sce->r.avicodecdata);
+ if (sce->r.avicodecdata) {
+ sce->r.avicodecdata->lpFormat = newdataadr(fd, sce->r.avicodecdata->lpFormat);
+ sce->r.avicodecdata->lpParms = newdataadr(fd, sce->r.avicodecdata->lpParms);
+ }
+
+ sce->r.qtcodecdata = newdataadr(fd, sce->r.qtcodecdata);
+ if (sce->r.qtcodecdata) {
+ sce->r.qtcodecdata->cdParms = newdataadr(fd, sce->r.qtcodecdata->cdParms);
+ }
+
+ link_list(fd, &(sce->markers));
+ link_list(fd, &(sce->r.layers));
+
+ sce->nodetree= newdataadr(fd, sce->nodetree);
+ if(sce->nodetree)
+ direct_link_nodetree(fd, sce->nodetree);
+
+}
+
+/* Nasty exception; IpoWindow stores a non-ID pointer in *from for sequence
+ strips... bad code warning!
+
+ We work around it by retrieving the missing pointer from the corresponding
+ Sequence-structure.
+
+ This is needed, to make Ipo-Pinning work for Sequence-Ipos...
+*/
+static Sequence * find_sequence_from_ipo_helper(Main * main, Ipo * ipo)
+{
+ Editing *ed;
+ Sequence *seq = NULL;
+
+ Scene * sce= main->scene.first;
+ while(sce) {
+ if(sce->ed) {
+ int found = 0;
+
+ ed= sce->ed;
+
+ WHILE_SEQ(&ed->seqbase) {
+ if (seq->ipo == ipo) {
+ found = 1;
+ break;
+ }
+ }
+ END_SEQ
+ if (found) {
+ break;
+ }
+ seq = NULL;
+ }
+ sce= sce->id.next;
+ }
+ if (seq)
+ return seq;
+ else
+ return NULL;
+}
+
+static void lib_link_screen_sequence_ipos(Main *main)
+{
+ bScreen *sc;
+ ScrArea *sa;
+
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ for(sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype == SPACE_IPO) {
+ SpaceIpo *sipo= (SpaceIpo *)sl;
+ if(sipo->blocktype==ID_SEQ) {
+ sipo->from = (ID*) find_sequence_from_ipo_helper(main, sipo->ipo);
+ }
+ }
+ }
+ }
+ }
+}
+
+/* ************ 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;
+ ScrArea *sa;
+
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ if(sc->id.flag & LIB_NEEDLINK) {
+ sc->id.us= 1;
+ sc->scene= newlibadr(fd, sc->id.lib, sc->scene);
+
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+
+ sa->full= newlibadr(fd, sc->id.lib, sa->full);
+
+ /* space handler scriptlinks */
+ lib_link_scriptlink(fd, &sc->id, &sa->scriptlink);
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+
+ v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera);
+ v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre);
+
+ if(v3d->bgpic) {
+ v3d->bgpic->ima= newlibadr_us(fd, sc->id.lib, v3d->bgpic->ima);
+ }
+ if(v3d->localvd) {
+ v3d->localvd->camera= newlibadr(fd, sc->id.lib, v3d->localvd->camera);
+ }
+ v3d->depths= NULL;
+ v3d->ri= NULL;
+ }
+ else if(sl->spacetype==SPACE_IPO) {
+ SpaceIpo *sipo= (SpaceIpo *)sl;
+ sipo->editipo= 0;
+
+ if(sipo->blocktype==ID_SEQ) sipo->from= NULL; // no libdata
+ else sipo->from= newlibadr(fd, sc->id.lib, sipo->from);
+
+ sipo->ipokey.first= sipo->ipokey.last= 0;
+ sipo->ipo= newlibadr(fd, sc->id.lib, sipo->ipo);
+ }
+ else if(sl->spacetype==SPACE_BUTS) {
+ SpaceButs *sbuts= (SpaceButs *)sl;
+ sbuts->lockpoin= NULL;
+ sbuts->ri= NULL;
+ if(main->versionfile<132) set_rects_butspace(sbuts);
+ }
+ else if(sl->spacetype==SPACE_FILE) {
+ SpaceFile *sfile= (SpaceFile *)sl;
+
+ sfile->filelist= NULL;
+ sfile->libfiledata= NULL;
+ sfile->returnfunc= NULL;
+ sfile->menup= NULL;
+ sfile->pupmenu= NULL;
+ }
+ else if(sl->spacetype==SPACE_IMASEL) {
+ SpaceImaSel *simasel= (SpaceImaSel *)sl;
+
+ simasel->files = NULL;
+ simasel->returnfunc= NULL;
+ simasel->menup= NULL;
+ simasel->pupmenu= NULL;
+ simasel->img= NULL;
+ }
+ else if(sl->spacetype==SPACE_ACTION) {
+ SpaceAction *saction= (SpaceAction *)sl;
+ saction->action = newlibadr(fd, sc->id.lib, saction->action);
+ }
+ else if(sl->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= (SpaceImage *)sl;
+
+ sima->image= newlibadr_us(fd, sc->id.lib, sima->image);
+ }
+ else if(sl->spacetype==SPACE_NLA){
+ /* SpaceNla *snla= (SpaceNla *)sl; */
+ }
+ else if(sl->spacetype==SPACE_TEXT) {
+ SpaceText *st= (SpaceText *)sl;
+
+ st->text= newlibadr(fd, sc->id.lib, 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;
+ TreeStoreElem *tselem;
+ int a;
+
+ oops= so->oops.first;
+ while(oops) {
+ oops->id= newlibadr(fd, NULL, oops->id);
+ oops= oops->next;
+ }
+ so->lockpoin= NULL;
+ so->tree.first= so->tree.last= NULL;
+ so->search_tse.id= newlibadr(fd, NULL, so->search_tse.id);
+
+ if(so->treestore) {
+ tselem= so->treestore->data;
+ for(a=0; a<so->treestore->usedelem; a++, tselem++) {
+ tselem->id= newlibadr(fd, NULL, tselem->id);
+ }
+ }
+ }
+ else if(sl->spacetype==SPACE_SOUND) {
+ SpaceSound *ssound= (SpaceSound *)sl;
+
+ ssound->sound= newlibadr_us(fd, sc->id.lib, ssound->sound);
+ }
+ }
+ sa= sa->next;
+ }
+ sc->id.flag -= LIB_NEEDLINK;
+ }
+ }
+}
+
+/* Only for undo files, or to restore a screen after reading without UI... */
+static void *restore_pointer_by_name(Main *mainp, ID *id, int user)
+{
+
+ if(id) {
+ ListBase *lb= wich_libbase(mainp, GS(id->name));
+
+ if(lb) { // there's still risk of checking corrupt mem (freed Ids in oops)
+ ID *idn= lb->first;
+ char *name= id->name+2;
+
+ while(idn) {
+ if(idn->name[2]==name[0] && strcmp(idn->name+2, name)==0) {
+ if(idn->lib==id->lib) {
+ if(user && idn->us==0) idn->us++;
+ break;
+ }
+ }
+ idn= idn->next;
+ }
+ return idn;
+ }
+ }
+ return NULL;
+}
+
+/* called from kernel/blender.c */
+/* used to link a file (without UI) to the current UI */
+/* note that it assumes the old pointers in UI are still valid, so old Main is not freed */
+void lib_link_screen_restore(Main *newmain, Scene *curscene)
+{
+ bScreen *sc;
+ ScrArea *sa;
+
+ for(sc= newmain->screen.first; sc; sc= sc->id.next) {
+
+ sc->scene= curscene;
+
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+
+ if (sa->scriptlink.totscript) {
+ /* restore screen area script links */
+ ScriptLink *slink = &sa->scriptlink;
+ int script_idx;
+ for (script_idx = 0; script_idx < slink->totscript; script_idx++) {
+ slink->scripts[script_idx] = restore_pointer_by_name(newmain,
+ (ID *)slink->scripts[script_idx], 1);
+ }
+ }
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+
+ v3d->camera= restore_pointer_by_name(newmain, (ID *)v3d->camera, 1);
+ if(v3d->camera==NULL)
+ v3d->camera= sc->scene->camera;
+ v3d->ob_centre= restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, 1);
+
+ if(v3d->bgpic) {
+ v3d->bgpic->ima= restore_pointer_by_name(newmain, (ID *)v3d->bgpic->ima, 1);
+ }
+ if(v3d->localvd) {
+ Base *base;
+
+ v3d->localvd->camera= sc->scene->camera;
+
+ /* localview can become invalid during undo/redo steps, so we exit it when no could be found */
+ for(base= sc->scene->base.first; base; base= base->next) {
+ if(base->lay & v3d->lay) break;
+ }
+ if(base==NULL) {
+ v3d->lay= v3d->localvd->lay;
+ v3d->layact= v3d->localvd->layact;
+ MEM_freeN(v3d->localvd);
+ v3d->localvd= NULL;
+ v3d->localview= 0;
+ }
+ }
+ else if(v3d->scenelock) v3d->lay= sc->scene->lay;
+
+ /* not very nice, but could help */
+ if((v3d->layact & v3d->lay)==0) v3d->layact= v3d->lay;
+
+ }
+ else if(sl->spacetype==SPACE_IPO) {
+ SpaceIpo *sipo= (SpaceIpo *)sl;
+
+ if(sipo->blocktype==ID_SEQ) sipo->from= NULL; // no libdata
+ else sipo->from= restore_pointer_by_name(newmain, (ID *)sipo->from, 0);
+
+ // not free sipo->ipokey, creates dependency with src/
+ sipo->ipo= restore_pointer_by_name(newmain, (ID *)sipo->ipo, 0);
+ 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->ri) sbuts->ri->curtile = 0;
+ }
+ else if(sl->spacetype==SPACE_FILE) {
+ SpaceFile *sfile= (SpaceFile *)sl;
+ if(sfile->libfiledata)
+ BLO_blendhandle_close(sfile->libfiledata);
+ sfile->libfiledata= 0;
+ }
+ else if(sl->spacetype==SPACE_IMASEL) {
+ SpaceImaSel *simasel= (SpaceImaSel *)sl;
+ if (simasel->files) {
+ BIF_filelist_freelib(simasel->files);
+ }
+ }
+ else if(sl->spacetype==SPACE_ACTION) {
+ SpaceAction *saction= (SpaceAction *)sl;
+ saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, 1);
+ }
+ else if(sl->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= (SpaceImage *)sl;
+
+ sima->image= restore_pointer_by_name(newmain, (ID *)sima->image, 1);
+ }
+ 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, 1);
+ if(st->text==NULL) st->text= newmain->text.first;
+ }
+ 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;
+ int a;
+
+ oops= so->oops.first;
+ while(oops) {
+ oops->id= restore_pointer_by_name(newmain, (ID *)oops->id, 0);
+ oops= oops->next;
+ }
+ so->lockpoin= NULL;
+ so->search_tse.id= restore_pointer_by_name(newmain, so->search_tse.id, 0);
+
+ if(so->treestore) {
+ TreeStore *ts= so->treestore;
+ TreeStoreElem *tselem=ts->data;
+ for(a=0; a<ts->usedelem; a++, tselem++) {
+ tselem->id= restore_pointer_by_name(newmain, tselem->id, 0);
+ }
+ }
+ }
+ else if(sl->spacetype==SPACE_SOUND) {
+ SpaceSound *ssound= (SpaceSound *)sl;
+
+ ssound->sound= restore_pointer_by_name(newmain, (ID *)ssound->sound, 1);
+ }
+ else if(sl->spacetype==SPACE_NODE) {
+ SpaceNode *snode= (SpaceNode *)sl;
+
+ snode->nodetree= snode->edittree= NULL;
+ snode->flag |= SNODE_DO_PREVIEW;
+ }
+ }
+ sa= sa->next;
+ }
+ }
+}
+
+static void direct_link_screen(FileData *fd, bScreen *sc)
+{
+ ScrArea *sa;
+ ScrVert *sv;
+ ScrEdge *se;
+ Oops *oops;
+ int a;
+
+ link_list(fd, &(sc->vertbase));
+ link_list(fd, &(sc->edgebase));
+ link_list(fd, &(sc->areabase));
+ sc->winakt= 0;
+
+ /* hacky patch... but people have been saving files with the verse-blender,
+ causing the handler to keep running for ever, with no means to disable it */
+ for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
+ if( sc->handler[a]==SCREEN_HANDLER_VERSE) {
+ sc->handler[a]= 0;
+ break;
+ }
+ }
+
+ /* edges */
+ se= sc->edgebase.first;
+ while(se) {
+ se->v1= newdataadr(fd, se->v1);
+ se->v2= newdataadr(fd, se->v2);
+ if( (long)se->v1 > (long)se->v2) {
+ sv= se->v1;
+ se->v1= se->v2;
+ se->v2= sv;
+ }
+
+ if(se->v1==NULL) {
+ printf("error reading screen... file corrupt\n");
+ se->v1= se->v2;
+ }
+ se= se->next;
+ }
+
+ /* areas */
+ sa= sc->areabase.first;
+ while(sa) {
+ Panel *pa;
+ SpaceLink *sl;
+
+ link_list(fd, &(sa->spacedata));
+ link_list(fd, &(sa->panels));
+
+ /* accident can happen when read/save new file with older version */
+ if(sa->spacedata.first==NULL && sa->spacetype>SPACE_NLA)
+ sa->spacetype= SPACE_EMPTY;
+
+ for(pa= sa->panels.first; pa; pa=pa->next) {
+ pa->paneltab= newdataadr(fd, pa->paneltab);
+ pa->active= 0;
+ pa->sortcounter= 0;
+ }
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if (sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+ v3d->bgpic= newdataadr(fd, v3d->bgpic);
+ if(v3d->bgpic)
+ v3d->bgpic->iuser.ok= 1;
+ v3d->localvd= newdataadr(fd, v3d->localvd);
+ v3d->afterdraw.first= v3d->afterdraw.last= NULL;
+ v3d->clipbb= newdataadr(fd, v3d->clipbb);
+ v3d->retopo_view_data= NULL;
+ v3d->properties_storage= NULL;
+ }
+ else if (sl->spacetype==SPACE_OOPS) {
+ SpaceOops *soops= (SpaceOops*) sl;
+
+ link_list(fd, &(soops->oops));
+ oops= soops->oops.first;
+ while(oops) {
+ oops->link.first= oops->link.last= 0;
+ oops= oops->next;
+ }
+
+ soops->treestore= newdataadr(fd, soops->treestore);
+ if(soops->treestore) {
+ soops->treestore->data= newdataadr(fd, soops->treestore->data);
+ /* we only saved what was used */
+ soops->treestore->totelem= soops->treestore->usedelem;
+ soops->storeflag |= SO_TREESTORE_CLEANUP; // at first draw
+ }
+ }
+ else if(sl->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= (SpaceImage *)sl;
+
+ sima->cumap= newdataadr(fd, sima->cumap);
+ if(sima->cumap)
+ direct_link_curvemapping(fd, sima->cumap);
+ sima->info_str= sima->info_spare= NULL;
+ sima->spare= NULL;
+ sima->iuser.ok= 1;
+ }
+ else if(sl->spacetype==SPACE_NODE) {
+ SpaceNode *snode= (SpaceNode *)sl;
+ snode->nodetree= snode->edittree= NULL;
+ snode->flag |= SNODE_DO_PREVIEW;
+ }
+ }
+
+ sa->v1= newdataadr(fd, sa->v1);
+ sa->v2= newdataadr(fd, sa->v2);
+ sa->v3= newdataadr(fd, sa->v3);
+ sa->v4= newdataadr(fd, sa->v4);
+
+ sa->win= sa->headwin= 0;
+
+ sa->uiblocks.first= sa->uiblocks.last= NULL;
+
+ /* space handler scriptlinks */
+ direct_link_scriptlink(fd, &sa->scriptlink);
+
+ sa= sa->next;
+ }
+}
+
+/* ********** READ LIBRARY *************** */
+
+
+static void direct_link_library(FileData *fd, Library *lib, Main *main)
+{
+ Main *newmain;
+
+ for(newmain= fd->mainlist.first; newmain; newmain= newmain->next) {
+ if(newmain->curlib) {
+ if(strcmp(newmain->curlib->filename, lib->filename)==0) {
+ printf("Fixed error in file; multiple instances of lib:\n %s\n", lib->filename);
+
+ change_idid_adr(&fd->mainlist, fd, lib, newmain->curlib);
+// change_idid_adr_fd(fd, lib, newmain->curlib);
+
+ BLI_remlink(&main->library, lib);
+ MEM_freeN(lib);
+
+ error("Library had multiple instances, save and reload!");
+ return;
+ }
+ }
+ }
+ /* make sure we have full path in lib->filename */
+ BLI_strncpy(lib->filename, lib->name, sizeof(lib->name));
+ cleanup_path(fd->filename, lib->filename);
+
+// printf("direct_link_library: name %s\n", lib->name);
+// printf("direct_link_library: filename %s\n", lib->filename);
+
+ /* new main */
+ newmain= MEM_callocN(sizeof(Main), "directlink");
+ BLI_addtail(&fd->mainlist, newmain);
+ newmain->curlib= lib;
+
+ lib->parent= NULL;
+}
+
+static void lib_link_library(FileData *fd, Main *main)
+{
+ Library *lib;
+
+ lib= main->library.first;
+ while(lib) {
+ lib->id.us= 1;
+ lib= lib->id.next;
+ }
+}
+
+/* ************** READ SOUND ******************* */
+
+static void direct_link_sound(FileData *fd, bSound *sound)
+{
+ sound->sample = NULL;
+ sound->snd_sound = NULL;
+
+ sound->packedfile = direct_link_packedfile(fd, sound->packedfile);
+ sound->newpackedfile = direct_link_packedfile(fd, sound->newpackedfile);
+}
+
+static void lib_link_sound(FileData *fd, Main *main)
+{
+ bSound *sound;
+
+ sound= main->sound.first;
+ while(sound) {
+ if(sound->id.flag & LIB_NEEDLINK) {
+ sound->id.flag -= LIB_NEEDLINK;
+ sound->ipo= newlibadr_us(fd, sound->id.lib, sound->ipo);
+ sound->stream = 0;
+ }
+ sound= sound->id.next;
+ }
+}
+/* ***************** READ GROUP *************** */
+
+static void direct_link_group(FileData *fd, Group *group)
+{
+ link_list(fd, &group->gobject);
+}
+
+static void lib_link_group(FileData *fd, Main *main)
+{
+ Group *group= main->group.first;
+ GroupObject *go;
+ int add_us;
+
+ while(group) {
+ if(group->id.flag & LIB_NEEDLINK) {
+ group->id.flag -= LIB_NEEDLINK;
+
+ add_us= 0;
+
+ go= group->gobject.first;
+ while(go) {
+ go->ob= newlibadr(fd, group->id.lib, go->ob);
+ if(go->ob) {
+ go->ob->flag |= OB_FROMGROUP;
+ /* if group has an object, it increments user... */
+ add_us= 1;
+ if(go->ob->id.us==0)
+ go->ob->id.us= 1;
+ }
+ go= go->next;
+ }
+ if(add_us) group->id.us++;
+ rem_from_group(group, NULL); /* removes NULL entries */
+ }
+ group= group->id.next;
+ }
+}
+
+/* ************** GENERAL & MAIN ******************** */
+
+
+static char *dataname(short id_code)
+{
+
+ switch( id_code ) {
+ case ID_OB: return "Data from OB";
+ case ID_ME: return "Data from ME";
+ case ID_IP: return "Data from IP";
+ case ID_SCE: return "Data from SCE";
+ case ID_MA: return "Data from MA";
+ case ID_TE: return "Data from TE";
+ case ID_CU: return "Data from CU";
+ case ID_GR: return "Data from GR";
+ case ID_AR: return "Data from AR";
+ case ID_AC: return "Data from AC";
+ case ID_LI: return "Data from LI";
+ case ID_MB: return "Data from MB";
+ case ID_IM: return "Data from IM";
+ case ID_LT: return "Data from LT";
+ case ID_LA: return "Data from LA";
+ case ID_CA: return "Data from CA";
+ case ID_KE: return "Data from KE";
+ case ID_WO: return "Data from WO";
+ case ID_SCR: return "Data from SCR";
+ case ID_VF: return "Data from VF";
+ case ID_TXT : return "Data from TXT";
+ case ID_SO: return "Data from SO";
+ case ID_NT: return "Data from NT";
+ case ID_BR: return "Data from BR";
+ }
+ return "Data from Lib Block";
+
+}
+
+static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **id_r)
+{
+ /* this routine reads a libblock and its direct data. Use link functions
+ * to connect it all
+ */
+
+ ID *id;
+ ListBase *lb;
+ char *allocname;
+
+ /* read libblock */
+ id = read_struct(fd, bhead, "lib block");
+ if (id_r)
+ *id_r= id;
+ if (!id)
+ return blo_nextbhead(fd, bhead);
+
+ oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); /* for ID_ID check */
+
+ /* do after read_struct, for dna reconstruct */
+ if(bhead->code==ID_ID) {
+ lb= wich_libbase(main, GS(id->name));
+ }
+ else {
+ lb= wich_libbase(main, bhead->code);
+ }
+
+ BLI_addtail(lb, id);
+
+ /* clear first 8 bits */
+ id->flag= (id->flag & 0xFF00) | flag | LIB_NEEDLINK;
+ id->lib= main->curlib;
+ if(id->flag & LIB_FAKEUSER) id->us= 1;
+ else id->us= 0;
+ id->icon_id = 0;
+
+ /* this case cannot be direct_linked: it's just the ID part */
+ if(bhead->code==ID_ID) {
+ return blo_nextbhead(fd, bhead);
+ }
+
+ bhead = blo_nextbhead(fd, bhead);
+
+ /* need a name for the mallocN, just for debugging and sane prints on leaks */
+ allocname= dataname(GS(id->name));
+
+ /* read all data */
+ while(bhead && bhead->code==DATA) {
+ void *data= read_struct(fd, bhead, allocname);
+
+ if (data) {
+ oldnewmap_insert(fd->datamap, bhead->old, data, 0);
+ }
+
+ bhead = blo_nextbhead(fd, bhead);
+ }
+
+ /* init pointers direct data */
+ switch( GS(id->name) ) {
+ case ID_SCR:
+ direct_link_screen(fd, (bScreen *)id);
+ break;
+ case ID_SCE:
+ direct_link_scene(fd, (Scene *)id);
+ break;
+ case ID_OB:
+ direct_link_object(fd, (Object *)id);
+ break;
+ case ID_ME:
+ direct_link_mesh(fd, (Mesh *)id);
+ break;
+ case ID_CU:
+ direct_link_curve(fd, (Curve *)id);
+ break;
+ case ID_MB:
+ direct_link_mball(fd, (MetaBall *)id);
+ break;
+ case ID_MA:
+ direct_link_material(fd, (Material *)id);
+ break;
+ case ID_TE:
+ direct_link_texture(fd, (Tex *)id);
+ break;
+ case ID_IM:
+ direct_link_image(fd, (Image *)id);
+ break;
+ case ID_LA:
+ direct_link_lamp(fd, (Lamp *)id);
+ break;
+ case ID_VF:
+ direct_link_vfont(fd, (VFont *)id);
+ break;
+ case ID_TXT:
+ direct_link_text(fd, (Text *)id);
+ break;
+ case ID_IP:
+ direct_link_ipo(fd, (Ipo *)id);
+ break;
+ case ID_KE:
+ direct_link_key(fd, (Key *)id);
+ break;
+ case ID_LT:
+ direct_link_latt(fd, (Lattice *)id);
+ break;
+ case ID_WO:
+ direct_link_world(fd, (World *)id);
+ break;
+ case ID_LI:
+ direct_link_library(fd, (Library *)id, main);
+ break;
+ case ID_CA:
+ direct_link_camera(fd, (Camera *)id);
+ break;
+ case ID_SO:
+ direct_link_sound(fd, (bSound *)id);
+ break;
+ case ID_GR:
+ direct_link_group(fd, (Group *)id);
+ break;
+ case ID_AR:
+ direct_link_armature(fd, (bArmature*)id);
+ break;
+ case ID_AC:
+ direct_link_action(fd, (bAction*)id);
+ break;
+ case ID_NT:
+ direct_link_nodetree(fd, (bNodeTree*)id);
+ break;
+ case ID_BR:
+ direct_link_brush(fd, (Brush*)id);
+ break;
+ }
+
+ /*link direct data of ID properties*/
+ if (id->properties) {
+ id->properties = newdataadr(fd, id->properties);
+ IDP_DirectLinkProperty(id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+
+ oldnewmap_free_unused(fd->datamap);
+ oldnewmap_clear(fd->datamap);
+
+ return (bhead);
+}
+
+static void link_global(FileData *fd, BlendFileData *bfd, FileGlobal *fg)
+{
+ // 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)
+{
+ MFace *mface;
+ unsigned int *mcol, *mcoln, *mcolmain;
+ int a;
+
+ if(me->totface==0 || me->mcol==0) return;
+
+ mcoln= mcolmain= MEM_mallocN(4*sizeof(int)*me->totface, "mcoln");
+ mcol = (unsigned int *)me->mcol;
+ mface= me->mface;
+ for(a=me->totface; a>0; a--, mface++) {
+ mcoln[0]= mcol[mface->v1];
+ mcoln[1]= mcol[mface->v2];
+ mcoln[2]= mcol[mface->v3];
+ mcoln[3]= mcol[mface->v4];
+ mcoln+= 4;
+ }
+
+ MEM_freeN(me->mcol);
+ me->mcol= (MCol *)mcolmain;
+}
+
+static int map_223_keybd_code_to_224_keybd_code(int code)
+{
+ switch (code) {
+ case 312: return F12KEY;
+ case 159: return PADSLASHKEY;
+ case 161: return PAD0;
+ case 154: return PAD1;
+ case 150: return PAD2;
+ case 155: return PAD3;
+ case 151: return PAD4;
+ case 156: return PAD5;
+ case 152: return PAD6;
+ case 157: return PAD7;
+ case 153: return PAD8;
+ case 158: return PAD9;
+ default: return code;
+ }
+}
+
+static void bone_version_238(ListBase *lb)
+{
+ Bone *bone;
+
+ for(bone= lb->first; bone; bone= bone->next) {
+ if(bone->rad_tail==0.0f && bone->rad_head==0.0f) {
+ bone->rad_head= 0.25f*bone->length;
+ bone->rad_tail= 0.1f*bone->length;
+
+ bone->dist-= bone->rad_head;
+ if(bone->dist<=0.0f) bone->dist= 0.0f;
+ }
+ bone_version_238(&bone->childbase);
+ }
+}
+
+static void bone_version_239(ListBase *lb)
+{
+ Bone *bone;
+
+ for(bone= lb->first; bone; bone= bone->next) {
+ if(bone->layer==0)
+ bone->layer= 1;
+ bone_version_239(&bone->childbase);
+ }
+}
+
+static void ntree_version_241(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree->type==NTREE_COMPOSIT) {
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_BLUR) {
+ if(node->storage==NULL) {
+ NodeBlurData *nbd= MEM_callocN(sizeof(NodeBlurData), "node blur patch");
+ nbd->sizex= node->custom1;
+ nbd->sizey= node->custom2;
+ nbd->filtertype= R_FILTER_QUAD;
+ node->storage= nbd;
+ }
+ }
+ else if(node->type==CMP_NODE_VECBLUR) {
+ if(node->storage==NULL) {
+ NodeBlurData *nbd= MEM_callocN(sizeof(NodeBlurData), "node blur patch");
+ nbd->samples= node->custom1;
+ nbd->maxspeed= node->custom2;
+ nbd->fac= 1.0f;
+ node->storage= nbd;
+ }
+ }
+ }
+ }
+}
+
+static void ntree_version_242(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree->type==NTREE_COMPOSIT) {
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_HUE_SAT) {
+ if(node->storage) {
+ NodeHueSat *nhs= node->storage;
+ if(nhs->val==0.0f) nhs->val= 1.0f;
+ }
+ }
+ }
+ }
+ else if(ntree->type==NTREE_SHADER) {
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->type == SH_NODE_GEOMETRY && node->storage == NULL)
+ node->storage= MEM_callocN(sizeof(NodeGeometry), "NodeGeometry");
+ }
+
+}
+
+
+/* somehow, probably importing via python, keyblock adrcodes are not in order */
+static void sort_shape_fix(Main *main)
+{
+ Key *key;
+ KeyBlock *kb;
+ int sorted= 0;
+
+ while(sorted==0) {
+ sorted= 1;
+ for(key= main->key.first; key; key= key->id.next) {
+ for(kb= key->block.first; kb; kb= kb->next) {
+ if(kb->next && kb->adrcode>kb->next->adrcode) {
+ KeyBlock *next= kb->next;
+ BLI_remlink(&key->block, kb);
+ BLI_insertlink(&key->block, next, kb);
+ kb= next;
+ sorted= 0;
+ }
+ }
+ }
+ if(sorted==0) printf("warning, shape keys were sorted incorrect, fixed it!\n");
+ }
+}
+
+static void customdata_version_242(Mesh *me)
+{
+ CustomDataLayer *layer;
+ MTFace *mtf;
+ MCol *mcol;
+ TFace *tf;
+ int a, mtfacen, mcoln;
+
+ if (!me->vdata.totlayer) {
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, me->mvert, me->totvert);
+
+ if (me->msticky)
+ CustomData_add_layer(&me->vdata, CD_MSTICKY, CD_ASSIGN, me->msticky, me->totvert);
+ if (me->dvert)
+ CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_ASSIGN, me->dvert, me->totvert);
+ }
+
+ if (!me->edata.totlayer)
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, me->medge, me->totedge);
+
+ if (!me->fdata.totlayer) {
+ CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, me->mface, me->totface);
+
+ if (me->tface) {
+ if (me->mcol)
+ MEM_freeN(me->mcol);
+
+ me->mcol= CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface);
+ me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface);
+
+ mtf= me->mtface;
+ mcol= me->mcol;
+ tf= me->tface;
+
+ for (a=0; a < me->totface; a++, mtf++, tf++, mcol+=4) {
+ memcpy(mcol, tf->col, sizeof(tf->col));
+ memcpy(mtf->uv, tf->uv, sizeof(tf->uv));
+
+ mtf->flag= tf->flag;
+ mtf->unwrap= tf->unwrap;
+ mtf->mode= tf->mode;
+ mtf->tile= tf->tile;
+ mtf->tpage= tf->tpage;
+ mtf->transp= tf->transp;
+ }
+
+ MEM_freeN(me->tface);
+ me->tface= NULL;
+ }
+ else if (me->mcol) {
+ me->mcol= CustomData_add_layer(&me->fdata, CD_MCOL, CD_ASSIGN, me->mcol, me->totface);
+ }
+ }
+
+ if (me->tface) {
+ MEM_freeN(me->tface);
+ me->tface= NULL;
+ }
+
+ for (a=0, mtfacen=0, mcoln=0; a < me->fdata.totlayer; a++) {
+ layer= &me->fdata.layers[a];
+
+ if (layer->type == CD_MTFACE) {
+ if (layer->name[0] == 0) {
+ if (mtfacen == 0) strcpy(layer->name, "UVTex");
+ else sprintf(layer->name, "UVTex.%.3d", mtfacen);
+ }
+ mtfacen++;
+ }
+ else if (layer->type == CD_MCOL) {
+ if (layer->name[0] == 0) {
+ if (mcoln == 0) strcpy(layer->name, "Col");
+ else sprintf(layer->name, "Col.%.3d", mcoln);
+ }
+ mcoln++;
+ }
+ }
+
+ mesh_update_customdata_pointers(me);
+}
+
+/*only copy render texface layer from active*/
+static void customdata_version_243(Mesh *me)
+{
+ CustomDataLayer *layer;
+ int a;
+
+ for (a=0; a < me->fdata.totlayer; a++) {
+ layer= &me->fdata.layers[a];
+ layer->active_rnd = layer->active;
+ }
+}
+
+/* struct NodeImageAnim moved to ImageUser, and we make it default available */
+static void do_version_ntree_242_2(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree->type==NTREE_COMPOSIT) {
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
+ /* only image had storage */
+ if(node->storage) {
+ NodeImageAnim *nia= node->storage;
+ ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "ima user node");
+
+ iuser->frames= nia->frames;
+ iuser->sfra= nia->sfra;
+ iuser->offset= nia->nr-1;
+ iuser->cycl= nia->cyclic;
+ iuser->fie_ima= 2;
+ iuser->ok= 1;
+
+ node->storage= iuser;
+ MEM_freeN(nia);
+ }
+ else {
+ ImageUser *iuser= node->storage= MEM_callocN(sizeof(ImageUser), "node image user");
+ iuser->sfra= 1;
+ iuser->fie_ima= 2;
+ iuser->ok= 1;
+ }
+ }
+ }
+ }
+}
+
+static void do_versions(FileData *fd, Library *lib, Main *main)
+{
+ /* WATCH IT!!!: pointers from libdata have not been converted */
+
+ if(G.f & G_DEBUG)
+ printf("read file %s\n Version %d sub %d\n", fd->filename, main->versionfile, main->subversionfile);
+
+ if(main->versionfile == 100) {
+ /* tex->extend and tex->imageflag have changed: */
+ Tex *tex = main->tex.first;
+ while(tex) {
+ if(tex->id.flag & LIB_NEEDLINK) {
+
+ if(tex->extend==0) {
+ if(tex->xrepeat || tex->yrepeat) tex->extend= TEX_REPEAT;
+ else {
+ tex->extend= TEX_EXTEND;
+ tex->xrepeat= tex->yrepeat= 1;
+ }
+ }
+
+ }
+ tex= tex->id.next;
+ }
+ }
+ if(main->versionfile <= 101) {
+ /* frame mapping */
+ Scene *sce = main->scene.first;
+ while(sce) {
+ sce->r.framapto= 100;
+ sce->r.images= 100;
+ sce->r.framelen= 1.0;
+ sce= sce->id.next;
+ }
+ }
+ if(main->versionfile <= 102) {
+ /* init halo's at 1.0 */
+ Material *ma = main->mat.first;
+ while(ma) {
+ ma->add= 1.0;
+ ma= ma->id.next;
+ }
+ }
+ if(main->versionfile <= 103) {
+ /* new variable in object: colbits */
+ Object *ob = main->object.first;
+ int a;
+ while(ob) {
+ ob->colbits= 0;
+ if(ob->totcol) {
+ for(a=0; a<ob->totcol; a++) {
+ if(ob->mat[a]) ob->colbits |= (1<<a);
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+ if(main->versionfile <= 104) {
+ /* timeoffs moved */
+ Object *ob = main->object.first;
+ while(ob) {
+ if(ob->transflag & 1) {
+ ob->transflag -= 1;
+ ob->ipoflag |= OB_OFFS_OB;
+ }
+ ob= ob->id.next;
+ }
+ }
+ if(main->versionfile <= 105) {
+ Object *ob = main->object.first;
+ while(ob) {
+ ob->dupon= 1; ob->dupoff= 0;
+ ob->dupsta= 1; ob->dupend= 100;
+ ob= ob->id.next;
+ }
+ }
+ if(main->versionfile <= 106) {
+ /* mcol changed */
+ Mesh *me = main->mesh.first;
+ while(me) {
+ if(me->mcol) vcol_to_fcol(me);
+ me= me->id.next;
+ }
+
+ }
+ if(main->versionfile <= 107) {
+ Object *ob;
+ Scene *sce = main->scene.first;
+ while(sce) {
+ sce->r.mode |= R_GAMMA;
+ sce= sce->id.next;
+ }
+ ob= main->object.first;
+ while(ob) {
+ ob->ipoflag |= OB_OFFS_PARENT;
+ if(ob->dt==0) ob->dt= OB_SOLID;
+ ob= ob->id.next;
+ }
+
+ }
+ if(main->versionfile <= 109) {
+ /* new variable: gridlines */
+ bScreen *sc = main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while (sl) {
+ if (sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+
+ if (v3d->gridlines==0) v3d->gridlines= 20;
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+ if(main->versionfile <= 112) {
+ Mesh *me = main->mesh.first;
+ while(me) {
+ me->cubemapsize= 1.0;
+ me= me->id.next;
+ }
+ }
+ if(main->versionfile <= 113) {
+ Material *ma = main->mat.first;
+ while(ma) {
+ if(ma->flaresize==0.0) ma->flaresize= 1.0;
+ ma->subsize= 1.0;
+ ma->flareboost= 1.0;
+ ma= ma->id.next;
+ }
+ }
+
+ if(main->versionfile <= 134) {
+ Tex *tex = main->tex.first;
+ while (tex) {
+ if ((tex->rfac == 0.0) &&
+ (tex->gfac == 0.0) &&
+ (tex->bfac == 0.0)) {
+ tex->rfac = 1.0;
+ tex->gfac = 1.0;
+ tex->bfac = 1.0;
+ tex->filtersize = 1.0;
+ }
+ tex = tex->id.next;
+ }
+ }
+ if(main->versionfile <= 140) {
+ /* r-g-b-fac in texure */
+ Tex *tex = main->tex.first;
+ while (tex) {
+ if ((tex->rfac == 0.0) &&
+ (tex->gfac == 0.0) &&
+ (tex->bfac == 0.0)) {
+ tex->rfac = 1.0;
+ tex->gfac = 1.0;
+ tex->bfac = 1.0;
+ tex->filtersize = 1.0;
+ }
+ tex = tex->id.next;
+ }
+ }
+ if(main->versionfile <= 153) {
+ Scene *sce = main->scene.first;
+ while(sce) {
+ if(sce->r.blurfac==0.0) sce->r.blurfac= 1.0;
+ sce= sce->id.next;
+ }
+ }
+ if(main->versionfile <= 163) {
+ Scene *sce = main->scene.first;
+ while(sce) {
+ if(sce->r.frs_sec==0) sce->r.frs_sec= 25;
+ sce= sce->id.next;
+ }
+ }
+ if(main->versionfile <= 164) {
+ Mesh *me= main->mesh.first;
+ while(me) {
+ me->smoothresh= 30;
+ me= me->id.next;
+ }
+ }
+ if(main->versionfile <= 165) {
+ Mesh *me= main->mesh.first;
+ TFace *tface;
+ int nr;
+ char *cp;
+
+ while(me) {
+ if(me->tface) {
+ nr= me->totface;
+ tface= me->tface;
+ while(nr--) {
+ cp= (char *)&tface->col[0];
+ if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
+ if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
+ if(cp[3]>126) cp[3]= 255; else cp[3]*=2;
+ cp= (char *)&tface->col[1];
+ if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
+ if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
+ if(cp[3]>126) cp[3]= 255; else cp[3]*=2;
+ cp= (char *)&tface->col[2];
+ if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
+ if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
+ if(cp[3]>126) cp[3]= 255; else cp[3]*=2;
+ cp= (char *)&tface->col[3];
+ if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
+ if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
+ if(cp[3]>126) cp[3]= 255; else cp[3]*=2;
+
+ tface++;
+ }
+ }
+ me= me->id.next;
+ }
+ }
+
+ if(main->versionfile <= 169) {
+ Mesh *me= main->mesh.first;
+ while(me) {
+ if(me->subdiv==0) me->subdiv= 1;
+ me= me->id.next;
+ }
+ }
+
+ if(main->versionfile <= 169) {
+ bScreen *sc= main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_IPO) {
+ SpaceIpo *sipo= (SpaceIpo*) sl;
+ sipo->v2d.max[0]= 15000.0;
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+
+ if(main->versionfile <= 170) {
+ Object *ob = main->object.first;
+ PartEff *paf;
+ while (ob) {
+ paf = give_parteff(ob);
+ if (paf) {
+ if (paf->staticstep == 0) {
+ paf->staticstep= 5;
+ }
+ }
+ ob = ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 171) {
+ bScreen *sc= main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_TEXT) {
+ SpaceText *st= (SpaceText*) sl;
+ if(st->font_id>1) {
+ st->font_id= 0;
+ st->lheight= 13;
+ }
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+
+ if(main->versionfile <= 173) {
+ int a, b;
+ Mesh *me= main->mesh.first;
+ while(me) {
+ if(me->tface) {
+ TFace *tface= me->tface;
+ for(a=0; a<me->totface; a++, tface++) {
+ for(b=0; b<4; b++) {
+ tface->uv[b][0]/= 32767.0;
+ tface->uv[b][1]/= 32767.0;
+ }
+ }
+ }
+ me= me->id.next;
+ }
+ }
+
+ if(main->versionfile <= 191) {
+ bScreen *sc= main->screen.first;
+ Object *ob= main->object.first;
+ Material *ma = main->mat.first;
+
+ /* let faces have default add factor of 0.0 */
+ while(ma) {
+ if (!(ma->mode & MA_HALO)) ma->add = 0.0;
+ ma = ma->id.next;
+ }
+
+ while(ob) {
+ ob->mass= 1.0f;
+ ob->damping= 0.1f;
+ ob->quat[1]= 1.0f;
+ ob= ob->id.next;
+ }
+
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_BUTS) {
+ SpaceButs *sbuts= (SpaceButs*) sl;
+ sbuts->scaflag= BUTS_SENS_LINK|BUTS_SENS_ACT|BUTS_CONT_ACT|BUTS_ACT_ACT|BUTS_ACT_LINK;
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+
+ if(main->versionfile <= 193) {
+ Object *ob= main->object.first;
+ while(ob) {
+ ob->inertia= 1.0f;
+ ob->rdamping= 0.1f;
+ ob= ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 196) {
+ Mesh *me= main->mesh.first;
+ int a, b;
+ while(me) {
+ if(me->tface) {
+ TFace *tface= me->tface;
+ for(a=0; a<me->totface; a++, tface++) {
+ for(b=0; b<4; b++) {
+ tface->mode |= TF_DYNAMIC;
+ tface->mode &= ~TF_INVISIBLE;
+ }
+ }
+ }
+ me= me->id.next;
+ }
+ }
+
+ if(main->versionfile <= 200) {
+ Object *ob= main->object.first;
+ while(ob) {
+ ob->scaflag = ob->gameflag & (64+128+256+512+1024+2048);
+ /* 64 is do_fh */
+ ob->gameflag &= ~(128+256+512+1024+2048);
+ ob = ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 201) {
+ /* add-object + end-object are joined to edit-object actuator */
+ Object *ob = main->object.first;
+ bProperty *prop;
+ bActuator *act;
+ bIpoActuator *ia;
+ bEditObjectActuator *eoa;
+ bAddObjectActuator *aoa;
+ while (ob) {
+ act = ob->actuators.first;
+ while (act) {
+ if(act->type==ACT_IPO) {
+ ia= act->data;
+ prop= get_property(ob, ia->name);
+ if(prop) {
+ ia->type= ACT_IPO_FROM_PROP;
+ }
+ }
+ else if(act->type==ACT_ADD_OBJECT) {
+ aoa= act->data;
+ eoa= MEM_callocN(sizeof(bEditObjectActuator), "edit ob act");
+ eoa->type= ACT_EDOB_ADD_OBJECT;
+ eoa->ob= aoa->ob;
+ eoa->time= aoa->time;
+ MEM_freeN(aoa);
+ act->data= eoa;
+ act->type= act->otype= ACT_EDIT_OBJECT;
+ }
+ else if(act->type==ACT_END_OBJECT) {
+ eoa= MEM_callocN(sizeof(bEditObjectActuator), "edit ob act");
+ eoa->type= ACT_EDOB_END_OBJECT;
+ act->data= eoa;
+ act->type= act->otype= ACT_EDIT_OBJECT;
+ }
+ act= act->next;
+ }
+ ob = ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 202) {
+ /* add-object and end-object are joined to edit-object
+ * actuator */
+ Object *ob= main->object.first;
+ bActuator *act;
+ bObjectActuator *oa;
+ while(ob) {
+ act= ob->actuators.first;
+ while(act) {
+ if(act->type==ACT_OBJECT) {
+ oa= act->data;
+ oa->flag &= ~(ACT_TORQUE_LOCAL|ACT_DROT_LOCAL); /* this actuator didn't do local/glob rot before */
+ }
+ act= act->next;
+ }
+ ob= ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 204) {
+ /* patches for new physics */
+ Object *ob= main->object.first;
+ bActuator *act;
+ bObjectActuator *oa;
+ bSound *sound;
+ while(ob) {
+
+ /* please check this for demo20 files like
+ * original Egypt levels etc. converted
+ * rotation factor of 50 is not workable */
+ act= ob->actuators.first;
+ while(act) {
+ if(act->type==ACT_OBJECT) {
+ oa= act->data;
+
+ oa->forceloc[0]*= 25.0;
+ oa->forceloc[1]*= 25.0;
+ oa->forceloc[2]*= 25.0;
+
+ oa->forcerot[0]*= 10.0;
+ oa->forcerot[1]*= 10.0;
+ oa->forcerot[2]*= 10.0;
+ }
+ act= act->next;
+ }
+ ob= ob->id.next;
+ }
+
+ sound = main->sound.first;
+ while (sound) {
+ if (sound->volume < 0.01) {
+ sound->volume = 1.0;
+ }
+ sound = sound->id.next;
+ }
+ }
+
+ if(main->versionfile <= 205) {
+ /* patches for new physics */
+ Object *ob= main->object.first;
+ bActuator *act;
+ bSensor *sens;
+ bEditObjectActuator *oa;
+ bRaySensor *rs;
+ bCollisionSensor *cs;
+ while(ob) {
+ /* Set anisotropic friction off for old objects,
+ * values to 1.0. */
+ ob->gameflag &= ~OB_ANISOTROPIC_FRICTION;
+ ob->anisotropicFriction[0] = 1.0;
+ ob->anisotropicFriction[1] = 1.0;
+ ob->anisotropicFriction[2] = 1.0;
+
+ act= ob->actuators.first;
+ while(act) {
+ if(act->type==ACT_EDIT_OBJECT) {
+ /* Zero initial velocity for newly
+ * added objects */
+ oa= act->data;
+ oa->linVelocity[0] = 0.0;
+ oa->linVelocity[1] = 0.0;
+ oa->linVelocity[2] = 0.0;
+ oa->localflag = 0;
+ }
+ act= act->next;
+ }
+
+ sens= ob->sensors.first;
+ while (sens) {
+ /* Extra fields for radar sensors. */
+ if(sens->type == SENS_RADAR) {
+ bRadarSensor *s = sens->data;
+ s->range = 10000.0;
+ }
+
+ /* Pulsing: defaults for new sensors. */
+ if(sens->type != SENS_ALWAYS) {
+ sens->pulse = 0;
+ sens->freq = 0;
+ } else {
+ sens->pulse = 1;
+ }
+
+ /* Invert: off. */
+ sens->invert = 0;
+
+ /* Collision and ray: default = trigger
+ * on property. The material field can
+ * remain empty. */
+ if(sens->type == SENS_COLLISION) {
+ cs = (bCollisionSensor*) sens->data;
+ cs->mode = 0;
+ }
+ if(sens->type == SENS_RAY) {
+ rs = (bRaySensor*) sens->data;
+ rs->mode = 0;
+ }
+ sens = sens->next;
+ }
+ ob= ob->id.next;
+ }
+ /* have to check the exact multiplier */
+ }
+
+ if(main->versionfile <= 211) {
+ /* Render setting: per scene, the applicable gamma value
+ * can be set. Default is 1.0, which means no
+ * correction. */
+ bActuator *act;
+ bObjectActuator *oa;
+ Object *ob;
+
+ /* added alpha in obcolor */
+ ob= main->object.first;
+ while(ob) {
+ ob->col[3]= 1.0;
+ ob= ob->id.next;
+ }
+
+ /* added alpha in obcolor */
+ ob= main->object.first;
+ while(ob) {
+ act= ob->actuators.first;
+ while(act) {
+ if (act->type==ACT_OBJECT) {
+ /* multiply velocity with 50 in old files */
+ oa= act->data;
+ if (fabs(oa->linearvelocity[0]) >= 0.01f)
+ oa->linearvelocity[0] *= 50.0;
+ if (fabs(oa->linearvelocity[1]) >= 0.01f)
+ oa->linearvelocity[1] *= 50.0;
+ if (fabs(oa->linearvelocity[2]) >= 0.01f)
+ oa->linearvelocity[2] *= 50.0;
+ if (fabs(oa->angularvelocity[0])>=0.01f)
+ oa->angularvelocity[0] *= 50.0;
+ if (fabs(oa->angularvelocity[1])>=0.01f)
+ oa->angularvelocity[1] *= 50.0;
+ if (fabs(oa->angularvelocity[2])>=0.01f)
+ oa->angularvelocity[2] *= 50.0;
+ }
+ act= act->next;
+ }
+ ob= ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 212) {
+
+ bSound* sound;
+ bProperty *prop;
+ Object *ob;
+ Mesh *me;
+
+ sound = main->sound.first;
+ while (sound)
+ {
+ sound->max_gain = 1.0;
+ sound->min_gain = 0.0;
+ sound->distance = 1.0;
+
+ if (sound->attenuation > 0.0)
+ sound->flags |= SOUND_FLAGS_3D;
+ else
+ sound->flags &= ~SOUND_FLAGS_3D;
+
+ sound = sound->id.next;
+ }
+
+ ob = main->object.first;
+
+ while (ob) {
+ prop= ob->prop.first;
+ while(prop) {
+ if (prop->type == PROP_TIME) {
+ // convert old PROP_TIME values from int to float
+ *((float *)&prop->data) = (float) prop->data;
+ }
+
+ prop= prop->next;
+ }
+ ob = ob->id.next;
+ }
+
+ /* me->subdiv changed to reflect the actual reparametization
+ * better, and smeshes were removed - if it was a smesh make
+ * it a subsurf, and reset the subdiv level because subsurf
+ * takes a lot more work to calculate.
+ */
+ for (me= main->mesh.first; me; me= me->id.next) {
+ if (me->flag&ME_SMESH) {
+ me->flag&= ~ME_SMESH;
+ me->flag|= ME_SUBSURF;
+
+ me->subdiv= 1;
+ } else {
+ if (me->subdiv<2)
+ me->subdiv= 1;
+ else
+ me->subdiv--;
+ }
+ }
+ }
+
+ if(main->versionfile <= 220) {
+ Object *ob;
+ Mesh *me;
+
+ ob = main->object.first;
+
+ /* adapt form factor in order to get the 'old' physics
+ * behaviour back...*/
+
+ while (ob) {
+ /* in future, distinguish between different
+ * object bounding shapes */
+ ob->formfactor = 0.4f;
+ /* patch form factor , note that inertia equiv radius
+ * of a rotation symmetrical obj */
+ if (ob->inertia != 1.0) {
+ ob->formfactor /= ob->inertia * ob->inertia;
+ }
+ ob = ob->id.next;
+ }
+
+ /* Began using alpha component of vertex colors, but
+ * old file vertex colors are undefined, reset them
+ * to be fully opaque. -zr
+ */
+ for (me= main->mesh.first; me; me= me->id.next) {
+ if (me->mcol) {
+ int i;
+
+ for (i=0; i<me->totface*4; i++) {
+ MCol *mcol= &me->mcol[i];
+ mcol->a= 255;
+ }
+ }
+ if (me->tface) {
+ int i, j;
+
+ for (i=0; i<me->totface; i++) {
+ TFace *tf= &((TFace*) me->tface)[i];
+
+ for (j=0; j<4; j++) {
+ char *col= (char*) &tf->col[j];
+
+ col[0]= 255;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 221) {
+ Scene *sce= main->scene.first;
+
+ // new variables for std-alone player and runtime
+ while(sce) {
+
+ sce->r.xplay= 640;
+ sce->r.yplay= 480;
+ sce->r.freqplay= 60;
+
+ sce= sce->id.next;
+ }
+
+ }
+ if(main->versionfile <= 222) {
+ Scene *sce= main->scene.first;
+
+ // new variables for std-alone player and runtime
+ while(sce) {
+
+ sce->r.depth= 32;
+
+ sce= sce->id.next;
+ }
+ }
+
+
+ if(main->versionfile <= 223) {
+ VFont *vf;
+ Image *ima;
+ Object *ob;
+
+ for (vf= main->vfont.first; vf; vf= vf->id.next) {
+ if (BLI_streq(vf->name+strlen(vf->name)-6, ".Bfont")) {
+ strcpy(vf->name, "<builtin>");
+ }
+ }
+
+ /* Old textures animate at 25 FPS */
+ for (ima = main->image.first; ima; ima=ima->id.next){
+ ima->animspeed = 25;
+ }
+
+ /* Zr remapped some keyboard codes to be linear (stupid zr) */
+ for (ob= main->object.first; ob; ob= ob->id.next) {
+ bSensor *sens;
+
+ for (sens= ob->sensors.first; sens; sens= sens->next) {
+ if (sens->type==SENS_KEYBOARD) {
+ bKeyboardSensor *ks= sens->data;
+
+ ks->key= map_223_keybd_code_to_224_keybd_code(ks->key);
+ ks->qual= map_223_keybd_code_to_224_keybd_code(ks->qual);
+ ks->qual2= map_223_keybd_code_to_224_keybd_code(ks->qual2);
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 224) {
+ bSound* sound;
+ Scene *sce;
+ Mesh *me;
+ bScreen *sc;
+
+ for (sound=main->sound.first; sound; sound=sound->id.next) {
+ if (sound->packedfile) {
+ if (sound->newpackedfile == NULL) {
+ sound->newpackedfile = sound->packedfile;
+ }
+ sound->packedfile = NULL;
+ }
+ }
+ /* Make sure that old subsurf meshes don't have zero subdivision level for rendering */
+ for (me=main->mesh.first; me; me=me->id.next){
+ if ((me->flag & ME_SUBSURF) && (me->subdivr==0))
+ me->subdivr=me->subdiv;
+ }
+
+ for (sce= main->scene.first; sce; sce= sce->id.next) {
+ sce->r.stereomode = 1; // no stereo
+ }
+
+ /* some oldfile patch, moved from set_func_space */
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if (sl->spacetype==SPACE_IPO) {
+ SpaceSeq *sseq= (SpaceSeq*) sl;
+ sseq->v2d.keeptot= 0;
+ }
+ }
+ }
+ }
+
+ }
+
+
+ if(main->versionfile <= 225) {
+ World *wo;
+ /* Use Sumo for old games */
+ for (wo = main->world.first; wo; wo= wo->id.next) {
+ wo->physicsEngine = 2;
+ }
+ }
+
+ if(main->versionfile <= 227) {
+ Scene *sce;
+ Material *ma;
+ bScreen *sc;
+ Object *ob;
+
+ /* As of now, this insures that the transition from the old Track system
+ to the new full constraint Track is painless for everyone. - theeth
+ */
+ ob = main->object.first;
+
+ while (ob) {
+ ListBase *list;
+ list = &ob->constraints;
+
+ /* check for already existing TrackTo constraint
+ set their track and up flag correctly */
+
+ if (list){
+ bConstraint *curcon;
+ for (curcon = list->first; curcon; curcon=curcon->next){
+ if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
+ bTrackToConstraint *data = curcon->data;
+ data->reserved1 = ob->trackflag;
+ data->reserved2 = ob->upflag;
+ }
+ }
+ }
+
+ if (ob->type == OB_ARMATURE) {
+ if (ob->pose){
+ bConstraint *curcon;
+ bPoseChannel *pchan;
+ for (pchan = ob->pose->chanbase.first;
+ pchan; pchan=pchan->next){
+ for (curcon = pchan->constraints.first;
+ curcon; curcon=curcon->next){
+ if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
+ bTrackToConstraint *data = curcon->data;
+ data->reserved1 = ob->trackflag;
+ data->reserved2 = ob->upflag;
+ }
+ }
+ }
+ }
+ }
+
+ /* Change Ob->Track in real TrackTo constraint */
+
+ if (ob->track){
+ bConstraint *con;
+ bConstraintTypeInfo *cti;
+ bTrackToConstraint *data;
+ void *cdata;
+
+ list = &ob->constraints;
+ if (list)
+ {
+ con = MEM_callocN(sizeof(bConstraint), "constraint");
+ strcpy (con->name, "AutoTrack");
+ unique_constraint_name(con, list);
+ con->flag |= CONSTRAINT_EXPAND;
+ con->enforce=1.0F;
+ con->type = CONSTRAINT_TYPE_TRACKTO;
+
+ cti= get_constraint_typeinfo(CONSTRAINT_TYPE_TRACKTO);
+ cdata= MEM_callocN(cti->size, cti->structName);
+ cti->new_data(cdata);
+ data = (bTrackToConstraint *)cdata;
+
+ data->tar = ob->track;
+ data->reserved1 = ob->trackflag;
+ data->reserved2 = ob->upflag;
+ con->data= (void*) data;
+ BLI_addtail(list, con);
+ }
+ ob->track = 0;
+ }
+
+ ob = ob->id.next;
+ }
+
+
+ for (sce= main->scene.first; sce; sce= sce->id.next) {
+ sce->audio.mixrate = 44100;
+ sce->audio.flag |= AUDIO_SCRUB;
+ sce->r.mode |= R_ENVMAP;
+ }
+ // init new shader vars
+ for (ma= main->mat.first; ma; ma= ma->id.next) {
+ ma->refrac= 4.0f;
+ ma->roughness= 0.5f;
+ ma->param[0]= 0.5f;
+ ma->param[1]= 0.1f;
+ ma->param[2]= 0.1f;
+ ma->param[3]= 0.05f;
+ }
+ // patch for old wrong max view2d settings, allows zooming out more
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if (sl->spacetype==SPACE_ACTION) {
+ SpaceAction *sac= (SpaceAction *) sl;
+ sac->v2d.max[0]= 32000;
+ }
+ else if (sl->spacetype==SPACE_NLA) {
+ SpaceNla *sla= (SpaceNla *) sl;
+ sla->v2d.max[0]= 32000;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 228) {
+ Scene *sce;
+ bScreen *sc;
+ Object *ob;
+
+
+ /* As of now, this insures that the transition from the old Track system
+ to the new full constraint Track is painless for everyone.*/
+ ob = main->object.first;
+
+ while (ob) {
+ ListBase *list;
+ list = &ob->constraints;
+
+ /* check for already existing TrackTo constraint
+ set their track and up flag correctly */
+
+ if (list){
+ bConstraint *curcon;
+ for (curcon = list->first; curcon; curcon=curcon->next){
+ if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
+ bTrackToConstraint *data = curcon->data;
+ data->reserved1 = ob->trackflag;
+ data->reserved2 = ob->upflag;
+ }
+ }
+ }
+
+ if (ob->type == OB_ARMATURE) {
+ if (ob->pose){
+ bConstraint *curcon;
+ bPoseChannel *pchan;
+ for (pchan = ob->pose->chanbase.first;
+ pchan; pchan=pchan->next){
+ for (curcon = pchan->constraints.first;
+ curcon; curcon=curcon->next){
+ if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
+ bTrackToConstraint *data = curcon->data;
+ data->reserved1 = ob->trackflag;
+ data->reserved2 = ob->upflag;
+ }
+ }
+ }
+ }
+ }
+
+ ob = ob->id.next;
+ }
+
+ for (sce= main->scene.first; sce; sce= sce->id.next) {
+ sce->r.mode |= R_ENVMAP;
+ }
+
+ // convert old mainb values for new button panels
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if (sl->spacetype==SPACE_BUTS) {
+ SpaceButs *sbuts= (SpaceButs *) sl;
+
+ sbuts->v2d.maxzoom= 1.2f;
+ sbuts->align= 1; /* horizontal default */
+
+ if(sbuts->mainb==BUTS_LAMP) {
+ sbuts->mainb= CONTEXT_SHADING;
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_LAMP;
+ }
+ else if(sbuts->mainb==BUTS_MAT) {
+ sbuts->mainb= CONTEXT_SHADING;
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_MAT;
+ }
+ else if(sbuts->mainb==BUTS_TEX) {
+ sbuts->mainb= CONTEXT_SHADING;
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_TEX;
+ }
+ else if(sbuts->mainb==BUTS_ANIM) {
+ sbuts->mainb= CONTEXT_OBJECT;
+ }
+ else if(sbuts->mainb==BUTS_WORLD) {
+ sbuts->mainb= CONTEXT_SCENE;
+ sbuts->tab[CONTEXT_SCENE]= TAB_SCENE_WORLD;
+ }
+ else if(sbuts->mainb==BUTS_RENDER) {
+ sbuts->mainb= CONTEXT_SCENE;
+ sbuts->tab[CONTEXT_SCENE]= TAB_SCENE_RENDER;
+ }
+ else if(sbuts->mainb==BUTS_GAME) {
+ sbuts->mainb= CONTEXT_LOGIC;
+ }
+ else if(sbuts->mainb==BUTS_FPAINT) {
+ sbuts->mainb= CONTEXT_EDITING;
+ }
+ else if(sbuts->mainb==BUTS_RADIO) {
+ sbuts->mainb= CONTEXT_SHADING;
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_RAD;
+ }
+ else if(sbuts->mainb==BUTS_CONSTRAINT) {
+ sbuts->mainb= CONTEXT_OBJECT;
+ }
+ else if(sbuts->mainb==BUTS_SCRIPT) {
+ sbuts->mainb= CONTEXT_OBJECT;
+ }
+ else if(sbuts->mainb==BUTS_EDIT) {
+ sbuts->mainb= CONTEXT_EDITING;
+ }
+ else sbuts->mainb= CONTEXT_SCENE;
+ }
+ }
+ }
+ }
+ }
+ /* ton: made this 230 instead of 229,
+ to be sure (tuho files) and this is a reliable check anyway
+ nevertheless, we might need to think over a fitness (initialize)
+ check apart from the do_versions() */
+
+ if(main->versionfile <= 230) {
+ bScreen *sc;
+
+ // new variable blockscale, for panels in any area
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->blockscale==0.0) sl->blockscale= 0.7f;
+ /* added: 5x better zoom in for action */
+ if(sl->spacetype==SPACE_ACTION) {
+ SpaceAction *sac= (SpaceAction *)sl;
+ sac->v2d.maxzoom= 50;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 231) {
+ /* new bit flags for showing/hiding grid floor and axes */
+ bScreen *sc = main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while (sl) {
+ if (sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+
+ if (v3d->gridflag==0) {
+ v3d->gridflag |= V3D_SHOW_X;
+ v3d->gridflag |= V3D_SHOW_Y;
+ v3d->gridflag |= V3D_SHOW_FLOOR;
+ v3d->gridflag &= ~V3D_SHOW_Z;
+ }
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+ if(main->versionfile <= 231) {
+ Material *ma= main->mat.first;
+ bScreen *sc = main->screen.first;
+ Scene *sce;
+ Lamp *la;
+ World *wrld;
+
+ /* introduction of raytrace */
+ while(ma) {
+ if(ma->fresnel_tra_i==0.0) ma->fresnel_tra_i= 1.25;
+ if(ma->fresnel_mir_i==0.0) ma->fresnel_mir_i= 1.25;
+
+ ma->ang= 1.0;
+ ma->ray_depth= 2;
+ ma->ray_depth_tra= 2;
+ ma->fresnel_tra= 0.0;
+ ma->fresnel_mir= 0.0;
+
+ ma= ma->id.next;
+ }
+ sce= main->scene.first;
+ while(sce) {
+ if(sce->r.gauss==0.0) sce->r.gauss= 1.0;
+ sce= sce->id.next;
+ }
+ la= main->lamp.first;
+ while(la) {
+ if(la->k==0.0) la->k= 1.0;
+ if(la->ray_samp==0) la->ray_samp= 1;
+ if(la->ray_sampy==0) la->ray_sampy= 1;
+ if(la->ray_sampz==0) la->ray_sampz= 1;
+ if(la->area_size==0.0) la->area_size= 1.0;
+ if(la->area_sizey==0.0) la->area_sizey= 1.0;
+ if(la->area_sizez==0.0) la->area_sizez= 1.0;
+ la= la->id.next;
+ }
+ wrld= main->world.first;
+ while(wrld) {
+ if(wrld->range==0.0) {
+ wrld->range= 1.0f/wrld->exposure;
+ }
+ wrld= wrld->id.next;
+ }
+
+ /* new bit flags for showing/hiding grid floor and axes */
+
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while (sl) {
+ if (sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+
+ if (v3d->gridflag==0) {
+ v3d->gridflag |= V3D_SHOW_X;
+ v3d->gridflag |= V3D_SHOW_Y;
+ v3d->gridflag |= V3D_SHOW_FLOOR;
+ v3d->gridflag &= ~V3D_SHOW_Z;
+ }
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+ if(main->versionfile <= 232) {
+ Tex *tex= main->tex.first;
+ World *wrld= main->world.first;
+ bScreen *sc;
+ Scene *sce;
+
+ while(tex) {
+ if((tex->flag & (TEX_CHECKER_ODD+TEX_CHECKER_EVEN))==0) {
+ tex->flag |= TEX_CHECKER_ODD;
+ }
+ /* copied from kernel texture.c */
+ if(tex->ns_outscale==0.0) {
+ /* musgrave */
+ tex->mg_H = 1.0f;
+ tex->mg_lacunarity = 2.0f;
+ tex->mg_octaves = 2.0f;
+ tex->mg_offset = 1.0f;
+ tex->mg_gain = 1.0f;
+ tex->ns_outscale = 1.0f;
+ /* distnoise */
+ tex->dist_amount = 1.0f;
+ /* voronoi */
+ tex->vn_w1 = 1.0f;
+ tex->vn_mexp = 2.5f;
+ }
+ tex= tex->id.next;
+ }
+
+ while(wrld) {
+ if(wrld->aodist==0.0) {
+ wrld->aodist= 10.0f;
+ wrld->aobias= 0.05f;
+ }
+ if(wrld->aosamp==0.0) wrld->aosamp= 5;
+ if(wrld->aoenergy==0.0) wrld->aoenergy= 1.0;
+ wrld= wrld->id.next;
+ }
+
+
+ // new variable blockscale, for panels in any area, do again because new
+ // areas didnt initialize it to 0.7 yet
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->blockscale==0.0) sl->blockscale= 0.7f;
+
+ /* added: 5x better zoom in for nla */
+ if(sl->spacetype==SPACE_NLA) {
+ SpaceNla *snla= (SpaceNla *)sl;
+ snla->v2d.maxzoom= 50;
+ }
+ }
+ }
+ }
+ sce= main->scene.first;
+ while(sce) {
+ if(sce->r.ocres==0) sce->r.ocres= 64;
+ sce= sce->id.next;
+ }
+
+ }
+ if(main->versionfile <= 233) {
+ bScreen *sc;
+ Material *ma= main->mat.first;
+ Object *ob= main->object.first;
+
+ while(ma) {
+ if(ma->rampfac_col==0.0) ma->rampfac_col= 1.0;
+ if(ma->rampfac_spec==0.0) ma->rampfac_spec= 1.0;
+ if(ma->pr_lamp==0) ma->pr_lamp= 3;
+ ma= ma->id.next;
+ }
+
+ /* this should have been done loooong before! */
+ while(ob) {
+ if(ob->ipowin==0) ob->ipowin= ID_OB;
+ ob= ob->id.next;
+ }
+
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D *)sl;
+ v3d->flag |= V3D_SELECT_OUTLINE;
+ }
+ }
+ }
+ }
+ }
+
+
+
+
+ if(main->versionfile <= 234) {
+ Scene *sce;
+ World *wo;
+ bScreen *sc;
+ int set_zbuf_sel=0;
+
+ // force sumo engine to be active
+ for (wo = main->world.first; wo; wo= wo->id.next) {
+ if(wo->physicsEngine==0) wo->physicsEngine = 2;
+ }
+
+ for (sce= main->scene.first; sce; sce= sce->id.next) {
+ if(sce->selectmode==0) {
+ sce->selectmode= SCE_SELECT_VERTEX;
+ set_zbuf_sel= 1;
+ }
+ }
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D *)sl;
+ if(set_zbuf_sel) v3d->flag |= V3D_ZBUF_SELECT;
+ }
+ else if(sl->spacetype==SPACE_TEXT) {
+ SpaceText *st= (SpaceText *)sl;
+ if(st->tabnumber==0) st->tabnumber= 2;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 235) {
+ Tex *tex= main->tex.first;
+ Scene *sce= main->scene.first;
+ Sequence *seq;
+ Editing *ed;
+
+ while(tex) {
+ if(tex->nabla==0.0) tex->nabla= 0.025f;
+ tex= tex->id.next;
+ }
+ while(sce) {
+ ed= sce->ed;
+ if(ed) {
+ WHILE_SEQ(&ed->seqbase) {
+ if(seq->type==SEQ_IMAGE || seq->type==SEQ_MOVIE) seq->flag |= SEQ_MAKE_PREMUL;
+ }
+ END_SEQ
+ }
+
+ sce= sce->id.next;
+ }
+ }
+ if(main->versionfile <= 236) {
+ Object *ob;
+ Scene *sce= main->scene.first;
+ Camera *cam= main->camera.first;
+ Material *ma;
+ bScreen *sc;
+
+ while(sce) {
+ if(sce->editbutsize==0.0) sce->editbutsize= 0.1f;
+
+ sce= sce->id.next;
+ }
+ while(cam) {
+ if(cam->ortho_scale==0.0) {
+ cam->ortho_scale= 256.0f/cam->lens;
+ if(cam->type==CAM_ORTHO) printf("NOTE: ortho render has changed, tweak new Camera 'scale' value.\n");
+ }
+ cam= cam->id.next;
+ }
+ /* set manipulator type */
+ /* force oops draw if depgraph was set*/
+ /* set time line var */
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D *)sl;
+ if(v3d->twtype==0) v3d->twtype= V3D_MANIP_TRANSLATE;
+ }
+#ifndef SHOWDEPGRAPH
+ else if(sl->spacetype==SPACE_OOPS) {
+ if ( ((SpaceOops *)sl)->type==SO_DEPSGRAPH)
+ ((SpaceOops *)sl)->type=SO_OOPS;
+ }
+#endif
+ else if(sl->spacetype==SPACE_TIME) {
+ SpaceTime *stime= (SpaceTime *)sl;
+ if(stime->redraws==0)
+ stime->redraws= TIME_ALL_3D_WIN|TIME_ALL_ANIM_WIN;
+ }
+ }
+ }
+ }
+ // init new shader vars
+ for (ma= main->mat.first; ma; ma= ma->id.next) {
+ if(ma->darkness==0.0) {
+ ma->rms=0.1f;
+ ma->darkness=1.0f;
+ }
+ }
+
+ /* softbody init new vars */
+ for(ob= main->object.first; ob; ob= ob->id.next) {
+ if(ob->soft) {
+ if(ob->soft->defgoal==0.0) ob->soft->defgoal= 0.7f;
+ if(ob->soft->physics_speed==0.0) ob->soft->physics_speed= 1.0f;
+
+ if(ob->soft->interval==0) {
+ ob->soft->interval= 2;
+ ob->soft->sfra= 1;
+ ob->soft->efra= 100;
+ }
+ }
+ if(ob->soft && ob->soft->vertgroup==0) {
+ bDeformGroup *locGroup = get_named_vertexgroup(ob, "SOFTGOAL");
+ if(locGroup){
+ /* retrieve index for that group */
+ ob->soft->vertgroup = 1 + get_defgroup_num(ob, locGroup);
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 237) {
+ bArmature *arm;
+ bConstraint *con;
+ Object *ob;
+
+ // armature recode checks
+ for(arm= main->armature.first; arm; arm= arm->id.next) {
+ where_is_armature(arm);
+ }
+ for(ob= main->object.first; ob; ob= ob->id.next) {
+ if(ob->parent) {
+ Object *parent= newlibadr(fd, lib, ob->parent);
+ if (parent && parent->type==OB_LATTICE)
+ ob->partype = PARSKEL;
+ }
+
+ // btw. armature_rebuild_pose is further only called on leave editmode
+ if(ob->type==OB_ARMATURE) {
+ if(ob->pose)
+ ob->pose->flag |= POSE_RECALC;
+ ob->recalc |= OB_RECALC; // cannot call stuff now (pointers!), done in setup_app_data
+
+ /* new generic xray option */
+ arm= newlibadr(fd, lib, ob->data);
+ if(arm->flag & ARM_DRAWXRAY) {
+ ob->dtx |= OB_DRAWXRAY;
+ }
+ } else if (ob->type==OB_MESH) {
+ Mesh *me = newlibadr(fd, lib, ob->data);
+
+ if ((me->flag&ME_SUBSURF)) {
+ SubsurfModifierData *smd = (SubsurfModifierData*) modifier_new(eModifierType_Subsurf);
+
+ smd->levels = MAX2(1, me->subdiv);
+ smd->renderLevels = MAX2(1, me->subdivr);
+ smd->subdivType = me->subsurftype;
+
+ smd->modifier.mode = 0;
+ if (me->subdiv!=0)
+ smd->modifier.mode |= 1;
+ if (me->subdivr!=0)
+ smd->modifier.mode |= 2;
+ if (me->flag&ME_OPT_EDGES)
+ smd->flags |= eSubsurfModifierFlag_ControlEdges;
+
+ BLI_addtail(&ob->modifiers, smd);
+ }
+ }
+
+ // follow path constraint needs to set the 'path' option in curves...
+ for(con=ob->constraints.first; con; con= con->next) {
+ if(con->type==CONSTRAINT_TYPE_FOLLOWPATH) {
+ bFollowPathConstraint *data = con->data;
+ Object *obc= newlibadr(fd, lib, data->tar);
+
+ if(obc && obc->type==OB_CURVE) {
+ Curve *cu= newlibadr(fd, lib, obc->data);
+ if(cu) cu->flag |= CU_PATH;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 238) {
+ Lattice *lt;
+ Object *ob;
+ bArmature *arm;
+ Mesh *me;
+ Key *key;
+ Scene *sce= main->scene.first;
+
+ while(sce){
+ if(sce->toolsettings == NULL){
+ sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings),"Tool Settings Struct");
+ sce->toolsettings->cornertype=0;
+ sce->toolsettings->degr = 90;
+ sce->toolsettings->step = 9;
+ sce->toolsettings->turn = 1;
+ sce->toolsettings->extr_offs = 1;
+ sce->toolsettings->doublimit = 0.001f;
+ sce->toolsettings->segments = 32;
+ sce->toolsettings->rings = 32;
+ sce->toolsettings->vertices = 32;
+ sce->toolsettings->editbutflag =1;
+ }
+ sce= sce->id.next;
+ }
+
+ for (lt=main->latt.first; lt; lt=lt->id.next) {
+ if (lt->fu==0.0 && lt->fv==0.0 && lt->fw==0.0) {
+ calc_lat_fudu(lt->flag, lt->pntsu, &lt->fu, &lt->du);
+ calc_lat_fudu(lt->flag, lt->pntsv, &lt->fv, &lt->dv);
+ calc_lat_fudu(lt->flag, lt->pntsw, &lt->fw, &lt->dw);
+ }
+ }
+
+ for(ob=main->object.first; ob; ob= ob->id.next) {
+ ModifierData *md;
+ PartEff *paf;
+
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Subsurf) {
+ SubsurfModifierData *smd = (SubsurfModifierData*) md;
+
+ smd->flags &= ~(eSubsurfModifierFlag_Incremental|eSubsurfModifierFlag_DebugIncr);
+ }
+ }
+
+ if ((ob->softflag&OB_SB_ENABLE) && !modifiers_findByType(ob, eModifierType_Softbody)) {
+ if (ob->softflag&OB_SB_POSTDEF) {
+ md = ob->modifiers.first;
+
+ while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
+ md = md->next;
+ }
+
+ BLI_insertlinkbefore(&ob->modifiers, md, modifier_new(eModifierType_Softbody));
+ } else {
+ BLI_addhead(&ob->modifiers, modifier_new(eModifierType_Softbody));
+ }
+
+ ob->softflag &= ~OB_SB_ENABLE;
+ }
+ if(ob->pose) {
+ bPoseChannel *pchan;
+ bConstraint *con;
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ // note, pchan->bone is also lib-link stuff
+ if (pchan->limitmin[0] == 0.0f && pchan->limitmax[0] == 0.0f) {
+ pchan->limitmin[0]= pchan->limitmin[1]= pchan->limitmin[2]= -180.0f;
+ pchan->limitmax[0]= pchan->limitmax[1]= pchan->limitmax[2]= 180.0f;
+
+ for(con= pchan->constraints.first; con; con= con->next) {
+ if(con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = (bKinematicConstraint*)con->data;
+ data->weight = 1.0f;
+ data->orientweight = 1.0f;
+ data->flag &= ~CONSTRAINT_IK_ROT;
+
+ /* enforce conversion from old IK_TOPARENT to rootbone index */
+ data->rootbone= -1;
+
+ /* update_pose_etc handles rootbone==-1 */
+ ob->pose->flag |= POSE_RECALC;
+ }
+ }
+ }
+ }
+ }
+
+ paf = give_parteff(ob);
+ if (paf) {
+ if(paf->disp == 0)
+ paf->disp = 100;
+ if(paf->speedtex == 0)
+ paf->speedtex = 8;
+ if(paf->omat == 0)
+ paf->omat = 1;
+ }
+ }
+
+ for(arm=main->armature.first; arm; arm= arm->id.next) {
+ bone_version_238(&arm->bonebase);
+ arm->deformflag |= ARM_DEF_VGROUP;
+ }
+
+ for(me=main->mesh.first; me; me= me->id.next) {
+ if (!me->medge) {
+ make_edges(me, 1); /* 1 = use mface->edcode */
+ } else {
+ mesh_strip_loose_faces(me);
+ }
+ }
+
+ for(key= main->key.first; key; key= key->id.next) {
+ KeyBlock *kb;
+ int index= 1;
+
+ /* trick to find out if we already introduced adrcode */
+ for(kb= key->block.first; kb; kb= kb->next)
+ if(kb->adrcode) break;
+
+ if(kb==NULL) {
+ for(kb= key->block.first; kb; kb= kb->next) {
+ if(kb==key->refkey) {
+ if(kb->name[0]==0)
+ strcpy(kb->name, "Basis");
+ }
+ else {
+ if(kb->name[0]==0)
+ sprintf(kb->name, "Key %d", index);
+ kb->adrcode= index++;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 239) {
+ bArmature *arm;
+ Object *ob;
+ Scene *sce= main->scene.first;
+ Camera *cam= main->camera.first;
+ Material *ma= main->mat.first;
+ int set_passepartout= 0;
+
+ /* deformflag is local in modifier now */
+ for(ob=main->object.first; ob; ob= ob->id.next) {
+ ModifierData *md;
+
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Armature) {
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+ if(amd->object && amd->deformflag==0) {
+ Object *oba= newlibadr(fd, lib, amd->object);
+ bArmature *arm= newlibadr(fd, lib, oba->data);
+ amd->deformflag= arm->deformflag;
+ }
+ }
+ }
+ }
+
+ /* updating stepsize for ghost drawing */
+ for(arm= main->armature.first; arm; arm= arm->id.next) {
+ if (arm->ghostsize==0) arm->ghostsize=1;
+ bone_version_239(&arm->bonebase);
+ if(arm->layer==0) arm->layer= 1;
+ }
+
+ for(;sce;sce= sce->id.next) {
+ /* make 'innervert' the default subdivide type, for backwards compat */
+ sce->toolsettings->cornertype=1;
+
+ if(sce->r.scemode & R_PASSEPARTOUT) {
+ set_passepartout= 1;
+ sce->r.scemode &= ~R_PASSEPARTOUT;
+ }
+ /* gauss is filter variable now */
+ if(sce->r.mode & R_GAUSS) {
+ sce->r.filtertype= R_FILTER_GAUSS;
+ sce->r.mode &= ~R_GAUSS;
+ }
+ }
+
+ for(;cam; cam= cam->id.next) {
+ if(set_passepartout)
+ cam->flag |= CAM_SHOWPASSEPARTOUT;
+
+ /* make sure old cameras have title safe on */
+ if (!(cam->flag & CAM_SHOWTITLESAFE))
+ cam->flag |= CAM_SHOWTITLESAFE;
+
+ /* set an appropriate camera passepartout alpha */
+ if (!(cam->passepartalpha)) cam->passepartalpha = 0.2f;
+ }
+
+ for(; ma; ma= ma->id.next) {
+ if(ma->strand_sta==0.0f) {
+ ma->strand_sta= ma->strand_end= 1.0f;
+ ma->mode |= MA_TANGENT_STR;
+ }
+ if(ma->mode & MA_TRACEBLE) ma->mode |= MA_SHADBUF;
+ }
+ }
+
+ if(main->versionfile <= 241) {
+ Object *ob;
+ Tex *tex;
+ Scene *sce;
+ World *wo;
+ Lamp *la;
+ Material *ma;
+ bArmature *arm;
+ bNodeTree *ntree;
+
+ for (wo = main->world.first; wo; wo= wo->id.next) {
+ /* Migrate to Bullet for games, except for the NaN versions */
+ /* People can still explicitely choose for Sumo (after 2.42 is out) */
+ if(main->versionfile > 225)
+ wo->physicsEngine = WOPHY_BULLET;
+ if(WO_AODIST == wo->aomode)
+ wo->aocolor= WO_AOPLAIN;
+ }
+
+ /* updating layers still */
+ for(arm= main->armature.first; arm; arm= arm->id.next) {
+ bone_version_239(&arm->bonebase);
+ if(arm->layer==0) arm->layer= 1;
+ }
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ if(sce->jumpframe==0) sce->jumpframe= 10;
+ if(sce->audio.mixrate==0) sce->audio.mixrate= 44100;
+
+ if(sce->r.xparts<2) sce->r.xparts= 4;
+ if(sce->r.yparts<2) sce->r.yparts= 4;
+ /* adds default layer */
+ if(sce->r.layers.first==NULL)
+ scene_add_render_layer(sce);
+ else {
+ SceneRenderLayer *srl;
+ /* new layer flag for sky, was default for solid */
+ for(srl= sce->r.layers.first; srl; srl= srl->next) {
+ if(srl->layflag & SCE_LAY_SOLID)
+ srl->layflag |= SCE_LAY_SKY;
+ srl->passflag &= (SCE_PASS_COMBINED|SCE_PASS_Z|SCE_PASS_NORMAL|SCE_PASS_VECTOR);
+ }
+ }
+
+ /* node version changes */
+ if(sce->nodetree)
+ ntree_version_241(sce->nodetree);
+
+ /* uv calculation options moved to toolsettings */
+ if (sce->toolsettings->uvcalc_radius == 0.0) {
+ sce->toolsettings->uvcalc_radius = 1.0f;
+ sce->toolsettings->uvcalc_cubesize = 1.0f;
+ sce->toolsettings->uvcalc_mapdir = 1;
+ sce->toolsettings->uvcalc_mapalign = 1;
+ sce->toolsettings->uvcalc_flag = 1;
+ sce->toolsettings->unwrapper = 1;
+ }
+
+ if(sce->r.mode & R_PANORAMA) {
+ /* all these checks to ensure saved files with cvs version keep working... */
+ if(sce->r.xsch < sce->r.ysch) {
+ Object *obc= newlibadr(fd, lib, sce->camera);
+ if(obc && obc->type==OB_CAMERA) {
+ Camera *cam= newlibadr(fd, lib, obc->data);
+ if(cam->lens>=10.0f) {
+ sce->r.xsch*= sce->r.xparts;
+ cam->lens*= (float)sce->r.ysch/(float)sce->r.xsch;
+ }
+ }
+ }
+ }
+ }
+
+ for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next)
+ ntree_version_241(ntree);
+
+ for(la= main->lamp.first; la; la= la->id.next)
+ if(la->buffers==0)
+ la->buffers= 1;
+
+ for(tex= main->tex.first; tex; tex= tex->id.next) {
+ if(tex->env && tex->env->viewscale==0.0f)
+ tex->env->viewscale= 1.0f;
+// tex->imaflag |= TEX_GAUSS_MIP;
+ }
+
+ /* for empty drawsize and drawtype */
+ for(ob=main->object.first; ob; ob= ob->id.next) {
+ if(ob->empty_drawsize==0.0f) {
+ ob->empty_drawtype = OB_ARROWS;
+ ob->empty_drawsize = 1.0;
+ }
+ }
+
+ for(ma= main->mat.first; ma; ma= ma->id.next) {
+ /* stucci returns intensity from now on */
+ int a;
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a] && ma->mtex[a]->tex) {
+ Tex *tex= newlibadr(fd, lib, ma->mtex[a]->tex);
+ if(tex && tex->type==TEX_STUCCI)
+ ma->mtex[a]->mapto &= ~(MAP_COL|MAP_SPEC|MAP_REF);
+ }
+ }
+ /* transmissivity defaults */
+ if(ma->tx_falloff==0.0) ma->tx_falloff= 1.0;
+ }
+
+ /* during 2.41 images with this name were used for viewer node output, lets fix that */
+ if(main->versionfile == 241) {
+ Image *ima;
+ for(ima= main->image.first; ima; ima= ima->id.next)
+ if(strcmp(ima->name, "Compositor")==0) {
+ strcpy(ima->id.name+2, "Viewer Node");
+ strcpy(ima->name, "Viewer Node");
+ }
+ }
+ }
+
+ if(main->versionfile <= 242) {
+ Scene *sce;
+ bScreen *sc;
+ Object *ob;
+ Curve *cu;
+ Material *ma;
+ Mesh *me;
+ Group *group;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ bNodeTree *ntree;
+ int a;
+
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ 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 (v3d->gridsubdiv == 0)
+ v3d->gridsubdiv = 10;
+ }
+ }
+ sa = sa->next;
+ }
+ }
+
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ if (sce->toolsettings->select_thresh == 0.0f)
+ sce->toolsettings->select_thresh= 0.01f;
+ if (sce->toolsettings->clean_thresh == 0.0f)
+ sce->toolsettings->clean_thresh = 0.1f;
+
+ if (sce->r.threads==0) {
+ if (sce->r.mode & R_THREADS)
+ sce->r.threads= 2;
+ else
+ sce->r.threads= 1;
+ }
+ if(sce->nodetree)
+ ntree_version_242(sce->nodetree);
+ }
+
+ for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next)
+ ntree_version_242(ntree);
+
+ /* add default radius values to old curve points */
+ for(cu= main->curve.first; cu; cu= cu->id.next) {
+ for(nu= cu->nurb.first; nu; nu= nu->next) {
+ if (nu) {
+ if(nu->bezt) {
+ for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
+ if (!bezt->radius) bezt->radius= 1.0;
+ }
+ }
+ else if(nu->bp) {
+ for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
+ if(!bp->radius) bp->radius= 1.0;
+ }
+ }
+ }
+ }
+ }
+
+ for(ob = main->object.first; ob; ob= ob->id.next) {
+ ModifierData *md;
+ ListBase *list;
+ list = &ob->constraints;
+
+ /* check for already existing MinMax (floor) constraint
+ and update the sticky flagging */
+
+ if (list){
+ bConstraint *curcon;
+ for (curcon = list->first; curcon; curcon=curcon->next){
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_MINMAX:
+ {
+ bMinMaxConstraint *data = curcon->data;
+ if (data->sticky==1)
+ data->flag |= MINMAX_STICKY;
+ else
+ data->flag &= ~MINMAX_STICKY;
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data = curcon->data;
+
+ /* version patch from buttons_object.c */
+ if(data->flag==0)
+ data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z;
+ }
+ break;
+ }
+ }
+ }
+
+ if (ob->type == OB_ARMATURE) {
+ if (ob->pose){
+ bConstraint *curcon;
+ bPoseChannel *pchan;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next){
+ for (curcon = pchan->constraints.first; curcon; curcon=curcon->next){
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_MINMAX:
+ {
+ bMinMaxConstraint *data = curcon->data;
+ if (data->sticky==1)
+ data->flag |= MINMAX_STICKY;
+ else
+ data->flag &= ~MINMAX_STICKY;
+ }
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ {
+ bKinematicConstraint *data = curcon->data;
+ if (!(data->flag & CONSTRAINT_IK_POS)) {
+ data->flag |= CONSTRAINT_IK_POS;
+ data->flag |= CONSTRAINT_IK_STRETCH;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data = curcon->data;
+
+ /* version patch from buttons_object.c */
+ if(data->flag==0)
+ data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* copy old object level track settings to curve modifers */
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Curve) {
+ CurveModifierData *cmd = (CurveModifierData*) md;
+
+ if (cmd->defaxis == 0) cmd->defaxis = ob->trackflag+1;
+ }
+ }
+
+ }
+
+ for(ma = main->mat.first; ma; ma= ma->id.next) {
+ if(ma->shad_alpha==0.0f)
+ ma->shad_alpha= 1.0f;
+ if(ma->nodetree)
+ ntree_version_242(ma->nodetree);
+ }
+
+ for(me=main->mesh.first; me; me=me->id.next)
+ customdata_version_242(me);
+
+ for(group= main->group.first; group; group= group->id.next)
+ if(group->layer==0)
+ group->layer= (1<<20)-1;
+
+ /* History fix (python?), shape key adrcode numbers have to be sorted */
+ sort_shape_fix(main);
+
+ /* now, subversion control! */
+ if(main->subversionfile < 3) {
+ bScreen *sc;
+ Image *ima;
+ Tex *tex;
+
+ /* Image refactor initialize */
+ for(ima= main->image.first; ima; ima= ima->id.next) {
+ ima->source= IMA_SRC_FILE;
+ ima->type= IMA_TYPE_IMAGE;
+
+ ima->gen_x= 256; ima->gen_y= 256;
+ ima->gen_type= 1;
+
+ if(0==strncmp(ima->id.name+2, "Viewer Node", sizeof(ima->id.name+2))) {
+ ima->source= IMA_SRC_VIEWER;
+ ima->type= IMA_TYPE_COMPOSITE;
+ }
+ if(0==strncmp(ima->id.name+2, "Render Result", sizeof(ima->id.name+2))) {
+ ima->source= IMA_SRC_VIEWER;
+ ima->type= IMA_TYPE_R_RESULT;
+ }
+
+ }
+ for(tex= main->tex.first; tex; tex= tex->id.next) {
+ if(tex->type==TEX_IMAGE && tex->ima) {
+ ima= newlibadr(fd, lib, tex->ima);
+ if(tex->imaflag & TEX_ANIM5_)
+ ima->source= IMA_SRC_MOVIE;
+ if(tex->imaflag & TEX_FIELDS_)
+ ima->flag |= IMA_FIELDS;
+ if(tex->imaflag & TEX_STD_FIELD_)
+ ima->flag |= IMA_STD_FIELD;
+ if(tex->imaflag & TEX_ANTIALI_)
+ ima->flag |= IMA_ANTIALI;
+ }
+ tex->iuser.frames= tex->frames;
+ tex->iuser.fie_ima= tex->fie_ima;
+ tex->iuser.offset= tex->offset;
+ tex->iuser.sfra= tex->sfra;
+ tex->iuser.cycl= (tex->imaflag & TEX_ANIMCYCLIC_)!=0;
+ }
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ if(sce->nodetree)
+ do_version_ntree_242_2(sce->nodetree);
+ }
+ for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next)
+ do_version_ntree_242_2(ntree);
+ for(ma = main->mat.first; ma; ma= ma->id.next)
+ if(ma->nodetree)
+ do_version_ntree_242_2(ma->nodetree);
+
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ for(sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_IMAGE)
+ ((SpaceImage *)sl)->iuser.fie_ima= 2;
+ else if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D *)sl;
+ if(v3d->bgpic)
+ v3d->bgpic->iuser.fie_ima= 2;
+ }
+ }
+ }
+ }
+ }
+
+ if(main->subversionfile < 4) {
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ sce->r.bake_mode= 1; /* prevent to include render stuff here */
+ sce->r.bake_filter= 2;
+ sce->r.bake_osa= 5;
+ sce->r.bake_flag= R_BAKE_CLEAR;
+ }
+ }
+
+ if(main->subversionfile < 5) {
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ /* improved triangle to quad conversion settings */
+ if(sce->toolsettings->jointrilimit==0.0f)
+ sce->toolsettings->jointrilimit= 0.8f;
+ }
+ }
+ }
+ if(main->versionfile <= 243) {
+ Object *ob= main->object.first;
+ Camera *cam = main->camera.first;
+ Material *ma;
+
+ for(; cam; cam= cam->id.next) {
+ cam->angle= 360.0f * atan(16.0f/cam->lens) / M_PI;
+ }
+
+ for(ma=main->mat.first; ma; ma= ma->id.next) {
+ if(ma->sss_scale==0.0f) {
+ ma->sss_radius[0]= 1.0f;
+ ma->sss_radius[1]= 1.0f;
+ ma->sss_radius[2]= 1.0f;
+ ma->sss_col[0]= 0.8f;
+ ma->sss_col[1]= 0.8f;
+ ma->sss_col[2]= 0.8f;
+ ma->sss_error= 0.05f;
+ ma->sss_scale= 0.1f;
+ ma->sss_ior= 1.3f;
+ ma->sss_colfac= 1.0f;
+ ma->sss_texfac= 0.0f;
+ }
+ if(ma->sss_front==0 && ma->sss_back==0) {
+ ma->sss_front= 1.0f;
+ ma->sss_back= 1.0f;
+ }
+ if(ma->sss_col[0]==0 && ma->sss_col[1]==0 && ma->sss_col[2]==0) {
+ ma->sss_col[0]= ma->r;
+ ma->sss_col[1]= ma->g;
+ ma->sss_col[2]= ma->b;
+ }
+ }
+
+ for(; ob; ob= ob->id.next) {
+ bDeformGroup *curdef;
+
+ for(curdef= ob->defbase.first; curdef; curdef=curdef->next) {
+ /* replace an empty-string name with unique name */
+ if (curdef->name[0] == '\0') {
+ unique_vertexgroup_name(curdef, ob);
+ }
+ }
+
+ if(main->versionfile < 243 || main->subversionfile < 1) {
+ ModifierData *md;
+
+ /* translate old mirror modifier axis values to new flags */
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ switch(mmd->axis)
+ {
+ case 0:
+ mmd->flag |= MOD_MIR_AXIS_X;
+ break;
+ case 1:
+ mmd->flag |= MOD_MIR_AXIS_Y;
+ break;
+ case 2:
+ mmd->flag |= MOD_MIR_AXIS_Z;
+ break;
+ }
+
+ mmd->axis = 0;
+ }
+ }
+ }
+ }
+
+ /* render layer added, this is not the active layer */
+ if(main->versionfile <= 243 || main->subversionfile < 2) {
+ Mesh *me;
+ for(me=main->mesh.first; me; me=me->id.next)
+ customdata_version_243(me);
+ }
+
+ }
+
+ if(main->versionfile <= 244) {
+ Scene *sce;
+ bScreen *sc;
+ Lamp *la;
+ World *wrld;
+
+ if(main->versionfile != 244 || main->subversionfile < 2) {
+ Mesh *me;
+
+ for(sce= main->scene.first; sce; sce= sce->id.next)
+ sce->r.mode |= R_SSS;
+
+ /* Copy over old per-level multires vertex data
+ into a single vertex array in struct Multires */
+
+ for(me = main->mesh.first; me; me=me->id.next) {
+ if(me->mr) {
+ MultiresLevel *lvl = me->mr->levels.last;
+ if(lvl) {
+ me->mr->verts = lvl->verts;
+ lvl->verts = NULL;
+ /* Don't need the other vert arrays */
+ for(lvl = lvl->prev; lvl; lvl = lvl->prev) {
+ MEM_freeN(lvl->verts);
+ lvl->verts = NULL;
+ }
+ }
+ }
+ }
+
+ /* correct older action editors - incorrect scrolling */
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_ACTION) {
+ SpaceAction *saction= (SpaceAction*) sl;
+
+ saction->v2d.tot.ymin= -1000.0;
+ saction->v2d.tot.ymax= 0.0;
+
+ saction->v2d.cur.ymin= -75.0;
+ saction->v2d.cur.ymax= 5.0;
+ }
+ }
+ sa = sa->next;
+ }
+ }
+ }
+ if (main->versionfile != 244 || main->subversionfile < 3) {
+ /* constraints recode version patch used to be here. Moved to 245 now... */
+
+
+ for(wrld=main->world.first; wrld; wrld= wrld->id.next) {
+ if (wrld->mode & WO_AMB_OCC)
+ wrld->ao_samp_method = WO_AOSAMP_CONSTANT;
+ else
+ wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY;
+
+ wrld->ao_adapt_thresh = 0.005;
+ }
+
+ for(la=main->lamp.first; la; la= la->id.next) {
+ if (la->type == LA_AREA)
+ la->ray_samp_method = LA_SAMP_CONSTANT;
+ else
+ la->ray_samp_method = LA_SAMP_HALTON;
+
+ la->adapt_thresh = 0.001;
+ }
+ }
+ }
+ if(main->versionfile <= 245) {
+ bScreen *sc;
+ Object *ob;
+ Image *ima;
+ Lamp *la;
+ Material *ma;
+
+ /* unless the file was created 2.44.3 but not 2.45, update the constraints */
+ if ( !(main->versionfile==244 && main->subversionfile==3) &&
+ ((main->versionfile<245) || (main->versionfile==245 && main->subversionfile==0)) )
+ {
+ for (ob = main->object.first; ob; ob= ob->id.next) {
+ ListBase *list;
+ list = &ob->constraints;
+
+ /* fix up constraints due to constraint recode changes (originally at 2.44.3) */
+ if (list) {
+ bConstraint *curcon;
+ for (curcon = list->first; curcon; curcon=curcon->next) {
+ /* old CONSTRAINT_LOCAL check -> convert to CONSTRAINT_SPACE_LOCAL */
+ if (curcon->flag & 0x20) {
+ curcon->ownspace = CONSTRAINT_SPACE_LOCAL;
+ curcon->tarspace = CONSTRAINT_SPACE_LOCAL;
+ }
+
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ {
+ bLocLimitConstraint *data= (bLocLimitConstraint *)curcon->data;
+
+ /* old limit without parent option for objects */
+ if (data->flag2)
+ curcon->ownspace = CONSTRAINT_SPACE_LOCAL;
+ }
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ {
+ bStretchToConstraint *data= (bStretchToConstraint *)curcon->data;
+
+ /* force recalc of rest-length */
+ data->orglength = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ /* correctly initialise constinv matrix */
+ Mat4One(ob->constinv);
+
+ if (ob->type == OB_ARMATURE) {
+ if (ob->pose) {
+ bConstraint *curcon;
+ bPoseChannel *pchan;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ /* make sure constraints are all up to date */
+ for (curcon = pchan->constraints.first; curcon; curcon=curcon->next) {
+ /* old CONSTRAINT_LOCAL check -> convert to CONSTRAINT_SPACE_LOCAL */
+ if (curcon->flag & 0x20) {
+ curcon->ownspace = CONSTRAINT_SPACE_LOCAL;
+ curcon->tarspace = CONSTRAINT_SPACE_LOCAL;
+ }
+
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_ACTION:
+ {
+ bActionConstraint *data= (bActionConstraint *)curcon->data;
+
+ /* 'data->local' used to mean that target was in local-space */
+ if (data->local)
+ curcon->tarspace = CONSTRAINT_SPACE_LOCAL;
+ }
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ {
+ bStretchToConstraint *data= (bStretchToConstraint *)curcon->data;
+
+ /* force recalc of rest-length */
+ data->orglength = 0;
+ }
+ break;
+ }
+ }
+
+ /* correctly initialise constinv matrix */
+ Mat4One(pchan->constinv);
+ }
+ }
+ }
+ }
+ }
+
+ /* fix all versions before 2.45 */
+ if (main->versionfile != 245) {
+
+ /* repair preview from 242 - 244*/
+ for(ima= main->image.first; ima; ima= ima->id.next) {
+ ima->preview = NULL;
+ }
+
+ /* repair imasel space - completely reworked */
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_IMASEL) {
+ SpaceImaSel *simasel= (SpaceImaSel*) sl;
+ simasel->blockscale= 0.7;
+ /* view 2D */
+ simasel->v2d.tot.xmin= -10.0;
+ simasel->v2d.tot.ymin= -10.0;
+ simasel->v2d.tot.xmax= (float)sa->winx + 10.0f;
+ simasel->v2d.tot.ymax= (float)sa->winy + 10.0f;
+ simasel->v2d.cur.xmin= 0.0;
+ simasel->v2d.cur.ymin= 0.0;
+ simasel->v2d.cur.xmax= (float)sa->winx;
+ simasel->v2d.cur.ymax= (float)sa->winy;
+ simasel->v2d.min[0]= 1.0;
+ simasel->v2d.min[1]= 1.0;
+ simasel->v2d.max[0]= 32000.0f;
+ simasel->v2d.max[1]= 32000.0f;
+ simasel->v2d.minzoom= 0.5f;
+ simasel->v2d.maxzoom= 1.21f;
+ simasel->v2d.scroll= 0;
+ simasel->v2d.keepaspect= 1;
+ simasel->v2d.keepzoom= 1;
+ simasel->v2d.keeptot= 0;
+ simasel->prv_h = 96;
+ simasel->prv_w = 96;
+ simasel->flag = 7; /* ??? elubie */
+ strcpy (simasel->dir, U.textudir); /* TON */
+ strcpy (simasel->file, "");
+
+ simasel->returnfunc = 0;
+ simasel->title[0] = 0;
+ }
+ }
+ sa = sa->next;
+ }
+ }
+ }
+
+ if (main->versionfile != 245 || main->subversionfile < 1) {
+ for(la=main->lamp.first; la; la= la->id.next) {
+ if (la->mode & LA_QUAD) la->falloff_type = LA_FALLOFF_SLIDERS;
+ else la->falloff_type = LA_FALLOFF_INVLINEAR;
+
+ if (la->curfalloff == NULL) {
+ la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
+ curvemapping_initialize(la->curfalloff);
+ }
+ }
+ }
+
+ for(ma=main->mat.first; ma; ma= ma->id.next) {
+ if (ma->samp_gloss_mir == 0) {
+ ma->gloss_mir = ma->gloss_tra= 1.0;
+ ma->aniso_gloss_mir = 1.0;
+ ma->samp_gloss_mir = ma->samp_gloss_tra= 18;
+ ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005;
+ ma->dist_mir = 0.0;
+ ma->fadeto_mir = MA_RAYMIR_FADETOSKY;
+ }
+ }
+
+ }
+
+ if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 2)) {
+ Image *ima;
+
+ /* initialize 1:1 Aspect */
+ for(ima= main->image.first; ima; ima= ima->id.next) {
+ ima->aspx = ima->aspy = 1.0f;
+ }
+
+ }
+
+ if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 4)) {
+ bArmature *arm;
+ ModifierData *md;
+ Object *ob;
+
+ for(arm= main->armature.first; arm; arm= arm->id.next)
+ arm->deformflag |= ARM_DEF_B_BONE_REST;
+
+ for(ob = main->object.first; ob; ob= ob->id.next) {
+ for(md=ob->modifiers.first; md; md=md->next) {
+ if(md->type==eModifierType_Armature)
+ ((ArmatureModifierData*)md)->deformflag |= ARM_DEF_B_BONE_REST;
+ }
+ }
+ }
+
+ if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 5)) {
+ /* foreground color needs to be somthing other then black */
+ Scene *sce;
+ for(sce= main->scene.first; sce; sce=sce->id.next) {
+ sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8;
+ sce->r.fg_stamp[3] = 1.0; /* dont use text alpha yet */
+ sce->r.bg_stamp[3] = 0.25; /* make sure the background has full alpha */
+ }
+ }
+
+
+ if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 6)) {
+ Scene *sce;
+ /* fix frs_sec_base */
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ if (sce->r.frs_sec_base == 0) {
+ sce->r.frs_sec_base = 1;
+ }
+ }
+ }
+
+ if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 7)) {
+ Object *ob;
+ bPoseChannel *pchan;
+ bConstraint *con;
+ bConstraintTarget *ct;
+
+ for(ob = main->object.first; ob; ob= ob->id.next) {
+ if(ob->pose) {
+ for(pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ for(con=pchan->constraints.first; con; con=con->next) {
+ if(con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data= (bPythonConstraint *)con->data;
+ if (data->tar) {
+ /* version patching needs to be done */
+ ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget");
+
+ ct->tar = data->tar;
+ strcpy(ct->subtarget, data->subtarget);
+ ct->space = con->tarspace;
+
+ BLI_addtail(&data->targets, ct);
+ data->tarnum++;
+
+ /* clear old targets to avoid problems */
+ data->tar = NULL;
+ strcpy(data->subtarget, "");
+ }
+ }
+ }
+ }
+ }
+
+ for(con=ob->constraints.first; con; con=con->next) {
+ if(con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data= (bPythonConstraint *)con->data;
+ if (data->tar) {
+ /* version patching needs to be done */
+ ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget");
+
+ ct->tar = data->tar;
+ strcpy(ct->subtarget, data->subtarget);
+ ct->space = con->tarspace;
+
+ BLI_addtail(&data->targets, ct);
+ data->tarnum++;
+
+ /* clear old targets to avoid problems */
+ data->tar = NULL;
+ strcpy(data->subtarget, "");
+ }
+ }
+ }
+ }
+ }
+
+
+ /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
+ /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */
+
+ /* don't forget to set version number in blender.c! */
+}
+
+static void lib_link_all(FileData *fd, Main *main)
+{
+ oldnewmap_sort(fd);
+
+ lib_link_screen(fd, main);
+ lib_link_scene(fd, main);
+ lib_link_object(fd, main);
+ lib_link_curve(fd, main);
+ lib_link_mball(fd, main);
+ lib_link_material(fd, main);
+ lib_link_texture(fd, main);
+ lib_link_image(fd, main);
+ lib_link_ipo(fd, main);
+ lib_link_key(fd, main);
+ lib_link_world(fd, main);
+ lib_link_lamp(fd, main);
+ lib_link_latt(fd, main);
+ lib_link_text(fd, main);
+ lib_link_camera(fd, main);
+ lib_link_sound(fd, main);
+ lib_link_group(fd, main);
+ lib_link_armature(fd, main);
+ lib_link_action(fd, main);
+ lib_link_vfont(fd, main);
+ lib_link_screen_sequence_ipos(main);
+ lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
+ lib_link_brush(fd, main);
+
+ lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
+
+ lib_link_library(fd, main); /* only init users */
+}
+
+static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
+{
+ Link *link;
+
+ bfd->user= read_struct(fd, bhead, "user def");
+ bfd->user->themes.first= bfd->user->themes.last= NULL;
+
+ bhead = blo_nextbhead(fd, bhead);
+
+ /* read all attached data */
+ while(bhead && bhead->code==DATA) {
+ link= read_struct(fd, bhead, "user def data");
+ BLI_addtail(&bfd->user->themes, link);
+ bhead = blo_nextbhead(fd, bhead);
+ }
+
+ return bhead;
+}
+
+BlendFileData *blo_read_file_internal(FileData *fd, BlendReadError *error_r)
+{
+ BHead *bhead= blo_firstbhead(fd);
+ BlendFileData *bfd;
+ FileGlobal *fg = (FileGlobal *)NULL;
+
+ bfd= MEM_callocN(sizeof(BlendFileData), "blendfiledata");
+ bfd->main= MEM_callocN(sizeof(Main), "main");
+ BLI_addtail(&fd->mainlist, bfd->main);
+
+ bfd->main->versionfile= fd->fileversion;
+
+ while(bhead) {
+ switch(bhead->code) {
+ case GLOB:
+ case DATA:
+ case DNA1:
+ case TEST:
+ case REND:
+ if (bhead->code==GLOB) {
+ fg= read_struct(fd, bhead, "Global");
+ /* set right away */
+ bfd->main->subversionfile= fg->subversion;
+ bfd->main->minversionfile= fg->minversion;
+ bfd->main->minsubversionfile= fg->minsubversion;
+ }
+ bhead = blo_nextbhead(fd, bhead);
+ break;
+ case USER:
+ bhead= read_userdef(bfd, fd, bhead);
+ break;
+ case ENDB:
+ bhead = NULL;
+ break;
+
+ case ID_LI:
+ bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
+ break;
+ case ID_ID:
+ /* 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, fd->mainlist.last, bhead, LIB_READ+LIB_EXTERN, NULL);
+ break;
+
+ default:
+ bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
+ }
+ }
+
+ /* do before read_libraries, but skip undo case */
+// if(fd->memfile==NULL) (the mesh shuffle hacks don't work yet? ton)
+ do_versions(fd, NULL, bfd->main);
+
+ read_libraries(fd, &fd->mainlist);
+
+ blo_join_main(&fd->mainlist);
+
+ lib_link_all(fd, bfd->main);
+ lib_verify_nodetree(bfd->main);
+
+ if(fg)
+ link_global(fd, bfd, fg); /* as last */
+
+ /* removed here: check for existance of curscreen/scene, moved to kernel setup_app */
+ MEM_freeN(fg);
+
+ return bfd;
+}
+
+/* ************* APPEND LIBRARY ************** */
+
+static BHead *find_previous_lib(FileData *fd, BHead *bhead)
+{
+ for (; bhead; bhead= blo_prevbhead(fd, bhead))
+ if (bhead->code==ID_LI)
+ break;
+
+ return bhead;
+}
+
+static BHead *find_bhead(FileData *fd, void *old)
+{
+ BHead *bhead;
+
+ if (!old)
+ return NULL;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead))
+ if (bhead->old==old)
+ return bhead;
+
+ return NULL;
+}
+
+char *bhead_id_name(FileData *fd, BHead *bhead)
+{
+ return ((char *)(bhead+1)) + fd->id_name_offs;
+}
+
+static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
+{
+ ListBase *lb;
+ char *idname= bhead_id_name(fd, bhead);
+
+ lb= wich_libbase(mainvar, GS(idname));
+
+ if(lb) {
+ ID *id= lb->first;
+ while(id) {
+ if( strcmp(id->name, idname)==0 )
+ return id;
+ id= id->next;
+ }
+ }
+ return NULL;
+}
+
+static void expand_doit(FileData *fd, Main *mainvar, void *old)
+{
+ BHead *bhead;
+ ID *id;
+
+ bhead= find_bhead(fd, old);
+ if(bhead) {
+ /* from another library? */
+ if(bhead->code==ID_ID) {
+ BHead *bheadlib= find_previous_lib(fd, bhead);
+
+ if(bheadlib) {
+ Library *lib= read_struct(fd, bheadlib, "Library");
+ Main *ptr= blo_find_main(&fd->mainlist, lib->name, fd->filename);
+
+ id= is_yet_read(fd, ptr, bhead);
+
+ if(id==NULL) {
+ read_libblock(fd, ptr, bhead, LIB_READ+LIB_INDIRECT, NULL);
+ if(G.f & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name);
+
+ /* for outliner dependency only */
+ ptr->curlib->parent= mainvar->curlib;
+ }
+ else {
+ //oldnewmap_insert(fd->libmap, bhead->old, id, 1);
+
+ change_idid_adr_fd(fd, bhead->old, id);
+ if(G.f & G_DEBUG) printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name);
+ }
+
+ MEM_freeN(lib);
+ }
+ }
+ else {
+ id= is_yet_read(fd, mainvar, bhead);
+ if(id==NULL) {
+ read_libblock(fd, mainvar, bhead, LIB_TESTIND, NULL);
+ }
+ else {
+ /* this is actually only needed on UI call? when ID was already read before, and another append
+ happens which invokes same ID... in that case the lookup table needs this entry */
+ oldnewmap_insert(fd->libmap, bhead->old, id, 1);
+ if(G.f & G_DEBUG) printf("expand: already read %s\n", id->name);
+ }
+ }
+ }
+}
+
+static void expand_ipo(FileData *fd, Main *mainvar, Ipo *ipo)
+{
+ IpoCurve *icu;
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->driver)
+ expand_doit(fd, mainvar, icu->driver->ob);
+ }
+}
+
+static void expand_group(FileData *fd, Main *mainvar, Group *group)
+{
+ GroupObject *go;
+
+ for(go= group->gobject.first; go; go= go->next) {
+ expand_doit(fd, mainvar, go->ob);
+ }
+}
+
+static void expand_key(FileData *fd, Main *mainvar, Key *key)
+{
+ expand_doit(fd, mainvar, key->ipo);
+}
+
+
+static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
+{
+ expand_doit(fd, mainvar, tex->ima);
+ expand_doit(fd, mainvar, tex->ipo);
+}
+
+static void expand_brush(FileData *fd, Main *mainvar, Brush *brush)
+{
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++)
+ if(brush->mtex[a])
+ expand_doit(fd, mainvar, brush->mtex[a]->tex);
+ expand_doit(fd, mainvar, brush->clone.image);
+}
+
+static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
+{
+ bNode *node;
+
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->id && node->type!=CMP_NODE_R_LAYERS)
+ expand_doit(fd, mainvar, node->id);
+
+}
+
+static void expand_material(FileData *fd, Main *mainvar, Material *ma)
+{
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) {
+ expand_doit(fd, mainvar, ma->mtex[a]->tex);
+ expand_doit(fd, mainvar, ma->mtex[a]->object);
+ }
+ }
+
+ expand_doit(fd, mainvar, ma->ipo);
+
+ if(ma->nodetree)
+ expand_nodetree(fd, mainvar, ma->nodetree);
+}
+
+static void expand_lamp(FileData *fd, Main *mainvar, Lamp *la)
+{
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(la->mtex[a]) {
+ expand_doit(fd, mainvar, la->mtex[a]->tex);
+ expand_doit(fd, mainvar, la->mtex[a]->object);
+ }
+ }
+ expand_doit(fd, mainvar, la->ipo);
+}
+
+static void expand_lattice(FileData *fd, Main *mainvar, Lattice *lt)
+{
+ expand_doit(fd, mainvar, lt->ipo);
+ expand_doit(fd, mainvar, lt->key);
+}
+
+
+static void expand_world(FileData *fd, Main *mainvar, World *wrld)
+{
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(wrld->mtex[a]) {
+ expand_doit(fd, mainvar, wrld->mtex[a]->tex);
+ expand_doit(fd, mainvar, wrld->mtex[a]->object);
+ }
+ }
+ expand_doit(fd, mainvar, wrld->ipo);
+}
+
+
+static void expand_mball(FileData *fd, Main *mainvar, MetaBall *mb)
+{
+ int a;
+
+ for(a=0; a<mb->totcol; a++) {
+ expand_doit(fd, mainvar, mb->mat[a]);
+ }
+}
+
+static void expand_curve(FileData *fd, Main *mainvar, Curve *cu)
+{
+ int a;
+
+ for(a=0; a<cu->totcol; a++) {
+ expand_doit(fd, mainvar, cu->mat[a]);
+ }
+ expand_doit(fd, mainvar, cu->vfont);
+ expand_doit(fd, mainvar, cu->vfontb);
+ expand_doit(fd, mainvar, cu->vfonti);
+ expand_doit(fd, mainvar, cu->vfontbi);
+ expand_doit(fd, mainvar, cu->key);
+ expand_doit(fd, mainvar, cu->ipo);
+ expand_doit(fd, mainvar, cu->bevobj);
+ expand_doit(fd, mainvar, cu->taperobj);
+ expand_doit(fd, mainvar, cu->textoncurve);
+}
+
+static void expand_mesh(FileData *fd, Main *mainvar, Mesh *me)
+{
+ CustomDataLayer *layer;
+ MTFace *mtf;
+ TFace *tf;
+ int a, i;
+
+ for(a=0; a<me->totcol; a++) {
+ expand_doit(fd, mainvar, me->mat[a]);
+ }
+
+ expand_doit(fd, mainvar, me->key);
+ expand_doit(fd, mainvar, me->texcomesh);
+
+ if(me->tface) {
+ tf= me->tface;
+ for(i=0; i<me->totface; i++, tf++)
+ if(tf->tpage)
+ expand_doit(fd, mainvar, tf->tpage);
+ }
+
+ for(a=0; a<me->fdata.totlayer; a++) {
+ layer= &me->fdata.layers[a];
+
+ if(layer->type == CD_MTFACE) {
+ mtf= (MTFace*)layer->data;
+ for(i=0; i<me->totface; i++, mtf++)
+ if(mtf->tpage)
+ expand_doit(fd, mainvar, mtf->tpage);
+ }
+ }
+}
+
+static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb)
+{
+ bConstraint *curcon;
+
+ for (curcon=lb->first; curcon; curcon=curcon->next) {
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_NULL:
+ break;
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = (bPythonConstraint*)curcon->data;
+ bConstraintTarget *ct;
+
+ for (ct= data->targets.first; ct; ct= ct->next)
+ expand_doit(fd, mainvar, ct->tar);
+
+ expand_doit(fd, mainvar, data->text);
+ }
+ break;
+ case CONSTRAINT_TYPE_ACTION:
+ {
+ bActionConstraint *data = (bActionConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ expand_doit(fd, mainvar, data->act);
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCLIKE:
+ {
+ bLocateLikeConstraint *data = (bLocateLikeConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data = (bRotateLikeConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_SIZELIKE:
+ {
+ bSizeLikeConstraint *data = (bSizeLikeConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ {
+ bKinematicConstraint *data = (bKinematicConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ expand_doit(fd, mainvar, data->poletar);
+ }
+ break;
+ case CONSTRAINT_TYPE_TRACKTO:
+ {
+ bTrackToConstraint *data = (bTrackToConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_MINMAX:
+ {
+ bMinMaxConstraint *data = (bMinMaxConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCKTRACK:
+ {
+ bLockTrackConstraint *data = (bLockTrackConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_FOLLOWPATH:
+ {
+ bFollowPathConstraint *data = (bFollowPathConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ {
+ bStretchToConstraint *data = (bStretchToConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_RIGIDBODYJOINT:
+ {
+ bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_CLAMPTO:
+ {
+ bClampToConstraint *data = (bClampToConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_CHILDOF:
+ {
+ bChildOfConstraint *data = (bChildOfConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ {
+ bTransformConstraint *data = (bTransformConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void expand_bones(FileData *fd, Main *mainvar, Bone *bone)
+{
+ Bone *curBone;
+
+ for (curBone = bone->childbase.first; curBone; curBone=curBone->next) {
+ expand_bones(fd, mainvar, curBone);
+ }
+
+}
+
+static void expand_pose(FileData *fd, Main *mainvar, bPose *pose)
+{
+ bPoseChannel *chan;
+
+ if (!pose)
+ return;
+
+ for (chan = pose->chanbase.first; chan; chan=chan->next) {
+ expand_constraints(fd, mainvar, &chan->constraints);
+ expand_doit(fd, mainvar, chan->custom);
+ }
+}
+
+static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm)
+{
+ Bone *curBone;
+
+ for (curBone = arm->bonebase.first; curBone; curBone=curBone->next) {
+ expand_bones(fd, mainvar, curBone);
+ }
+}
+
+static void expand_constraint_channels(FileData *fd, Main *mainvar, ListBase *chanbase)
+{
+ bConstraintChannel *chan;
+ for (chan=chanbase->first; chan; chan=chan->next){
+ expand_doit(fd, mainvar, chan->ipo);
+ }
+}
+
+static void expand_action(FileData *fd, Main *mainvar, bAction *act)
+{
+ bActionChannel *chan;
+ for (chan=act->chanbase.first; chan; chan=chan->next) {
+ expand_doit(fd, mainvar, chan->ipo);
+ expand_constraint_channels(fd, mainvar, &chan->constraintChannels);
+ }
+}
+
+static void expand_modifier(FileData *fd, Main *mainvar, ModifierData *md)
+{
+ if (md->type==eModifierType_Lattice) {
+ LatticeModifierData *lmd = (LatticeModifierData*) md;
+
+ expand_doit(fd, mainvar, lmd->object);
+ }
+ else if (md->type==eModifierType_Curve) {
+ CurveModifierData *cmd = (CurveModifierData*) md;
+
+ expand_doit(fd, mainvar, cmd->object);
+ }
+ else if (md->type==eModifierType_Array) {
+ ArrayModifierData *amd = (ArrayModifierData*) md;
+
+ expand_doit(fd, mainvar, amd->curve_ob);
+ expand_doit(fd, mainvar, amd->offset_ob);
+ }
+}
+
+static void expand_scriptlink(FileData *fd, Main *mainvar, ScriptLink *slink)
+{
+ int i;
+
+ for(i=0; i<slink->totscript; i++) {
+ expand_doit(fd, mainvar, slink->scripts[i]);
+ }
+}
+
+static void expand_object(FileData *fd, Main *mainvar, Object *ob)
+{
+ ModifierData *md;
+ bSensor *sens;
+ bController *cont;
+ bActuator *act;
+ bActionStrip *strip;
+ PartEff *paf;
+ int a;
+
+
+ expand_doit(fd, mainvar, ob->data);
+ expand_doit(fd, mainvar, ob->ipo);
+ expand_doit(fd, mainvar, ob->action);
+
+ for (md=ob->modifiers.first; md; md=md->next) {
+ expand_modifier(fd, mainvar, md);
+ }
+
+ expand_pose(fd, mainvar, ob->pose);
+ expand_constraints(fd, mainvar, &ob->constraints);
+ expand_constraint_channels(fd, mainvar, &ob->constraintChannels);
+
+ for (strip=ob->nlastrips.first; strip; strip=strip->next){
+ expand_doit(fd, mainvar, strip->object);
+ expand_doit(fd, mainvar, strip->act);
+ expand_doit(fd, mainvar, strip->ipo);
+ }
+
+ for(a=0; a<ob->totcol; a++) {
+ expand_doit(fd, mainvar, ob->mat[a]);
+ }
+
+ paf = give_parteff(ob);
+ if (paf && paf->group)
+ expand_doit(fd, mainvar, paf->group);
+
+ if(ob->dup_group)
+ expand_doit(fd, mainvar, ob->dup_group);
+
+ if(ob->proxy)
+ expand_doit(fd, mainvar, ob->proxy);
+ if(ob->proxy_group)
+ expand_doit(fd, mainvar, ob->proxy_group);
+
+ sens= ob->sensors.first;
+ while(sens) {
+ for(a=0; a<sens->totlinks; a++) {
+ sens->links[a]= newglobadr(fd, sens->links[a]);
+ }
+ if(sens->type==SENS_TOUCH) {
+ bTouchSensor *ts= sens->data;
+ expand_doit(fd, mainvar, ts->ma);
+ }
+ else if(sens->type==SENS_MESSAGE) {
+ bMessageSensor *ms= sens->data;
+ expand_doit(fd, mainvar, ms->fromObject);
+ }
+ sens= sens->next;
+ }
+
+ cont= ob->controllers.first;
+ while(cont) {
+ for(a=0; a<cont->totlinks; a++) {
+ cont->links[a]= newglobadr(fd, cont->links[a]);
+ }
+ if(cont->type==CONT_PYTHON) {
+ bPythonCont *pc= cont->data;
+ expand_doit(fd, mainvar, pc->text);
+ }
+ cont= cont->next;
+ }
+
+ act= ob->actuators.first;
+ while(act) {
+ if(act->type==ACT_SOUND) {
+ bSoundActuator *sa= act->data;
+ expand_doit(fd, mainvar, sa->sound);
+ }
+ else if(act->type==ACT_CAMERA) {
+ bCameraActuator *ca= act->data;
+ expand_doit(fd, mainvar, ca->ob);
+ }
+ else if(act->type==ACT_EDIT_OBJECT) {
+ bEditObjectActuator *eoa= act->data;
+ if(eoa) {
+ expand_doit(fd, mainvar, eoa->ob);
+ expand_doit(fd, mainvar, eoa->me);
+ }
+ }
+ else if(act->type==ACT_SCENE) {
+ bSceneActuator *sa= act->data;
+ expand_doit(fd, mainvar, sa->camera);
+ expand_doit(fd, mainvar, sa->scene);
+ }
+ else if(act->type==ACT_ACTION) {
+ bActionActuator *aa= act->data;
+ expand_doit(fd, mainvar, aa->act);
+ }
+ else if(act->type==ACT_PROPERTY) {
+ bPropertyActuator *pa= act->data;
+ expand_doit(fd, mainvar, pa->ob);
+ }
+ else if(act->type==ACT_MESSAGE) {
+ bMessageActuator *ma= act->data;
+ expand_doit(fd, mainvar, ma->toObject);
+ }
+ act= act->next;
+ }
+
+ expand_scriptlink(fd, mainvar, &ob->scriptlink);
+}
+
+static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
+{
+ Base *base;
+ SceneRenderLayer *srl;
+
+ for(base= sce->base.first; base; base= base->next) {
+ expand_doit(fd, mainvar, base->object);
+ }
+ expand_doit(fd, mainvar, sce->camera);
+ expand_doit(fd, mainvar, sce->world);
+
+ if(sce->nodetree)
+ expand_nodetree(fd, mainvar, sce->nodetree);
+
+ for(srl= sce->r.layers.first; srl; srl= srl->next) {
+ expand_doit(fd, mainvar, srl->mat_override);
+ expand_doit(fd, mainvar, srl->light_override);
+ }
+
+}
+
+static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
+{
+ expand_doit(fd, mainvar, ca->ipo);
+}
+
+static void expand_sound(FileData *fd, Main *mainvar, bSound *snd)
+{
+ expand_doit(fd, mainvar, snd->ipo);
+}
+
+
+static void expand_main(FileData *fd, Main *mainvar)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a, doit= 1;
+
+ if(fd==0) return;
+
+ while(doit) {
+ doit= 0;
+
+ a= set_listbasepointers(mainvar, lbarray);
+ while(a--) {
+ id= lbarray[a]->first;
+
+ while(id) {
+ if(id->flag & LIB_TEST) {
+
+ switch(GS(id->name)) {
+
+ case ID_OB:
+ expand_object(fd, mainvar, (Object *)id);
+ break;
+ case ID_ME:
+ expand_mesh(fd, mainvar, (Mesh *)id);
+ break;
+ case ID_CU:
+ expand_curve(fd, mainvar, (Curve *)id);
+ break;
+ case ID_MB:
+ expand_mball(fd, mainvar, (MetaBall *)id);
+ break;
+ case ID_SCE:
+ expand_scene(fd, mainvar, (Scene *)id);
+ break;
+ case ID_MA:
+ expand_material(fd, mainvar, (Material *)id);
+ break;
+ case ID_TE:
+ expand_texture(fd, mainvar, (Tex *)id);
+ break;
+ case ID_WO:
+ expand_world(fd, mainvar, (World *)id);
+ break;
+ case ID_LT:
+ expand_lattice(fd, mainvar, (Lattice *)id);
+ break;
+ case ID_LA:
+ expand_lamp(fd, mainvar,(Lamp *)id);
+ break;
+ case ID_KE:
+ expand_key(fd, mainvar, (Key *)id);
+ break;
+ case ID_CA:
+ expand_camera(fd, mainvar, (Camera *)id);
+ break;
+ case ID_SO:
+ expand_sound(fd, mainvar, (bSound *)id);
+ break;
+ case ID_AR:
+ expand_armature(fd, mainvar, (bArmature *)id);
+ break;
+ case ID_AC:
+ expand_action(fd, mainvar, (bAction *)id);
+ break;
+ case ID_GR:
+ expand_group(fd, mainvar, (Group *)id);
+ break;
+ case ID_NT:
+ expand_nodetree(fd, mainvar, (bNodeTree *)id);
+ break;
+ case ID_BR:
+ expand_brush(fd, mainvar, (Brush *)id);
+ break;
+ case ID_IP:
+ expand_ipo(fd, mainvar, (Ipo *)id);
+ break;
+ }
+
+ doit= 1;
+ id->flag -= LIB_TEST;
+
+ }
+ id= id->next;
+ }
+ }
+ }
+}
+
+static int object_in_any_scene(Object *ob)
+{
+ Scene *sce;
+
+ for(sce= G.main->scene.first; sce; sce= sce->id.next)
+ if(object_in_scene(ob, sce))
+ return 1;
+ return 0;
+}
+
+/* when *lib set, it also does objects that were in the appended group */
+static void give_base_to_objects(Scene *sce, ListBase *lb, Library *lib)
+{
+ Object *ob;
+ Base *base;
+
+ /* give all objects which are LIB_INDIRECT a base, or for a group when *lib has been set */
+ for(ob= lb->first; ob; ob= ob->id.next) {
+
+ if( ob->id.flag & LIB_INDIRECT ) {
+ int do_it= 0;
+
+ if(ob->id.us==0)
+ do_it= 1;
+ else if(ob->id.us==1 && lib)
+ if(ob->id.lib==lib && (ob->flag & OB_FROMGROUP) && object_in_any_scene(ob)==0)
+ do_it= 1;
+
+ if(do_it) {
+ base= MEM_callocN( sizeof(Base), "add_ext_base");
+ BLI_addtail(&(sce->base), base);
+ base->lay= ob->lay;
+ base->object= ob;
+ base->flag= ob->flag;
+ ob->id.us= 1;
+
+ ob->id.flag -= LIB_INDIRECT;
+ ob->id.flag |= LIB_EXTERN;
+
+ }
+ }
+ }
+}
+
+
+static void append_named_part(FileData *fd, Main *mainvar, Scene *scene, char *name, int idcode, short flag)
+{
+ Object *ob;
+ Base *base;
+ BHead *bhead;
+ ID *id;
+ int endloop=0;
+
+ bhead = blo_firstbhead(fd);
+ while(bhead && endloop==0) {
+
+ if(bhead->code==ENDB) endloop= 1;
+ else if(bhead->code==idcode) {
+ char *idname= bhead_id_name(fd, bhead);
+
+ if(strcmp(idname+2, name)==0) {
+
+ id= is_yet_read(fd, mainvar, bhead);
+ if(id==NULL) {
+ read_libblock(fd, mainvar, bhead, LIB_TESTEXT, NULL);
+ }
+ else {
+ printf("append: already linked\n");
+ oldnewmap_insert(fd->libmap, bhead->old, id, 1);
+ if(id->flag & LIB_INDIRECT) {
+ id->flag -= LIB_INDIRECT;
+ id->flag |= LIB_EXTERN;
+ }
+ }
+
+ if(idcode==ID_OB) { /* loose object: give a base */
+ base= MEM_callocN( sizeof(Base), "app_nam_part");
+ BLI_addtail(&scene->base, base);
+
+ if(id==NULL) ob= mainvar->object.last;
+ else ob= (Object *)id;
+
+ /* this is bad code... G.vd nor G.scene should be used on this level... */
+ if((flag & FILE_ACTIVELAY)) {
+ if(G.vd) ob->lay= G.vd->layact;
+ else ob->lay = G.scene->lay;
+ }
+ base->lay= ob->lay;
+ base->object= ob;
+ ob->id.us++;
+
+ if(flag & FILE_AUTOSELECT) {
+ base->flag |= SELECT;
+ base->object->flag = base->flag;
+ /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
+ }
+ }
+ endloop= 1;
+ }
+ }
+
+ bhead = blo_nextbhead(fd, bhead);
+ }
+}
+
+static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **id_r)
+{
+ BHead *bhead;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code == GS(id->name)) {
+
+ if (BLI_streq(id->name, bhead_id_name(fd, bhead))) {
+ id->flag &= ~LIB_READ;
+ id->flag |= LIB_TEST;
+// printf("read lib block %s\n", id->name);
+ read_libblock(fd, mainvar, bhead, id->flag, id_r);
+
+ break;
+ }
+ } else if (bhead->code==ENDB)
+ break;
+ }
+}
+
+/* common routine to append/link something from a library */
+
+static Library* library_append( Scene *scene, char* file, char *dir, int idcode,
+ int totsel, FileData *fd, struct direntry* filelist, int totfile, short flag)
+{
+ Main *mainl;
+ Library *curlib;
+
+ /* make mains */
+ blo_split_main(&fd->mainlist, G.main);
+
+ /* which one do we need? */
+ mainl = blo_find_main(&fd->mainlist, dir, G.sce);
+
+ mainl->versionfile= fd->fileversion; /* needed for do_version */
+
+ curlib= mainl->curlib;
+
+ if(totsel==0) {
+ append_named_part(fd, mainl, scene, file, idcode, flag);
+ }
+ else {
+ int a;
+ for(a=0; a<totfile; a++) {
+ if(filelist[a].flags & ACTIVE) {
+ append_named_part(fd, mainl, scene, filelist[a].relname, idcode, flag);
+ }
+ }
+ }
+
+ /* make main consistant */
+ expand_main(fd, mainl);
+
+ /* do this when expand found other libs */
+ read_libraries(fd, &fd->mainlist);
+
+ if(flag & FILE_STRINGCODE) {
+
+ /* use the full path, this could have been read by other library even */
+ BLI_strncpy(mainl->curlib->name, mainl->curlib->filename, sizeof(mainl->curlib->name));
+
+ /* uses current .blend file as reference */
+ BLI_makestringcode(G.sce, mainl->curlib->name);
+ }
+
+ blo_join_main(&fd->mainlist);
+ G.main= fd->mainlist.first;
+
+ lib_link_all(fd, G.main);
+ lib_verify_nodetree(G.main);
+
+ /* give a base to loose objects. If group append, do it for objects too */
+ if(idcode==ID_GR)
+ give_base_to_objects(scene, &(G.main->object), (flag & FILE_LINK)?NULL:curlib);
+ else
+ give_base_to_objects(scene, &(G.main->object), NULL);
+
+ /* 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 );
+ }
+
+ return curlib;
+}
+
+/* this is a version of BLO_library_append needed by the BPython API, so
+ * scripts can load data from .blend files -- see Blender.Library module.*/
+/* append to G.scene */
+/* this should probably be moved into the Python code anyway */
+
+void BLO_script_library_append(BlendHandle *bh, char *dir, char *name,
+ int idcode, short flag, Scene *scene )
+{
+ /* try to append the requested object */
+ library_append( scene, name, dir, idcode, 0, (FileData *)bh, NULL, 0, flag );
+
+ /* do we need to do this? */
+ DAG_scene_sort(G.scene);
+}
+
+/* append to G.scene */
+/* dir is a full path */
+void BLO_library_append(SpaceFile *sfile, char *dir, int idcode)
+{
+ BLO_library_append_(&sfile->libfiledata, sfile->filelist, sfile->totfile, dir, sfile->file, sfile->flag, idcode);
+}
+
+void BLO_library_append_(BlendHandle** libfiledata, struct direntry* filelist, int totfile, char *dir, char* file, short flag, int idcode)
+{
+ FileData *fd= (FileData*) (*libfiledata);
+ Library *curlib;
+ Base *centerbase;
+ Object *ob;
+ int a, totsel=0;
+
+ /* are there files selected? */
+ for(a=0; a<totfile; a++) {
+ if(filelist[a].flags & ACTIVE) {
+ totsel++;
+ }
+ }
+
+ if(totsel==0) {
+ /* is the indicated file in the filelist? */
+ if(file[0]) {
+ for(a=0; a<totfile; a++) {
+ if( strcmp(filelist[a].relname, file)==0) break;
+ }
+ if(a==totfile) {
+ error("Wrong indicated name");
+ return;
+ }
+ }
+ else {
+ error("Nothing indicated");
+ return;
+ }
+ }
+ /* now we have or selected, or an indicated file */
+
+ if(flag & FILE_AUTOSELECT) scene_deselect_all(G.scene);
+
+ curlib = library_append( G.scene, file, dir, idcode, totsel, fd, filelist, totfile,flag );
+
+ /* patch to prevent switch_endian happens twice */
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ (*libfiledata)= 0;
+ }
+
+ /* when not linking (appending)... */
+ if((flag & FILE_LINK)==0) {
+ if(flag & FILE_ATCURSOR) {
+ float *curs, centerloc[3], vec[3], min[3], max[3];
+ int count= 0;
+
+ INIT_MINMAX(min, max);
+
+ centerbase= (G.scene->base.first);
+ while(centerbase) {
+ if(centerbase->object->id.lib==curlib && centerbase->object->parent==NULL) {
+ VECCOPY(vec, centerbase->object->loc);
+ DO_MINMAX(vec, min, max);
+ count++;
+ }
+ centerbase= centerbase->next;
+ }
+ if(count) {
+ centerloc[0]= (min[0]+max[0])/2;
+ centerloc[1]= (min[1]+max[1])/2;
+ centerloc[2]= (min[2]+max[2])/2;
+ curs = G.scene->cursor;
+ VECSUB(centerloc,curs,centerloc);
+
+ centerbase= (G.scene->base.first);
+ while(centerbase) {
+ if(centerbase->object->id.lib==curlib && centerbase->object->parent==NULL) {
+ ob= centerbase->object;
+ ob->loc[0] += centerloc[0];
+ ob->loc[1] += centerloc[1];
+ ob->loc[2] += centerloc[2];
+ }
+ centerbase= centerbase->next;
+ }
+ }
+ }
+ }
+}
+
+/* ************* READ LIBRARY ************** */
+
+static int mainvar_count_libread_blocks(Main *mainvar)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a, tot= 0;
+
+ a= set_listbasepointers(mainvar, lbarray);
+ while(a--) {
+ ID *id= lbarray[a]->first;
+
+ for (id= lbarray[a]->first; id; id= id->next)
+ if (id->flag & LIB_READ)
+ tot++;
+ }
+ return tot;
+}
+
+static void read_libraries(FileData *basefd, ListBase *mainlist)
+{
+ Main *mainl= mainlist->first;
+ Main *mainptr;
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a, doit= 1;
+
+ while(doit) {
+ doit= 0;
+
+ /* test 1: read libdata */
+ mainptr= mainl->next;
+ while(mainptr) {
+ int tot= mainvar_count_libread_blocks(mainptr);
+
+ // printf("found LIB_READ %s\n", mainptr->curlib->name);
+ if(tot) {
+ FileData *fd= mainptr->curlib->filedata;
+
+ if(fd==NULL) {
+ BlendReadError err;
+ printf("read library: lib %s\n", mainptr->curlib->name);
+ fd= blo_openblenderfile(mainptr->curlib->filename, &err);
+ if (fd) {
+ if (fd->libmap)
+ oldnewmap_free(fd->libmap);
+
+ fd->libmap = oldnewmap_new();
+
+ mainptr->curlib->filedata= fd;
+ mainptr->versionfile= fd->fileversion;
+ }
+ else mainptr->curlib->filedata= NULL;
+
+ if (fd==NULL)
+ printf("ERROR: can't find lib %s \n", mainptr->curlib->filename);
+ }
+ if(fd) {
+ doit= 1;
+ 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)
+ printf("LIB ERROR: can't find %s\n", id->name);
+
+ change_idid_adr(mainlist, basefd, id, realid);
+
+ MEM_freeN(id);
+ }
+ id= idn;
+ }
+ }
+
+ expand_main(fd, mainptr);
+
+ /* dang FileData... now new libraries need to be appended to original filedata, it is not a good replacement for the old global (ton) */
+ while( fd->mainlist.first ) {
+ Main *mp= fd->mainlist.first;
+ BLI_remlink(&fd->mainlist, mp);
+ BLI_addtail(&basefd->mainlist, mp);
+ }
+ }
+ }
+
+ mainptr= mainptr->next;
+ }
+ }
+
+ /* test if there are unread libblocks */
+ for(mainptr= mainl->next; mainptr; mainptr= mainptr->next) {
+ a= set_listbasepointers(mainptr, lbarray);
+ while(a--) {
+ ID *id= lbarray[a]->first;
+ while(id) {
+ ID *idn= id->next;
+ if(id->flag & LIB_READ) {
+ BLI_remlink(lbarray[a], id);
+
+ printf("LIB ERROR: can't find %s\n", id->name);
+ change_idid_adr(mainlist, basefd, id, NULL);
+
+ MEM_freeN(id);
+ }
+ id= idn;
+ }
+ }
+ }
+
+ /* do versions, link, and free */
+ for(mainptr= mainl->next; mainptr; mainptr= mainptr->next) {
+ /* some mains still have to be read, then
+ * versionfile is still zero! */
+ if(mainptr->versionfile) {
+ if(mainptr->curlib->filedata) // can be zero... with shift+f1 append
+ do_versions(mainptr->curlib->filedata, mainptr->curlib, mainptr);
+ else
+ do_versions(basefd, NULL, mainptr);
+ }
+
+ if(mainptr->curlib->filedata)
+ lib_link_all(mainptr->curlib->filedata, mainptr);
+
+ if(mainptr->curlib->filedata) blo_freefiledata(mainptr->curlib->filedata);
+ mainptr->curlib->filedata= NULL;
+
+ }
+}
+
+/* reading runtime */
+
+BlendFileData *blo_read_blendafterruntime(int file, int actualsize, BlendReadError *error_r)
+{
+ BlendFileData *bfd = NULL;
+ FileData *fd = filedata_new();
+ fd->filedes = file;
+ fd->buffersize = actualsize;
+ fd->read = fd_read_from_file;
+
+ fd = blo_decode_and_check(fd, error_r);
+ if (!fd)
+ return NULL;
+
+ bfd= blo_read_file_internal(fd, error_r);
+ blo_freefiledata(fd);
+
+ return bfd;
+}
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
new file mode 100644
index 00000000000..79392023a56
--- /dev/null
+++ b/source/blender/blenloader/intern/readfile.h
@@ -0,0 +1,127 @@
+/*
+ * $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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * blenloader readfile private function prototypes
+ */
+#ifndef READFILE_H
+#define READFILE_H
+
+#include "zlib.h"
+
+struct OldNewMap;
+struct MemFile;
+
+typedef struct FileData {
+ // linked list of BHeadN's
+ ListBase listbase;
+ int flags;
+ int eof;
+ int buffersize;
+ int seek;
+ int (*read)(struct FileData *filedata, void *buffer, int size);
+
+ // variables needed for reading from memory / stream
+ char *buffer;
+ // variables needed for reading from memfile (undo)
+ struct MemFile *memfile;
+
+ // variables needed for reading from file
+ int filedes;
+ gzFile gzfiledes;
+
+ // now only in use for library appending
+ char filename[FILE_MAXDIR+FILE_MAXFILE];
+
+ // variables needed for reading from stream
+ char headerdone;
+ int inbuffer;
+
+ // general reading variables
+ struct SDNA *filesdna;
+ struct SDNA *memsdna;
+ char *compflags;
+
+ int fileversion;
+ int id_name_offs; /* used to retrieve ID names from (bhead+1) */
+
+ struct OldNewMap *datamap;
+ struct OldNewMap *globmap;
+ struct OldNewMap *libmap;
+ struct OldNewMap *imamap;
+
+ ListBase mainlist;
+
+ /* ick ick, used to return
+ * data through streamglue.
+ */
+ BlendFileData **bfd_r;
+ BlendReadError *error_r;
+} FileData;
+
+typedef struct BHeadN {
+ struct BHeadN *next, *prev;
+ struct BHead bhead;
+} BHeadN;
+
+
+#define FD_FLAGS_SWITCH_ENDIAN (1<<0)
+#define FD_FLAGS_FILE_POINTSIZE_IS_4 (1<<1)
+#define FD_FLAGS_POINTSIZE_DIFFERS (1<<2)
+#define FD_FLAGS_FILE_OK (1<<3)
+#define FD_FLAGS_NOT_MY_BUFFER (1<<4)
+#define FD_FLAGS_NOT_MY_LIBMAP (1<<5)
+
+#define SIZEOFBLENDERHEADER 12
+
+ /***/
+struct Main;
+void blo_join_main(ListBase *mainlist);
+void blo_split_main(ListBase *mainlist, struct Main *main);
+
+BlendFileData *blo_read_file_internal( FileData *fd, BlendReadError *error_r);
+
+FileData *blo_openblenderfile( char *name, BlendReadError *error_r);
+FileData *blo_openblendermemory( void *buffer, int buffersize, BlendReadError *error_r);
+FileData *blo_openblendermemfile(struct MemFile *memfile, BlendReadError *error_r);
+
+void blo_make_image_pointer_map(FileData *fd);
+void blo_end_image_pointer_map(FileData *fd);
+void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd);
+
+void blo_freefiledata( FileData *fd);
+
+BHead *blo_firstbhead(FileData *fd);
+BHead *blo_nextbhead(FileData *fd, BHead *thisblock);
+BHead *blo_prevbhead(FileData *fd, BHead *thisblock);
+
+char *bhead_id_name(FileData *fd, BHead *bhead);
+
+#endif
+
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
new file mode 100644
index 00000000000..c8c31f4f2ac
--- /dev/null
+++ b/source/blender/blenloader/intern/undofile.c
@@ -0,0 +1,146 @@
+/**
+ * $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 *****
+ * .blend file reading entry point
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+
+#include "BLO_undofile.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+
+
+
+/* **************** support for memory-write, for undo buffers *************** */
+
+/* not memfile itself */
+void BLO_free_memfile(MemFile *memfile)
+{
+ MemFileChunk *chunk;
+
+ while( (chunk = (memfile->chunks.first) ) ) {
+ if(chunk->ident==0) MEM_freeN(chunk->buf);
+ BLI_remlink(&memfile->chunks, chunk);
+ MEM_freeN(chunk);
+ }
+ memfile->size= 0;
+}
+
+/* to keep list of memfiles consistant, 'first' is always first in list */
+/* result is that 'first' is being freed */
+void BLO_merge_memfile(MemFile *first, MemFile *second)
+{
+ MemFileChunk *fc, *sc;
+
+ fc= first->chunks.first;
+ sc= second->chunks.first;
+ while (fc || sc) {
+ if(fc && sc) {
+ if(sc->ident) {
+ sc->ident= 0;
+ fc->ident= 1;
+ }
+ }
+ if(fc) fc= fc->next;
+ if(sc) sc= sc->next;
+ }
+
+ BLO_free_memfile(first);
+}
+
+static int my_memcmp(int *mem1, int *mem2, int len)
+{
+ register int a= len, *mema= mem1, *memb= mem2;
+
+ while(a--) {
+ if( *mema != *memb) return 1;
+ mema++;
+ memb++;
+ }
+ return 0;
+}
+
+void add_memfilechunk(MemFile *compare, MemFile *current, char *buf, unsigned int size)
+{
+ static MemFileChunk *compchunk=NULL;
+ MemFileChunk *curchunk;
+
+ /* this function inits when compare != NULL or when current==NULL */
+ if(compare) {
+ compchunk= compare->chunks.first;
+ return;
+ }
+ if(current==NULL) {
+ compchunk= NULL;
+ return;
+ }
+
+ curchunk= MEM_mallocN(sizeof(MemFileChunk), "MemFileChunk");
+ curchunk->size= size;
+ curchunk->buf= NULL;
+ curchunk->ident= 0;
+ BLI_addtail(&current->chunks, curchunk);
+
+ /* we compare compchunk with buf */
+ if(compchunk) {
+ if(compchunk->size == curchunk->size) {
+ if( my_memcmp((int *)compchunk->buf, (int *)buf, size/4)==0) {
+ curchunk->buf= compchunk->buf;
+ curchunk->ident= 1;
+ }
+ }
+ compchunk= compchunk->next;
+ }
+
+ /* not equal... */
+ if(curchunk->buf==NULL) {
+ curchunk->buf= MEM_mallocN(size, "Chunk buffer");
+ memcpy(curchunk->buf, buf, size);
+ current->size += size;
+ }
+}
+
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
new file mode 100644
index 00000000000..43907a30ac2
--- /dev/null
+++ b/source/blender/blenloader/intern/writefile.c
@@ -0,0 +1,2202 @@
+/* writefile.c
+ *
+ * .blend file writing
+ *
+ * $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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+FILEFORMAT: IFF-style structure (but not IFF compatible!)
+
+start file:
+ BLENDER_V100 12 bytes (versie 1.00)
+ V = big endian, v = little endian
+ _ = 4 byte pointer, - = 8 byte pointer
+
+datablocks: also see struct BHead
+ <bh.code> 4 chars
+ <bh.len> int, len data after BHead
+ <bh.old> void, old pointer
+ <bh.SDNAnr> int
+ <bh.nr> int, in case of array: amount of structs
+ data
+ ...
+ ...
+
+Almost all data in Blender are structures. Each struct saved
+gets a BHead header. With BHead the struct can be linked again
+and compared with StructDNA .
+
+WRITE
+
+Preferred writing order: (not really a must, but why would you do it random?)
+Any case: direct data is ALWAYS after the lib block
+
+(Local file data)
+- for each LibBlock
+ - write LibBlock
+ - write associated direct data
+(External file data)
+- per library
+ - write library block
+ - per LibBlock
+ - write the ID of LibBlock
+- write FileGlobal (some global vars)
+- write SDNA
+- write USER if filename is ~/.B.blend
+*/
+
+/* for version 2.2+
+Important to know is that 'streaming' has been added to files, for Blender Publisher
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "zlib.h"
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include "winsock2.h"
+#include "BLI_winstuff.h"
+#include <io.h>
+#include <process.h> // for getpid
+#endif
+
+#include <math.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "nla.h" // __NLA is defined
+
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"
+#include "DNA_actuator_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_color_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_fileglobal_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_listBase.h" /* for Listbase, the type of samples, ...*/
+#include "DNA_lamp_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_material_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_oops_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_property_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sdna_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_text_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_world_types.h"
+
+#include "MEM_guardedalloc.h" // MEM_freeN
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+
+#include "BKE_action.h"
+#include "BKE_bad_level_calls.h" // build_seqar (from WHILE_SEQ) free_oops error
+#include "BKE_blender.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_constraint.h"
+#include "BKE_global.h" // for G
+#include "BKE_library.h" // for set_listbasepointers
+#include "BKE_main.h" // G.main
+#include "BKE_node.h"
+#include "BKE_packedFile.h" // for packAll
+#include "BKE_screen.h" // for waitcursor
+#include "BKE_scene.h" // for do_seq
+#include "BKE_sound.h" /* ... and for samples */
+#include "BKE_utildefines.h" // for defines
+#include "BKE_modifier.h"
+#include "BKE_idprop.h"
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#include "BIF_verse.h"
+#endif
+
+#include "GEN_messaging.h"
+
+#include "BLO_writefile.h"
+#include "BLO_readfile.h"
+#include "BLO_undofile.h"
+
+#include "readfile.h"
+#include "genfile.h"
+
+#include <errno.h>
+
+/* ********* my write, buffered writing with minimum 50k chunks ************ */
+
+typedef struct {
+ struct SDNA *sdna;
+
+ int file;
+ unsigned char *buf;
+ MemFile *compare, *current;
+
+ int tot, count, error, memsize;
+} WriteData;
+
+static WriteData *writedata_new(int file)
+{
+ extern unsigned char DNAstr[]; /* DNA.c */
+ extern int DNAlen;
+
+ WriteData *wd= MEM_callocN(sizeof(*wd), "writedata");
+
+ /* XXX, see note about this in readfile.c, remove
+ * once we have an xp lock - zr
+ */
+
+ if (wd == NULL) return NULL;
+
+ wd->sdna= dna_sdna_from_data(DNAstr, DNAlen, 0);
+
+ wd->file= file;
+
+ wd->buf= MEM_mallocN(100000, "wd->buf");
+
+ return wd;
+}
+
+static void writedata_do_write(WriteData *wd, void *mem, int memlen)
+{
+ if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) return;
+ if (wd->error) return;
+
+ /* 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)
+{
+ dna_freestructDNA(wd->sdna);
+
+ MEM_freeN(wd->buf);
+ MEM_freeN(wd);
+}
+
+/***/
+
+int mywfile;
+
+/**
+ * Low level WRITE(2) wrapper that buffers data
+ * @param adr Pointer to new chunk of data
+ * @param len Length of new chunk of data
+ * @warning Talks to other functions with global parameters
+ */
+
+#define MYWRITE_FLUSH NULL
+
+static void mywrite( WriteData *wd, void *adr, int len)
+{
+ if (wd->error) return;
+
+ 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);
+ wd->count= 0;
+ }
+ writedata_do_write(wd, adr, len);
+ return;
+ }
+ if(len+wd->count>99999) {
+ writedata_do_write(wd, wd->buf, wd->count);
+ wd->count= 0;
+ }
+ memcpy(&wd->buf[wd->count], adr, len);
+ wd->count+= len;
+
+}
+
+/**
+ * BeGiN initializer for mywrite
+ * @param file File descriptor
+ * @param write_flags Write parameters
+ * @warning Talks to other functions with global parameters
+ */
+static WriteData *bgnwrite(int file, MemFile *compare, MemFile *current, int write_flags)
+{
+ WriteData *wd= writedata_new(file);
+
+ if (wd == NULL) return NULL;
+
+ wd->compare= compare;
+ wd->current= current;
+ /* this inits comparing */
+ add_memfilechunk(compare, NULL, NULL, 0);
+
+ return wd;
+}
+
+/**
+ * END the mywrite wrapper
+ * @return 1 if write failed
+ * @return unknown global variable otherwise
+ * @warning Talks to other functions with global parameters
+ */
+static int endwrite(WriteData *wd)
+{
+ int err;
+
+ if (wd->count) {
+ writedata_do_write(wd, wd->buf, wd->count);
+ wd->count= 0;
+ }
+
+ err= wd->error;
+ writedata_free(wd);
+
+ return err;
+}
+
+/* ********** WRITE FILE ****************** */
+
+static void writestruct(WriteData *wd, int filecode, char *structname, int nr, void *adr)
+{
+ BHead bh;
+ short *sp;
+
+ if(adr==NULL || nr==0) return;
+
+ /* init BHead */
+ bh.code= filecode;
+ bh.old= adr;
+ bh.nr= nr;
+
+ bh.SDNAnr= dna_findstruct_nr(wd->sdna, structname);
+ if(bh.SDNAnr== -1) {
+ printf("error: can't find SDNA code <%s>\n", structname);
+ return;
+ }
+ sp= wd->sdna->structs[bh.SDNAnr];
+
+ bh.len= nr*wd->sdna->typelens[sp[0]];
+
+ if(bh.len==0) return;
+
+ mywrite(wd, &bh, sizeof(BHead));
+ mywrite(wd, adr, bh.len);
+}
+
+static void writedata(WriteData *wd, int filecode, int len, void *adr) /* do not use for structs */
+{
+ BHead bh;
+
+ if(adr==0) return;
+ if(len==0) return;
+
+ len+= 3;
+ len-= ( len % 4);
+
+ /* init BHead */
+ bh.code= filecode;
+ bh.old= adr;
+ bh.nr= 1;
+ bh.SDNAnr= 0;
+ bh.len= len;
+
+ mywrite(wd, &bh, sizeof(BHead));
+ if(len) mywrite(wd, adr, len);
+}
+
+/* *************** writing some direct data structs used in more code parts **************** */
+/*These functions are used by blender's .blend system for file saving/loading.*/
+void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd);
+void IDP_WriteProperty(IDProperty *prop, void *wd);
+
+void IDP_WriteArray(IDProperty *prop, void *wd)
+{
+ /*REMEMBER to set totalen to len in the linking code!!*/
+ if (prop->data.pointer) {
+ writedata(wd, DATA, MEM_allocN_len(prop->data.pointer), prop->data.pointer);
+ }
+}
+
+void IDP_WriteString(IDProperty *prop, void *wd)
+{
+ /*REMEMBER to set totalen to len in the linking code!!*/
+ writedata(wd, DATA, prop->len+1, prop->data.pointer);
+}
+
+void IDP_WriteGroup(IDProperty *prop, void *wd)
+{
+ IDProperty *loop;
+
+ for (loop=prop->data.group.first; loop; loop=loop->next) {
+ IDP_WriteProperty(loop, wd);
+ }
+}
+
+/* Functions to read/write ID Properties */
+void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd)
+{
+ switch (prop->type) {
+ case IDP_GROUP:
+ IDP_WriteGroup(prop, wd);
+ break;
+ case IDP_STRING:
+ IDP_WriteString(prop, wd);
+ break;
+ case IDP_ARRAY:
+ IDP_WriteArray(prop, wd);
+ break;
+ }
+}
+
+void IDP_WriteProperty(IDProperty *prop, void *wd)
+{
+ writestruct(wd, DATA, "IDProperty", 1, prop);
+ IDP_WriteProperty_OnlyData(prop, wd);
+}
+
+static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
+{
+ int a;
+
+ writestruct(wd, DATA, "CurveMapping", 1, cumap);
+ for(a=0; a<CM_TOT; a++)
+ writestruct(wd, DATA, "CurveMapPoint", cumap->cm[a].totpoint, cumap->cm[a].curve);
+}
+
+/* this is only direct data, tree itself should have been written */
+static void write_nodetree(WriteData *wd, bNodeTree *ntree)
+{
+ bNode *node;
+ bNodeSocket *sock;
+ bNodeLink *link;
+
+ /* for link_list() speed, we write per list */
+
+ for(node= ntree->nodes.first; node; node= node->next)
+ writestruct(wd, DATA, "bNode", 1, node);
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->storage) {
+ /* could be handlerized at some point, now only 1 exception still */
+ if(ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
+ write_curvemapping(wd, node->storage);
+ else if(ntree->type==NTREE_COMPOSIT && (node->type==CMP_NODE_TIME || node->type==CMP_NODE_CURVE_VEC || node->type==CMP_NODE_CURVE_RGB))
+ write_curvemapping(wd, node->storage);
+ else
+ writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ }
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ writestruct(wd, DATA, "bNodeSocket", 1, sock);
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ writestruct(wd, DATA, "bNodeSocket", 1, sock);
+ }
+
+ for(link= ntree->links.first; link; link= link->next)
+ writestruct(wd, DATA, "bNodeLink", 1, link);
+}
+
+static void write_scriptlink(WriteData *wd, ScriptLink *slink)
+{
+ writedata(wd, DATA, sizeof(void *)*slink->totscript, slink->scripts);
+ writedata(wd, DATA, sizeof(short)*slink->totscript, slink->flag);
+}
+
+static void write_renderinfo(WriteData *wd) /* for renderdeamon */
+{
+ Scene *sce;
+ int data[8];
+
+ sce= G.main->scene.first;
+ while(sce) {
+ if(sce->id.lib==0 && ( sce==G.scene || (sce->r.scemode & R_BG_RENDER)) ) {
+ data[0]= sce->r.sfra;
+ data[1]= sce->r.efra;
+
+ memset(data+2, 0, sizeof(int)*6);
+ strncpy((char *)(data+2), sce->id.name+2, 21);
+
+ writedata(wd, REND, 32, data);
+ }
+ sce= sce->id.next;
+ }
+}
+
+static void write_userdef(WriteData *wd)
+{
+ bTheme *btheme;
+
+ writestruct(wd, USER, "UserDef", 1, &U);
+
+ btheme= U.themes.first;
+ while(btheme) {
+ writestruct(wd, DATA, "bTheme", 1, btheme);
+ btheme= btheme->next;
+ }
+}
+
+static void write_effects(WriteData *wd, ListBase *lb)
+{
+ Effect *eff;
+
+ eff= lb->first;
+ while(eff) {
+
+ switch(eff->type) {
+ case EFF_PARTICLE:
+ writestruct(wd, DATA, "PartEff", 1, eff);
+ break;
+ default:
+ writedata(wd, DATA, MEM_allocN_len(eff), eff);
+ }
+
+ eff= eff->next;
+ }
+}
+
+static void write_properties(WriteData *wd, ListBase *lb)
+{
+ bProperty *prop;
+
+ prop= lb->first;
+ while(prop) {
+ writestruct(wd, DATA, "bProperty", 1, prop);
+
+ if(prop->poin && prop->poin != &prop->data)
+ writedata(wd, DATA, MEM_allocN_len(prop->poin), prop->poin);
+
+ prop= prop->next;
+ }
+}
+
+static void write_sensors(WriteData *wd, ListBase *lb)
+{
+ bSensor *sens;
+
+ sens= lb->first;
+ while(sens) {
+ writestruct(wd, DATA, "bSensor", 1, sens);
+
+ writedata(wd, DATA, sizeof(void *)*sens->totlinks, sens->links);
+
+ switch(sens->type) {
+ case SENS_NEAR:
+ writestruct(wd, DATA, "bNearSensor", 1, sens->data);
+ break;
+ case SENS_MOUSE:
+ writestruct(wd, DATA, "bMouseSensor", 1, sens->data);
+ break;
+ case SENS_TOUCH:
+ writestruct(wd, DATA, "bTouchSensor", 1, sens->data);
+ break;
+ case SENS_KEYBOARD:
+ writestruct(wd, DATA, "bKeyboardSensor", 1, sens->data);
+ break;
+ case SENS_PROPERTY:
+ writestruct(wd, DATA, "bPropertySensor", 1, sens->data);
+ break;
+ case SENS_COLLISION:
+ writestruct(wd, DATA, "bCollisionSensor", 1, sens->data);
+ break;
+ case SENS_RADAR:
+ writestruct(wd, DATA, "bRadarSensor", 1, sens->data);
+ break;
+ case SENS_RANDOM:
+ writestruct(wd, DATA, "bRandomSensor", 1, sens->data);
+ break;
+ case SENS_RAY:
+ writestruct(wd, DATA, "bRaySensor", 1, sens->data);
+ break;
+ case SENS_MESSAGE:
+ writestruct(wd, DATA, "bMessageSensor", 1, sens->data);
+ break;
+ case SENS_JOYSTICK:
+ writestruct(wd, DATA, "bJoystickSensor", 1, sens->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
+ }
+
+ sens= sens->next;
+ }
+}
+
+static void write_controllers(WriteData *wd, ListBase *lb)
+{
+ bController *cont;
+
+ cont= lb->first;
+ while(cont) {
+ writestruct(wd, DATA, "bController", 1, cont);
+
+ writedata(wd, DATA, sizeof(void *)*cont->totlinks, cont->links);
+
+ switch(cont->type) {
+ case CONT_EXPRESSION:
+ writestruct(wd, DATA, "bExpressionCont", 1, cont->data);
+ break;
+ case CONT_PYTHON:
+ writestruct(wd, DATA, "bPythonCont", 1, cont->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
+ }
+
+ cont= cont->next;
+ }
+}
+
+static void write_actuators(WriteData *wd, ListBase *lb)
+{
+ bActuator *act;
+
+ act= lb->first;
+ while(act) {
+ writestruct(wd, DATA, "bActuator", 1, act);
+
+ switch(act->type) {
+ case ACT_ACTION:
+ writestruct(wd, DATA, "bActionActuator", 1, act->data);
+ break;
+ case ACT_SOUND:
+ writestruct(wd, DATA, "bSoundActuator", 1, act->data);
+ break;
+ case ACT_CD:
+ writestruct(wd, DATA, "bCDActuator", 1, act->data);
+ break;
+ case ACT_OBJECT:
+ writestruct(wd, DATA, "bObjectActuator", 1, act->data);
+ break;
+ case ACT_IPO:
+ writestruct(wd, DATA, "bIpoActuator", 1, act->data);
+ break;
+ case ACT_PROPERTY:
+ writestruct(wd, DATA, "bPropertyActuator", 1, act->data);
+ break;
+ case ACT_CAMERA:
+ writestruct(wd, DATA, "bCameraActuator", 1, act->data);
+ break;
+ case ACT_CONSTRAINT:
+ writestruct(wd, DATA, "bConstraintActuator", 1, act->data);
+ break;
+ case ACT_EDIT_OBJECT:
+ writestruct(wd, DATA, "bEditObjectActuator", 1, act->data);
+ break;
+ case ACT_SCENE:
+ writestruct(wd, DATA, "bSceneActuator", 1, act->data);
+ break;
+ case ACT_GROUP:
+ writestruct(wd, DATA, "bGroupActuator", 1, act->data);
+ break;
+ case ACT_RANDOM:
+ writestruct(wd, DATA, "bRandomActuator", 1, act->data);
+ break;
+ case ACT_MESSAGE:
+ writestruct(wd, DATA, "bMessageActuator", 1, act->data);
+ break;
+ case ACT_GAME:
+ writestruct(wd, DATA, "bGameActuator", 1, act->data);
+ break;
+ case ACT_VISIBILITY:
+ writestruct(wd, DATA, "bVisibilityActuator", 1, act->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
+ }
+
+ act= act->next;
+ }
+}
+
+static void write_nlastrips(WriteData *wd, ListBase *nlabase)
+{
+ bActionStrip *strip;
+ bActionModifier *amod;
+
+ for (strip=nlabase->first; strip; strip=strip->next)
+ writestruct(wd, DATA, "bActionStrip", 1, strip);
+ for (strip=nlabase->first; strip; strip=strip->next) {
+ for(amod= strip->modifiers.first; amod; amod= amod->next)
+ writestruct(wd, DATA, "bActionModifier", 1, amod);
+ }
+}
+
+static void write_constraints(WriteData *wd, ListBase *conlist)
+{
+ bConstraint *con;
+
+ for (con=conlist->first; con; con=con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+
+ /* Write the specific data */
+ if (cti && con->data) {
+ /* firstly, just write the plain con->data struct */
+ writestruct(wd, DATA, cti->structName, 1, con->data);
+
+ /* do any constraint specific stuff */
+ switch (con->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = (bPythonConstraint *)con->data;
+ bConstraintTarget *ct;
+
+ /* write targets */
+ for (ct= data->targets.first; ct; ct= ct->next)
+ writestruct(wd, DATA, "bConstraintTarget", 1, ct);
+
+ /* Write ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ IDP_WriteProperty(data->prop, wd);
+ }
+ break;
+ }
+ }
+
+ /* Write the constraint */
+ writestruct(wd, DATA, "bConstraint", 1, con);
+ }
+}
+
+static void write_pose(WriteData *wd, bPose *pose)
+{
+ bPoseChannel *chan;
+
+ /* Write each channel */
+ if (!pose)
+ return;
+
+ /* Write channels */
+ for (chan=pose->chanbase.first; chan; chan=chan->next) {
+ write_constraints(wd, &chan->constraints);
+
+ /* prevent crashes with autosave, when a bone duplicated in editmode has not yet been assigned to its posechannel */
+ if (chan->bone)
+ chan->selectflag= chan->bone->flag & (BONE_SELECTED|BONE_ACTIVE); /* gets restored on read, for library armatures */
+
+ writestruct(wd, DATA, "bPoseChannel", 1, chan);
+ }
+
+ /* Write this pose */
+ writestruct(wd, DATA, "bPose", 1, pose);
+}
+
+static void write_defgroups(WriteData *wd, ListBase *defbase)
+{
+ bDeformGroup *defgroup;
+
+ for (defgroup=defbase->first; defgroup; defgroup=defgroup->next)
+ writestruct(wd, DATA, "bDeformGroup", 1, defgroup);
+}
+
+static void write_constraint_channels(WriteData *wd, ListBase *chanbase)
+{
+ bConstraintChannel *chan;
+
+ for (chan = chanbase->first; chan; chan=chan->next)
+ writestruct(wd, DATA, "bConstraintChannel", 1, chan);
+
+}
+
+static void write_modifiers(WriteData *wd, ListBase *modbase)
+{
+ ModifierData *md;
+
+ if (modbase == NULL) return;
+ for (md=modbase->first; md; md= md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ if (mti == NULL) return;
+
+ writestruct(wd, DATA, mti->structName, 1, md);
+
+ if (md->type==eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ writedata(wd, DATA, sizeof(int)*hmd->totindex, hmd->indexar);
+ }
+ else if (md->type==eModifierType_MeshDeform) {
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+
+ writedata(wd, DATA, sizeof(float)*mmd->totvert*mmd->totcagevert,
+ mmd->bindweights);
+ writedata(wd, DATA, sizeof(float)*3*mmd->totcagevert,
+ mmd->bindcos);
+ }
+ }
+}
+
+static void write_objects(WriteData *wd, ListBase *idbase)
+{
+ Object *ob;
+ int a;
+
+ ob= idbase->first;
+ while(ob) {
+ if(ob->id.us>0 || wd->current) {
+ /* write LibData */
+#ifdef WITH_VERSE
+ /* pointer at vnode stored in file have to be NULL */
+ struct VNode *vnode = (VNode*)ob->vnode;
+ if(vnode) ob->vnode = NULL;
+#endif
+ writestruct(wd, ID_OB, "Object", 1, ob);
+#ifdef WITH_VERSE
+ if(vnode) ob->vnode = (void*)vnode;
+#endif
+
+ /*Write ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ if (ob->id.properties) IDP_WriteProperty(ob->id.properties, wd);
+
+ /* direct data */
+ writedata(wd, DATA, sizeof(void *)*ob->totcol, ob->mat);
+ write_effects(wd, &ob->effect);
+ write_properties(wd, &ob->prop);
+ write_sensors(wd, &ob->sensors);
+ write_controllers(wd, &ob->controllers);
+ write_actuators(wd, &ob->actuators);
+ write_scriptlink(wd, &ob->scriptlink);
+ write_pose(wd, ob->pose);
+ write_defgroups(wd, &ob->defbase);
+ write_constraints(wd, &ob->constraints);
+ write_constraint_channels(wd, &ob->constraintChannels);
+ write_nlastrips(wd, &ob->nlastrips);
+
+ writestruct(wd, DATA, "PartDeflect", 1, ob->pd);
+ writestruct(wd, DATA, "SoftBody", 1, ob->soft);
+ if(ob->soft) {
+ SoftBody *sb= ob->soft;
+ if(sb->keys) {
+ writedata(wd, DATA, sizeof(void *)*sb->totkey, sb->keys);
+ for(a=0; a<sb->totkey; a++) {
+ writestruct(wd, DATA, "SBVertex", sb->totpoint, sb->keys[a]);
+ }
+ }
+ }
+ writestruct(wd, DATA, "FluidsimSettings", 1, ob->fluidsimSettings); // NT
+
+ write_modifiers(wd, &ob->modifiers);
+ }
+ ob= ob->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+
+static void write_vfonts(WriteData *wd, ListBase *idbase)
+{
+ VFont *vf;
+ PackedFile * pf;
+
+ vf= idbase->first;
+ while(vf) {
+ if(vf->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_VF, "VFont", 1, vf);
+ if (vf->id.properties) IDP_WriteProperty(vf->id.properties, wd);
+
+ /* direct data */
+
+ if (vf->packedfile) {
+ pf = vf->packedfile;
+ writestruct(wd, DATA, "PackedFile", 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
+ }
+ }
+
+ vf= vf->id.next;
+ }
+}
+
+static void write_ipos(WriteData *wd, ListBase *idbase)
+{
+ Ipo *ipo;
+ IpoCurve *icu;
+
+ ipo= idbase->first;
+ while(ipo) {
+ if(ipo->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_IP, "Ipo", 1, ipo);
+ if (ipo->id.properties) IDP_WriteProperty(ipo->id.properties, wd);
+
+ /* direct data */
+ icu= ipo->curve.first;
+ while(icu) {
+ writestruct(wd, DATA, "IpoCurve", 1, icu);
+ icu= icu->next;
+ }
+
+ icu= ipo->curve.first;
+ while(icu) {
+ if(icu->bezt) writestruct(wd, DATA, "BezTriple", icu->totvert, icu->bezt);
+ if(icu->bp) writestruct(wd, DATA, "BPoint", icu->totvert, icu->bp);
+ if(icu->driver) writestruct(wd, DATA, "IpoDriver", 1, icu->driver);
+ icu= icu->next;
+ }
+ }
+
+ ipo= ipo->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_keys(WriteData *wd, ListBase *idbase)
+{
+ Key *key;
+ KeyBlock *kb;
+
+ key= idbase->first;
+ while(key) {
+ if(key->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_KE, "Key", 1, key);
+ if (key->id.properties) IDP_WriteProperty(key->id.properties, wd);
+
+ /* direct data */
+ kb= key->block.first;
+ while(kb) {
+ writestruct(wd, DATA, "KeyBlock", 1, kb);
+ if(kb->data) writedata(wd, DATA, kb->totelem*key->elemsize, kb->data);
+ kb= kb->next;
+ }
+ }
+
+ key= key->id.next;
+ }
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_cameras(WriteData *wd, ListBase *idbase)
+{
+ Camera *cam;
+
+ cam= idbase->first;
+ while(cam) {
+ if(cam->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_CA, "Camera", 1, cam);
+ if (cam->id.properties) IDP_WriteProperty(cam->id.properties, wd);
+
+ /* direct data */
+ write_scriptlink(wd, &cam->scriptlink);
+ }
+
+ cam= cam->id.next;
+ }
+}
+
+static void write_mballs(WriteData *wd, ListBase *idbase)
+{
+ MetaBall *mb;
+ MetaElem *ml;
+
+ mb= idbase->first;
+ while(mb) {
+ if(mb->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_MB, "MetaBall", 1, mb);
+ if (mb->id.properties) IDP_WriteProperty(mb->id.properties, wd);
+
+ /* direct data */
+ writedata(wd, DATA, sizeof(void *)*mb->totcol, mb->mat);
+
+ ml= mb->elems.first;
+ while(ml) {
+ writestruct(wd, DATA, "MetaElem", 1, ml);
+ ml= ml->next;
+ }
+ }
+ mb= mb->id.next;
+ }
+}
+
+int amount_of_chars(char *str)
+{
+ // Since the data is saved as UTF-8 to the cu->str
+ // The cu->len is not same as the strlen(cu->str)
+ return strlen(str);
+}
+
+static void write_curves(WriteData *wd, ListBase *idbase)
+{
+ Curve *cu;
+ Nurb *nu;
+
+ cu= idbase->first;
+ while(cu) {
+ if(cu->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_CU, "Curve", 1, cu);
+
+ /* direct data */
+ writedata(wd, DATA, sizeof(void *)*cu->totcol, cu->mat);
+ if (cu->id.properties) IDP_WriteProperty(cu->id.properties, wd);
+
+ if(cu->vfont) {
+ writedata(wd, DATA, amount_of_chars(cu->str)+1, cu->str);
+ writestruct(wd, DATA, "CharInfo", cu->len, cu->strinfo);
+ writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb);
+ }
+ else {
+ /* is also the order of reading */
+ nu= cu->nurb.first;
+ while(nu) {
+ writestruct(wd, DATA, "Nurb", 1, nu);
+ nu= nu->next;
+ }
+ nu= cu->nurb.first;
+ while(nu) {
+ if( (nu->type & 7)==CU_BEZIER)
+ writestruct(wd, DATA, "BezTriple", nu->pntsu, nu->bezt);
+ else {
+ writestruct(wd, DATA, "BPoint", nu->pntsu*nu->pntsv, nu->bp);
+ if(nu->knotsu) writedata(wd, DATA, KNOTSU(nu)*sizeof(float), nu->knotsu);
+ if(nu->knotsv) writedata(wd, DATA, KNOTSV(nu)*sizeof(float), nu->knotsv);
+ }
+ nu= nu->next;
+ }
+ }
+ }
+ 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)
+{
+ if (dvlist) {
+ int i;
+
+ /* Write the dvert list */
+ writestruct(wd, DATA, "MDeformVert", count, dvlist);
+
+ /* Write deformation data for each dvert */
+ for (i=0; i<count; i++) {
+ if (dvlist[i].dw)
+ writestruct(wd, DATA, "MDeformWeight", dvlist[i].totweight, dvlist[i].dw);
+ }
+ }
+}
+
+static void write_customdata(WriteData *wd, int count, CustomData *data, int partial_type, int partial_count)
+{
+ int i;
+
+ writestruct(wd, DATA, "CustomDataLayer", data->maxlayer, data->layers);
+
+ for (i=0; i<data->totlayer; i++) {
+ CustomDataLayer *layer= &data->layers[i];
+ char *structname;
+ int structnum, datasize;
+
+ if (layer->type == CD_MDEFORMVERT) {
+ /* layer types that allocate own memory need special handling */
+ write_dverts(wd, count, layer->data);
+ }
+ else {
+ CustomData_file_write_info(layer->type, &structname, &structnum);
+ if (structnum) {
+ /* when using partial visibility, the MEdge and MFace layers
+ are smaller than the original, so their type and count is
+ passed to make this work */
+ if (layer->type != partial_type) datasize= structnum*count;
+ else datasize= structnum*partial_count;
+
+ writestruct(wd, DATA, structname, datasize, layer->data);
+ }
+ else
+ printf("error: this CustomDataLayer must not be written to file\n");
+ }
+ }
+}
+
+static void write_meshs(WriteData *wd, ListBase *idbase)
+{
+ Mesh *mesh;
+ MultiresLevel *lvl;
+
+ mesh= idbase->first;
+ while(mesh) {
+ if(mesh->id.us>0 || wd->current) {
+ /* write LibData */
+#ifdef WITH_VERSE
+ struct VNode *vnode = (VNode*)mesh->vnode;
+ if(vnode) {
+ /* mesh has to be created from verse geometry node*/
+ create_meshdata_from_geom_node(mesh, vnode);
+ /* pointer at verse node can't be stored in file */
+ mesh->vnode = NULL;
+ }
+#endif
+
+ writestruct(wd, ID_ME, "Mesh", 1, mesh);
+#ifdef WITH_VERSE
+ if(vnode) mesh->vnode = (void*)vnode;
+#endif
+
+ /* direct data */
+ if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
+
+ writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
+
+ if(mesh->pv) {
+ write_customdata(wd, mesh->pv->totvert, &mesh->vdata, -1, 0);
+ write_customdata(wd, mesh->pv->totedge, &mesh->edata,
+ CD_MEDGE, mesh->totedge);
+ write_customdata(wd, mesh->pv->totface, &mesh->fdata,
+ CD_MFACE, mesh->totface);
+ }
+ else {
+ write_customdata(wd, mesh->totvert, &mesh->vdata, -1, 0);
+ write_customdata(wd, mesh->totedge, &mesh->edata, -1, 0);
+ write_customdata(wd, mesh->totface, &mesh->fdata, -1, 0);
+ }
+
+ /* Multires data */
+ writestruct(wd, DATA, "Multires", 1, mesh->mr);
+ if(mesh->mr) {
+ lvl= mesh->mr->levels.first;
+ if(lvl) {
+ write_customdata(wd, lvl->totvert, &mesh->mr->vdata, -1, 0);
+ write_customdata(wd, lvl->totface, &mesh->mr->fdata, -1, 0);
+ writedata(wd, DATA, sizeof(short)*lvl->totedge, mesh->mr->edge_flags);
+ writedata(wd, DATA, sizeof(char)*lvl->totedge, mesh->mr->edge_creases);
+ }
+
+ for(; lvl; lvl= lvl->next) {
+ writestruct(wd, DATA, "MultiresLevel", 1, lvl);
+ writestruct(wd, DATA, "MultiresFace", lvl->totface, lvl->faces);
+ writestruct(wd, DATA, "MultiresEdge", lvl->totedge, lvl->edges);
+ writestruct(wd, DATA, "MultiresColFace", lvl->totface, lvl->colfaces);
+ }
+
+ lvl= mesh->mr->levels.last;
+ if(lvl)
+ writestruct(wd, DATA, "MVert", lvl->totvert, mesh->mr->verts);
+ }
+
+ /* PMV data */
+ if(mesh->pv) {
+ writestruct(wd, DATA, "PartialVisibility", 1, mesh->pv);
+ writedata(wd, DATA, sizeof(unsigned int)*mesh->pv->totvert, mesh->pv->vert_map);
+ writedata(wd, DATA, sizeof(int)*mesh->pv->totedge, mesh->pv->edge_map);
+ writestruct(wd, DATA, "MFace", mesh->pv->totface, mesh->pv->old_faces);
+ writestruct(wd, DATA, "MEdge", mesh->pv->totedge, mesh->pv->old_edges);
+ }
+ }
+ mesh= mesh->id.next;
+ }
+}
+
+static void write_lattices(WriteData *wd, ListBase *idbase)
+{
+ Lattice *lt;
+
+ lt= idbase->first;
+ while(lt) {
+ if(lt->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_LT, "Lattice", 1, lt);
+ if (lt->id.properties) IDP_WriteProperty(lt->id.properties, wd);
+
+ /* direct data */
+ writestruct(wd, DATA, "BPoint", lt->pntsu*lt->pntsv*lt->pntsw, lt->def);
+
+ write_dverts(wd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert);
+
+ }
+ lt= lt->id.next;
+ }
+}
+
+static void write_previews(WriteData *wd, PreviewImage *prv)
+{
+ if (prv) {
+ 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;
+ PackedFile * pf;
+
+
+ ima= idbase->first;
+ while(ima) {
+ if(ima->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_IM, "Image", 1, ima);
+ if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd);
+
+ if (ima->packedfile) {
+ pf = ima->packedfile;
+ writestruct(wd, DATA, "PackedFile", 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
+ }
+
+ write_previews(wd, ima->preview);
+
+ }
+ ima= ima->id.next;
+ }
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_textures(WriteData *wd, ListBase *idbase)
+{
+ Tex *tex;
+
+ tex= idbase->first;
+ while(tex) {
+ if(tex->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_TE, "Tex", 1, tex);
+ if (tex->id.properties) IDP_WriteProperty(tex->id.properties, wd);
+
+ /* direct data */
+ if(tex->plugin) writestruct(wd, DATA, "PluginTex", 1, tex->plugin);
+ if(tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba);
+ if(tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env);
+
+ write_previews(wd, tex->preview);
+ }
+ tex= tex->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_materials(WriteData *wd, ListBase *idbase)
+{
+ Material *ma;
+ int a;
+
+ ma= idbase->first;
+ while(ma) {
+ if(ma->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_MA, "Material", 1, ma);
+
+ /*Write ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ /*manually set head group property to IDP_GROUP, just in case it hadn't been
+ set yet :) */
+ if (ma->id.properties) IDP_WriteProperty(ma->id.properties, wd);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) writestruct(wd, DATA, "MTex", 1, ma->mtex[a]);
+ }
+
+ if(ma->ramp_col) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_col);
+ if(ma->ramp_spec) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_spec);
+
+ write_scriptlink(wd, &ma->scriptlink);
+
+ /* nodetree is integral part of material, no libdata */
+ if(ma->nodetree) {
+ writestruct(wd, DATA, "bNodeTree", 1, ma->nodetree);
+ write_nodetree(wd, ma->nodetree);
+ }
+
+ write_previews(wd, ma->preview);
+ }
+ ma= ma->id.next;
+ }
+}
+
+static void write_worlds(WriteData *wd, ListBase *idbase)
+{
+ World *wrld;
+ int a;
+
+ wrld= idbase->first;
+ while(wrld) {
+ if(wrld->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_WO, "World", 1, wrld);
+ if (wrld->id.properties) IDP_WriteProperty(wrld->id.properties, wd);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(wrld->mtex[a]) writestruct(wd, DATA, "MTex", 1, wrld->mtex[a]);
+ }
+
+ write_scriptlink(wd, &wrld->scriptlink);
+
+ write_previews(wd, wrld->preview);
+
+ }
+ wrld= wrld->id.next;
+ }
+}
+
+static void write_lamps(WriteData *wd, ListBase *idbase)
+{
+ Lamp *la;
+ int a;
+
+ la= idbase->first;
+ while(la) {
+ if(la->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_LA, "Lamp", 1, la);
+ if (la->id.properties) IDP_WriteProperty(la->id.properties, wd);
+
+ /* direct data */
+ for(a=0; a<MAX_MTEX; a++) {
+ if(la->mtex[a]) writestruct(wd, DATA, "MTex", 1, la->mtex[a]);
+ }
+
+ if(la->curfalloff)
+ write_curvemapping(wd, la->curfalloff);
+
+ write_scriptlink(wd, &la->scriptlink);
+
+ write_previews(wd, la->preview);
+
+ }
+ la= la->id.next;
+ }
+}
+
+
+static void write_scenes(WriteData *wd, ListBase *scebase)
+{
+ Scene *sce;
+ Base *base;
+ Editing *ed;
+ Sequence *seq;
+ MetaStack *ms;
+ Strip *strip;
+ TimeMarker *marker;
+ SceneRenderLayer *srl;
+ int a;
+
+ sce= scebase->first;
+ while(sce) {
+ /* write LibData */
+ writestruct(wd, ID_SCE, "Scene", 1, sce);
+ if (sce->id.properties) IDP_WriteProperty(sce->id.properties, wd);
+
+ /* direct data */
+ base= sce->base.first;
+ while(base) {
+ writestruct(wd, DATA, "Base", 1, base);
+ base= base->next;
+ }
+
+ writestruct(wd, DATA, "Radio", 1, sce->radio);
+ writestruct(wd, DATA, "ToolSettings", 1, sce->toolsettings);
+
+ for(a=0; a<MAX_MTEX; ++a)
+ writestruct(wd, DATA, "MTex", 1, sce->sculptdata.mtex[a]);
+
+ ed= sce->ed;
+ if(ed) {
+ writestruct(wd, DATA, "Editing", 1, ed);
+
+ /* reset write flags too */
+ WHILE_SEQ(&ed->seqbase) {
+ if(seq->strip) seq->strip->done= 0;
+ writestruct(wd, DATA, "Sequence", 1, seq);
+ }
+ END_SEQ
+
+ WHILE_SEQ(&ed->seqbase) {
+ if(seq->strip && seq->strip->done==0) {
+ /* write strip with 'done' at 0 because readfile */
+
+ if(seq->plugin) writestruct(wd, DATA, "PluginSeq", 1, seq->plugin);
+ if(seq->effectdata) {
+ switch(seq->type){
+ case SEQ_COLOR:
+ writestruct(wd, DATA, "SolidColorVars", 1, seq->effectdata);
+ break;
+ case SEQ_SPEED:
+ writestruct(wd, DATA, "SpeedControlVars", 1, seq->effectdata);
+ break;
+ case SEQ_WIPE:
+ writestruct(wd, DATA, "WipeVars", 1, seq->effectdata);
+ break;
+ case SEQ_GLOW:
+ writestruct(wd, DATA, "GlowVars", 1, seq->effectdata);
+ break;
+ case SEQ_TRANSFORM:
+ writestruct(wd, DATA, "TransformVars", 1, seq->effectdata);
+ break;
+ }
+ }
+
+ strip= seq->strip;
+ writestruct(wd, DATA, "Strip", 1, strip);
+
+ if(seq->type==SEQ_IMAGE)
+ writestruct(wd, DATA, "StripElem", strip->len, strip->stripdata);
+ else if(seq->type==SEQ_MOVIE || seq->type==SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND)
+ writestruct(wd, DATA, "StripElem", 1, strip->stripdata);
+
+ strip->done= 1;
+ }
+ }
+ END_SEQ
+
+ /* new; meta stack too, even when its nasty restore code */
+ for(ms= ed->metastack.first; ms; ms= ms->next) {
+ writestruct(wd, DATA, "MetaStack", 1, ms);
+ }
+ }
+
+ write_scriptlink(wd, &sce->scriptlink);
+
+ if (sce->r.avicodecdata) {
+ writestruct(wd, DATA, "AviCodecData", 1, sce->r.avicodecdata);
+ if (sce->r.avicodecdata->lpFormat) writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
+ if (sce->r.avicodecdata->lpParms) writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
+ }
+
+ if (sce->r.qtcodecdata) {
+ writestruct(wd, DATA, "QuicktimeCodecData", 1, sce->r.qtcodecdata);
+ if (sce->r.qtcodecdata->cdParms) writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms);
+ }
+
+ /* writing dynamic list of TimeMarkers to the blend file */
+ for(marker= sce->markers.first; marker; marker= marker->next)
+ writestruct(wd, DATA, "TimeMarker", 1, marker);
+
+ for(srl= sce->r.layers.first; srl; srl= srl->next)
+ writestruct(wd, DATA, "SceneRenderLayer", 1, srl);
+
+ if(sce->nodetree) {
+ writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree);
+ write_nodetree(wd, sce->nodetree);
+ }
+
+ sce= sce->id.next;
+ }
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_screens(WriteData *wd, ListBase *scrbase)
+{
+ bScreen *sc;
+ ScrArea *sa;
+ ScrVert *sv;
+ ScrEdge *se;
+
+ sc= scrbase->first;
+ while(sc) {
+ /* write LibData */
+ writestruct(wd, ID_SCR, "Screen", 1, sc);
+ if (sc->id.properties) IDP_WriteProperty(sc->id.properties, wd);
+
+ /* direct data */
+ sv= sc->vertbase.first;
+ while(sv) {
+ writestruct(wd, DATA, "ScrVert", 1, sv);
+ sv= sv->next;
+ }
+
+ se= sc->edgebase.first;
+ while(se) {
+ writestruct(wd, DATA, "ScrEdge", 1, se);
+ se= se->next;
+ }
+
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+ Panel *pa;
+
+ writestruct(wd, DATA, "ScrArea", 1, sa);
+
+ pa= sa->panels.first;
+ while(pa) {
+ writestruct(wd, DATA, "Panel", 1, pa);
+ pa= pa->next;
+ }
+
+ /* space handler scriptlinks */
+ write_scriptlink(wd, &sa->scriptlink);
+
+ sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+ writestruct(wd, DATA, "View3D", 1, v3d);
+ if(v3d->bgpic) writestruct(wd, DATA, "BGpic", 1, v3d->bgpic);
+ if(v3d->localvd) writestruct(wd, DATA, "View3D", 1, v3d->localvd);
+ if(v3d->clipbb) writestruct(wd, DATA, "BoundBox", 1, v3d->clipbb);
+ }
+ else if(sl->spacetype==SPACE_IPO) {
+ writestruct(wd, DATA, "SpaceIpo", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_BUTS) {
+ writestruct(wd, DATA, "SpaceButs", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_FILE) {
+ writestruct(wd, DATA, "SpaceFile", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_SEQ) {
+ writestruct(wd, DATA, "SpaceSeq", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_OOPS) {
+ SpaceOops *so= (SpaceOops *)sl;
+ Oops *oops;
+
+ /* cleanup */
+ oops= so->oops.first;
+ while(oops) {
+ Oops *oopsn= oops->next;
+ if(oops->id==0) {
+ BLI_remlink(&so->oops, oops);
+ free_oops(oops);
+ }
+ oops= oopsn;
+ }
+
+ /* ater cleanup, because of listbase! */
+ writestruct(wd, DATA, "SpaceOops", 1, so);
+
+ oops= so->oops.first;
+ while(oops) {
+ writestruct(wd, DATA, "Oops", 1, oops);
+ oops= oops->next;
+ }
+ /* outliner */
+ if(so->treestore) {
+ writestruct(wd, DATA, "TreeStore", 1, so->treestore);
+ if(so->treestore->data)
+ writestruct(wd, DATA, "TreeStoreElem", so->treestore->usedelem, so->treestore->data);
+ }
+ }
+ else if(sl->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= (SpaceImage *)sl;
+
+ writestruct(wd, DATA, "SpaceImage", 1, sl);
+ if(sima->cumap)
+ write_curvemapping(wd, sima->cumap);
+ }
+ else if(sl->spacetype==SPACE_IMASEL) {
+ writestruct(wd, DATA, "SpaceImaSel", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_TEXT) {
+ writestruct(wd, DATA, "SpaceText", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_SCRIPT) {
+ SpaceScript *sc = (SpaceScript*)sl;
+ sc->but_refs = NULL;
+ writestruct(wd, DATA, "SpaceScript", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_ACTION) {
+ writestruct(wd, DATA, "SpaceAction", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_SOUND) {
+ writestruct(wd, DATA, "SpaceSound", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_NLA){
+ writestruct(wd, DATA, "SpaceNla", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_TIME){
+ writestruct(wd, DATA, "SpaceTime", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_NODE){
+ writestruct(wd, DATA, "SpaceNode", 1, sl);
+ }
+ sl= sl->next;
+ }
+
+ sa= sa->next;
+ }
+
+ sc= sc->id.next;
+ }
+}
+
+static void write_libraries(WriteData *wd, Main *main)
+{
+ ListBase *lbarray[30];
+ ID *id;
+ int a, tot, foundone;
+
+ for(; main; main= main->next) {
+
+ a=tot= set_listbasepointers(main, lbarray);
+
+ /* test: is lib being used */
+ foundone= 0;
+ while(tot--) {
+ for(id= lbarray[tot]->first; id; id= id->next) {
+ if(id->us>0 && (id->flag & LIB_EXTERN)) {
+ foundone= 1;
+ break;
+ }
+ }
+ if(foundone) break;
+ }
+
+ if(foundone) {
+ writestruct(wd, ID_LI, "Library", 1, main->curlib);
+
+ while(a--) {
+ for(id= lbarray[a]->first; id; id= id->next) {
+ if(id->us>0 && (id->flag & LIB_EXTERN)) {
+ writestruct(wd, ID_ID, "ID", 1, id);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void write_bone(WriteData *wd, Bone* bone)
+{
+ Bone* cbone;
+
+ // PATCH for upward compatibility after 2.37+ armature recode
+ bone->size[0]= bone->size[1]= bone->size[2]= 1.0f;
+
+ // Write this bone
+ writestruct(wd, DATA, "Bone", 1, bone);
+
+ // Write Children
+ cbone= bone->childbase.first;
+ while(cbone) {
+ write_bone(wd, cbone);
+ cbone= cbone->next;
+ }
+}
+
+static void write_armatures(WriteData *wd, ListBase *idbase)
+{
+ bArmature *arm;
+ Bone *bone;
+
+ arm=idbase->first;
+ while (arm) {
+ if (arm->id.us>0 || wd->current) {
+ writestruct(wd, ID_AR, "bArmature", 1, arm);
+ if (arm->id.properties) IDP_WriteProperty(arm->id.properties, wd);
+
+ /* Direct data */
+ bone= arm->bonebase.first;
+ while(bone) {
+ write_bone(wd, bone);
+ bone=bone->next;
+ }
+ }
+ arm=arm->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_actions(WriteData *wd, ListBase *idbase)
+{
+ bAction *act;
+ bActionChannel *chan;
+
+ for(act=idbase->first; act; act= act->id.next) {
+ if (act->id.us>0 || wd->current) {
+ writestruct(wd, ID_AC, "bAction", 1, act);
+ if (act->id.properties) IDP_WriteProperty(act->id.properties, wd);
+
+ for (chan=act->chanbase.first; chan; chan=chan->next) {
+ writestruct(wd, DATA, "bActionChannel", 1, chan);
+ write_constraint_channels(wd, &chan->constraintChannels);
+ }
+ }
+ }
+}
+
+static void write_texts(WriteData *wd, ListBase *idbase)
+{
+ Text *text;
+ TextLine *tmp;
+
+ text= idbase->first;
+ while(text) {
+ if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) text->flags &= ~TXT_ISEXT;
+
+ /* write LibData */
+ writestruct(wd, ID_TXT, "Text", 1, text);
+ if(text->name) writedata(wd, DATA, strlen(text->name)+1, text->name);
+ if (text->id.properties) IDP_WriteProperty(text->id.properties, wd);
+
+ if(!(text->flags & TXT_ISEXT)) {
+ /* now write the text data, in two steps for optimization in the readfunction */
+ tmp= text->lines.first;
+ while (tmp) {
+ writestruct(wd, DATA, "TextLine", 1, tmp);
+ tmp= tmp->next;
+ }
+
+ tmp= text->lines.first;
+ while (tmp) {
+ writedata(wd, DATA, tmp->len+1, tmp->line);
+ tmp= tmp->next;
+ }
+ }
+ text= text->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_sounds(WriteData *wd, ListBase *idbase)
+{
+ bSound *sound;
+ bSample *sample;
+
+ PackedFile * pf;
+
+ // set all samples to unsaved status
+
+ sample = samples->first;
+ while (sample) {
+ sample->flags |= SAMPLE_NEEDS_SAVE;
+ sample = sample->id.next;
+ }
+
+ sound= idbase->first;
+ while(sound) {
+ if(sound->id.us>0 || wd->current) {
+ // do we need to save the packedfile as well ?
+ sample = sound->sample;
+ if (sample) {
+ if (sample->flags & SAMPLE_NEEDS_SAVE) {
+ sound->newpackedfile = sample->packedfile;
+ sample->flags &= ~SAMPLE_NEEDS_SAVE;
+ } else {
+ sound->newpackedfile = NULL;
+ }
+ }
+
+ /* write LibData */
+ writestruct(wd, ID_SO, "bSound", 1, sound);
+ if (sound->id.properties) IDP_WriteProperty(sound->id.properties, wd);
+
+ if (sound->newpackedfile) {
+ pf = sound->newpackedfile;
+ writestruct(wd, DATA, "PackedFile", 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
+ }
+
+ if (sample) {
+ sound->newpackedfile = sample->packedfile;
+ }
+ }
+ sound= sound->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_groups(WriteData *wd, ListBase *idbase)
+{
+ Group *group;
+ GroupObject *go;
+
+ for(group= idbase->first; group; group= group->id.next) {
+ if(group->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_GR, "Group", 1, group);
+ if (group->id.properties) IDP_WriteProperty(group->id.properties, wd);
+
+ go= group->gobject.first;
+ while(go) {
+ writestruct(wd, DATA, "GroupObject", 1, go);
+ go= go->next;
+ }
+ }
+ }
+}
+
+static void write_nodetrees(WriteData *wd, ListBase *idbase)
+{
+ bNodeTree *ntree;
+
+ for(ntree=idbase->first; ntree; ntree= ntree->id.next) {
+ if (ntree->id.us>0 || wd->current) {
+ writestruct(wd, ID_NT, "bNodeTree", 1, ntree);
+ write_nodetree(wd, ntree);
+ if (ntree->id.properties) IDP_WriteProperty(ntree->id.properties, wd);
+ }
+ }
+}
+
+static void write_brushes(WriteData *wd, ListBase *idbase)
+{
+ Brush *brush;
+ int a;
+
+ for(brush=idbase->first; brush; brush= brush->id.next) {
+ if(brush->id.us>0 || wd->current) {
+ writestruct(wd, ID_BR, "Brush", 1, brush);
+ if (brush->id.properties) IDP_WriteProperty(brush->id.properties, wd);
+ for(a=0; a<MAX_MTEX; a++)
+ if(brush->mtex[a])
+ writestruct(wd, DATA, "MTex", 1, brush->mtex[a]);
+ }
+ }
+}
+
+static void write_global(WriteData *wd)
+{
+ FileGlobal fg;
+ char subvstr[8];
+
+ fg.curscreen= G.curscreen;
+ fg.curscene= G.scene;
+ fg.displaymode= G.displaymode;
+ fg.winpos= G.winpos;
+ fg.fileflags= (G.fileflags & ~G_FILE_NO_UI); // prevent to save this, is not good convention, and feature with concerns...
+ fg.globalf= G.f;
+
+ sprintf(subvstr, "%4d", BLENDER_SUBVERSION);
+ memcpy(fg.subvstr, subvstr, 4);
+
+ fg.subversion= BLENDER_SUBVERSION;
+ fg.minversion= BLENDER_MINVERSION;
+ fg.minsubversion= BLENDER_MINSUBVERSION;
+
+ writestruct(wd, GLOB, "FileGlobal", 1, &fg);
+}
+
+/* if MemFile * 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[16];
+ WriteData *wd;
+
+ blo_split_main(&mainlist, G.main);
+
+ 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_global(wd);
+
+ if(current==NULL)
+ write_screens (wd, &G.main->screen); /* no UI save in undo */
+ write_scenes (wd, &G.main->scene);
+ write_curves (wd, &G.main->curve);
+ write_mballs (wd, &G.main->mball);
+ write_images (wd, &G.main->image);
+ write_cameras (wd, &G.main->camera);
+ write_lamps (wd, &G.main->lamp);
+ write_lattices (wd, &G.main->latt);
+ write_vfonts (wd, &G.main->vfont);
+ write_ipos (wd, &G.main->ipo);
+ write_keys (wd, &G.main->key);
+ write_worlds (wd, &G.main->world);
+ write_texts (wd, &G.main->text);
+ write_sounds (wd, &G.main->sound);
+ 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_nodetrees(wd, &G.main->nodetree);
+ write_brushes (wd, &G.main->brush);
+ if(current==NULL)
+ write_libraries(wd, G.main->next); /* no library save in undo */
+
+ if (write_user_block) {
+ write_userdef(wd);
+ }
+
+ /* dna as last, because (to be implemented) test for which structs are written */
+ writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data);
+
+ /* end of file */
+ memset(&bhead, 0, sizeof(BHead));
+ bhead.code= ENDB;
+ mywrite(wd, &bhead, sizeof(BHead));
+
+ blo_join_main(&mainlist);
+ G.main= mainlist.first;
+
+ return endwrite(wd);
+}
+
+/* return: success (1) */
+int BLO_write_file(char *dir, int write_flags, char **error_r)
+{
+ char userfilename[FILE_MAXDIR+FILE_MAXFILE];
+ char tempname[FILE_MAXDIR+FILE_MAXFILE];
+ int file, err, write_user_block;
+
+ sprintf(tempname, "%s@", dir);
+
+ file = open(tempname,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666);
+ if(file == -1) {
+ *error_r= "Unable to open";
+ return 0;
+ }
+
+ BLI_make_file_string(G.sce, userfilename, BLI_gethome(), ".B.blend");
+
+ write_user_block= BLI_streq(dir, userfilename);
+
+ err= write_file_handle(file, NULL,NULL, write_user_block, write_flags);
+ close(file);
+
+ if(!err) {
+ if(write_flags & G_FILE_COMPRESS)
+ {
+ // compressed files have the same ending as regular files... only from 2.4!!!
+
+ int ret = BLI_gzip(tempname, dir);
+
+ if(-1==ret) {
+ *error_r= "Failed opening .gz file";
+ return 0;
+ }
+ if(-2==ret) {
+ *error_r= "Failed opening .blend file for compression";
+ return 0;
+ }
+ }
+ else
+ if(BLI_rename(tempname, dir) < 0) {
+ *error_r= "Can't change old file. File saved with @";
+ return 0;
+ }
+
+
+ } else {
+ *error_r= strerror(errno);
+ remove(tempname);
+
+ return 0;
+ }
+
+ 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
+#define PATHSEPERATOR "\\"
+#else
+#define PATHSEPERATOR "/"
+#endif
+
+static char *get_install_dir(void) {
+ extern char bprogname[];
+ char *tmpname = BLI_strdup(bprogname);
+ char *cut;
+
+#ifdef __APPLE__
+ cut = strstr(tmpname, ".app");
+ if (cut) cut[0] = 0;
+#endif
+
+ cut = BLI_last_slash(tmpname);
+
+ if (cut) {
+ cut[0] = 0;
+ return tmpname;
+ } else {
+ MEM_freeN(tmpname);
+ return NULL;
+ }
+}
+
+static char *get_runtime_path(char *exename) {
+ char *installpath= get_install_dir();
+
+ if (!installpath) {
+ return NULL;
+ } else {
+ char *path= MEM_mallocN(strlen(installpath)+strlen(PATHSEPERATOR)+strlen(exename)+1, "runtimepath");
+
+ if (path == NULL) {
+ MEM_freeN(installpath);
+ return NULL;
+ }
+
+ strcpy(path, installpath);
+ strcat(path, PATHSEPERATOR);
+ strcat(path, exename);
+
+ MEM_freeN(installpath);
+
+ return path;
+ }
+}
+
+#ifdef __APPLE__
+
+static int recursive_copy_runtime(char *outname, char *exename, char **cause_r)
+{
+ char *cause = NULL, *runtime = get_runtime_path(exename);
+ char command[2 * (FILE_MAXDIR+FILE_MAXFILE) + 32];
+ int progfd = -1;
+
+ if (!runtime) {
+ cause= "Unable to find runtime";
+ goto cleanup;
+ }
+ //printf("runtimepath %s\n", runtime);
+
+ progfd= open(runtime, O_BINARY|O_RDONLY, 0);
+ if (progfd==-1) {
+ cause= "Unable to find runtime";
+ goto cleanup;
+ }
+
+ sprintf(command, "/bin/cp -R \"%s\" \"%s\"", runtime, outname);
+ //printf("command %s\n", command);
+ if (system(command) == -1) {
+ cause = "Couldn't copy runtime";
+ }
+
+cleanup:
+ if (progfd!=-1)
+ close(progfd);
+ if (runtime)
+ MEM_freeN(runtime);
+
+ if (cause) {
+ *cause_r= cause;
+ return 0;
+ } else
+ return 1;
+}
+
+void BLO_write_runtime(char *file, char *exename) {
+ char gamename[FILE_MAXDIR+FILE_MAXFILE];
+ int outfd = -1;
+ char *cause= NULL;
+
+ // remove existing file / bundle
+ //printf("Delete file %s\n", file);
+ BLI_delete(file, 0, TRUE);
+
+ if (!recursive_copy_runtime(file, exename, &cause))
+ goto cleanup;
+
+ strcpy(gamename, file);
+ strcat(gamename, "/Contents/Resources/game.blend");
+ //printf("gamename %s\n", gamename);
+ outfd= open(gamename, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0777);
+ if (outfd != -1) {
+
+ write_file_handle(outfd, NULL,NULL, 0, G.fileflags);
+
+ if (write(outfd, " ", 1) != 1) {
+ cause= "Unable to write to output file";
+ goto cleanup;
+ }
+ } else {
+ cause = "Unable to open blenderfile";
+ }
+
+cleanup:
+ if (outfd!=-1)
+ close(outfd);
+
+ if (cause)
+ error("Unable to make runtime: %s", cause);
+}
+
+#else /* !__APPLE__ */
+
+static int handle_append_runtime(int handle, char *exename, char **cause_r) {
+ char *cause= NULL, *runtime= get_runtime_path(exename);
+ unsigned char buf[1024];
+ int count, progfd= -1;
+
+ if (!runtime) {
+ cause= "Unable to find runtime";
+ goto cleanup;
+ }
+
+ progfd= open(runtime, O_BINARY|O_RDONLY, 0);
+ if (progfd==-1) {
+ cause= "Unable to find runtime";
+ goto cleanup;
+ }
+
+ while ((count= read(progfd, buf, sizeof(buf)))>0) {
+ if (write(handle, buf, count)!=count) {
+ cause= "Unable to write to output file";
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ if (progfd!=-1)
+ close(progfd);
+ if (runtime)
+ MEM_freeN(runtime);
+
+ if (cause) {
+ *cause_r= cause;
+ return 0;
+ } else
+ return 1;
+}
+
+static int handle_write_msb_int(int handle, int i) {
+ unsigned char buf[4];
+ buf[0]= (i>>24)&0xFF;
+ buf[1]= (i>>16)&0xFF;
+ buf[2]= (i>>8)&0xFF;
+ buf[3]= (i>>0)&0xFF;
+
+ return (write(handle, buf, 4)==4);
+}
+
+void BLO_write_runtime(char *file, char *exename) {
+ int outfd= open(file, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0777);
+ char *cause= NULL;
+ int datastart;
+
+ if (!outfd) {
+ cause= "Unable to open output file";
+ goto cleanup;
+ }
+ if (!handle_append_runtime(outfd, exename, &cause))
+ goto cleanup;
+
+ datastart= lseek(outfd, 0, SEEK_CUR);
+
+ 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";
+ goto cleanup;
+ }
+
+cleanup:
+ if (outfd!=-1)
+ close(outfd);
+
+ if (cause)
+ error("Unable to make runtime: %s", cause);
+}
+
+#endif /* !__APPLE__ */