Files
blender/source/blender/blenloader/intern/readfile.c
Severin e81d077c85 Input Method Editor (IME) support for text buttons
Original patch by @random (D765) with some minor work done by @campbell
and me.

At this place, I'd like call out a number of people who were involved and
deserve a big "Thank you!":
* At the first place @randon who developed and submitted the patch
* The Blendercn community which helped a lot with testing - espacially
* @yuzukyo, @leon_cheung and @kjym3
* @campbellbarton, @mont29 and @sergey for their help and advises during
* review
* @ton who realized the importance of this early on and asked me for
* reviewing

We are still not finished, as this is only the first part of the
implementaion, but there's more to come!
2014-12-07 00:58:17 +01:00

9559 lines
260 KiB
C

/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*
*/
/** \file blender/blenloader/intern/readfile.c
* \ingroup blenloader
*/
#include "zlib.h"
#include <limits.h>
#include <stdio.h> // for printf fopen fwrite fclose sprintf FILE
#include <stdlib.h> // for getenv atoi
#include <stddef.h> // for offsetof
#include <fcntl.h> // for open
#include <string.h> // for strrchr strncmp strstr
#include <math.h> // for fabs
#include <stdarg.h> /* for va_start/end */
#include <time.h> /* for gmtime */
#include "BLI_utildefines.h"
#ifndef WIN32
# include <unistd.h> // for read close
#else
# include <io.h> // for open close read
# include "winsock2.h"
# include "BLI_winstuff.h"
#endif
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
#include "DNA_controller_types.h"
#include "DNA_constraint_types.h"
#include "DNA_dynamicpaint_types.h"
#include "DNA_effect_types.h"
#include "DNA_fileglobal_types.h"
#include "DNA_genfile.h"
#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_ipo_types.h"
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_lamp_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_meta_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_nla_types.h"
#include "DNA_node_types.h"
#include "DNA_object_fluidsim.h" // NT
#include "DNA_object_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_particle_types.h"
#include "DNA_property_types.h"
#include "DNA_rigidbody_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_smoke_types.h"
#include "DNA_speaker_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_vfont_types.h"
#include "DNA_world_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_endian_switch.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_threads.h"
#include "BLI_mempool.h"
#include "BLF_translation.h"
#include "BKE_armature.h"
#include "BKE_brush.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_global.h" // for G
#include "BKE_group.h"
#include "BKE_library.h" // for which_libbase
#include "BKE_idcode.h"
#include "BKE_material.h"
#include "BKE_main.h" // for Main
#include "BKE_mesh.h" // for ME_ defines (patching)
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_node.h" // for tree type defines
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
#include "BKE_sca.h" // for init_actuator
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_treehash.h"
#include "BKE_sound.h"
#include "NOD_common.h"
#include "NOD_socket.h"
#include "BLO_readfile.h"
#include "BLO_undofile.h"
#include "BLO_blend_defs.h"
#include "RE_engine.h"
#include "readfile.h"
#include <errno.h>
/*
* Remark: still a weak point is the newaddress() 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 ~/X.XX/startup.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
*/
/***/
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, const char *blockname);
static void direct_link_modifiers(FileData *fd, ListBase *lb);
static void convert_tface_mt(FileData *fd, Main *main);
/* this function ensures that reports are printed,
* in the case of libraray linking errors this is important!
*
* bit kludge but better then doubling up on prints,
* we could alternatively have a versions of a report function which forces printing - campbell
*/
void blo_reportf_wrap(ReportList *reports, ReportType type, const char *format, ...)
{
char fixed_buf[1024]; /* should be long enough */
va_list args;
va_start(args, format);
vsnprintf(fixed_buf, sizeof(fixed_buf), format, args);
va_end(args);
fixed_buf[sizeof(fixed_buf) - 1] = '\0';
BKE_report(reports, type, fixed_buf);
if (G.background == 0) {
printf("%s\n", fixed_buf);
}
}
/* for reporting linking messages */
static const char *library_parent_filepath(Library *lib)
{
return lib->parent ? lib->parent->filepath : "<direct>";
}
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;
}
void blo_do_versions_oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr)
{
oldnewmap_insert(onm, oldaddr, newaddr, nr);
}
static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_users)
{
int i;
if (addr == NULL) return NULL;
if (onm->lasthit < onm->nentries-1) {
OldNew *entry = &onm->entries[++onm->lasthit];
if (entry->old == addr) {
if (increase_users)
entry->nr++;
return entry->newp;
}
}
for (i = 0; i < onm->nentries; i++) {
OldNew *entry = &onm->entries[i];
if (entry->old == addr) {
onm->lasthit = i;
if (increase_users)
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)
{
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 id;
}
}
}
else {
/* note, this can be a bottle neck when loading some files */
unsigned int nentries = (unsigned int)onm->nentries;
unsigned int i;
OldNew *entry;
for (i = 0, entry = onm->entries; i < nentries; i++, entry++) {
if (entry->old == addr) {
ID *id = entry->newp;
if (id && (!lib || id->lib)) {
return id;
}
}
}
}
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;
set_listbasepointers(mainvar, lbarray);
a = set_listbasepointers(from, fromarray);
while (a--) {
BLI_movelisttolist(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);
BKE_main_free(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= which_libbase(mainvar, GS(id->name));
BLI_remlink(lb, id);
BLI_addtail(lbn, id);
break;
}
mainvar = mainvar->next;
}
if (mainvar == NULL) 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 (BLI_listbase_is_empty(&main->library))
return;
for (lib = main->library.first; lib; lib = lib->id.next) {
Main *libmain = BKE_main_new();
libmain->curlib = lib;
BLI_addtail(mainlist, libmain);
}
i = set_listbasepointers(main, lbarray);
while (i--)
split_libdata(lbarray[i], main->next);
}
static void read_file_version(FileData *fd, Main *main)
{
BHead *bhead;
for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
if (bhead->code == GLOB) {
FileGlobal *fg= read_struct(fd, bhead, "Global");
if (fg) {
main->subversionfile= fg->subversion;
main->minversionfile= fg->minversion;
main->minsubversionfile= fg->minsubversion;
MEM_freeN(fg);
}
else if (bhead->code == ENDB)
break;
}
}
}
static Main *blo_find_main(FileData *fd, const char *filepath, const char *relabase)
{
ListBase *mainlist = fd->mainlist;
Main *m;
Library *lib;
char name1[FILE_MAX];
BLI_strncpy(name1, filepath, sizeof(name1));
BLI_cleanup_path(relabase, name1);
// printf("blo_find_main: relabase %s\n", relabase);
// printf("blo_find_main: original in %s\n", filepath);
// printf("blo_find_main: converted to %s\n", name1);
for (m = mainlist->first; m; m = m->next) {
const char *libname = (m->curlib) ? m->curlib->filepath : m->name;
if (BLI_path_cmp(name1, libname) == 0) {
if (G.debug & G_DEBUG) printf("blo_find_main: found library %s\n", libname);
return m;
}
}
m = BKE_main_new();
BLI_addtail(mainlist, m);
lib = BKE_libblock_alloc(m, ID_LI, "lib");
BLI_strncpy(lib->name, filepath, sizeof(lib->name));
BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath));
m->curlib = lib;
read_file_version(fd, m);
if (G.debug & G_DEBUG) printf("blo_find_main: added new lib %s\n", filepath);
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) {
BLI_endian_switch_int32(&bhead->len);
BLI_endian_switch_int32(&bhead->SDNAnr);
BLI_endian_switch_int32(&bhead->nr);
}
}
static void switch_endian_bh8(BHead8 *bhead)
{
/* the ID_.. codes */
if ((bhead->code & 0xFFFF)==0) bhead->code >>= 16;
if (bhead->code != ENDB) {
BLI_endian_switch_int32(&bhead->len);
BLI_endian_switch_int32(&bhead->SDNAnr);
BLI_endian_switch_int32(&bhead->nr);
}
}
static void bh4_from_bh8(BHead *bhead, BHead8 *bhead8, int do_endian_swap)
{
BHead4 *bhead4 = (BHead4 *) bhead;
int64_t old;
bhead4->code = bhead8->code;
bhead4->len = bhead8->len;
if (bhead4->code != ENDB) {
/* perform a endian swap on 64bit pointers, otherwise the pointer might map to zero
* 0x0000000000000000000012345678 would become 0x12345678000000000000000000000000
*/
if (do_endian_swap) {
BLI_endian_switch_int64(&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)
{
BHeadN *new_bhead = NULL;
int readsize;
if (fd) {
if (!fd->eof) {
/* initializing to zero isn't strictly needed but shuts valgrind up
* since uninitialized memory gets compared */
BHead8 bhead8 = {0};
BHead4 bhead4 = {0};
BHead bhead = {0};
/* 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 = NULL;
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 = NULL;
}
}
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 = NULL;
/* Rewind the file
* Read in a new block if necessary
*/
new_bhead = fd->listbase.first;
if (new_bhead == NULL) {
new_bhead = get_bhead(fd);
}
if (new_bhead) {
bhead = &new_bhead->bhead;
}
return(bhead);
}
BHead *blo_prevbhead(FileData *UNUSED(fd), BHead *thisblock)
{
BHeadN *bheadn = (BHeadN *) (((char *) thisblock) - offsetof(BHeadN, bhead));
BHeadN *prev = bheadn->prev;
return (prev) ? &prev->bhead : NULL;
}
BHead *blo_nextbhead(FileData *fd, BHead *thisblock)
{
BHeadN *new_bhead = NULL;
BHead *bhead = NULL;
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) - offsetof(BHeadN, bhead));
/* get the next BHeadN. If it doesn't exist we read in the next one */
new_bhead = new_bhead->next;
if (new_bhead == NULL) {
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);
}
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) {
const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
fd->filesdna = DNA_sdna_from_data(&bhead[1], bhead->len, do_endian_swap);
if (fd->filesdna) {
fd->compflags = DNA_struct_get_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, unsigned 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, unsigned 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, unsigned int size)
{
/* don't read more bytes then there are available in the buffer */
int readsize = (int)MIN2(size, (unsigned int)(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, unsigned int size)
{
static unsigned int seek = (1<<30); /* the current position */
static unsigned int offset = 0; /* size of previous chunks */
static MemFileChunk *chunk = NULL;
unsigned int chunkoffset, readsize, totread;
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) {
totread = 0;
do {
/* 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;
}
chunkoffset = seek-offset;
readsize = size-totread;
/* data can be spread over multiple chunks, so clamp size
* to within this chunk, and then it will read further in
* the next chunk */
if (chunkoffset+readsize > chunk->size)
readsize= chunk->size-chunkoffset;
memcpy((char *)buffer + totread, chunk->buf + chunkoffset, readsize);
totread += readsize;
filedata->seek += readsize;
seek += readsize;
} while (totread < size);
return totread;
}
return 0;
}
static FileData *filedata_new(void)
{
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 re-entrant, remove once we have
* a lib that provides a nice lock. - zr
*/
fd->memsdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
fd->datamap = oldnewmap_new();
fd->globmap = oldnewmap_new();
fd->libmap = oldnewmap_new();
return fd;
}
static FileData *blo_decode_and_check(FileData *fd, ReportList *reports)
{
decode_blender_header(fd);
if (fd->flags & FD_FLAGS_FILE_OK) {
if (!read_file_dna(fd)) {
BKE_reportf(reports, RPT_ERROR, "Failed to read blend file '%s', incomplete", fd->relabase);
blo_freefiledata(fd);
fd = NULL;
}
}
else {
BKE_reportf(reports, RPT_ERROR, "Failed to read blend file '%s', not a blend file", fd->relabase);
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(const char *filepath, ReportList *reports)
{
gzFile gzfile;
errno = 0;
gzfile = BLI_gzopen(filepath, "rb");
if (gzfile == (gzFile)Z_NULL) {
BKE_reportf(reports, RPT_WARNING, "Unable to open '%s': %s",
filepath, errno ? strerror(errno) : TIP_("unknown error reading file"));
return NULL;
}
else {
FileData *fd = filedata_new();
fd->gzfiledes = gzfile;
fd->read = fd_read_gzip_from_file;
/* needed for library_append and read_libraries */
BLI_strncpy(fd->relabase, filepath, sizeof(fd->relabase));
return blo_decode_and_check(fd, reports);
}
}
static int fd_read_gzip_from_memory(FileData *filedata, void *buffer, unsigned int size)
{
int err;
filedata->strm.next_out = (Bytef *) buffer;
filedata->strm.avail_out = size;
// Inflate another chunk.
err = inflate (&filedata->strm, Z_SYNC_FLUSH);
if (err == Z_STREAM_END) {
return 0;
}
else if (err != Z_OK) {
printf("fd_read_gzip_from_memory: zlib error\n");
return 0;
}
filedata->seek += size;
return (size);
}
static int fd_read_gzip_from_memory_init(FileData *fd)
{
fd->strm.next_in = (Bytef *) fd->buffer;
fd->strm.avail_in = fd->buffersize;
fd->strm.total_out = 0;
fd->strm.zalloc = Z_NULL;
fd->strm.zfree = Z_NULL;
if (inflateInit2(&fd->strm, (16+MAX_WBITS)) != Z_OK)
return 0;
fd->read = fd_read_gzip_from_memory;
return 1;
}
FileData *blo_openblendermemory(const void *mem, int memsize, ReportList *reports)
{
if (!mem || memsize<SIZEOFBLENDERHEADER) {
BKE_report(reports, RPT_WARNING, (mem) ? TIP_("Unable to read"): TIP_("Unable to open"));
return NULL;
}
else {
FileData *fd = filedata_new();
const char *cp = mem;
fd->buffer = mem;
fd->buffersize = memsize;
/* test if gzip */
if (cp[0] == 0x1f && cp[1] == 0x8b) {
if (0 == fd_read_gzip_from_memory_init(fd)) {
blo_freefiledata(fd);
return NULL;
}
}
else
fd->read = fd_read_from_memory;
fd->flags |= FD_FLAGS_NOT_MY_BUFFER;
return blo_decode_and_check(fd, reports);
}
}
FileData *blo_openblendermemfile(MemFile *memfile, ReportList *reports)
{
if (!memfile) {
BKE_report(reports, RPT_WARNING, "Unable to open blend <memory>");
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, reports);
}
}
void blo_freefiledata(FileData *fd)
{
if (fd) {
if (fd->filedes != -1) {
close(fd->filedes);
}
if (fd->gzfiledes != NULL) {
gzclose(fd->gzfiledes);
}
if (fd->strm.next_in) {
if (inflateEnd (&fd->strm) != Z_OK) {
printf("close gzip stream error\n");
}
}
if (fd->buffer && !(fd->flags & FD_FLAGS_NOT_MY_BUFFER)) {
MEM_freeN((void *)fd->buffer);
fd->buffer = NULL;
}
// Free all BHeadN data blocks
BLI_freelistN(&fd->listbase);
if (fd->memsdna)
DNA_sdna_free(fd->memsdna);
if (fd->filesdna)
DNA_sdna_free(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->movieclipmap)
oldnewmap_free(fd->movieclipmap);
if (fd->soundmap)
oldnewmap_free(fd->soundmap);
if (fd->packedmap)
oldnewmap_free(fd->packedmap);
if (fd->libmap && !(fd->flags & FD_FLAGS_NOT_MY_LIBMAP))
oldnewmap_free(fd->libmap);
if (fd->bheadmap)
MEM_freeN(fd->bheadmap);
MEM_freeN(fd);
}
}
/* ************ DIV ****************** */
bool BLO_has_bfile_extension(const char *str)
{
const char *ext_test[4] = {".blend", ".ble", ".blend.gz", NULL};
return BLI_testextensie_array(str, ext_test);
}
bool BLO_is_a_library(const char *path, char *dir, char *group)
{
/* return ok when a blenderfile, in dir is the filename,
* in group the type of libdata
*/
int len;
char *fd;
/* if path leads to a directory we can be sure we're not in a library */
if (BLI_is_dir(path)) return 0;
strcpy(dir, path);
len = strlen(dir);
if (len < 7) return 0;
if ((dir[len - 1] != '/') && (dir[len - 1] != '\\')) return 0;
group[0] = '\0';
dir[len - 1] = '\0';
/* Find the last slash */
fd = (char *)BLI_last_slash(dir);
if (fd == NULL) return 0;
*fd = 0;
if (BLO_has_bfile_extension(fd+1)) {
/* the last part of the dir is a .blend file, no group follows */
*fd = '/'; /* put back the removed slash separating the dir and the .blend file name */
}
else {
const char * const gp = fd + 1; // in case we have a .blend file, gp points to the group
/* Find the last slash */
fd = (char *)BLI_last_slash(dir);
if (!fd || !BLO_has_bfile_extension(fd+1)) return 0;
/* now we know that we are in a blend file and it is safe to
* assume that gp actually points to a group */
if (strcmp("Screen", gp) != 0)
BLI_strncpy(group, gp, BLO_GROUP_MAX);
}
return 1;
}
/* ************** OLD POINTERS ******************* */
static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
{
return oldnewmap_lookup_and_inc(fd->datamap, adr, true);
}
static void *newdataadr_no_us(FileData *fd, void *adr) /* only direct databocks */
{
return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
}
static void *newglobadr(FileData *fd, void *adr) /* direct datablocks with global linking */
{
return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
}
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, true);
return NULL;
}
static void *newmclipadr(FileData *fd, void *adr) /* used to restore movie clip data after undo */
{
if (fd->movieclipmap && adr)
return oldnewmap_lookup_and_inc(fd->movieclipmap, adr, true);
return NULL;
}
static void *newsoundadr(FileData *fd, void *adr) /* used to restore sound data after undo */
{
if (fd->soundmap && adr)
return oldnewmap_lookup_and_inc(fd->soundmap, adr, true);
return NULL;
}
static void *newpackedadr(FileData *fd, void *adr) /* used to restore packed data after undo */
{
if (fd->packedmap && adr)
return oldnewmap_lookup_and_inc(fd->packedmap, adr, true);
return oldnewmap_lookup_and_inc(fd->datamap, adr, true);
}
static void *newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
{
return oldnewmap_liblookup(fd->libmap, adr, lib);
}
void *blo_do_versions_newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
{
return newlibadr(fd, lib, adr);
}
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;
}
void *blo_do_versions_newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */
{
return newlibadr_us(fd, lib, adr);
}
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 );
}
}
}
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);
}
}
}
/* lib linked proxy objects point to our local data, we need
* to clear that pointer before reading the undo memfile since
* the object might be removed, it is set again in reading
* if the local object still exists */
void blo_clear_proxy_pointers_from_lib(Main *oldmain)
{
Object *ob = oldmain->object.first;
for (; ob; ob= ob->id.next) {
if (ob->id.lib)
ob->proxy_from = NULL;
}
}
void blo_make_image_pointer_map(FileData *fd, Main *oldmain)
{
Image *ima = oldmain->image.first;
Scene *sce = oldmain->scene.first;
int a;
fd->imamap = oldnewmap_new();
for (; ima; ima = ima->id.next) {
if (ima->cache)
oldnewmap_insert(fd->imamap, ima->cache, ima->cache, 0);
if (ima->gputexture)
oldnewmap_insert(fd->imamap, ima->gputexture, ima->gputexture, 0);
if (ima->rr)
oldnewmap_insert(fd->imamap, ima->rr, ima->rr, 0);
for (a=0; a < IMA_MAX_RENDER_SLOT; a++)
if (ima->renders[a])
oldnewmap_insert(fd->imamap, ima->renders[a], ima->renders[a], 0);
}
for (; sce; sce = sce->id.next) {
if (sce->nodetree && sce->nodetree->previews) {
bNodeInstanceHashIterator iter;
NODE_INSTANCE_HASH_ITER(iter, sce->nodetree->previews) {
bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
oldnewmap_insert(fd->imamap, preview, preview, 0);
}
}
}
}
/* set old main image ibufs to zero if it has been restored */
/* this works because freeing old main only happens after this call */
void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
{
OldNew *entry = fd->imamap->entries;
Image *ima = oldmain->image.first;
Scene *sce = oldmain->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) {
ima->cache = newimaadr(fd, ima->cache);
if (ima->cache == NULL) {
ima->bindcode = 0;
ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
ima->gputexture = NULL;
ima->rr = NULL;
}
for (i = 0; i < IMA_MAX_RENDER_SLOT; i++)
ima->renders[i] = newimaadr(fd, ima->renders[i]);
ima->gputexture = newimaadr(fd, ima->gputexture);
ima->rr = newimaadr(fd, ima->rr);
}
for (; sce; sce = sce->id.next) {
if (sce->nodetree && sce->nodetree->previews) {
bNodeInstanceHash *new_previews = BKE_node_instance_hash_new("node previews");
bNodeInstanceHashIterator iter;
/* reconstruct the preview hash, only using remaining pointers */
NODE_INSTANCE_HASH_ITER(iter, sce->nodetree->previews) {
bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
if (preview) {
bNodePreview *new_preview = newimaadr(fd, preview);
if (new_preview) {
bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
BKE_node_instance_hash_insert(new_previews, key, new_preview);
}
}
}
BKE_node_instance_hash_free(sce->nodetree->previews, NULL);
sce->nodetree->previews = new_previews;
}
}
}
void blo_make_movieclip_pointer_map(FileData *fd, Main *oldmain)
{
MovieClip *clip = oldmain->movieclip.first;
Scene *sce = oldmain->scene.first;
fd->movieclipmap = oldnewmap_new();
for (; clip; clip = clip->id.next) {
if (clip->cache)
oldnewmap_insert(fd->movieclipmap, clip->cache, clip->cache, 0);
if (clip->tracking.camera.intrinsics)
oldnewmap_insert(fd->movieclipmap, clip->tracking.camera.intrinsics, clip->tracking.camera.intrinsics, 0);
}
for (; sce; sce = sce->id.next) {
if (sce->nodetree) {
bNode *node;
for (node = sce->nodetree->nodes.first; node; node = node->next)
if (node->type == CMP_NODE_MOVIEDISTORTION)
oldnewmap_insert(fd->movieclipmap, node->storage, node->storage, 0);
}
}
}
/* set old main movie clips caches to zero if it has been restored */
/* this works because freeing old main only happens after this call */
void blo_end_movieclip_pointer_map(FileData *fd, Main *oldmain)
{
OldNew *entry = fd->movieclipmap->entries;
MovieClip *clip = oldmain->movieclip.first;
Scene *sce = oldmain->scene.first;
int i;
/* used entries were restored, so we put them to zero */
for (i=0; i < fd->movieclipmap->nentries; i++, entry++) {
if (entry->nr > 0)
entry->newp = NULL;
}
for (; clip; clip = clip->id.next) {
clip->cache = newmclipadr(fd, clip->cache);
clip->tracking.camera.intrinsics = newmclipadr(fd, clip->tracking.camera.intrinsics);
}
for (; sce; sce = sce->id.next) {
if (sce->nodetree) {
bNode *node;
for (node = sce->nodetree->nodes.first; node; node = node->next)
if (node->type == CMP_NODE_MOVIEDISTORTION)
node->storage = newmclipadr(fd, node->storage);
}
}
}
void blo_make_sound_pointer_map(FileData *fd, Main *oldmain)
{
bSound *sound = oldmain->sound.first;
fd->soundmap = oldnewmap_new();
for (; sound; sound = sound->id.next) {
if (sound->waveform)
oldnewmap_insert(fd->soundmap, sound->waveform, sound->waveform, 0);
}
}
/* set old main sound caches to zero if it has been restored */
/* this works because freeing old main only happens after this call */
void blo_end_sound_pointer_map(FileData *fd, Main *oldmain)
{
OldNew *entry = fd->soundmap->entries;
bSound *sound = oldmain->sound.first;
int i;
/* used entries were restored, so we put them to zero */
for (i = 0; i < fd->soundmap->nentries; i++, entry++) {
if (entry->nr > 0)
entry->newp = NULL;
}
for (; sound; sound = sound->id.next) {
sound->waveform = newsoundadr(fd, sound->waveform);
}
}
/* XXX disabled this feature - packed files also belong in temp saves and quit.blend, to make restore work */
static void insert_packedmap(FileData *fd, PackedFile *pf)
{
oldnewmap_insert(fd->packedmap, pf, pf, 0);
oldnewmap_insert(fd->packedmap, pf->data, pf->data, 0);
}
void blo_make_packed_pointer_map(FileData *fd, Main *oldmain)
{
Image *ima;
VFont *vfont;
bSound *sound;
Library *lib;
fd->packedmap = oldnewmap_new();
for (ima = oldmain->image.first; ima; ima = ima->id.next)
if (ima->packedfile)
insert_packedmap(fd, ima->packedfile);
for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next)
if (vfont->packedfile)
insert_packedmap(fd, vfont->packedfile);
for (sound = oldmain->sound.first; sound; sound = sound->id.next)
if (sound->packedfile)
insert_packedmap(fd, sound->packedfile);
for (lib = oldmain->library.first; lib; lib = lib->id.next)
if (lib->packedfile)
insert_packedmap(fd, lib->packedfile);
}
/* set old main packed data to zero if it has been restored */
/* this works because freeing old main only happens after this call */
void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
{
Image *ima;
VFont *vfont;
bSound *sound;
Library *lib;
OldNew *entry = fd->packedmap->entries;
int i;
/* used entries were restored, so we put them to zero */
for (i=0; i < fd->packedmap->nentries; i++, entry++) {
if (entry->nr > 0)
entry->newp = NULL;
}
for (ima = oldmain->image.first; ima; ima = ima->id.next)
ima->packedfile = newpackedadr(fd, ima->packedfile);
for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next)
vfont->packedfile = newpackedadr(fd, vfont->packedfile);
for (sound = oldmain->sound.first; sound; sound = sound->id.next)
sound->packedfile = newpackedadr(fd, sound->packedfile);
for (lib = oldmain->library.first; lib; lib = lib->id.next)
lib->packedfile = newpackedadr(fd, lib->packedfile);
}
/* 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_struct_switch_endian(filesdna, bhead->SDNAnr, data);
data += blocksize;
}
}
static void *read_struct(FileData *fd, BHead *bh, const 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_struct_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 (BLI_listbase_is_empty(lb)) 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 (BLI_listbase_is_empty(lb)) return;
poin = newdataadr(fd, lb->first);
if (lb->first) {
oldnewmap_insert(fd->globmap, lb->first, poin, 0);
}
lb->first = poin;
ln = lb->first;
prev = NULL;
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)
{
int64_t *lpoin, *lmat;
int *ipoin, *imat;
size_t len;
/* 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))
BLI_endian_switch_int64(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 *************** */
static void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, FileData *fd);
static void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, FileData *fd);
static void IDP_DirectLinkIDPArray(IDProperty *prop, int switch_endian, FileData *fd)
{
IDProperty *array;
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);
array = (IDProperty *)prop->data.pointer;
/* note!, idp-arrays didn't exist in 2.4x, so the pointer will be cleared
* theres not really anything we can do to correct this, at least don't crash */
if (array == NULL) {
prop->len = 0;
prop->totallen = 0;
}
for (i = 0; i < prop->len; i++)
IDP_DirectLinkProperty(&array[i], switch_endian, fd);
}
static void IDP_DirectLinkArray(IDProperty *prop, int switch_endian, FileData *fd)
{
IDProperty **array;
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 (prop->subtype == IDP_GROUP) {
test_pointer_array(fd, prop->data.pointer);
array = prop->data.pointer;
for (i = 0; i < prop->len; i++)
IDP_DirectLinkProperty(array[i], switch_endian, fd);
}
else if (prop->subtype == IDP_DOUBLE) {
if (switch_endian) {
BLI_endian_switch_double_array(prop->data.pointer, prop->len);
}
}
else {
if (switch_endian) {
/* also used for floats */
BLI_endian_switch_int32_array(prop->data.pointer, prop->len);
}
}
}
static void IDP_DirectLinkString(IDProperty *prop, FileData *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);
}
static void IDP_DirectLinkGroup(IDProperty *prop, int switch_endian, FileData *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);
}
}
static void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, FileData *fd)
{
switch (prop->type) {
case IDP_GROUP:
IDP_DirectLinkGroup(prop, switch_endian, fd);
break;
case IDP_STRING:
IDP_DirectLinkString(prop, fd);
break;
case IDP_ARRAY:
IDP_DirectLinkArray(prop, switch_endian, fd);
break;
case IDP_IDPARRAY:
IDP_DirectLinkIDPArray(prop, switch_endian, fd);
break;
case IDP_DOUBLE:
/* erg, stupid doubles. since I'm storing them
* in the same field as int val; val2 in the
* IDPropertyData struct, they have to deal with
* endianness specifically
*
* in theory, val and val2 would've already been swapped
* if switch_endian is true, so we have to first unswap
* them then reswap them as a single 64-bit entity.
*/
if (switch_endian) {
BLI_endian_switch_int32(&prop->data.val);
BLI_endian_switch_int32(&prop->data.val2);
BLI_endian_switch_int64((int64_t *)&prop->data.val);
}
break;
}
}
#define IDP_DirectLinkGroup_OrFree(prop, switch_endian, fd) \
_IDP_DirectLinkGroup_OrFree(prop, switch_endian, fd, __func__)
static void _IDP_DirectLinkGroup_OrFree(IDProperty **prop, int switch_endian, FileData *fd,
const char *caller_func_id)
{
if (*prop) {
if ((*prop)->type == IDP_GROUP) {
IDP_DirectLinkGroup(*prop, switch_endian, fd);
}
else {
/* corrupt file! */
printf("%s: found non group data, freeing type %d!\n",
caller_func_id, (*prop)->type);
/* don't risk id, data's likely corrupt. */
// IDP_FreeProperty(*prop);
*prop = NULL;
}
}
}
/* stub function */
static void IDP_LibLinkProperty(IDProperty *UNUSED(prop), int UNUSED(switch_endian), FileData *UNUSED(fd))
{
}
/* ************ READ ID *************** */
static void direct_link_id(FileData *fd, ID *id)
{
/*link direct data of ID properties*/
if (id->properties) {
id->properties = newdataadr(fd, id->properties);
/* this case means the data was written incorrectly, it should not happen */
IDP_DirectLinkGroup_OrFree(&id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
}
/* ************ 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;
cumap->cm[a].premultable = NULL;
}
}
/* ************ READ Brush *************** */
/* library brush linking after fileread */
static void lib_link_brush(FileData *fd, Main *main)
{
Brush *brush;
/* only link ID pointers */
for (brush = main->brush.first; brush; brush = brush->id.next) {
if (brush->id.flag & LIB_NEED_LINK) {
brush->id.flag -= LIB_NEED_LINK;
brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex);
brush->clone.image = newlibadr_us(fd, brush->id.lib, brush->clone.image);
brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve);
}
}
}
static void direct_link_brush(FileData *fd, Brush *brush)
{
/* brush itself has been read */
/* fallof curve */
brush->curve = newdataadr(fd, brush->curve);
brush->gradient = newdataadr(fd, brush->gradient);
if (brush->curve)
direct_link_curvemapping(fd, brush->curve);
else
BKE_brush_curve_preset(brush, CURVE_PRESET_SHARP);
brush->preview = NULL;
brush->icon_imbuf = NULL;
}
/* ************ READ Palette *************** */
static void lib_link_palette(FileData *UNUSED(fd), Main *main)
{
Palette *palette;
/* only link ID pointers */
for (palette = main->palettes.first; palette; palette = palette->id.next) {
if (palette->id.flag & LIB_NEED_LINK) {
palette->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_palette(FileData *fd, Palette *palette)
{
/* palette itself has been read */
link_list(fd, &palette->colors);
BLI_listbase_clear(&palette->deleted);
}
static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main)
{
PaintCurve *pc;
/* only link ID pointers */
for (pc = main->paintcurves.first; pc; pc = pc->id.next) {
if (pc->id.flag & LIB_NEED_LINK) {
pc->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_paint_curve(FileData *fd, PaintCurve *pc)
{
pc->points = newdataadr(fd, pc->points);
}
static void direct_link_script(FileData *UNUSED(fd), Script *script)
{
script->id.us = 1;
SCRIPT_SET_NULL(script);
}
/* ************ READ PACKEDFILE *************** */
static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
{
PackedFile *pf = newpackedadr(fd, oldpf);
if (pf) {
pf->data = newpackedadr(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 < NUM_ICON_SIZES; ++i) {
if (prv->rect[i]) {
prv->rect[i] = newdataadr(fd, prv->rect[i]);
}
prv->gputexture[i] = NULL;
}
}
return prv;
}
/* ************ READ ANIMATION STUFF ***************** */
/* Legacy Data Support (for Version Patching) ----------------------------- */
// XXX deprecated - old animation system
static void lib_link_ipo(FileData *fd, Main *main)
{
Ipo *ipo;
for (ipo = main->ipo.first; ipo; ipo = ipo->id.next) {
if (ipo->id.flag & LIB_NEED_LINK) {
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_NEED_LINK;
}
}
}
// XXX deprecated - old animation system
static void direct_link_ipo(FileData *fd, Ipo *ipo)
{
IpoCurve *icu;
link_list(fd, &(ipo->curve));
for (icu = ipo->curve.first; icu; icu = icu->next) {
icu->bezt = newdataadr(fd, icu->bezt);
icu->bp = newdataadr(fd, icu->bp);
icu->driver = newdataadr(fd, icu->driver);
}
}
// XXX deprecated - old animation system
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);
}
}
// XXX deprecated - old animation system
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);
}
// XXX deprecated - old animation system
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);
}
}
/* Data Linking ----------------------------- */
static void lib_link_fmodifiers(FileData *fd, ID *id, ListBase *list)
{
FModifier *fcm;
for (fcm = list->first; fcm; fcm = fcm->next) {
/* data for specific modifiers */
switch (fcm->type) {
case FMODIFIER_TYPE_PYTHON:
{
FMod_Python *data = (FMod_Python *)fcm->data;
data->script = newlibadr(fd, id->lib, data->script);
}
break;
}
}
}
static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list)
{
FCurve *fcu;
if (list == NULL)
return;
/* relink ID-block references... */
for (fcu = list->first; fcu; fcu = fcu->next) {
/* driver data */
if (fcu->driver) {
ChannelDriver *driver = fcu->driver;
DriverVar *dvar;
for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
DRIVER_TARGETS_LOOPER(dvar)
{
/* only relink if still used */
if (tarIndex < dvar->num_targets)
dtar->id = newlibadr(fd, id->lib, dtar->id);
else
dtar->id = NULL;
}
DRIVER_TARGETS_LOOPER_END
}
}
/* modifiers */
lib_link_fmodifiers(fd, id, &fcu->modifiers);
}
}
/* NOTE: this assumes that link_list has already been called on the list */
static void direct_link_fmodifiers(FileData *fd, ListBase *list)
{
FModifier *fcm;
for (fcm = list->first; fcm; fcm = fcm->next) {
/* relink general data */
fcm->data = newdataadr(fd, fcm->data);
/* do relinking of data for specific types */
switch (fcm->type) {
case FMODIFIER_TYPE_GENERATOR:
{
FMod_Generator *data = (FMod_Generator *)fcm->data;
data->coefficients = newdataadr(fd, data->coefficients);
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
BLI_endian_switch_float_array(data->coefficients, data->arraysize);
}
}
break;
case FMODIFIER_TYPE_ENVELOPE:
{
FMod_Envelope *data= (FMod_Envelope *)fcm->data;
data->data= newdataadr(fd, data->data);
}
break;
case FMODIFIER_TYPE_PYTHON:
{
FMod_Python *data = (FMod_Python *)fcm->data;
data->prop = newdataadr(fd, data->prop);
IDP_DirectLinkGroup_OrFree(&data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
break;
}
}
}
/* NOTE: this assumes that link_list has already been called on the list */
static void direct_link_fcurves(FileData *fd, ListBase *list)
{
FCurve *fcu;
/* link F-Curve data to F-Curve again (non ID-libs) */
for (fcu = list->first; fcu; fcu = fcu->next) {
/* curve data */
fcu->bezt = newdataadr(fd, fcu->bezt);
fcu->fpt = newdataadr(fd, fcu->fpt);
/* rna path */
fcu->rna_path = newdataadr(fd, fcu->rna_path);
/* group */
fcu->grp = newdataadr(fd, fcu->grp);
/* clear disabled flag - allows disabled drivers to be tried again ([#32155]),
* but also means that another method for "reviving disabled F-Curves" exists
*/
fcu->flag &= ~FCURVE_DISABLED;
/* driver */
fcu->driver= newdataadr(fd, fcu->driver);
if (fcu->driver) {
ChannelDriver *driver= fcu->driver;
DriverVar *dvar;
/* compiled expression data will need to be regenerated (old pointer may still be set here) */
driver->expr_comp = NULL;
/* give the driver a fresh chance - the operating environment may be different now
* (addons, etc. may be different) so the driver namespace may be sane now [#32155]
*/
driver->flag &= ~DRIVER_FLAG_INVALID;
/* relink variables, targets and their paths */
link_list(fd, &driver->variables);
for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
DRIVER_TARGETS_LOOPER(dvar)
{
/* only relink the targets being used */
if (tarIndex < dvar->num_targets)
dtar->rna_path = newdataadr(fd, dtar->rna_path);
else
dtar->rna_path = NULL;
}
DRIVER_TARGETS_LOOPER_END
}
}
/* modifiers */
link_list(fd, &fcu->modifiers);
direct_link_fmodifiers(fd, &fcu->modifiers);
}
}
static void lib_link_action(FileData *fd, Main *main)
{
bAction *act;
bActionChannel *chan;
for (act = main->action.first; act; act = act->id.next) {
if (act->id.flag & LIB_NEED_LINK) {
act->id.flag -= LIB_NEED_LINK;
// XXX deprecated - old animation system <<<
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);
}
// >>> XXX deprecated - old animation system
lib_link_fcurves(fd, &act->id, &act->curves);
}
}
}
static void direct_link_action(FileData *fd, bAction *act)
{
bActionChannel *achan; // XXX deprecated - old animation system
bActionGroup *agrp;
link_list(fd, &act->curves);
link_list(fd, &act->chanbase); // XXX deprecated - old animation system
link_list(fd, &act->groups);
link_list(fd, &act->markers);
// XXX deprecated - old animation system <<<
for (achan = act->chanbase.first; achan; achan=achan->next) {
achan->grp = newdataadr(fd, achan->grp);
link_list(fd, &achan->constraintChannels);
}
// >>> XXX deprecated - old animation system
direct_link_fcurves(fd, &act->curves);
for (agrp = act->groups.first; agrp; agrp= agrp->next) {
agrp->channels.first= newdataadr(fd, agrp->channels.first);
agrp->channels.last= newdataadr(fd, agrp->channels.last);
}
}
static void lib_link_nladata_strips(FileData *fd, ID *id, ListBase *list)
{
NlaStrip *strip;
for (strip = list->first; strip; strip = strip->next) {
/* check strip's children */
lib_link_nladata_strips(fd, id, &strip->strips);
/* check strip's F-Curves */
lib_link_fcurves(fd, id, &strip->fcurves);
/* reassign the counted-reference to action */
strip->act = newlibadr_us(fd, id->lib, strip->act);
/* fix action id-root (i.e. if it comes from a pre 2.57 .blend file) */
if ((strip->act) && (strip->act->idroot == 0))
strip->act->idroot = GS(id->name);
}
}
static void lib_link_nladata(FileData *fd, ID *id, ListBase *list)
{
NlaTrack *nlt;
/* we only care about the NLA strips inside the tracks */
for (nlt = list->first; nlt; nlt = nlt->next) {
lib_link_nladata_strips(fd, id, &nlt->strips);
}
}
/* This handles Animato NLA-Strips linking
* NOTE: this assumes that link_list has already been called on the list
*/
static void direct_link_nladata_strips(FileData *fd, ListBase *list)
{
NlaStrip *strip;
for (strip = list->first; strip; strip = strip->next) {
/* strip's child strips */
link_list(fd, &strip->strips);
direct_link_nladata_strips(fd, &strip->strips);
/* strip's F-Curves */
link_list(fd, &strip->fcurves);
direct_link_fcurves(fd, &strip->fcurves);
/* strip's F-Modifiers */
link_list(fd, &strip->modifiers);
direct_link_fmodifiers(fd, &strip->modifiers);
}
}
/* NOTE: this assumes that link_list has already been called on the list */
static void direct_link_nladata(FileData *fd, ListBase *list)
{
NlaTrack *nlt;
for (nlt = list->first; nlt; nlt = nlt->next) {
/* relink list of strips */
link_list(fd, &nlt->strips);
/* relink strip data */
direct_link_nladata_strips(fd, &nlt->strips);
}
}
/* ------- */
static void lib_link_keyingsets(FileData *fd, ID *id, ListBase *list)
{
KeyingSet *ks;
KS_Path *ksp;
/* here, we're only interested in the ID pointer stored in some of the paths */
for (ks = list->first; ks; ks = ks->next) {
for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
ksp->id= newlibadr(fd, id->lib, ksp->id);
}
}
}
/* NOTE: this assumes that link_list has already been called on the list */
static void direct_link_keyingsets(FileData *fd, ListBase *list)
{
KeyingSet *ks;
KS_Path *ksp;
/* link KeyingSet data to KeyingSet again (non ID-libs) */
for (ks = list->first; ks; ks = ks->next) {
/* paths */
link_list(fd, &ks->paths);
for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
/* rna path */
ksp->rna_path= newdataadr(fd, ksp->rna_path);
}
}
}
/* ------- */
static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt)
{
if (adt == NULL)
return;
/* link action data */
adt->action= newlibadr_us(fd, id->lib, adt->action);
adt->tmpact= newlibadr_us(fd, id->lib, adt->tmpact);
/* fix action id-roots (i.e. if they come from a pre 2.57 .blend file) */
if ((adt->action) && (adt->action->idroot == 0))
adt->action->idroot = GS(id->name);
if ((adt->tmpact) && (adt->tmpact->idroot == 0))
adt->tmpact->idroot = GS(id->name);
/* link drivers */
lib_link_fcurves(fd, id, &adt->drivers);
/* overrides don't have lib-link for now, so no need to do anything */
/* link NLA-data */
lib_link_nladata(fd, id, &adt->nla_tracks);
}
static void direct_link_animdata(FileData *fd, AnimData *adt)
{
/* NOTE: must have called newdataadr already before doing this... */
if (adt == NULL)
return;
/* link drivers */
link_list(fd, &adt->drivers);
direct_link_fcurves(fd, &adt->drivers);
/* link overrides */
// TODO...
/* link NLA-data */
link_list(fd, &adt->nla_tracks);
direct_link_nladata(fd, &adt->nla_tracks);
/* relink active strip - even though strictly speaking this should only be used
* if we're in 'tweaking mode', we need to be able to have this loaded back for
* undo, but also since users may not exit tweakmode before saving (#24535)
*/
// TODO: it's not really nice that anyone should be able to save the file in this
// state, but it's going to be too hard to enforce this single case...
adt->actstrip = newdataadr(fd, adt->actstrip);
}
/* ************ READ MOTION PATHS *************** */
/* direct data for cache */
static void direct_link_motionpath(FileData *fd, bMotionPath *mpath)
{
/* sanity check */
if (mpath == NULL)
return;
/* relink points cache */
mpath->points = newdataadr(fd, mpath->points);
}
/* ************ READ NODE TREE *************** */
static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock)
{
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
if (sock->prop)
IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
/* 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;
bNodeSocket *sock;
if (ntree->adt) lib_link_animdata(fd, &ntree->id, ntree->adt);
ntree->gpd = newlibadr_us(fd, id->lib, ntree->gpd);
for (node = ntree->nodes.first; node; node = node->next) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
if (node->prop)
IDP_LibLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
node->id= newlibadr_us(fd, id->lib, node->id);
for (sock = node->inputs.first; sock; sock = sock->next)
lib_link_node_socket(fd, id, sock);
for (sock = node->outputs.first; sock; sock = sock->next)
lib_link_node_socket(fd, id, sock);
}
for (sock = ntree->inputs.first; sock; sock = sock->next)
lib_link_node_socket(fd, id, sock);
for (sock = ntree->outputs.first; sock; sock = sock->next)
lib_link_node_socket(fd, id, sock);
}
/* 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_NEED_LINK) {
ntree->id.flag -= LIB_NEED_LINK;
lib_link_ntree(fd, &ntree->id, ntree);
}
}
}
/* get node tree stored locally in other IDs */
static bNodeTree *nodetree_from_id(ID *id)
{
if (!id)
return NULL;
switch (GS(id->name)) {
case ID_SCE: return ((Scene *)id)->nodetree;
case ID_MA: return ((Material *)id)->nodetree;
case ID_WO: return ((World *)id)->nodetree;
case ID_LA: return ((Lamp *)id)->nodetree;
case ID_TE: return ((Tex *)id)->nodetree;
case ID_LS: return ((FreestyleLineStyle *)id)->nodetree;
}
return NULL;
}
/* updates group node socket identifier so that
* external links to/from the group node are preserved.
*/
static void lib_node_do_versions_group_indices(bNode *gnode)
{
bNodeTree *ngroup = (bNodeTree*)gnode->id;
bNodeSocket *sock;
bNodeLink *link;
for (sock=gnode->outputs.first; sock; sock = sock->next) {
int old_index = sock->to_index;
for (link = ngroup->links.first; link; link = link->next) {
if (link->tonode == NULL && link->fromsock->own_index == old_index) {
strcpy(sock->identifier, link->fromsock->identifier);
/* deprecated */
sock->own_index = link->fromsock->own_index;
sock->to_index = 0;
sock->groupsock = NULL;
}
}
}
for (sock=gnode->inputs.first; sock; sock = sock->next) {
int old_index = sock->to_index;
for (link = ngroup->links.first; link; link = link->next) {
if (link->fromnode == NULL && link->tosock->own_index == old_index) {
strcpy(sock->identifier, link->tosock->identifier);
/* deprecated */
sock->own_index = link->tosock->own_index;
sock->to_index = 0;
sock->groupsock = NULL;
}
}
}
}
/* verify types for nodes and groups, all data has to be read */
/* open = 0: appending/linking, open = 1: open new file (need to clean out dynamic
* typedefs */
static void lib_verify_nodetree(Main *main, int UNUSED(open))
{
bNodeTree *ntree;
/* this crashes blender on undo/redo */
#if 0
if (open == 1) {
reinit_nodesystem();
}
#endif
/* set node->typeinfo pointers */
FOREACH_NODETREE(main, ntree, id) {
ntreeSetTypes(NULL, ntree);
} FOREACH_NODETREE_END
/* verify static socket templates */
FOREACH_NODETREE(main, ntree, id) {
bNode *node;
for (node=ntree->nodes.first; node; node=node->next)
node_verify_socket_templates(ntree, node);
} FOREACH_NODETREE_END
{
bool has_old_groups = false;
/* XXX this should actually be part of do_versions, but since we need
* finished library linking, it is not possible there. Instead in do_versions
* we have set the NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2 flag, so at this point we can do the
* actual group node updates.
*/
for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
if (ntree->flag & NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2)
has_old_groups = 1;
}
if (has_old_groups) {
FOREACH_NODETREE(main, ntree, id) {
/* updates external links for all group nodes in a tree */
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP) {
bNodeTree *ngroup = (bNodeTree*)node->id;
if (ngroup && (ngroup->flag & NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2))
lib_node_do_versions_group_indices(node);
}
}
} FOREACH_NODETREE_END
}
for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
ntree->flag &= ~NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2;
}
{
/* Convert the previously used ntree->inputs/ntree->outputs lists to interface nodes.
* Pre 2.56.2 node trees automatically have all unlinked sockets exposed already
* (see NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2).
*
* XXX this should actually be part of do_versions,
* but needs valid typeinfo pointers to create interface nodes.
*
* Note: theoretically only needed in node groups (main->nodetree),
* but due to a temporary bug such links could have been added in all trees,
* so have to clean up all of them ...
*/
FOREACH_NODETREE(main, ntree, id) {
if (ntree->flag & NTREE_DO_VERSIONS_CUSTOMNODES_GROUP) {
bNode *input_node = NULL, *output_node = NULL;
int num_inputs = 0, num_outputs = 0;
bNodeLink *link, *next_link;
/* Only create new interface nodes for actual older files.
* New file versions already have input/output nodes with duplicate links,
* in that case just remove the invalid links.
*/
int create_io_nodes = (ntree->flag & NTREE_DO_VERSIONS_CUSTOMNODES_GROUP_CREATE_INTERFACE);
float input_locx = 1000000.0f, input_locy = 0.0f;
float output_locx = -1000000.0f, output_locy = 0.0f;
/* rough guess, not nice but we don't have access to UI constants here ... */
static const float offsetx = 42 + 3*20 + 20;
/*static const float offsety = 0.0f;*/
if (create_io_nodes) {
if (ntree->inputs.first)
input_node = nodeAddStaticNode(NULL, ntree, NODE_GROUP_INPUT);
if (ntree->outputs.first)
output_node = nodeAddStaticNode(NULL, ntree, NODE_GROUP_OUTPUT);
}
/* Redirect links from/to the node tree interface to input/output node.
* If the fromnode/tonode pointers are NULL, this means a link from/to
* the ntree interface sockets, which need to be redirected to new interface nodes.
*/
for (link = ntree->links.first; link; link = next_link) {
bool free_link = false;
next_link = link->next;
if (link->fromnode == NULL) {
if (input_node) {
link->fromnode = input_node;
link->fromsock = node_group_input_find_socket(input_node, link->fromsock->identifier);
++num_inputs;
if (link->tonode) {
if (input_locx > link->tonode->locx - offsetx)
input_locx = link->tonode->locx - offsetx;
input_locy += link->tonode->locy;
}
}
else {
free_link = true;
}
}
if (link->tonode == NULL) {
if (output_node) {
link->tonode = output_node;
link->tosock = node_group_output_find_socket(output_node, link->tosock->identifier);
++num_outputs;
if (link->fromnode) {
if (output_locx < link->fromnode->locx + offsetx)
output_locx = link->fromnode->locx + offsetx;
output_locy += link->fromnode->locy;
}
}
else {
free_link = true;
}
}
if (free_link)
nodeRemLink(ntree, link);
}
if (num_inputs > 0) {
input_locy /= num_inputs;
input_node->locx = input_locx;
input_node->locy = input_locy;
}
if (num_outputs > 0) {
output_locy /= num_outputs;
output_node->locx = output_locx;
output_node->locy = output_locy;
}
/* clear do_versions flags */
ntree->flag &= ~(NTREE_DO_VERSIONS_CUSTOMNODES_GROUP | NTREE_DO_VERSIONS_CUSTOMNODES_GROUP_CREATE_INTERFACE);
}
}
FOREACH_NODETREE_END
}
/* verify all group user nodes */
for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
ntreeVerifyNodes(main, &ntree->id);
}
/* make update calls where necessary */
{
FOREACH_NODETREE(main, ntree, id) {
/* make an update call for the tree */
ntreeUpdateTree(main, ntree);
} FOREACH_NODETREE_END
}
}
static void direct_link_node_socket(FileData *fd, bNodeSocket *sock)
{
sock->prop = newdataadr(fd, sock->prop);
IDP_DirectLinkGroup_OrFree(&sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
sock->link = newdataadr(fd, sock->link);
sock->typeinfo = NULL;
sock->storage = newdataadr(fd, sock->storage);
sock->default_value = newdataadr(fd, sock->default_value);
sock->cache = NULL;
}
/* 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->is_updating = false;
ntree->typeinfo= NULL;
ntree->interface_type = NULL;
ntree->progress = NULL;
ntree->execdata = NULL;
ntree->adt = newdataadr(fd, ntree->adt);
direct_link_animdata(fd, ntree->adt);
ntree->id.flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA);
link_list(fd, &ntree->nodes);
for (node = ntree->nodes.first; node; node = node->next) {
node->typeinfo = NULL;
link_list(fd, &node->inputs);
link_list(fd, &node->outputs);
node->prop = newdataadr(fd, node->prop);
IDP_DirectLinkGroup_OrFree(&node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
link_list(fd, &node->internal_links);
for (link = node->internal_links.first; link; link = link->next) {
link->fromnode = newdataadr(fd, link->fromnode);
link->fromsock = newdataadr(fd, link->fromsock);
link->tonode = newdataadr(fd, link->tonode);
link->tosock = newdataadr(fd, link->tosock);
}
if (node->type == CMP_NODE_MOVIEDISTORTION) {
node->storage = newmclipadr(fd, node->storage);
}
else {
node->storage = newdataadr(fd, node->storage);
}
if (node->storage) {
/* could be handlerized at some point */
if (ntree->type==NTREE_SHADER) {
if (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB) {
direct_link_curvemapping(fd, node->storage);
}
else if (node->type==SH_NODE_SCRIPT) {
NodeShaderScript *nss = (NodeShaderScript *) node->storage;
nss->bytecode = newdataadr(fd, nss->bytecode);
}
}
else if (ntree->type==NTREE_COMPOSIT) {
if (ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
direct_link_curvemapping(fd, node->storage);
else if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
((ImageUser *)node->storage)->ok = 1;
}
else if ( ntree->type==NTREE_TEXTURE) {
if (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME)
direct_link_curvemapping(fd, node->storage);
else if (node->type==TEX_NODE_IMAGE)
((ImageUser *)node->storage)->ok = 1;
}
}
}
link_list(fd, &ntree->links);
/* and we connect the rest */
for (node = ntree->nodes.first; node; node = node->next) {
node->parent = newdataadr(fd, node->parent);
node->lasty = 0;
for (sock = node->inputs.first; sock; sock = sock->next)
direct_link_node_socket(fd, sock);
for (sock = node->outputs.first; sock; sock = sock->next)
direct_link_node_socket(fd, sock);
}
/* interface socket lists */
link_list(fd, &ntree->inputs);
link_list(fd, &ntree->outputs);
for (sock = ntree->inputs.first; sock; sock = sock->next)
direct_link_node_socket(fd, sock);
for (sock = ntree->outputs.first; sock; sock = sock->next)
direct_link_node_socket(fd, sock);
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);
}
#if 0
if (ntree->previews) {
bNodeInstanceHash *new_previews = BKE_node_instance_hash_new("node previews");
bNodeInstanceHashIterator iter;
NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
if (preview) {
bNodePreview *new_preview = newimaadr(fd, preview);
if (new_preview) {
bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
BKE_node_instance_hash_insert(new_previews, key, new_preview);
}
}
}
BKE_node_instance_hash_free(ntree->previews, NULL);
ntree->previews = new_previews;
}
#else
/* XXX TODO */
ntree->previews = NULL;
#endif
/* type verification is in lib-link */
}
/* ************ READ ARMATURE ***************** */
/* temp struct used to transport needed info to lib_link_constraint_cb() */
typedef struct tConstraintLinkData {
FileData *fd;
ID *id;
} tConstraintLinkData;
/* callback function used to relink constraint ID-links */
static void lib_link_constraint_cb(bConstraint *UNUSED(con), ID **idpoin, bool is_reference, void *userdata)
{
tConstraintLinkData *cld= (tConstraintLinkData *)userdata;
/* for reference types, we need to increment the usercounts on load... */
if (is_reference) {
/* reference type - with usercount */
*idpoin = newlibadr_us(cld->fd, cld->id->lib, *idpoin);
}
else {
/* target type - no usercount needed */
*idpoin = newlibadr(cld->fd, cld->id->lib, *idpoin);
}
}
static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
{
tConstraintLinkData cld;
bConstraint *con;
/* legacy fixes */
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;
}
/* own ipo, all constraints have it */
con->ipo = newlibadr_us(fd, id->lib, con->ipo); // XXX deprecated - old animation system
}
/* relink all ID-blocks used by the constraints */
cld.fd = fd;
cld.id = id;
BKE_constraints_id_loop(conlist, lib_link_constraint_cb, &cld);
}
static void direct_link_constraints(FileData *fd, ListBase *lb)
{
bConstraint *con;
link_list(fd, lb);
for (con=lb->first; con; con=con->next) {
con->data = newdataadr(fd, con->data);
switch (con->type) {
case CONSTRAINT_TYPE_PYTHON:
{
bPythonConstraint *data= con->data;
link_list(fd, &data->targets);
data->prop = newdataadr(fd, data->prop);
IDP_DirectLinkGroup_OrFree(&data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
break;
}
case CONSTRAINT_TYPE_SPLINEIK:
{
bSplineIKConstraint *data= con->data;
data->points= newdataadr(fd, data->points);
break;
}
case CONSTRAINT_TYPE_KINEMATIC:
{
bKinematicConstraint *data = con->data;
con->lin_error = 0.f;
con->rot_error = 0.f;
/* version patch for runtime flag, was not cleared in some case */
data->flag &= ~CONSTRAINT_IK_AUTO;
break;
}
case CONSTRAINT_TYPE_CHILDOF:
{
/* XXX version patch, in older code this flag wasn't always set, and is inherent to type */
if (con->ownspace == CONSTRAINT_SPACE_POSE)
con->flag |= CONSTRAINT_SPACEONCE;
break;
}
}
}
}
static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
{
bPoseChannel *pchan;
bArmature *arm = ob->data;
int rebuild = 0;
if (!pose || !arm)
return;
/* always rebuild to match proxy or lib changes, but on Undo */
if (fd->memfile == NULL)
if (ob->proxy || (ob->id.lib==NULL && arm->id.lib))
rebuild = 1;
if (ob->proxy) {
/* sync proxy layer */
if (pose->proxy_layer)
arm->layer = pose->proxy_layer;
/* sync proxy active bone */
if (pose->proxy_act_bone[0]) {
Bone *bone = BKE_armature_find_bone_name(arm, pose->proxy_act_bone);
if (bone)
arm->act_bone = bone;
}
}
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 = BKE_armature_find_bone_name(arm, pchan->name);
pchan->custom = newlibadr_us(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;
pchan->bone->flag |= pchan->selectflag;
}
}
if (rebuild) {
DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
pose->flag |= POSE_RECALC;
}
}
static void lib_link_armature(FileData *fd, Main *main)
{
bArmature *arm;
for (arm = main->armature.first; arm; arm = arm->id.next) {
if (arm->id.flag & LIB_NEED_LINK) {
if (arm->adt) lib_link_animdata(fd, &arm->id, arm->adt);
arm->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_bones(FileData *fd, Bone *bone)
{
Bone *child;
bone->parent = newdataadr(fd, bone->parent);
bone->prop = newdataadr(fd, bone->prop);
IDP_DirectLinkGroup_OrFree(&bone->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
bone->flag &= ~BONE_DRAW_ACTIVE;
link_list(fd, &bone->childbase);
for (child=bone->childbase.first; child; child=child->next)
direct_link_bones(fd, child);
}
static void direct_link_armature(FileData *fd, bArmature *arm)
{
Bone *bone;
link_list(fd, &arm->bonebase);
arm->edbo = NULL;
arm->sketch = NULL;
arm->adt = newdataadr(fd, arm->adt);
direct_link_animdata(fd, arm->adt);
for (bone = arm->bonebase.first; bone; bone = bone->next) {
direct_link_bones(fd, bone);
}
arm->act_bone = newdataadr(fd, arm->act_bone);
arm->act_edbone = NULL;
}
/* ************ READ CAMERA ***************** */
static void lib_link_camera(FileData *fd, Main *main)
{
Camera *ca;
for (ca = main->camera.first; ca; ca = ca->id.next) {
if (ca->id.flag & LIB_NEED_LINK) {
if (ca->adt) lib_link_animdata(fd, &ca->id, ca->adt);
ca->ipo = newlibadr_us(fd, ca->id.lib, ca->ipo); // XXX deprecated - old animation system
ca->dof_ob = newlibadr_us(fd, ca->id.lib, ca->dof_ob);
ca->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_camera(FileData *fd, Camera *ca)
{
ca->adt = newdataadr(fd, ca->adt);
direct_link_animdata(fd, ca->adt);
}
/* ************ READ LAMP ***************** */
static void lib_link_lamp(FileData *fd, Main *main)
{
Lamp *la;
MTex *mtex;
int a;
for (la = main->lamp.first; la; la = la->id.next) {
if (la->id.flag & LIB_NEED_LINK) {
if (la->adt) lib_link_animdata(fd, &la->id, la->adt);
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); // XXX deprecated - old animation system
if (la->nodetree) {
lib_link_ntree(fd, &la->id, la->nodetree);
la->nodetree->id.lib = la->id.lib;
}
la->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_lamp(FileData *fd, Lamp *la)
{
int a;
la->adt = newdataadr(fd, la->adt);
direct_link_animdata(fd, la->adt);
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->nodetree= newdataadr(fd, la->nodetree);
if (la->nodetree) {
direct_link_id(fd, &la->nodetree->id);
direct_link_nodetree(fd, la->nodetree);
}
la->preview = direct_link_preview_image(fd, la->preview);
}
/* ************ READ keys ***************** */
void blo_do_versions_key_uidgen(Key *key)
{
KeyBlock *block;
key->uidgen = 1;
for (block = key->block.first; block; block = block->next) {
block->uid = key->uidgen++;
}
}
static void lib_link_key(FileData *fd, Main *main)
{
Key *key;
for (key = main->key.first; key; key = key->id.next) {
/*check if we need to generate unique ids for the shapekeys*/
if (!key->uidgen) {
blo_do_versions_key_uidgen(key);
}
if (key->id.flag & LIB_NEED_LINK) {
if (key->adt) lib_link_animdata(fd, &key->id, key->adt);
key->ipo = newlibadr_us(fd, key->id.lib, key->ipo); // XXX deprecated - old animation system
key->from = newlibadr(fd, key->id.lib, key->from);
key->id.flag -= LIB_NEED_LINK;
}
}
}
static void switch_endian_keyblock(Key *key, KeyBlock *kb)
{
int elemsize, a, b;
const 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];
BLI_endian_switch_float_array((float *)poin, b);
poin += sizeof(float) * b;
break;
}
cp += 2;
}
data += elemsize;
}
}
static void direct_link_key(FileData *fd, Key *key)
{
KeyBlock *kb;
link_list(fd, &(key->block));
key->adt = newdataadr(fd, key->adt);
direct_link_animdata(fd, key->adt);
key->refkey= newdataadr(fd, key->refkey);
for (kb = key->block.first; kb; kb = kb->next) {
kb->data = newdataadr(fd, kb->data);
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN)
switch_endian_keyblock(key, kb);
}
}
/* ************ READ mball ***************** */
static void lib_link_mball(FileData *fd, Main *main)
{
MetaBall *mb;
int a;
for (mb = main->mball.first; mb; mb = mb->id.next) {
if (mb->id.flag & LIB_NEED_LINK) {
if (mb->adt) lib_link_animdata(fd, &mb->id, mb->adt);
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); // XXX deprecated - old animation system
mb->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_mball(FileData *fd, MetaBall *mb)
{
mb->adt = newdataadr(fd, mb->adt);
direct_link_animdata(fd, mb->adt);
mb->mat = newdataadr(fd, mb->mat);
test_pointer_array(fd, (void **)&mb->mat);
link_list(fd, &(mb->elems));
BLI_listbase_clear(&mb->disp);
mb->editelems = NULL;
/* mb->edit_elems.first= mb->edit_elems.last= NULL;*/
mb->lastelem = NULL;
}
/* ************ READ WORLD ***************** */
static void lib_link_world(FileData *fd, Main *main)
{
World *wrld;
MTex *mtex;
int a;
for (wrld = main->world.first; wrld; wrld = wrld->id.next) {
if (wrld->id.flag & LIB_NEED_LINK) {
if (wrld->adt) lib_link_animdata(fd, &wrld->id, wrld->adt);
wrld->ipo = newlibadr_us(fd, wrld->id.lib, wrld->ipo); // XXX deprecated - old animation system
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);
}
}
if (wrld->nodetree) {
lib_link_ntree(fd, &wrld->id, wrld->nodetree);
wrld->nodetree->id.lib = wrld->id.lib;
}
wrld->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_world(FileData *fd, World *wrld)
{
int a;
wrld->adt = newdataadr(fd, wrld->adt);
direct_link_animdata(fd, wrld->adt);
for (a = 0; a < MAX_MTEX; a++) {
wrld->mtex[a] = newdataadr(fd, wrld->mtex[a]);
}
wrld->nodetree = newdataadr(fd, wrld->nodetree);
if (wrld->nodetree) {
direct_link_id(fd, &wrld->nodetree->id);
direct_link_nodetree(fd, wrld->nodetree);
}
wrld->preview = direct_link_preview_image(fd, wrld->preview);
BLI_listbase_clear(&wrld->gpumaterial);
}
/* ************ READ VFONT ***************** */
static void lib_link_vfont(FileData *UNUSED(fd), Main *main)
{
VFont *vf;
for (vf = main->vfont.first; vf; vf = vf->id.next) {
if (vf->id.flag & LIB_NEED_LINK) {
vf->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_vfont(FileData *fd, VFont *vf)
{
vf->data = NULL;
vf->temp_pf = NULL;
vf->packedfile = direct_link_packedfile(fd, vf->packedfile);
}
/* ************ READ TEXT ****************** */
static void lib_link_text(FileData *UNUSED(fd), Main *main)
{
Text *text;
for (text = main->text.first; text; text = text->id.next) {
if (text->id.flag & LIB_NEED_LINK) {
text->id.flag -= LIB_NEED_LINK;
}
}
}
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 0
if (text->flags & TXT_ISEXT) {
BKE_text_reload(text);
}
/* else { */
#endif
link_list(fd, &text->lines);
text->curl = newdataadr(fd, text->curl);
text->sell = newdataadr(fd, text->sell);
for (ln = text->lines.first; ln; ln = ln->next) {
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);
}
}
text->flags = (text->flags) & ~TXT_ISEXT;
text->id.us = 1;
}
/* ************ READ IMAGE ***************** */
static void lib_link_image(FileData *fd, Main *main)
{
Image *ima;
for (ima = main->image.first; ima; ima = ima->id.next) {
if (ima->id.flag & LIB_NEED_LINK) {
if (ima->id.properties) IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
ima->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_image(FileData *fd, Image *ima)
{
/* for undo system, pointers could be restored */
if (fd->imamap)
ima->cache = newimaadr(fd, ima->cache);
else
ima->cache = NULL;
/* if not restored, we keep the binded opengl index */
if (!ima->cache) {
ima->bindcode = 0;
ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
ima->gputexture = NULL;
ima->rr = NULL;
}
ima->anim = NULL;
ima->repbind = NULL;
/* undo system, try to restore render buffers */
if (fd->imamap) {
int a;
for (a = 0; a < IMA_MAX_RENDER_SLOT; a++)
ima->renders[a] = newimaadr(fd, ima->renders[a]);
}
else {
memset(ima->renders, 0, sizeof(ima->renders));
ima->last_render_slot = ima->render_slot;
}
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;
for (cu = main->curve.first; cu; cu = cu->id.next) {
if (cu->id.flag & LIB_NEED_LINK) {
if (cu->adt) lib_link_animdata(fd, &cu->id, cu->adt);
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); // XXX deprecated - old animation system
cu->key = newlibadr_us(fd, cu->id.lib, cu->key);
cu->id.flag -= LIB_NEED_LINK;
}
}
}
static void switch_endian_knots(Nurb *nu)
{
if (nu->knotsu) {
BLI_endian_switch_float_array(nu->knotsu, KNOTSU(nu));
}
if (nu->knotsv) {
BLI_endian_switch_float_array(nu->knotsv, KNOTSV(nu));
}
}
static void direct_link_curve(FileData *fd, Curve *cu)
{
Nurb *nu;
TextBox *tb;
cu->adt= newdataadr(fd, cu->adt);
direct_link_animdata(fd, cu->adt);
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 == NULL) {
link_list(fd, &(cu->nurb));
}
else {
cu->nurb.first=cu->nurb.last= NULL;
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.0f) cu->wordspace = 1.0f;
}
cu->editnurb = NULL;
cu->editfont = NULL;
for (nu = cu->nurb.first; nu; nu = nu->next) {
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 == NULL) nu->charidx= nu->mat_nr;
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
switch_endian_knots(nu);
}
}
cu->bb = NULL;
}
/* ************ READ TEX ***************** */
static void lib_link_texture(FileData *fd, Main *main)
{
Tex *tex;
for (tex = main->tex.first; tex; tex = tex->id.next) {
if (tex->id.flag & LIB_NEED_LINK) {
if (tex->adt) lib_link_animdata(fd, &tex->id, tex->adt);
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);
if (tex->pd)
tex->pd->object = newlibadr(fd, tex->id.lib, tex->pd->object);
if (tex->vd)
tex->vd->object = newlibadr(fd, tex->id.lib, tex->vd->object);
if (tex->ot)
tex->ot->object = newlibadr(fd, tex->id.lib, tex->ot->object);
if (tex->nodetree) {
lib_link_ntree(fd, &tex->id, tex->nodetree);
tex->nodetree->id.lib = tex->id.lib;
}
tex->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_texture(FileData *fd, Tex *tex)
{
tex->adt = newdataadr(fd, tex->adt);
direct_link_animdata(fd, tex->adt);
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->pd = newdataadr(fd, tex->pd);
if (tex->pd) {
tex->pd->point_tree = NULL;
tex->pd->coba = newdataadr(fd, tex->pd->coba);
tex->pd->falloff_curve = newdataadr(fd, tex->pd->falloff_curve);
if (tex->pd->falloff_curve) {
direct_link_curvemapping(fd, tex->pd->falloff_curve);
}
}
tex->vd = newdataadr(fd, tex->vd);
if (tex->vd) {
tex->vd->dataset = NULL;
tex->vd->ok = 0;
}
else {
if (tex->type == TEX_VOXELDATA)
tex->vd = MEM_callocN(sizeof(VoxelData), "direct_link_texture VoxelData");
}
tex->ot = newdataadr(fd, tex->ot);
tex->nodetree = newdataadr(fd, tex->nodetree);
if (tex->nodetree) {
direct_link_id(fd, &tex->nodetree->id);
direct_link_nodetree(fd, tex->nodetree);
}
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;
for (ma = main->mat.first; ma; ma = ma->id.next) {
if (ma->id.flag & LIB_NEED_LINK) {
if (ma->adt) lib_link_animdata(fd, &ma->id, ma->adt);
/* 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);
}
}
if (ma->nodetree) {
lib_link_ntree(fd, &ma->id, ma->nodetree);
ma->nodetree->id.lib = ma->id.lib;
}
ma->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_material(FileData *fd, Material *ma)
{
int a;
ma->adt = newdataadr(fd, ma->adt);
direct_link_animdata(fd, ma->adt);
for (a = 0; a < MAX_MTEX; a++) {
ma->mtex[a] = newdataadr(fd, ma->mtex[a]);
}
ma->texpaintslot = NULL;
ma->ramp_col = newdataadr(fd, ma->ramp_col);
ma->ramp_spec = newdataadr(fd, ma->ramp_spec);
ma->nodetree = newdataadr(fd, ma->nodetree);
if (ma->nodetree) {
direct_link_id(fd, &ma->nodetree->id);
direct_link_nodetree(fd, ma->nodetree);
}
ma->preview = direct_link_preview_image(fd, ma->preview);
BLI_listbase_clear(&ma->gpumaterial);
}
/* ************ READ PARTICLE SETTINGS ***************** */
/* update this also to writefile.c */
static const char *ptcache_data_struct[] = {
"", // BPHYS_DATA_INDEX
"", // BPHYS_DATA_LOCATION
"", // BPHYS_DATA_VELOCITY
"", // BPHYS_DATA_ROTATION
"", // BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST */
"", // BPHYS_DATA_SIZE:
"", // BPHYS_DATA_TIMES:
"BoidData" // case BPHYS_DATA_BOIDS:
};
static void direct_link_pointcache(FileData *fd, PointCache *cache)
{
if ((cache->flag & PTCACHE_DISK_CACHE)==0) {
PTCacheMem *pm;
PTCacheExtra *extra;
int i;
link_list(fd, &cache->mem_cache);
pm = cache->mem_cache.first;
for (; pm; pm=pm->next) {
for (i=0; i<BPHYS_TOT_DATA; i++) {
pm->data[i] = newdataadr(fd, pm->data[i]);
/* the cache saves non-struct data without DNA */
if (pm->data[i] && ptcache_data_struct[i][0]=='\0' && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) {
int tot = (BKE_ptcache_data_size (i) * pm->totpoint) / sizeof(int); /* data_size returns bytes */
int *poin = pm->data[i];
BLI_endian_switch_int32_array(poin, tot);
}
}
link_list(fd, &pm->extradata);
for (extra=pm->extradata.first; extra; extra=extra->next)
extra->data = newdataadr(fd, extra->data);
}
}
else
BLI_listbase_clear(&cache->mem_cache);
cache->flag &= ~PTCACHE_SIMULATION_VALID;
cache->simframe = 0;
cache->edit = NULL;
cache->free_edit = NULL;
cache->cached_frames = NULL;
}
static void direct_link_pointcache_list(FileData *fd, ListBase *ptcaches, PointCache **ocache, int force_disk)
{
if (ptcaches->first) {
PointCache *cache= NULL;
link_list(fd, ptcaches);
for (cache=ptcaches->first; cache; cache=cache->next) {
direct_link_pointcache(fd, cache);
if (force_disk) {
cache->flag |= PTCACHE_DISK_CACHE;
cache->step = 1;
}
}
*ocache = newdataadr(fd, *ocache);
}
else if (*ocache) {
/* old "single" caches need to be linked too */
*ocache = newdataadr(fd, *ocache);
direct_link_pointcache(fd, *ocache);
if (force_disk) {
(*ocache)->flag |= PTCACHE_DISK_CACHE;
(*ocache)->step = 1;
}
ptcaches->first = ptcaches->last = *ocache;
}
}
static void lib_link_partdeflect(FileData *fd, ID *id, PartDeflect *pd)
{
if (pd && pd->tex)
pd->tex = newlibadr_us(fd, id->lib, pd->tex);
if (pd && pd->f_source)
pd->f_source = newlibadr_us(fd, id->lib, pd->f_source);
}
static void lib_link_particlesettings(FileData *fd, Main *main)
{
ParticleSettings *part;
ParticleDupliWeight *dw;
MTex *mtex;
int a;
for (part = main->particle.first; part; part = part->id.next) {
if (part->id.flag & LIB_NEED_LINK) {
if (part->adt) lib_link_animdata(fd, &part->id, part->adt);
part->ipo = newlibadr_us(fd, part->id.lib, part->ipo); // XXX deprecated - old animation system
part->dup_ob = newlibadr(fd, part->id.lib, part->dup_ob);
part->dup_group = newlibadr(fd, part->id.lib, part->dup_group);
part->eff_group = newlibadr(fd, part->id.lib, part->eff_group);
part->bb_ob = newlibadr(fd, part->id.lib, part->bb_ob);
lib_link_partdeflect(fd, &part->id, part->pd);
lib_link_partdeflect(fd, &part->id, part->pd2);
if (part->effector_weights)
part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group);
if (part->dupliweights.first && part->dup_group) {
int index_ok = 0;
/* check for old files without indices (all indexes 0) */
if (BLI_listbase_is_single(&part->dupliweights)) {
/* special case for only one object in the group */
index_ok = 1;
}
else {
for (dw = part->dupliweights.first; dw; dw = dw->next) {
if (dw->index > 0) {
index_ok = 1;
break;
}
}
}
if (index_ok) {
/* if we have indexes, let's use them */
for (dw = part->dupliweights.first; dw; dw = dw->next) {
GroupObject *go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index);
dw->ob = go ? go->ob : NULL;
}
}
else {
/* otherwise try to get objects from own library (won't work on library linked groups) */
for (dw = part->dupliweights.first; dw; dw = dw->next) {
dw->ob = newlibadr(fd, part->id.lib, dw->ob);
}
}
}
else {
BLI_listbase_clear(&part->dupliweights);
}
if (part->boids) {
BoidState *state = part->boids->states.first;
BoidRule *rule;
for (; state; state=state->next) {
rule = state->rules.first;
for (; rule; rule=rule->next)
switch (rule->type) {
case eBoidRuleType_Goal:
case eBoidRuleType_Avoid:
{
BoidRuleGoalAvoid *brga = (BoidRuleGoalAvoid*)rule;
brga->ob = newlibadr(fd, part->id.lib, brga->ob);
break;
}
case eBoidRuleType_FollowLeader:
{
BoidRuleFollowLeader *brfl = (BoidRuleFollowLeader*)rule;
brfl->ob = newlibadr(fd, part->id.lib, brfl->ob);
break;
}
}
}
}
for (a = 0; a < MAX_MTEX; a++) {
mtex= part->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, part->id.lib, mtex->tex);
mtex->object = newlibadr(fd, part->id.lib, mtex->object);
}
}
part->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_partdeflect(PartDeflect *pd)
{
if (pd) pd->rng = NULL;
}
static void direct_link_particlesettings(FileData *fd, ParticleSettings *part)
{
int a;
part->adt = newdataadr(fd, part->adt);
part->pd = newdataadr(fd, part->pd);
part->pd2 = newdataadr(fd, part->pd2);
direct_link_animdata(fd, part->adt);
direct_link_partdeflect(part->pd);
direct_link_partdeflect(part->pd2);
part->effector_weights = newdataadr(fd, part->effector_weights);
if (!part->effector_weights)
part->effector_weights = BKE_add_effector_weights(part->eff_group);
link_list(fd, &part->dupliweights);
part->boids = newdataadr(fd, part->boids);
part->fluid = newdataadr(fd, part->fluid);
if (part->boids) {
BoidState *state;
link_list(fd, &part->boids->states);
for (state=part->boids->states.first; state; state=state->next) {
link_list(fd, &state->rules);
link_list(fd, &state->conditions);
link_list(fd, &state->actions);
}
}
for (a = 0; a < MAX_MTEX; a++) {
part->mtex[a] = newdataadr(fd, part->mtex[a]);
}
}
static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase *particles)
{
ParticleSystem *psys, *psysnext;
for (psys=particles->first; psys; psys=psysnext) {
psysnext = psys->next;
psys->part = newlibadr_us(fd, id->lib, psys->part);
if (psys->part) {
ParticleTarget *pt = psys->targets.first;
for (; pt; pt=pt->next)
pt->ob=newlibadr(fd, id->lib, pt->ob);
psys->parent = newlibadr(fd, id->lib, psys->parent);
psys->target_ob = newlibadr(fd, id->lib, psys->target_ob);
if (psys->clmd) {
/* XXX - from reading existing code this seems correct but intended usage of
* pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
psys->clmd->point_cache = psys->pointcache;
psys->clmd->ptcaches.first = psys->clmd->ptcaches.last= NULL;
psys->clmd->coll_parms->group = newlibadr(fd, id->lib, psys->clmd->coll_parms->group);
psys->clmd->modifier.error = NULL;
}
}
else {
/* particle modifier must be removed before particle system */
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
BLI_remlink(&ob->modifiers, psmd);
modifier_free((ModifierData *)psmd);
BLI_remlink(particles, psys);
MEM_freeN(psys);
}
}
}
static void direct_link_particlesystems(FileData *fd, ListBase *particles)
{
ParticleSystem *psys;
ParticleData *pa;
int a;
for (psys=particles->first; psys; psys=psys->next) {
psys->particles=newdataadr(fd, psys->particles);
if (psys->particles && psys->particles->hair) {
for (a=0, pa=psys->particles; a<psys->totpart; a++, pa++)
pa->hair=newdataadr(fd, pa->hair);
}
if (psys->particles && psys->particles->keys) {
for (a=0, pa=psys->particles; a<psys->totpart; a++, pa++) {
pa->keys= NULL;
pa->totkey= 0;
}
psys->flag &= ~PSYS_KEYED;
}
if (psys->particles && psys->particles->boid) {
pa = psys->particles;
pa->boid = newdataadr(fd, pa->boid);
for (a=1, pa++; a<psys->totpart; a++, pa++)
pa->boid = (pa-1)->boid + 1;
}
else if (psys->particles) {
for (a=0, pa=psys->particles; a<psys->totpart; a++, pa++)
pa->boid = NULL;
}
psys->fluid_springs = newdataadr(fd, psys->fluid_springs);
psys->child = newdataadr(fd, psys->child);
psys->effectors = NULL;
link_list(fd, &psys->targets);
psys->edit = NULL;
psys->free_edit = NULL;
psys->pathcache = NULL;
psys->childcache = NULL;
BLI_listbase_clear(&psys->pathcachebufs);
BLI_listbase_clear(&psys->childcachebufs);
psys->pdd = NULL;
psys->renderdata = NULL;
direct_link_pointcache_list(fd, &psys->ptcaches, &psys->pointcache, 0);
if (psys->clmd) {
psys->clmd = newdataadr(fd, psys->clmd);
psys->clmd->clothObject = NULL;
psys->clmd->sim_parms= newdataadr(fd, psys->clmd->sim_parms);
psys->clmd->coll_parms= newdataadr(fd, psys->clmd->coll_parms);
if (psys->clmd->sim_parms) {
psys->clmd->sim_parms->effector_weights = NULL;
if (psys->clmd->sim_parms->presets > 10)
psys->clmd->sim_parms->presets = 0;
}
psys->hair_in_dm = psys->hair_out_dm = NULL;
psys->clmd->point_cache = psys->pointcache;
}
psys->tree = NULL;
psys->bvhtree = NULL;
}
return;
}
/* ************ READ MESH ***************** */
static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface)
{
MTFace *tf= mtface;
int i;
/* Add pseudo-references (not fake users!) to images used by texface. A
* little bogus; it would be better if each mesh consistently added one ref
* to each image it used. - z0r */
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_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata, int totface)
{
int i;
for (i=0; i < pdata->totlayer; i++) {
CustomDataLayer *layer = &pdata->layers[i];
if (layer->type == CD_MTEXPOLY) {
MTexPoly *tf= layer->data;
int j;
for (j = 0; j < totface; j++, 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_mesh(FileData *fd, Main *main)
{
Mesh *me;
for (me = main->mesh.first; me; me = me->id.next) {
if (me->id.flag & LIB_NEED_LINK) {
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);
if (me->adt) lib_link_animdata(fd, &me->id, me->adt);
/* 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); // XXX: deprecated: old anim sys
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);
lib_link_customdata_mtpoly(fd, me, &me->pdata, me->totpoly);
if (me->mr && me->mr->levels.first)
lib_link_customdata_mtface(fd, me, &me->mr->fdata,
((MultiresLevel*)me->mr->levels.first)->totface);
}
}
/* convert texface options to material */
convert_tface_mt(fd, main);
for (me = main->mesh.first; me; me = me->id.next) {
if (me->id.flag & LIB_NEED_LINK) {
/*check if we need to convert mfaces to mpolys*/
if (me->totface && !me->totpoly) {
/* temporarily switch main so that reading from
* external CustomData works */
Main *gmain = G.main;
G.main = main;
BKE_mesh_do_versions_convert_mfaces_to_mpolys(me);
G.main = gmain;
}
/*
* Re-tessellate, even if the polys were just created from tessfaces, this
* is important because it:
* - fill the CD_ORIGINDEX layer
* - gives consistency of tessface between loading from a file and
* converting an edited BMesh back into a mesh (i.e. it replaces
* quad tessfaces in a loaded mesh immediately, instead of lazily
* waiting until edit mode has been entered/exited, making it easier
* to recognize problems that would otherwise only show up after edits).
*/
#ifdef USE_TESSFACE_DEFAULT
BKE_mesh_tessface_calc(me);
#else
BKE_mesh_tessface_clear(me);
#endif
me->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_dverts(FileData *fd, int count, MDeformVert *mdverts)
{
int i;
if (mdverts == NULL) {
return;
}
for (i = count; i > 0; i--, mdverts++) {
/*convert to vgroup allocation system*/
MDeformWeight *dw;
if (mdverts->dw && (dw = newdataadr(fd, mdverts->dw))) {
const ssize_t dw_len = mdverts->totweight * sizeof(MDeformWeight);
void *dw_tmp = MEM_mallocN(dw_len, "direct_link_dverts");
memcpy(dw_tmp, dw, dw_len);
mdverts->dw = dw_tmp;
MEM_freeN(dw);
}
else {
mdverts->dw = NULL;
mdverts->totweight = 0;
}
}
}
static void direct_link_mdisps(FileData *fd, int count, MDisps *mdisps, int external)
{
if (mdisps) {
int i;
for (i = 0; i < count; ++i) {
mdisps[i].disps = newdataadr(fd, mdisps[i].disps);
mdisps[i].hidden = newdataadr(fd, mdisps[i].hidden);
if (mdisps[i].totdisp && !mdisps[i].level) {
/* this calculation is only correct for loop mdisps;
* if loading pre-BMesh face mdisps this will be
* overwritten with the correct value in
* bm_corners_to_loops() */
float gridsize = sqrtf(mdisps[i].totdisp);
mdisps[i].level = (int)(logf(gridsize - 1.0f) / (float)M_LN2) + 1;
}
if ((fd->flags & FD_FLAGS_SWITCH_ENDIAN) && (mdisps[i].disps)) {
/* DNA_struct_switch_endian doesn't do endian swap for (*disps)[] */
/* this does swap for data written at write_mdisps() - readfile.c */
BLI_endian_switch_float_array(*mdisps[i].disps, mdisps[i].totdisp * 3);
}
if (!external && !mdisps[i].disps)
mdisps[i].totdisp = 0;
}
}
}
static void direct_link_grid_paint_mask(FileData *fd, int count, GridPaintMask *grid_paint_mask)
{
if (grid_paint_mask) {
int i;
for (i = 0; i < count; ++i) {
GridPaintMask *gpm = &grid_paint_mask[i];
if (gpm->data)
gpm->data = newdataadr(fd, gpm->data);
}
}
}
/*this isn't really a public api function, so prototyped here*/
static void direct_link_customdata(FileData *fd, CustomData *data, int count)
{
int i = 0;
data->layers = newdataadr(fd, data->layers);
/* annoying workaround for bug [#31079] loading legacy files with
* no polygons _but_ have stale customdata */
if (UNLIKELY(count == 0 && data->layers == NULL && data->totlayer != 0)) {
CustomData_reset(data);
return;
}
data->external = newdataadr(fd, data->external);
while (i < data->totlayer) {
CustomDataLayer *layer = &data->layers[i];
if (layer->flag & CD_FLAG_EXTERNAL)
layer->flag &= ~CD_FLAG_IN_MEMORY;
layer->flag &= ~CD_FLAG_NOFREE;
if (CustomData_verify_versions(data, i)) {
layer->data = newdataadr(fd, layer->data);
if (layer->type == CD_MDISPS)
direct_link_mdisps(fd, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
else if (layer->type == CD_GRID_PAINT_MASK)
direct_link_grid_paint_mask(fd, count, layer->data);
i++;
}
}
CustomData_update_typemap(data);
}
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->mloop = newdataadr(fd, mesh->mloop);
mesh->mpoly = newdataadr(fd, mesh->mpoly);
mesh->tface = newdataadr(fd, mesh->tface);
mesh->mtface = newdataadr(fd, mesh->mtface);
mesh->mcol = newdataadr(fd, mesh->mcol);
mesh->dvert = newdataadr(fd, mesh->dvert);
mesh->mloopcol = newdataadr(fd, mesh->mloopcol);
mesh->mloopuv = newdataadr(fd, mesh->mloopuv);
mesh->mtpoly = newdataadr(fd, mesh->mtpoly);
mesh->mselect = newdataadr(fd, mesh->mselect);
/* animdata */
mesh->adt = newdataadr(fd, mesh->adt);
direct_link_animdata(fd, mesh->adt);
/* 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->totvert, mesh->dvert);
direct_link_customdata(fd, &mesh->vdata, mesh->totvert);
direct_link_customdata(fd, &mesh->edata, mesh->totedge);
direct_link_customdata(fd, &mesh->fdata, mesh->totface);
direct_link_customdata(fd, &mesh->ldata, mesh->totloop);
direct_link_customdata(fd, &mesh->pdata, mesh->totpoly);
mesh->bb = NULL;
mesh->edit_btmesh = NULL;
/* happens with old files */
if (mesh->mselect == NULL) {
mesh->totselect = 0;
}
if (mesh->mloopuv || mesh->mtpoly) {
/* for now we have to ensure texpoly and mloopuv layers are aligned
* in the future we may allow non-aligned layers */
BKE_mesh_cd_validate(mesh);
}
/* 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);
mesh->mr->edge_flags = newdataadr(fd, mesh->mr->edge_flags);
mesh->mr->edge_creases = newdataadr(fd, mesh->mr->edge_creases);
mesh->mr->verts = newdataadr(fd, mesh->mr->verts);
/* If mesh has the same number of vertices as the
* highest multires level, load the current mesh verts
* into multires and discard the old data. Needed
* because some saved files either do not have a verts
* array, or the verts array contains out-of-date
* data. */
if (mesh->totvert == ((MultiresLevel*)mesh->mr->levels.last)->totvert) {
if (mesh->mr->verts)
MEM_freeN(mesh->mr->verts);
mesh->mr->verts = MEM_dupallocN(mesh->mvert);
}
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);
}
}
/* if multires is present but has no valid vertex data,
* there's no way to recover it; silently remove multires */
if (mesh->mr && !mesh->mr->verts) {
multires_free(mesh->mr);
mesh->mr = NULL;
}
if ((fd->flags & FD_FLAGS_SWITCH_ENDIAN) && mesh->tface) {
TFace *tf = mesh->tface;
int i;
for (i = 0; i < mesh->totface; i++, tf++) {
BLI_endian_switch_uint32_array(tf->col, 4);
}
}
}
/* ************ READ LATTICE ***************** */
static void lib_link_latt(FileData *fd, Main *main)
{
Lattice *lt;
for (lt = main->latt.first; lt; lt = lt->id.next) {
if (lt->id.flag & LIB_NEED_LINK) {
if (lt->adt) lib_link_animdata(fd, &lt->id, lt->adt);
lt->ipo = newlibadr_us(fd, lt->id.lib, lt->ipo); // XXX deprecated - old animation system
lt->key = newlibadr_us(fd, lt->id.lib, lt->key);
lt->id.flag -= LIB_NEED_LINK;
}
}
}
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);
lt->editlatt = NULL;
lt->adt = newdataadr(fd, lt->adt);
direct_link_animdata(fd, lt->adt);
}
/* ************ 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;
for (ob = main->object.first; ob; ob = ob->id.next) {
if (ob->id.flag & LIB_NEED_LINK) {
if (ob->id.properties) IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
if (ob->adt) lib_link_animdata(fd, &ob->id, ob->adt);
// XXX deprecated - old animation system <<<
ob->ipo = newlibadr_us(fd, ob->id.lib, ob->ipo);
ob->action = newlibadr_us(fd, ob->id.lib, ob->action);
// >>> XXX deprecated - old animation system
ob->parent = newlibadr(fd, ob->id.lib, ob->parent);
ob->track = newlibadr(fd, ob->id.lib, ob->track);
ob->poselib = newlibadr_us(fd, ob->id.lib, ob->poselib);
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;
if (ob->id.lib)
printf("Proxy lost from object %s lib %s\n", ob->id.name + 2, ob->id.lib->name);
else
printf("Proxy lost from object %s lib <NONE>\n", ob->id.name + 2);
}
else {
/* this triggers object_update to always use a copy */
ob->proxy->proxy_from = ob;
}
}
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) {
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.\n", ob->id.name + 2);
ob->type = OB_EMPTY;
warn = 1;
if (ob->pose) {
/* we can't call #BKE_pose_free() here because of library linking
* freeing will recurse down into every pose constraints ID pointers
* which are not always valid, so for now free directly and suffer
* some leaked memory rather then crashing immediately
* while bad this _is_ an exceptional case - campbell */
#if 0
BKE_pose_free(ob->pose);
#else
MEM_freeN(ob->pose);
#endif
ob->pose= NULL;
ob->mode &= ~OB_MODE_POSE;
}
}
for (a=0; a < ob->totcol; a++)
ob->mat[a] = newlibadr_us(fd, ob->id.lib, ob->mat[a]);
/* When the object is local and the data is library its possible
* the material list size gets out of sync. [#22663] */
if (ob->data && ob->id.lib != ((ID *)ob->data)->lib) {
const short *totcol_data = give_totcolp(ob);
/* Only expand so as not to loose any object materials that might be set. */
if (totcol_data && (*totcol_data > ob->totcol)) {
/* printf("'%s' %d -> %d\n", ob->id.name, ob->totcol, *totcol_data); */
BKE_material_resize_object(ob, *totcol_data, false);
}
}
ob->gpd = newlibadr_us(fd, ob->id.lib, ob->gpd);
ob->duplilist = NULL;
ob->id.flag -= LIB_NEED_LINK;
/* 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, main, ob, ob->pose);
lib_link_constraints(fd, &ob->id, &ob->constraints);
// XXX deprecated - old animation system <<<
lib_link_constraint_channels(fd, &ob->id, &ob->constraintChannels);
lib_link_nlastrips(fd, &ob->id, &ob->nlastrips);
// >>> XXX deprecated - old animation system
for (paf = ob->effect.first; paf; paf = paf->next) {
if (paf->type == EFF_PARTICLE) {
paf->group = newlibadr_us(fd, ob->id.lib, paf->group);
}
}
for (sens = ob->sensors.first; sens; sens = sens->next) {
for (a = 0; a < sens->totlinks; a++)
sens->links[a] = newglobadr(fd, sens->links[a]);
if (sens->type == SENS_MESSAGE) {
bMessageSensor *ms = sens->data;
ms->fromObject =
newlibadr(fd, ob->id.lib, ms->fromObject);
}
}
for (cont = ob->controllers.first; cont; cont = cont->next) {
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;
}
for (act = ob->actuators.first; act; act = act->next) {
if (act->type == ACT_SOUND) {
bSoundActuator *sa = act->data;
sa->sound= newlibadr_us(fd, ob->id.lib, sa->sound);
}
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_OBJECT) {
bObjectActuator *oa = act->data;
if (oa == NULL) {
init_actuator(act);
}
else {
oa->reference = newlibadr(fd, ob->id.lib, oa->reference);
}
}
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_SHAPEACTION) {
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);
}
else if (act->type == ACT_2DFILTER) {
bTwoDFilterActuator *_2dfa = act->data;
_2dfa->text= newlibadr(fd, ob->id.lib, _2dfa->text);
}
else if (act->type == ACT_PARENT) {
bParentActuator *parenta = act->data;
parenta->ob = newlibadr(fd, ob->id.lib, parenta->ob);
}
else if (act->type == ACT_STATE) {
/* bStateActuator *statea = act->data; */
}
else if (act->type == ACT_ARMATURE) {
bArmatureActuator *arma= act->data;
arma->target= newlibadr(fd, ob->id.lib, arma->target);
arma->subtarget= newlibadr(fd, ob->id.lib, arma->subtarget);
}
else if (act->type == ACT_STEERING) {
bSteeringActuator *steeringa = act->data;
steeringa->target = newlibadr(fd, ob->id.lib, steeringa->target);
steeringa->navmesh = newlibadr(fd, ob->id.lib, steeringa->navmesh);
}
else if(act->type == ACT_MOUSE) {
/* bMouseActuator *moa= act->data; */
}
}
{
FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
if (fluidmd && fluidmd->fss)
fluidmd->fss->ipo = newlibadr_us(fd, ob->id.lib, fluidmd->fss->ipo);
}
{
SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke);
if (smd && (smd->type == MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
smd->domain->flags |= MOD_SMOKE_FILE_LOAD; /* flag for refreshing the simulation after loading */
}
}
/* texture field */
if (ob->pd)
lib_link_partdeflect(fd, &ob->id, ob->pd);
if (ob->soft)
ob->soft->effector_weights->group = newlibadr(fd, ob->id.lib, ob->soft->effector_weights->group);
lib_link_particlesystems(fd, ob, &ob->id, &ob->particlesystem);
lib_link_modifiers(fd, ob);
if (ob->rigidbody_constraint) {
ob->rigidbody_constraint->ob1 = newlibadr(fd, ob->id.lib, ob->rigidbody_constraint->ob1);
ob->rigidbody_constraint->ob2 = newlibadr(fd, ob->id.lib, ob->rigidbody_constraint->ob2);
}
{
LodLevel *level;
for (level = ob->lodlevels.first; level; level = level->next) {
level->source = newlibadr(fd, ob->id.lib, level->source);
if (!level->source && level == ob->lodlevels.first)
level->source = ob;
}
}
}
}
if (warn) {
BKE_report(fd->reports, RPT_WARNING, "Warning in console");
}
}
static void direct_link_pose(FileData *fd, bPose *pose)
{
bPoseChannel *pchan;
if (!pose)
return;
link_list(fd, &pose->chanbase);
link_list(fd, &pose->agroups);
pose->chanhash = NULL;
for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
pchan->bone = NULL;
pchan->parent = newdataadr(fd, pchan->parent);
pchan->child = newdataadr(fd, pchan->child);
pchan->custom_tx = newdataadr(fd, pchan->custom_tx);
direct_link_constraints(fd, &pchan->constraints);
pchan->prop = newdataadr(fd, pchan->prop);
IDP_DirectLinkGroup_OrFree(&pchan->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
pchan->mpath = newdataadr(fd, pchan->mpath);
if (pchan->mpath)
direct_link_motionpath(fd, pchan->mpath);
BLI_listbase_clear(&pchan->iktree);
BLI_listbase_clear(&pchan->siktree);
/* in case this value changes in future, clamp else we get undefined behavior */
CLAMP(pchan->rotmode, ROT_MODE_MIN, ROT_MODE_MAX);
}
pose->ikdata = NULL;
if (pose->ikparam != NULL) {
pose->ikparam = newdataadr(fd, pose->ikparam);
}
}
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;
md->scene = 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 = NULL;
}
else if (md->type == eModifierType_Armature) {
ArmatureModifierData *amd = (ArmatureModifierData *)md;
amd->prevCos = NULL;
}
else if (md->type == eModifierType_Cloth) {
ClothModifierData *clmd = (ClothModifierData *)md;
clmd->clothObject = NULL;
clmd->sim_parms= newdataadr(fd, clmd->sim_parms);
clmd->coll_parms= newdataadr(fd, clmd->coll_parms);
direct_link_pointcache_list(fd, &clmd->ptcaches, &clmd->point_cache, 0);
if (clmd->sim_parms) {
if (clmd->sim_parms->presets > 10)
clmd->sim_parms->presets = 0;
clmd->sim_parms->reset = 0;
clmd->sim_parms->effector_weights = newdataadr(fd, clmd->sim_parms->effector_weights);
if (!clmd->sim_parms->effector_weights) {
clmd->sim_parms->effector_weights = BKE_add_effector_weights(NULL);
}
}
}
else if (md->type == eModifierType_Fluidsim) {
FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
fluidmd->fss = newdataadr(fd, fluidmd->fss);
if (fluidmd->fss) {
fluidmd->fss->fmd = fluidmd;
fluidmd->fss->meshVelocities = NULL;
}
}
else if (md->type == eModifierType_Smoke) {
SmokeModifierData *smd = (SmokeModifierData *)md;
if (smd->type == MOD_SMOKE_TYPE_DOMAIN) {
smd->flow = NULL;
smd->coll = NULL;
smd->domain = newdataadr(fd, smd->domain);
smd->domain->smd = smd;
smd->domain->fluid = NULL;
smd->domain->fluid_mutex = BLI_rw_mutex_alloc();
smd->domain->wt = NULL;
smd->domain->shadow = NULL;
smd->domain->tex = NULL;
smd->domain->tex_shadow = NULL;
smd->domain->tex_wt = NULL;
smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights);
if (!smd->domain->effector_weights)
smd->domain->effector_weights = BKE_add_effector_weights(NULL);
direct_link_pointcache_list(fd, &(smd->domain->ptcaches[0]), &(smd->domain->point_cache[0]), 1);
/* Smoke uses only one cache from now on, so store pointer convert */
if (smd->domain->ptcaches[1].first || smd->domain->point_cache[1]) {
if (smd->domain->point_cache[1]) {
PointCache *cache = newdataadr(fd, smd->domain->point_cache[1]);
if (cache->flag & PTCACHE_FAKE_SMOKE) {
/* Smoke was already saved in "new format" and this cache is a fake one. */
}
else {
printf("High resolution smoke cache not available due to pointcache update. Please reset the simulation.\n");
}
BKE_ptcache_free(cache);
}
BLI_listbase_clear(&smd->domain->ptcaches[1]);
smd->domain->point_cache[1] = NULL;
}
}
else if (smd->type == MOD_SMOKE_TYPE_FLOW) {
smd->domain = NULL;
smd->coll = NULL;
smd->flow = newdataadr(fd, smd->flow);
smd->flow->smd = smd;
smd->flow->dm = NULL;
smd->flow->verts_old = NULL;
smd->flow->numverts = 0;
smd->flow->psys = newdataadr(fd, smd->flow->psys);
}
else if (smd->type == MOD_SMOKE_TYPE_COLL) {
smd->flow = NULL;
smd->domain = NULL;
smd->coll = newdataadr(fd, smd->coll);
if (smd->coll) {
smd->coll->smd = smd;
smd->coll->verts_old = NULL;
smd->coll->numverts = 0;
smd->coll->dm = NULL;
}
else {
smd->type = 0;
smd->flow = NULL;
smd->domain = NULL;
smd->coll = NULL;
}
}
}
else if (md->type == eModifierType_DynamicPaint) {
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
if (pmd->canvas) {
pmd->canvas = newdataadr(fd, pmd->canvas);
pmd->canvas->pmd = pmd;
pmd->canvas->dm = NULL;
pmd->canvas->flags &= ~MOD_DPAINT_BAKING; /* just in case */
if (pmd->canvas->surfaces.first) {
DynamicPaintSurface *surface;
link_list(fd, &pmd->canvas->surfaces);
for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next) {
surface->canvas = pmd->canvas;
surface->data = NULL;
direct_link_pointcache_list(fd, &(surface->ptcaches), &(surface->pointcache), 1);
if (!(surface->effector_weights = newdataadr(fd, surface->effector_weights)))
surface->effector_weights = BKE_add_effector_weights(NULL);
}
}
}
if (pmd->brush) {
pmd->brush = newdataadr(fd, pmd->brush);
pmd->brush->pmd = pmd;
pmd->brush->psys = newdataadr(fd, pmd->brush->psys);
pmd->brush->paint_ramp = newdataadr(fd, pmd->brush->paint_ramp);
pmd->brush->vel_ramp = newdataadr(fd, pmd->brush->vel_ramp);
pmd->brush->dm = NULL;
}
}
else if (md->type == eModifierType_Collision) {
CollisionModifierData *collmd = (CollisionModifierData *)md;
#if 0
// TODO: CollisionModifier should use pointcache
// + have proper reset events before enabling this
collmd->x = newdataadr(fd, collmd->x);
collmd->xnew = newdataadr(fd, collmd->xnew);
collmd->mfaces = newdataadr(fd, collmd->mfaces);
collmd->current_x = MEM_callocN(sizeof(MVert)*collmd->numverts, "current_x");
collmd->current_xnew = MEM_callocN(sizeof(MVert)*collmd->numverts, "current_xnew");
collmd->current_v = MEM_callocN(sizeof(MVert)*collmd->numverts, "current_v");
#endif
collmd->x = NULL;
collmd->xnew = NULL;
collmd->current_x = NULL;
collmd->current_xnew = NULL;
collmd->current_v = NULL;
collmd->time_x = collmd->time_xnew = -1000;
collmd->numverts = 0;
collmd->bvhtree = NULL;
collmd->mfaces = NULL;
}
else if (md->type == eModifierType_Surface) {
SurfaceModifierData *surmd = (SurfaceModifierData *)md;
surmd->dm = NULL;
surmd->bvhtree = NULL;
surmd->x = NULL;
surmd->v = NULL;
surmd->numverts = 0;
}
else if (md->type == eModifierType_Hook) {
HookModifierData *hmd = (HookModifierData *)md;
hmd->indexar = newdataadr(fd, hmd->indexar);
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
BLI_endian_switch_int32_array(hmd->indexar, hmd->totindex);
}
}
else if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
psmd->dm= NULL;
psmd->psys= newdataadr(fd, psmd->psys);
psmd->flag &= ~eParticleSystemFlag_psys_updated;
psmd->flag |= eParticleSystemFlag_file_loaded;
}
else if (md->type == eModifierType_Explode) {
ExplodeModifierData *psmd = (ExplodeModifierData *)md;
psmd->facepa = NULL;
}
else if (md->type == eModifierType_MeshDeform) {
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
mmd->bindinfluences = newdataadr(fd, mmd->bindinfluences);
mmd->bindoffsets = newdataadr(fd, mmd->bindoffsets);
mmd->bindcagecos = newdataadr(fd, mmd->bindcagecos);
mmd->dyngrid = newdataadr(fd, mmd->dyngrid);
mmd->dyninfluences = newdataadr(fd, mmd->dyninfluences);
mmd->dynverts = newdataadr(fd, mmd->dynverts);
mmd->bindweights = newdataadr(fd, mmd->bindweights);
mmd->bindcos = newdataadr(fd, mmd->bindcos);
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
if (mmd->bindoffsets) BLI_endian_switch_int32_array(mmd->bindoffsets, mmd->totvert + 1);
if (mmd->bindcagecos) BLI_endian_switch_float_array(mmd->bindcagecos, mmd->totcagevert * 3);
if (mmd->dynverts) BLI_endian_switch_int32_array(mmd->dynverts, mmd->totvert);
if (mmd->bindweights) BLI_endian_switch_float_array(mmd->bindweights, mmd->totvert);
if (mmd->bindcos) BLI_endian_switch_float_array(mmd->bindcos, mmd->totcagevert * 3);
}
}
else if (md->type == eModifierType_Ocean) {
OceanModifierData *omd = (OceanModifierData *)md;
omd->oceancache = NULL;
omd->ocean = NULL;
omd->refresh = (MOD_OCEAN_REFRESH_ADD|MOD_OCEAN_REFRESH_RESET|MOD_OCEAN_REFRESH_SIM);
}
else if (md->type == eModifierType_Warp) {
WarpModifierData *tmd = (WarpModifierData *)md;
tmd->curfalloff= newdataadr(fd, tmd->curfalloff);
if (tmd->curfalloff)
direct_link_curvemapping(fd, tmd->curfalloff);
}
else if (md->type == eModifierType_WeightVGEdit) {
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
wmd->cmap_curve = newdataadr(fd, wmd->cmap_curve);
if (wmd->cmap_curve)
direct_link_curvemapping(fd, wmd->cmap_curve);
}
else if (md->type == eModifierType_LaplacianDeform) {
LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md;
lmd->vertexco = newdataadr(fd, lmd->vertexco);
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
BLI_endian_switch_float_array(lmd->vertexco, lmd->total_verts * 3);
}
lmd->cache_system = NULL;
}
}
}
static void direct_link_object(FileData *fd, Object *ob)
{
PartEff *paf;
bProperty *prop;
bSensor *sens;
bController *cont;
bActuator *act;
/* weak weak... this was only meant as draw flag, now is used in give_base_to_objects too */
ob->flag &= ~OB_FROMGROUP;
/* This is a transient flag; clear in order to avoid unneeded object update pending from
* time when file was saved.
*/
ob->recalc = 0;
/* loading saved files with editmode enabled works, but for undo we like
* to stay in object mode during undo presses so keep editmode disabled.
*
* Also when linking in a file don't allow editmode: [#34776] */
if (fd->memfile || (ob->id.flag & (LIB_EXTERN | LIB_INDIRECT))) {
ob->mode &= ~(OB_MODE_EDIT | OB_MODE_PARTICLE_EDIT);
}
ob->adt = newdataadr(fd, ob->adt);
direct_link_animdata(fd, ob->adt);
ob->pose = newdataadr(fd, ob->pose);
direct_link_pose(fd, ob->pose);
ob->mpath = newdataadr(fd, ob->mpath);
if (ob->mpath)
direct_link_motionpath(fd, ob->mpath);
link_list(fd, &ob->defbase);
// XXX deprecated - old animation system <<<
direct_link_nlastrips(fd, &ob->nlastrips);
link_list(fd, &ob->constraintChannels);
// >>> XXX deprecated - old animation system
ob->mat= newdataadr(fd, ob->mat);
test_pointer_array(fd, (void **)&ob->mat);
ob->matbits= newdataadr(fd, ob->matbits);
/* 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);
direct_link_partdeflect(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;
/* although not used anymore */
/* still have to be loaded to be compatible with old files */
sb->keys = newdataadr(fd, sb->keys);
test_pointer_array(fd, (void **)&sb->keys);
if (sb->keys) {
int a;
for (a = 0; a < sb->totkey; a++) {
sb->keys[a] = newdataadr(fd, sb->keys[a]);
}
}
sb->effector_weights = newdataadr(fd, sb->effector_weights);
if (!sb->effector_weights)
sb->effector_weights = BKE_add_effector_weights(NULL);
direct_link_pointcache_list(fd, &sb->ptcaches, &sb->pointcache, 0);
}
ob->bsoft = newdataadr(fd, ob->bsoft);
ob->fluidsimSettings= newdataadr(fd, ob->fluidsimSettings); /* NT */
ob->rigidbody_object = newdataadr(fd, ob->rigidbody_object);
if (ob->rigidbody_object) {
RigidBodyOb *rbo = ob->rigidbody_object;
/* must nullify the references to physics sim objects, since they no-longer exist
* (and will need to be recalculated)
*/
rbo->physics_object = NULL;
rbo->physics_shape = NULL;
}
ob->rigidbody_constraint = newdataadr(fd, ob->rigidbody_constraint);
if (ob->rigidbody_constraint)
ob->rigidbody_constraint->physics_constraint = NULL;
link_list(fd, &ob->particlesystem);
direct_link_particlesystems(fd, &ob->particlesystem);
link_list(fd, &ob->prop);
for (prop = ob->prop.first; prop; prop = prop->next) {
prop->poin = newdataadr(fd, prop->poin);
if (prop->poin == NULL)
prop->poin = &prop->data;
}
link_list(fd, &ob->sensors);
for (sens = ob->sensors.first; sens; sens = sens->next) {
sens->data = newdataadr(fd, sens->data);
sens->links = newdataadr(fd, sens->links);
test_pointer_array(fd, (void **)&sens->links);
}
direct_link_constraints(fd, &ob->constraints);
link_glob_list(fd, &ob->controllers);
if (ob->init_state) {
/* if a known first state is specified, set it so that the game will start ok */
ob->state = ob->init_state;
}
else if (!ob->state) {
ob->state = 1;
}
for (cont = ob->controllers.first; cont; cont = cont->next) {
cont->data = newdataadr(fd, cont->data);
cont->links = newdataadr(fd, cont->links);
test_pointer_array(fd, (void **)&cont->links);
if (cont->state_mask == 0)
cont->state_mask = 1;
}
link_glob_list(fd, &ob->actuators);
for (act = ob->actuators.first; act; act = act->next) {
act->data = newdataadr(fd, act->data);
}
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) {
BLI_endian_switch_int32_array(hook->indexar, hook->totindex);
}
/* Do conversion here because if we have loaded
* a hook we need to make sure it gets converted
* and freed, regardless of version.
*/
copy_v3_v3(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);
modifier_unique_name(&ob->modifiers, (ModifierData*)hmd);
MEM_freeN(hook);
}
ob->iuser = newdataadr(fd, ob->iuser);
if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE && !ob->iuser) {
BKE_object_empty_draw_type_set(ob, ob->empty_drawtype);
}
ob->customdata_mask = 0;
ob->bb = NULL;
ob->derivedDeform = NULL;
ob->derivedFinal = NULL;
BLI_listbase_clear(&ob->gpulamp);
link_list(fd, &ob->pc_ids);
/* Runtime curve data */
ob->curve_cache = NULL;
/* in case this value changes in future, clamp else we get undefined behavior */
CLAMP(ob->rotmode, ROT_MODE_MIN, ROT_MODE_MAX);
if (ob->sculpt) {
ob->sculpt = MEM_callocN(sizeof(SculptSession), "reload sculpt session");
}
link_list(fd, &ob->lodlevels);
ob->currentlod = ob->lodlevels.first;
}
/* ************ READ SCENE ***************** */
/* patch for missing scene IDs, can't be in do-versions */
static void composite_patch(bNodeTree *ntree, Scene *scene)
{
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
if (node->id==NULL && node->type == CMP_NODE_R_LAYERS)
node->id = &scene->id;
}
}
static void link_paint(FileData *fd, Scene *sce, Paint *p)
{
if (p) {
p->brush = newlibadr_us(fd, sce->id.lib, p->brush);
p->palette = newlibadr_us(fd, sce->id.lib, p->palette);
p->paint_cursor = NULL;
}
}
static void lib_link_sequence_modifiers(FileData *fd, Scene *scene, ListBase *lb)
{
SequenceModifierData *smd;
for (smd = lb->first; smd; smd = smd->next) {
if (smd->mask_id)
smd->mask_id = newlibadr_us(fd, scene->id.lib, smd->mask_id);
}
}
/* check for cyclic set-scene,
* libs can cause this case which is normally prevented, see (T#####) */
#define USE_SETSCENE_CHECK
#ifdef USE_SETSCENE_CHECK
/**
* A version of #BKE_scene_validate_setscene with special checks for linked libs.
*/
static bool scene_validate_setscene__liblink(Scene *sce, const int totscene)
{
Scene *sce_iter;
int a;
if (sce->set == NULL) return 1;
for (a = 0, sce_iter = sce; sce_iter->set; sce_iter = sce_iter->set, a++) {
if (sce_iter->id.flag & LIB_NEED_LINK) {
return 1;
}
if (a > totscene) {
sce->set = NULL;
return 0;
}
}
return 1;
}
#endif
static void lib_link_scene(FileData *fd, Main *main)
{
Scene *sce;
Base *base, *next;
Sequence *seq;
SceneRenderLayer *srl;
TimeMarker *marker;
FreestyleModuleConfig *fmc;
FreestyleLineSet *fls;
#ifdef USE_SETSCENE_CHECK
bool need_check_set = false;
int totscene = 0;
#endif
for (sce = main->scene.first; sce; sce = sce->id.next) {
if (sce->id.flag & LIB_NEED_LINK) {
/* 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);
if (sce->adt) lib_link_animdata(fd, &sce->id, sce->adt);
lib_link_keyingsets(fd, &sce->id, &sce->keyingsets);
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->gpd = newlibadr_us(fd, sce->id.lib, sce->gpd);
link_paint(fd, sce, &sce->toolsettings->sculpt->paint);
link_paint(fd, sce, &sce->toolsettings->vpaint->paint);
link_paint(fd, sce, &sce->toolsettings->wpaint->paint);
link_paint(fd, sce, &sce->toolsettings->imapaint.paint);
link_paint(fd, sce, &sce->toolsettings->uvsculpt->paint);
if (sce->toolsettings->sculpt)
sce->toolsettings->sculpt->gravity_object =
newlibadr_us(fd, sce->id.lib, sce->toolsettings->sculpt->gravity_object);
if (sce->toolsettings->imapaint.stencil)
sce->toolsettings->imapaint.stencil =
newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.stencil);
if (sce->toolsettings->imapaint.clone)
sce->toolsettings->imapaint.clone =
newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.clone);
if (sce->toolsettings->imapaint.canvas)
sce->toolsettings->imapaint.canvas =
newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.canvas);
sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);
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);
if (base->object == NULL) {
blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB ERROR: object lost from scene: '%s'"),
sce->id.name + 2);
BLI_remlink(&sce->base, base);
if (base == sce->basact) sce->basact = NULL;
MEM_freeN(base);
}
}
SEQ_BEGIN (sce->ed, seq)
{
if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo);
seq->scene_sound = NULL;
if (seq->scene) {
seq->scene = newlibadr(fd, sce->id.lib, seq->scene);
if (seq->scene) {
seq->scene_sound = sound_scene_add_scene_sound_defaults(sce, seq);
}
}
if (seq->clip) {
seq->clip = newlibadr(fd, sce->id.lib, seq->clip);
if (seq->clip) {
seq->clip->id.us++;
}
}
if (seq->mask) {
seq->mask = newlibadr(fd, sce->id.lib, seq->mask);
if (seq->mask) {
seq->mask->id.us++;
}
}
if (seq->scene_camera) {
seq->scene_camera = newlibadr(fd, sce->id.lib, seq->scene_camera);
}
if (seq->sound) {
seq->scene_sound = NULL;
if (seq->type == SEQ_TYPE_SOUND_HD) {
seq->type = SEQ_TYPE_SOUND_RAM;
}
else {
seq->sound = newlibadr(fd, sce->id.lib, seq->sound);
}
if (seq->sound) {
seq->sound->id.us++;
seq->scene_sound = sound_add_scene_sound_defaults(sce, seq);
}
}
seq->anim = NULL;
lib_link_sequence_modifiers(fd, sce, &seq->modifiers);
}
SEQ_END
#ifdef DURIAN_CAMERA_SWITCH
for (marker = sce->markers.first; marker; marker = marker->next) {
if (marker->camera) {
marker->camera = newlibadr(fd, sce->id.lib, marker->camera);
}
}
#else
(void)marker;
#endif
BKE_sequencer_update_muting(sce->ed);
BKE_sequencer_update_sound_bounds_all(sce);
/* rigidbody world relies on it's linked groups */
if (sce->rigidbody_world) {
RigidBodyWorld *rbw = sce->rigidbody_world;
if (rbw->group)
rbw->group = newlibadr(fd, sce->id.lib, rbw->group);
if (rbw->constraints)
rbw->constraints = newlibadr(fd, sce->id.lib, rbw->constraints);
if (rbw->effector_weights)
rbw->effector_weights->group = newlibadr(fd, sce->id.lib, rbw->effector_weights->group);
}
if (sce->nodetree) {
lib_link_ntree(fd, &sce->id, sce->nodetree);
sce->nodetree->id.lib = sce->id.lib;
composite_patch(sce->nodetree, sce);
}
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);
for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
fmc->script = newlibadr(fd, sce->id.lib, fmc->script);
}
for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
fls->linestyle = newlibadr_us(fd, sce->id.lib, fls->linestyle);
fls->group = newlibadr_us(fd, sce->id.lib, fls->group);
}
}
/*Game Settings: Dome Warp Text*/
sce->gm.dome.warptext = newlibadr(fd, sce->id.lib, sce->gm.dome.warptext);
/* Motion Tracking */
sce->clip = newlibadr_us(fd, sce->id.lib, sce->clip);
#ifdef USE_SETSCENE_CHECK
if (sce->set != NULL) {
/* link flag for scenes with set would be reset later,
* so this way we only check cyclic for newly linked scenes.
*/
need_check_set = true;
}
else {
/* postpone un-setting the flag until we've checked the set-scene */
sce->id.flag &= ~LIB_NEED_LINK;
}
#else
sce->id.flag &= ~LIB_NEED_LINK;
#endif
}
#ifdef USE_SETSCENE_CHECK
totscene++;
#endif
}
#ifdef USE_SETSCENE_CHECK
if (need_check_set) {
for (sce = main->scene.first; sce; sce = sce->id.next) {
if (sce->id.flag & LIB_NEED_LINK) {
sce->id.flag &= ~LIB_NEED_LINK;
if (!scene_validate_setscene__liblink(sce, totscene)) {
printf("Found cyclic background scene when linking %s\n", sce->id.name + 2);
}
}
}
}
#endif
}
#undef USE_SETSCENE_CHECK
static void link_recurs_seq(FileData *fd, ListBase *lb)
{
Sequence *seq;
link_list(fd, lb);
for (seq = lb->first; seq; seq = seq->next) {
if (seq->seqbase.first)
link_recurs_seq(fd, &seq->seqbase);
}
}
static void direct_link_paint(FileData *fd, Paint **paint)
{
/* TODO. is this needed */
(*paint) = newdataadr(fd, (*paint));
if (*paint && (*paint)->num_input_samples < 1)
(*paint)->num_input_samples = 1;
}
static void direct_link_sequence_modifiers(FileData *fd, ListBase *lb)
{
SequenceModifierData *smd;
link_list(fd, lb);
for (smd = lb->first; smd; smd = smd->next) {
if (smd->mask_sequence)
smd->mask_sequence = newdataadr(fd, smd->mask_sequence);
if (smd->type == seqModifierType_Curves) {
CurvesModifierData *cmd = (CurvesModifierData *) smd;
direct_link_curvemapping(fd, &cmd->curve_mapping);
}
else if (smd->type == seqModifierType_HueCorrect) {
HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
direct_link_curvemapping(fd, &hcmd->curve_mapping);
}
}
}
static void direct_link_view_settings(FileData *fd, ColorManagedViewSettings *view_settings)
{
view_settings->curve_mapping = newdataadr(fd, view_settings->curve_mapping);
if (view_settings->curve_mapping)
direct_link_curvemapping(fd, view_settings->curve_mapping);
}
static void direct_link_scene(FileData *fd, Scene *sce)
{
Editing *ed;
Sequence *seq;
MetaStack *ms;
RigidBodyWorld *rbw;
SceneRenderLayer *srl;
sce->theDag = NULL;
sce->obedit = NULL;
sce->stats = NULL;
sce->fps_info = NULL;
sce->customdata_mask_modal = 0;
sce->lay_updated = 0;
sound_create_scene(sce);
/* 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->adt = newdataadr(fd, sce->adt);
direct_link_animdata(fd, sce->adt);
link_list(fd, &sce->keyingsets);
direct_link_keyingsets(fd, &sce->keyingsets);
sce->basact = newdataadr(fd, sce->basact);
sce->toolsettings= newdataadr(fd, sce->toolsettings);
if (sce->toolsettings) {
direct_link_paint(fd, (Paint**)&sce->toolsettings->sculpt);
direct_link_paint(fd, (Paint**)&sce->toolsettings->vpaint);
direct_link_paint(fd, (Paint**)&sce->toolsettings->wpaint);
direct_link_paint(fd, (Paint**)&sce->toolsettings->uvsculpt);
sce->toolsettings->imapaint.paintcursor = NULL;
sce->toolsettings->particle.paintcursor = NULL;
sce->toolsettings->particle.scene = NULL;
sce->toolsettings->particle.object = NULL;
/* in rare cases this is needed, see [#33806] */
if (sce->toolsettings->vpaint) {
sce->toolsettings->vpaint->vpaint_prev = NULL;
sce->toolsettings->vpaint->tot = 0;
}
if (sce->toolsettings->wpaint) {
sce->toolsettings->wpaint->wpaint_prev = NULL;
sce->toolsettings->wpaint->tot = 0;
}
}
if (sce->ed) {
ListBase *old_seqbasep = &sce->ed->seqbase;
ed = sce->ed = newdataadr(fd, sce->ed);
ed->act_seq = newdataadr(fd, ed->act_seq);
/* recursive link sequences, lb will be correctly initialized */
link_recurs_seq(fd, &ed->seqbase);
SEQ_BEGIN (ed, seq)
{
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 == NULL) seq->seq3 = seq->seq2;
seq->effectdata = newdataadr(fd, seq->effectdata);
if (seq->type & SEQ_TYPE_EFFECT)
seq->flag |= SEQ_EFFECT_NOT_LOADED;
if (seq->type == SEQ_TYPE_SPEED) {
SpeedControlVars *s = seq->effectdata;
s->frameMap = NULL;
}
seq->strip = newdataadr(fd, seq->strip);
if (seq->strip && seq->strip->done==0) {
seq->strip->done = true;
if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
seq->strip->stripdata = newdataadr(fd, seq->strip->stripdata);
}
else {
seq->strip->stripdata = NULL;
}
if (seq->flag & SEQ_USE_CROP) {
seq->strip->crop = newdataadr(
fd, seq->strip->crop);
}
else {
seq->strip->crop = NULL;
}
if (seq->flag & SEQ_USE_TRANSFORM) {
seq->strip->transform = newdataadr(
fd, seq->strip->transform);
}
else {
seq->strip->transform = NULL;
}
if (seq->flag & SEQ_USE_PROXY) {
seq->strip->proxy = newdataadr(
fd, seq->strip->proxy);
seq->strip->proxy->anim = NULL;
}
else {
seq->strip->proxy = NULL;
}
/* need to load color balance to it could be converted to modifier */
seq->strip->color_balance = newdataadr(fd, seq->strip->color_balance);
}
direct_link_sequence_modifiers(fd, &seq->modifiers);
}
SEQ_END
/* link metastack, slight abuse of structs here, have to restore pointer to internal part in struct */
{
Sequence temp;
char *poin;
intptr_t offset;
offset = ((intptr_t)&(temp.seqbase)) - ((intptr_t)&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;
}
}
}
}
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);
}
if (sce->r.ffcodecdata.properties) {
sce->r.ffcodecdata.properties = newdataadr(fd, sce->r.ffcodecdata.properties);
IDP_DirectLinkGroup_OrFree(&sce->r.ffcodecdata.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
link_list(fd, &(sce->markers));
link_list(fd, &(sce->transform_spaces));
link_list(fd, &(sce->r.layers));
for (srl = sce->r.layers.first; srl; srl = srl->next) {
link_list(fd, &(srl->freestyleConfig.modules));
}
for (srl = sce->r.layers.first; srl; srl = srl->next) {
link_list(fd, &(srl->freestyleConfig.linesets));
}
sce->nodetree = newdataadr(fd, sce->nodetree);
if (sce->nodetree) {
direct_link_id(fd, &sce->nodetree->id);
direct_link_nodetree(fd, sce->nodetree);
}
direct_link_view_settings(fd, &sce->view_settings);
sce->rigidbody_world = newdataadr(fd, sce->rigidbody_world);
rbw = sce->rigidbody_world;
if (rbw) {
/* must nullify the reference to physics sim object, since it no-longer exist
* (and will need to be recalculated)
*/
rbw->physics_world = NULL;
rbw->objects = NULL;
rbw->numbodies = 0;
/* set effector weights */
rbw->effector_weights = newdataadr(fd, rbw->effector_weights);
if (!rbw->effector_weights)
rbw->effector_weights = BKE_add_effector_weights(NULL);
/* link cache */
direct_link_pointcache_list(fd, &rbw->ptcaches, &rbw->pointcache, false);
/* make sure simulation starts from the beginning after loading file */
if (rbw->pointcache) {
rbw->ltime = (float)rbw->pointcache->startframe;
}
}
}
/* ************ READ WM ***************** */
static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
{
wmWindow *win;
wm->id.us = 1;
link_list(fd, &wm->windows);
for (win = wm->windows.first; win; win = win->next) {
win->ghostwin = NULL;
win->eventstate = NULL;
win->curswin = NULL;
win->tweak = NULL;
#ifdef WIN32
win->ime_data = NULL;
#endif
BLI_listbase_clear(&win->queue);
BLI_listbase_clear(&win->handlers);
BLI_listbase_clear(&win->modalhandlers);
BLI_listbase_clear(&win->subwindows);
BLI_listbase_clear(&win->gesture);
win->drawdata = NULL;
win->drawmethod = -1;
win->drawfail = 0;
win->active = 0;
win->cursor = 0;
win->lastcursor = 0;
win->modalcursor = 0;
}
BLI_listbase_clear(&wm->timers);
BLI_listbase_clear(&wm->operators);
BLI_listbase_clear(&wm->paintcursors);
BLI_listbase_clear(&wm->queue);
BKE_reports_init(&wm->reports, RPT_STORE);
BLI_listbase_clear(&wm->keyconfigs);
wm->defaultconf = NULL;
wm->addonconf = NULL;
wm->userconf = NULL;
BLI_listbase_clear(&wm->jobs);
BLI_listbase_clear(&wm->drags);
wm->windrawable = NULL;
wm->winactive = NULL;
wm->initialized = 0;
wm->op_undo_depth = 0;
wm->is_interface_locked = 0;
}
static void lib_link_windowmanager(FileData *fd, Main *main)
{
wmWindowManager *wm;
wmWindow *win;
for (wm = main->wm.first; wm; wm = wm->id.next) {
if (wm->id.flag & LIB_NEED_LINK) {
for (win = wm->windows.first; win; win = win->next)
win->screen = newlibadr(fd, NULL, win->screen);
wm->id.flag -= LIB_NEED_LINK;
}
}
}
/* ****************** READ GREASE PENCIL ***************** */
/* relink's grease pencil data's refs */
static void lib_link_gpencil(FileData *fd, Main *main)
{
bGPdata *gpd;
for (gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
if (gpd->id.flag & LIB_NEED_LINK) {
gpd->id.flag -= LIB_NEED_LINK;
if (gpd->adt)
lib_link_animdata(fd, &gpd->id, gpd->adt);
}
}
}
/* relinks grease-pencil data - used for direct_link and old file linkage */
static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
{
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
/* we must firstly have some grease-pencil data to link! */
if (gpd == NULL)
return;
/* relink animdata */
gpd->adt = newdataadr(fd, gpd->adt);
direct_link_animdata(fd, gpd->adt);
/* relink layers */
link_list(fd, &gpd->layers);
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* relink frames */
link_list(fd, &gpl->frames);
gpl->actframe = newdataadr(fd, gpl->actframe);
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
/* relink strokes (and their points) */
link_list(fd, &gpf->strokes);
for (gps = gpf->strokes.first; gps; gps = gps->next) {
gps->points = newdataadr(fd, gps->points);
}
}
}
}
/* ****************** 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_NEED_LINK) {
sc->id.us = 1;
sc->scene = newlibadr(fd, sc->id.lib, sc->scene);
sc->animtimer = NULL; /* saved in rare cases */
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
sa->full = newlibadr(fd, sc->id.lib, sa->full);
for (sl = sa->spacedata.first; sl; sl= sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D*) sl;
BGpic *bgpic = NULL;
v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera);
v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre);
/* should be do_versions but not easy adding into the listbase */
if (v3d->bgpic) {
v3d->bgpic = newlibadr(fd, sc->id.lib, v3d->bgpic);
BLI_addtail(&v3d->bgpicbase, bgpic);
v3d->bgpic = NULL;
}
for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
bgpic->ima = newlibadr_us(fd, sc->id.lib, bgpic->ima);
bgpic->clip = newlibadr_us(fd, sc->id.lib, bgpic->clip);
}
if (v3d->localvd) {
v3d->localvd->camera = newlibadr(fd, sc->id.lib, v3d->localvd->camera);
}
}
else if (sl->spacetype == SPACE_IPO) {
SpaceIpo *sipo = (SpaceIpo *)sl;
bDopeSheet *ads = sipo->ads;
if (ads) {
ads->source = newlibadr(fd, sc->id.lib, ads->source);
ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
}
}
else if (sl->spacetype == SPACE_BUTS) {
SpaceButs *sbuts = (SpaceButs *)sl;
sbuts->pinid = newlibadr(fd, sc->id.lib, sbuts->pinid);
}
else if (sl->spacetype == SPACE_FILE) {
;
}
else if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
bDopeSheet *ads = &saction->ads;
if (ads) {
ads->source = newlibadr(fd, sc->id.lib, ads->source);
ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
}
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);
sima->mask_info.mask = newlibadr_us(fd, sc->id.lib, sima->mask_info.mask);
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so fingers crossed this works fine!
*/
sima->gpd = newlibadr_us(fd, sc->id.lib, sima->gpd);
}
else if (sl->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)sl;
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so fingers crossed this works fine!
*/
sseq->gpd = newlibadr_us(fd, sc->id.lib, sseq->gpd);
}
else if (sl->spacetype == SPACE_NLA) {
SpaceNla *snla= (SpaceNla *)sl;
bDopeSheet *ads= snla->ads;
if (ads) {
ads->source = newlibadr(fd, sc->id.lib, ads->source);
ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
}
}
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 *scpt = (SpaceScript *)sl;
/*scpt->script = NULL; - 2.45 set to null, better re-run the script */
if (scpt->script) {
scpt->script = newlibadr(fd, sc->id.lib, scpt->script);
if (scpt->script) {
SCRIPT_SET_NULL(scpt->script);
}
}
}
else if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *so= (SpaceOops *)sl;
so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id);
if (so->treestore) {
TreeStoreElem *tselem;
BLI_mempool_iter iter;
BLI_mempool_iternew(so->treestore, &iter);
while ((tselem = BLI_mempool_iterstep(&iter))) {
tselem->id = newlibadr(fd, NULL, tselem->id);
}
if (so->treehash) {
/* rebuild hash table, because it depends on ids too */
BKE_treehash_rebuild_from_treestore(so->treehash, so->treestore);
}
}
}
else if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
bNodeTreePath *path, *path_next;
bNodeTree *ntree;
/* node tree can be stored locally in id too, link this first */
snode->id = newlibadr(fd, sc->id.lib, snode->id);
snode->from = newlibadr(fd, sc->id.lib, snode->from);
ntree = nodetree_from_id(snode->id);
if (ntree)
snode->nodetree = ntree;
else {
snode->nodetree = newlibadr_us(fd, sc->id.lib, snode->nodetree);
}
for (path = snode->treepath.first; path; path = path->next) {
if (path == snode->treepath.first) {
/* first nodetree in path is same as snode->nodetree */
path->nodetree = snode->nodetree;
}
else
path->nodetree = newlibadr_us(fd, sc->id.lib, path->nodetree);
if (!path->nodetree)
break;
}
/* remaining path entries are invalid, remove */
for (; path; path = path_next) {
path_next = path->next;
BLI_remlink(&snode->treepath, path);
MEM_freeN(path);
}
/* edittree is just the last in the path,
* set this directly since the path may have been shortened above */
if (snode->treepath.last) {
path = snode->treepath.last;
snode->edittree = path->nodetree;
}
else
snode->edittree = NULL;
}
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
sclip->clip = newlibadr_us(fd, sc->id.lib, sclip->clip);
sclip->mask_info.mask = newlibadr_us(fd, sc->id.lib, sclip->mask_info.mask);
}
else if (sl->spacetype == SPACE_LOGIC) {
SpaceLogic *slogic = (SpaceLogic *)sl;
slogic->gpd = newlibadr_us(fd, sc->id.lib, slogic->gpd);
}
}
}
sc->id.flag -= LIB_NEED_LINK;
}
}
}
/* how to handle user count on pointer restore */
typedef enum ePointerUserMode {
USER_IGNORE = 0, /* ignore user count */
USER_ONE = 1, /* ensure at least one user (fake also counts) */
USER_REAL = 2, /* ensure at least one real user (fake user ignored) */
} ePointerUserMode;
static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user)
{
if (strcmp(newid->name + 2, id->name + 2) == 0) {
if (newid->lib == id->lib) {
if (user == USER_ONE) {
if (newid->us == 0) {
newid->us++;
}
}
else if (user == USER_REAL) {
id_us_ensure_real(newid);
}
return true;
}
}
return false;
}
/**
* Only for undo files, or to restore a screen after reading without UI...
*
* user
* - USER_IGNORE: no usercount change
* - USER_ONE: ensure a user
* - USER_REAL: ensure a real user (even if a fake one is set)
*/
static void *restore_pointer_by_name(Main *mainp, ID *id, ePointerUserMode user)
{
if (id) {
ListBase *lb = which_libbase(mainp, GS(id->name));
if (lb) { // there's still risk of checking corrupt mem (freed Ids in oops)
ID *idn = lb->first;
for (; idn; idn = idn->next) {
if (restore_pointer(id, idn, user))
break;
}
return idn;
}
}
return NULL;
}
static void lib_link_seq_clipboard_pt_restore(ID *id, Main *newmain)
{
if (id) {
/* clipboard must ensure this */
BLI_assert(id->newid != NULL);
id->newid = restore_pointer_by_name(newmain, (ID *)id->newid, USER_ONE);
}
}
static int lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt)
{
Main *newmain = (Main *)arg_pt;
lib_link_seq_clipboard_pt_restore((ID *)seq->scene, newmain);
lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, newmain);
lib_link_seq_clipboard_pt_restore((ID *)seq->clip, newmain);
lib_link_seq_clipboard_pt_restore((ID *)seq->mask, newmain);
lib_link_seq_clipboard_pt_restore((ID *)seq->sound, newmain);
return 1;
}
static void lib_link_clipboard_restore(Main *newmain)
{
/* update IDs stored in sequencer clipboard */
BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, newmain);
}
/* 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 blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *curscene)
{
wmWindow *win;
wmWindowManager *wm;
bScreen *sc;
ScrArea *sa;
/* first windowmanager */
for (wm = newmain->wm.first; wm; wm = wm->id.next) {
for (win= wm->windows.first; win; win= win->next) {
win->screen = restore_pointer_by_name(newmain, (ID *)win->screen, USER_ONE);
if (win->screen == NULL)
win->screen = curscreen;
win->screen->winid = win->winid;
}
}
for (sc = newmain->screen.first; sc; sc = sc->id.next) {
Scene *oldscene = sc->scene;
sc->scene= restore_pointer_by_name(newmain, (ID *)sc->scene, USER_ONE);
if (sc->scene == NULL)
sc->scene = curscene;
/* keep cursor location through undo */
copy_v3_v3(sc->scene->cursor, oldscene->cursor);
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;
BGpic *bgpic;
ARegion *ar;
if (v3d->scenelock)
v3d->camera = NULL; /* always get from scene */
else
v3d->camera = restore_pointer_by_name(newmain, (ID *)v3d->camera, USER_ONE);
if (v3d->camera == NULL)
v3d->camera = sc->scene->camera;
v3d->ob_centre = restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, USER_ONE);
for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) {
if ((bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_IGNORE))) {
id_us_plus((ID *)bgpic->ima);
}
if ((bgpic->clip = restore_pointer_by_name(newmain, (ID *)bgpic->clip, USER_IGNORE))) {
id_us_plus((ID *)bgpic->clip);
}
}
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 */
#if 0 /* XXX regionlocalview ? */
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;
}
#endif
}
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;
/* free render engines for now */
for (ar = sa->regionbase.first; ar; ar = ar->next) {
RegionView3D *rv3d= ar->regiondata;
if (rv3d && rv3d->render_engine) {
RE_engine_free(rv3d->render_engine);
rv3d->render_engine = NULL;
}
}
}
else if (sl->spacetype == SPACE_IPO) {
SpaceIpo *sipo = (SpaceIpo *)sl;
bDopeSheet *ads = sipo->ads;
if (ads) {
ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_ONE);
if (ads->filter_grp)
ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE);
}
/* force recalc of list of channels (i.e. includes calculating F-Curve colors)
* thus preventing the "black curves" problem post-undo
*/
sipo->flag |= SIPO_TEMP_NEEDCHANSYNC;
}
else if (sl->spacetype == SPACE_BUTS) {
SpaceButs *sbuts = (SpaceButs *)sl;
sbuts->pinid = restore_pointer_by_name(newmain, sbuts->pinid, USER_IGNORE);
/* TODO: restore path pointers: T40046
* (complicated because this contains data pointers too, not just ID)*/
MEM_SAFE_FREE(sbuts->path);
}
else if (sl->spacetype == SPACE_FILE) {
SpaceFile *sfile = (SpaceFile *)sl;
sfile->op = NULL;
}
else if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, USER_ONE);
saction->ads.source = restore_pointer_by_name(newmain, (ID *)saction->ads.source, USER_ONE);
if (saction->ads.filter_grp)
saction->ads.filter_grp = restore_pointer_by_name(newmain, (ID *)saction->ads.filter_grp, USER_IGNORE);
/* force recalc of list of channels, potentially updating the active action
* while we're at it (as it can only be updated that way) [#28962]
*/
saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
}
else if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
sima->image = restore_pointer_by_name(newmain, (ID *)sima->image, USER_REAL);
/* this will be freed, not worth attempting to find same scene,
* since it gets initialized later */
sima->iuser.scene = NULL;
sima->scopes.waveform_1 = NULL;
sima->scopes.waveform_2 = NULL;
sima->scopes.waveform_3 = NULL;
sima->scopes.vecscope = NULL;
sima->scopes.ok = 0;
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so assume that here we're doing for undo only...
*/
sima->gpd = restore_pointer_by_name(newmain, (ID *)sima->gpd, USER_ONE);
sima->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sima->mask_info.mask, USER_REAL);
}
else if (sl->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)sl;
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so assume that here we're doing for undo only...
*/
sseq->gpd = restore_pointer_by_name(newmain, (ID *)sseq->gpd, USER_ONE);
}
else if (sl->spacetype == SPACE_NLA) {
SpaceNla *snla = (SpaceNla *)sl;
bDopeSheet *ads = snla->ads;
if (ads) {
ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_ONE);
if (ads->filter_grp)
ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE);
}
}
else if (sl->spacetype == SPACE_TEXT) {
SpaceText *st = (SpaceText *)sl;
st->text = restore_pointer_by_name(newmain, (ID *)st->text, USER_ONE);
if (st->text == NULL) st->text = newmain->text.first;
}
else if (sl->spacetype == SPACE_SCRIPT) {
SpaceScript *scpt = (SpaceScript *)sl;
scpt->script = restore_pointer_by_name(newmain, (ID *)scpt->script, USER_ONE);
/*sc->script = NULL; - 2.45 set to null, better re-run the script */
if (scpt->script) {
SCRIPT_SET_NULL(scpt->script);
}
}
else if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *so= (SpaceOops *)sl;
so->search_tse.id = restore_pointer_by_name(newmain, so->search_tse.id, USER_IGNORE);
if (so->treestore) {
TreeStoreElem *tselem;
BLI_mempool_iter iter;
BLI_mempool_iternew(so->treestore, &iter);
while ((tselem = BLI_mempool_iterstep(&iter))) {
tselem->id = restore_pointer_by_name(newmain, tselem->id, USER_IGNORE);
}
if (so->treehash) {
/* rebuild hash table, because it depends on ids too */
BKE_treehash_rebuild_from_treestore(so->treehash, so->treestore);
}
}
}
else if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode= (SpaceNode *)sl;
bNodeTreePath *path, *path_next;
bNodeTree *ntree;
/* node tree can be stored locally in id too, link this first */
snode->id = restore_pointer_by_name(newmain, snode->id, USER_ONE);
snode->from = restore_pointer_by_name(newmain, snode->from, USER_IGNORE);
ntree = nodetree_from_id(snode->id);
if (ntree)
snode->nodetree = ntree;
else
snode->nodetree = restore_pointer_by_name(newmain, (ID*)snode->nodetree, USER_REAL);
for (path = snode->treepath.first; path; path = path->next) {
if (path == snode->treepath.first) {
/* first nodetree in path is same as snode->nodetree */
path->nodetree = snode->nodetree;
}
else
path->nodetree= restore_pointer_by_name(newmain, (ID*)path->nodetree, USER_REAL);
if (!path->nodetree)
break;
}
/* remaining path entries are invalid, remove */
for (; path; path = path_next) {
path_next = path->next;
BLI_remlink(&snode->treepath, path);
MEM_freeN(path);
}
/* edittree is just the last in the path,
* set this directly since the path may have been shortened above */
if (snode->treepath.last) {
path = snode->treepath.last;
snode->edittree = path->nodetree;
}
else
snode->edittree = NULL;
}
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
sclip->clip = restore_pointer_by_name(newmain, (ID *)sclip->clip, USER_REAL);
sclip->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sclip->mask_info.mask, USER_REAL);
sclip->scopes.ok = 0;
}
else if (sl->spacetype == SPACE_LOGIC) {
SpaceLogic *slogic = (SpaceLogic *)sl;
slogic->gpd = restore_pointer_by_name(newmain, (ID *)slogic->gpd, USER_ONE);
}
}
}
}
/* update IDs stored in all possible clipboards */
lib_link_clipboard_restore(newmain);
}
static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
{
Panel *pa;
uiList *ui_list;
link_list(fd, &ar->panels);
for (pa = ar->panels.first; pa; pa = pa->next) {
pa->paneltab = newdataadr(fd, pa->paneltab);
pa->runtime_flag = 0;
pa->activedata = NULL;
pa->type = NULL;
}
link_list(fd, &ar->panels_category_active);
link_list(fd, &ar->ui_lists);
for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) {
ui_list->type = NULL;
ui_list->dyn_data = NULL;
ui_list->properties = newdataadr(fd, ui_list->properties);
IDP_DirectLinkGroup_OrFree(&ui_list->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
link_list(fd, &ar->ui_previews);
if (spacetype == SPACE_EMPTY) {
/* unkown space type, don't leak regiondata */
ar->regiondata = NULL;
}
else {
ar->regiondata = newdataadr(fd, ar->regiondata);
if (ar->regiondata) {
if (spacetype == SPACE_VIEW3D) {
RegionView3D *rv3d = ar->regiondata;
rv3d->localvd = newdataadr(fd, rv3d->localvd);
rv3d->clipbb = newdataadr(fd, rv3d->clipbb);
rv3d->depths = NULL;
rv3d->gpuoffscreen = NULL;
rv3d->render_engine = NULL;
rv3d->sms = NULL;
rv3d->smooth_timer = NULL;
}
}
}
ar->v2d.tab_offset = NULL;
ar->v2d.tab_num = 0;
ar->v2d.tab_cur = 0;
ar->v2d.sms = NULL;
BLI_listbase_clear(&ar->panels_category);
BLI_listbase_clear(&ar->handlers);
BLI_listbase_clear(&ar->uiblocks);
ar->headerstr = NULL;
ar->swinid = 0;
ar->type = NULL;
ar->swap = 0;
ar->do_draw = 0;
ar->regiontimer = NULL;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
}
/* for the saved 2.50 files without regiondata */
/* and as patch for 2.48 and older */
void blo_do_versions_view3d_split_250(View3D *v3d, ListBase *regions)
{
ARegion *ar;
for (ar = regions->first; ar; ar = ar->next) {
if (ar->regiontype==RGN_TYPE_WINDOW && ar->regiondata==NULL) {
RegionView3D *rv3d;
rv3d = ar->regiondata = MEM_callocN(sizeof(RegionView3D), "region v3d patch");
rv3d->persp = (char)v3d->persp;
rv3d->view = (char)v3d->view;
rv3d->dist = v3d->dist;
copy_v3_v3(rv3d->ofs, v3d->ofs);
copy_qt_qt(rv3d->viewquat, v3d->viewquat);
}
}
/* this was not initialized correct always */
if (v3d->twtype == 0)
v3d->twtype = V3D_MANIP_TRANSLATE;
}
static bool direct_link_screen(FileData *fd, bScreen *sc)
{
ScrArea *sa;
ScrVert *sv;
ScrEdge *se;
bool wrong_id = false;
link_list(fd, &(sc->vertbase));
link_list(fd, &(sc->edgebase));
link_list(fd, &(sc->areabase));
sc->regionbase.first = sc->regionbase.last= NULL;
sc->context = NULL;
sc->mainwin = sc->subwinactive= 0; /* indices */
sc->swap = 0;
/* edges */
for (se = sc->edgebase.first; se; se = se->next) {
se->v1 = newdataadr(fd, se->v1);
se->v2 = newdataadr(fd, se->v2);
if ((intptr_t)se->v1 > (intptr_t)se->v2) {
sv = se->v1;
se->v1 = se->v2;
se->v2 = sv;
}
if (se->v1 == NULL) {
printf("Error reading Screen %s... removing it.\n", sc->id.name+2);
BLI_remlink(&sc->edgebase, se);
wrong_id = true;
}
}
/* areas */
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
ARegion *ar;
link_list(fd, &(sa->spacedata));
link_list(fd, &(sa->regionbase));
BLI_listbase_clear(&sa->handlers);
sa->type = NULL; /* spacetype callbacks */
sa->region_active_win = -1;
/* if we do not have the spacetype registered (game player), we cannot
* free it, so don't allocate any new memory for such spacetypes. */
if (!BKE_spacetype_exists(sa->spacetype))
sa->spacetype = SPACE_EMPTY;
for (ar = sa->regionbase.first; ar; ar = ar->next)
direct_link_region(fd, ar, sa->spacetype);
/* accident can happen when read/save new file with older version */
/* 2.50: we now always add spacedata for info */
if (sa->spacedata.first==NULL) {
SpaceInfo *sinfo= MEM_callocN(sizeof(SpaceInfo), "spaceinfo");
sa->spacetype= sinfo->spacetype= SPACE_INFO;
BLI_addtail(&sa->spacedata, sinfo);
}
/* add local view3d too */
else if (sa->spacetype == SPACE_VIEW3D)
blo_do_versions_view3d_split_250(sa->spacedata.first, &sa->regionbase);
/* incase we set above */
sa->butspacetype = sa->spacetype;
for (sl = sa->spacedata.first; sl; sl = sl->next) {
link_list(fd, &(sl->regionbase));
/* if we do not have the spacetype registered (game player), we cannot
* free it, so don't allocate any new memory for such spacetypes. */
if (!BKE_spacetype_exists(sl->spacetype))
sl->spacetype = SPACE_EMPTY;
for (ar = sl->regionbase.first; ar; ar = ar->next)
direct_link_region(fd, ar, sl->spacetype);
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d= (View3D*) sl;
BGpic *bgpic;
v3d->flag |= V3D_INVALID_BACKBUF;
link_list(fd, &v3d->bgpicbase);
/* should be do_versions except this doesnt fit well there */
if (v3d->bgpic) {
bgpic = newdataadr(fd, v3d->bgpic);
BLI_addtail(&v3d->bgpicbase, bgpic);
v3d->bgpic = NULL;
}
for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next)
bgpic->iuser.ok = 1;
if (v3d->gpd) {
v3d->gpd = newdataadr(fd, v3d->gpd);
direct_link_gpencil(fd, v3d->gpd);
}
v3d->localvd = newdataadr(fd, v3d->localvd);
BLI_listbase_clear(&v3d->afterdraw_transp);
BLI_listbase_clear(&v3d->afterdraw_xray);
BLI_listbase_clear(&v3d->afterdraw_xraytransp);
v3d->properties_storage = NULL;
v3d->defmaterial = NULL;
/* render can be quite heavy, set to solid on load */
if (v3d->drawtype == OB_RENDER)
v3d->drawtype = OB_SOLID;
blo_do_versions_view3d_split_250(v3d, &sl->regionbase);
}
else if (sl->spacetype == SPACE_IPO) {
SpaceIpo *sipo = (SpaceIpo *)sl;
sipo->ads = newdataadr(fd, sipo->ads);
BLI_listbase_clear(&sipo->ghostCurves);
}
else if (sl->spacetype == SPACE_NLA) {
SpaceNla *snla = (SpaceNla *)sl;
snla->ads = newdataadr(fd, snla->ads);
}
else if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *soops = (SpaceOops *) sl;
/* use newdataadr_no_us and do not free old memory avoiding double
* frees and use of freed memory. this could happen because of a
* bug fixed in revision 58959 where the treestore memory address
* was not unique */
TreeStore *ts = newdataadr_no_us(fd, soops->treestore);
soops->treestore = NULL;
if (ts) {
TreeStoreElem *elems = newdataadr_no_us(fd, ts->data);
soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), ts->usedelem,
512, BLI_MEMPOOL_ALLOW_ITER);
if (ts->usedelem && elems) {
int i;
for (i = 0; i < ts->usedelem; i++) {
TreeStoreElem *new_elem = BLI_mempool_alloc(soops->treestore);
*new_elem = elems[i];
}
}
/* we only saved what was used */
soops->storeflag |= SO_TREESTORE_CLEANUP; // at first draw
}
soops->treehash = NULL;
soops->tree.first = soops->tree.last= NULL;
}
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->iuser.scene = NULL;
sima->iuser.ok = 1;
sima->scopes.waveform_1 = NULL;
sima->scopes.waveform_2 = NULL;
sima->scopes.waveform_3 = NULL;
sima->scopes.vecscope = NULL;
sima->scopes.ok = 0;
/* WARNING: gpencil data is no longer stored directly in sima after 2.5
* so sacrifice a few old files for now to avoid crashes with new files!
* committed: r28002 */
#if 0
sima->gpd = newdataadr(fd, sima->gpd);
if (sima->gpd)
direct_link_gpencil(fd, sima->gpd);
#endif
}
else if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
if (snode->gpd) {
snode->gpd = newdataadr(fd, snode->gpd);
direct_link_gpencil(fd, snode->gpd);
}
link_list(fd, &snode->treepath);
snode->edittree = NULL;
BLI_listbase_clear(&snode->linkdrag);
}
else if (sl->spacetype == SPACE_TEXT) {
SpaceText *st= (SpaceText *)sl;
st->drawcache = NULL;
st->scroll_accum[0] = 0.0f;
st->scroll_accum[1] = 0.0f;
}
else if (sl->spacetype == SPACE_TIME) {
SpaceTime *stime = (SpaceTime *)sl;
BLI_listbase_clear(&stime->caches);
}
else if (sl->spacetype == SPACE_LOGIC) {
SpaceLogic *slogic = (SpaceLogic *)sl;
/* XXX: this is new stuff, which shouldn't be directly linking to gpd... */
if (slogic->gpd) {
slogic->gpd = newdataadr(fd, slogic->gpd);
direct_link_gpencil(fd, slogic->gpd);
}
}
else if (sl->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)sl;
/* grease pencil data is not a direct data and can't be linked from direct_link*
* functions, it should be linked from lib_link* functions instead
*
* otherwise it'll lead to lost grease data on open because it'll likely be
* read from file after all other users of grease pencil and newdataadr would
* simple return NULL here (sergey)
*/
#if 0
if (sseq->gpd) {
sseq->gpd = newdataadr(fd, sseq->gpd);
direct_link_gpencil(fd, sseq->gpd);
}
#endif
sseq->scopes.reference_ibuf = NULL;
sseq->scopes.zebra_ibuf = NULL;
sseq->scopes.waveform_ibuf = NULL;
sseq->scopes.sep_waveform_ibuf = NULL;
sseq->scopes.vector_ibuf = NULL;
sseq->scopes.histogram_ibuf = NULL;
}
else if (sl->spacetype == SPACE_BUTS) {
SpaceButs *sbuts = (SpaceButs *)sl;
sbuts->path= NULL;
sbuts->texuser= NULL;
sbuts->mainbo = sbuts->mainb;
sbuts->mainbuser = sbuts->mainb;
}
else if (sl->spacetype == SPACE_CONSOLE) {
SpaceConsole *sconsole = (SpaceConsole *)sl;
ConsoleLine *cl, *cl_next;
link_list(fd, &sconsole->scrollback);
link_list(fd, &sconsole->history);
//for (cl= sconsole->scrollback.first; cl; cl= cl->next)
// cl->line= newdataadr(fd, cl->line);
/* comma expressions, (e.g. expr1, expr2, expr3) evaluate each expression,
* from left to right. the right-most expression sets the result of the comma
* expression as a whole*/
for (cl = sconsole->history.first; cl; cl = cl_next) {
cl_next = cl->next;
cl->line = newdataadr(fd, cl->line);
if (cl->line) {
/* the allocted length is not written, so reset here */
cl->len_alloc = cl->len + 1;
}
else {
BLI_remlink(&sconsole->history, cl);
MEM_freeN(cl);
}
}
}
else if (sl->spacetype == SPACE_FILE) {
SpaceFile *sfile = (SpaceFile *)sl;
/* this sort of info is probably irrelevant for reloading...
* plus, it isn't saved to files yet!
*/
sfile->folders_prev = sfile->folders_next = NULL;
sfile->files = NULL;
sfile->layout = NULL;
sfile->op = NULL;
sfile->params = newdataadr(fd, sfile->params);
}
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
sclip->scopes.track_search = NULL;
sclip->scopes.track_preview = NULL;
sclip->scopes.ok = 0;
}
}
BLI_listbase_clear(&sa->actionzones);
sa->v1 = newdataadr(fd, sa->v1);
sa->v2 = newdataadr(fd, sa->v2);
sa->v3 = newdataadr(fd, sa->v3);
sa->v4 = newdataadr(fd, sa->v4);
}
return wrong_id;
}
/* ********** READ LIBRARY *************** */
static void direct_link_library(FileData *fd, Library *lib, Main *main)
{
Main *newmain;
/* check if the library was already read */
for (newmain = fd->mainlist->first; newmain; newmain = newmain->next) {
if (newmain->curlib) {
if (BLI_path_cmp(newmain->curlib->filepath, lib->filepath) == 0) {
blo_reportf_wrap(fd->reports, RPT_WARNING,
TIP_("Library '%s', '%s' had multiple instances, save and reload!"),
lib->name, lib->filepath);
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);
return;
}
}
}
/* make sure we have full path in lib->filepath */
BLI_strncpy(lib->filepath, lib->name, sizeof(lib->name));
BLI_cleanup_path(fd->relabase, lib->filepath);
// printf("direct_link_library: name %s\n", lib->name);
// printf("direct_link_library: filepath %s\n", lib->filepath);
lib->packedfile = direct_link_packedfile(fd, lib->packedfile);
/* new main */
newmain = BKE_main_new();
BLI_addtail(fd->mainlist, newmain);
newmain->curlib = lib;
lib->parent = NULL;
}
static void lib_link_library(FileData *UNUSED(fd), Main *main)
{
Library *lib;
for (lib = main->library.first; lib; lib = lib->id.next) {
lib->id.us = 1;
}
}
/* Always call this once you have loaded new library data to set the relative paths correctly in relation to the blend file */
static void fix_relpaths_library(const char *basepath, Main *main)
{
Library *lib;
/* BLO_read_from_memory uses a blank filename */
if (basepath == NULL || basepath[0] == '\0') {
for (lib = main->library.first; lib; lib= lib->id.next) {
/* when loading a linked lib into a file which has not been saved,
* there is nothing we can be relative to, so instead we need to make
* it absolute. This can happen when appending an object with a relative
* link into an unsaved blend file. See [#27405].
* The remap relative option will make it relative again on save - campbell */
if (BLI_path_is_rel(lib->name)) {
BLI_strncpy(lib->name, lib->filepath, sizeof(lib->name));
}
}
}
else {
for (lib = main->library.first; lib; lib = lib->id.next) {
/* Libraries store both relative and abs paths, recreate relative paths,
* relative to the blend file since indirectly linked libs will be relative to their direct linked library */
if (BLI_path_is_rel(lib->name)) { /* if this is relative to begin with? */
BLI_strncpy(lib->name, lib->filepath, sizeof(lib->name));
BLI_path_rel(lib->name, basepath);
}
}
}
}
/* ************ READ SPEAKER ***************** */
static void lib_link_speaker(FileData *fd, Main *main)
{
Speaker *spk;
for (spk = main->speaker.first; spk; spk = spk->id.next) {
if (spk->id.flag & LIB_NEED_LINK) {
if (spk->adt) lib_link_animdata(fd, &spk->id, spk->adt);
spk->sound= newlibadr(fd, spk->id.lib, spk->sound);
if (spk->sound) {
spk->sound->id.us++;
}
spk->id.flag -= LIB_NEED_LINK;
}
}
}
static void direct_link_speaker(FileData *fd, Speaker *spk)
{
spk->adt = newdataadr(fd, spk->adt);
direct_link_animdata(fd, spk->adt);
#if 0
spk->sound = newdataadr(fd, spk->sound);
direct_link_sound(fd, spk->sound);
#endif
}
/* ************** READ SOUND ******************* */
static void direct_link_sound(FileData *fd, bSound *sound)
{
sound->handle = NULL;
sound->playback_handle = NULL;
/* versioning stuff, if there was a cache, then we enable caching: */
if (sound->cache) {
sound->flags |= SOUND_FLAGS_CACHING;
sound->cache = NULL;
}
if (fd->soundmap) {
sound->waveform = newsoundadr(fd, sound->waveform);
}
else {
sound->waveform = NULL;
}
if (sound->mutex)
sound->mutex = BLI_mutex_alloc();
/* clear waveform loading flag */
sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING;
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;
for (sound = main->sound.first; sound; sound = sound->id.next) {
if (sound->id.flag & LIB_NEED_LINK) {
sound->id.flag -= LIB_NEED_LINK;
sound->ipo = newlibadr_us(fd, sound->id.lib, sound->ipo); // XXX deprecated - old animation system
sound_load(main, sound);
}
}
}
/* ***************** 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;
GroupObject *go;
int add_us;
for (group = main->group.first; group; group = group->id.next) {
if (group->id.flag & LIB_NEED_LINK) {
group->id.flag -= LIB_NEED_LINK;
add_us = 0;
for (go = group->gobject.first; go; go = go->next) {
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;
}
}
if (add_us) group->id.us++;
BKE_group_object_unlink(group, NULL, NULL, NULL); /* removes NULL entries */
}
}
}
/* ***************** READ MOVIECLIP *************** */
static void direct_link_movieReconstruction(FileData *fd, MovieTrackingReconstruction *reconstruction)
{
reconstruction->cameras = newdataadr(fd, reconstruction->cameras);
}
static void direct_link_movieTracks(FileData *fd, ListBase *tracksbase)
{
MovieTrackingTrack *track;
link_list(fd, tracksbase);
for (track = tracksbase->first; track; track = track->next) {
track->markers = newdataadr(fd, track->markers);
}
}
static void direct_link_moviePlaneTracks(FileData *fd, ListBase *plane_tracks_base)
{
MovieTrackingPlaneTrack *plane_track;
link_list(fd, plane_tracks_base);
for (plane_track = plane_tracks_base->first;
plane_track;
plane_track = plane_track->next)
{
int i;
plane_track->point_tracks = newdataadr(fd, plane_track->point_tracks);
for (i = 0; i < plane_track->point_tracksnr; i++) {
plane_track->point_tracks[i] = newdataadr(fd, plane_track->point_tracks[i]);
}
plane_track->markers = newdataadr(fd, plane_track->markers);
}
}
static void direct_link_movieclip(FileData *fd, MovieClip *clip)
{
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object;
clip->adt= newdataadr(fd, clip->adt);
if (fd->movieclipmap) clip->cache = newmclipadr(fd, clip->cache);
else clip->cache = NULL;
if (fd->movieclipmap) clip->tracking.camera.intrinsics = newmclipadr(fd, clip->tracking.camera.intrinsics);
else clip->tracking.camera.intrinsics = NULL;
direct_link_movieTracks(fd, &tracking->tracks);
direct_link_moviePlaneTracks(fd, &tracking->plane_tracks);
direct_link_movieReconstruction(fd, &tracking->reconstruction);
clip->tracking.act_track = newdataadr(fd, clip->tracking.act_track);
clip->tracking.act_plane_track = newdataadr(fd, clip->tracking.act_plane_track);
clip->anim = NULL;
clip->tracking_context = NULL;
clip->tracking.stats = NULL;
clip->tracking.stabilization.ok = 0;
clip->tracking.stabilization.rot_track = newdataadr(fd, clip->tracking.stabilization.rot_track);
clip->tracking.dopesheet.ok = 0;
BLI_listbase_clear(&clip->tracking.dopesheet.channels);
BLI_listbase_clear(&clip->tracking.dopesheet.coverage_segments);
link_list(fd, &tracking->objects);
for (object = tracking->objects.first; object; object = object->next) {
direct_link_movieTracks(fd, &object->tracks);
direct_link_moviePlaneTracks(fd, &object->plane_tracks);
direct_link_movieReconstruction(fd, &object->reconstruction);
}
}
static void lib_link_movieTracks(FileData *fd, MovieClip *clip, ListBase *tracksbase)
{
MovieTrackingTrack *track;
for (track = tracksbase->first; track; track = track->next) {
track->gpd = newlibadr_us(fd, clip->id.lib, track->gpd);
}
}
static void lib_link_moviePlaneTracks(FileData *fd, MovieClip *clip, ListBase *tracksbase)
{
MovieTrackingPlaneTrack *plane_track;
for (plane_track = tracksbase->first; plane_track; plane_track = plane_track->next) {
plane_track->image = newlibadr_us(fd, clip->id.lib, plane_track->image);
}
}
static void lib_link_movieclip(FileData *fd, Main *main)
{
MovieClip *clip;
for (clip = main->movieclip.first; clip; clip = clip->id.next) {
if (clip->id.flag & LIB_NEED_LINK) {
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object;
if (clip->adt)
lib_link_animdata(fd, &clip->id, clip->adt);
clip->gpd = newlibadr_us(fd, clip->id.lib, clip->gpd);
lib_link_movieTracks(fd, clip, &tracking->tracks);
lib_link_moviePlaneTracks(fd, clip, &tracking->plane_tracks);
for (object = tracking->objects.first; object; object = object->next) {
lib_link_movieTracks(fd, clip, &object->tracks);
}
clip->id.flag -= LIB_NEED_LINK;
}
}
}
/* ***************** READ MOVIECLIP *************** */
static void direct_link_mask(FileData *fd, Mask *mask)
{
MaskLayer *masklay;
mask->adt = newdataadr(fd, mask->adt);
link_list(fd, &mask->masklayers);
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
MaskLayerShape *masklay_shape;
link_list(fd, &masklay->splines);
for (spline = masklay->splines.first; spline; spline = spline->next) {
int i;
spline->points = newdataadr(fd, spline->points);
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
if (point->tot_uw)
point->uw = newdataadr(fd, point->uw);
}
}
link_list(fd, &masklay->splines_shapes);
for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
masklay_shape->data = newdataadr(fd, masklay_shape->data);
if (masklay_shape->tot_vert) {
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
BLI_endian_switch_float_array(masklay_shape->data,
masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
}
}
}
masklay->act_spline = newdataadr(fd, masklay->act_spline);
masklay->act_point = newdataadr(fd, masklay->act_point);
}
}
static void lib_link_mask_parent(FileData *fd, Mask *mask, MaskParent *parent)
{
parent->id = newlibadr_us(fd, mask->id.lib, parent->id);
}
static void lib_link_mask(FileData *fd, Main *main)
{
Mask *mask;
mask = main->mask.first;
while (mask) {
if (mask->id.flag & LIB_NEED_LINK) {
MaskLayer *masklay;
if (mask->adt)
lib_link_animdata(fd, &mask->id, mask->adt);
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
spline = masklay->splines.first;
while (spline) {
int i;
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
lib_link_mask_parent(fd, mask, &point->parent);
}
lib_link_mask_parent(fd, mask, &spline->parent);
spline = spline->next;
}
}
mask->id.flag -= LIB_NEED_LINK;
}
mask = mask->id.next;
}
}
/* ************ READ LINE STYLE ***************** */
static void lib_link_linestyle(FileData *fd, Main *main)
{
FreestyleLineStyle *linestyle;
LineStyleModifier *m;
MTex *mtex;
int a;
linestyle = main->linestyle.first;
while (linestyle) {
if (linestyle->id.flag & LIB_NEED_LINK) {
linestyle->id.flag -= LIB_NEED_LINK;
if (linestyle->id.properties)
IDP_LibLinkProperty(linestyle->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
if (linestyle->adt)
lib_link_animdata(fd, &linestyle->id, linestyle->adt);
for (m = linestyle->color_modifiers.first; m; m = m->next) {
switch (m->type) {
case LS_MODIFIER_DISTANCE_FROM_OBJECT:
{
LineStyleColorModifier_DistanceFromObject *cm = (LineStyleColorModifier_DistanceFromObject *)m;
cm->target = newlibadr(fd, linestyle->id.lib, cm->target);
}
break;
}
}
for (m = linestyle->alpha_modifiers.first; m; m = m->next) {
switch (m->type) {
case LS_MODIFIER_DISTANCE_FROM_OBJECT:
{
LineStyleAlphaModifier_DistanceFromObject *am = (LineStyleAlphaModifier_DistanceFromObject *)m;
am->target = newlibadr(fd, linestyle->id.lib, am->target);
}
break;
}
}
for (m = linestyle->thickness_modifiers.first; m; m = m->next) {
switch (m->type) {
case LS_MODIFIER_DISTANCE_FROM_OBJECT:
{
LineStyleThicknessModifier_DistanceFromObject *tm = (LineStyleThicknessModifier_DistanceFromObject *)m;
tm->target = newlibadr(fd, linestyle->id.lib, tm->target);
}
break;
}
}
for (a=0; a < MAX_MTEX; a++) {
mtex = linestyle->mtex[a];
if (mtex) {
mtex->tex = newlibadr_us(fd, linestyle->id.lib, mtex->tex);
mtex->object = newlibadr(fd, linestyle->id.lib, mtex->object);
}
}
if (linestyle->nodetree) {
lib_link_ntree(fd, &linestyle->id, linestyle->nodetree);
linestyle->nodetree->id.lib = linestyle->id.lib;
}
}
linestyle = linestyle->id.next;
}
}
static void direct_link_linestyle_color_modifier(FileData *fd, LineStyleModifier *modifier)
{
switch (modifier->type) {
case LS_MODIFIER_ALONG_STROKE:
{
LineStyleColorModifier_AlongStroke *m = (LineStyleColorModifier_AlongStroke *)modifier;
m->color_ramp = newdataadr(fd, m->color_ramp);
}
break;
case LS_MODIFIER_DISTANCE_FROM_CAMERA:
{
LineStyleColorModifier_DistanceFromCamera *m = (LineStyleColorModifier_DistanceFromCamera *)modifier;
m->color_ramp = newdataadr(fd, m->color_ramp);
}
break;
case LS_MODIFIER_DISTANCE_FROM_OBJECT:
{
LineStyleColorModifier_DistanceFromObject *m = (LineStyleColorModifier_DistanceFromObject *)modifier;
m->color_ramp = newdataadr(fd, m->color_ramp);
}
break;
case LS_MODIFIER_MATERIAL:
{
LineStyleColorModifier_Material *m = (LineStyleColorModifier_Material *)modifier;
m->color_ramp = newdataadr(fd, m->color_ramp);
}
break;
}
}
static void direct_link_linestyle_alpha_modifier(FileData *fd, LineStyleModifier *modifier)
{
switch (modifier->type) {
case LS_MODIFIER_ALONG_STROKE:
{
LineStyleAlphaModifier_AlongStroke *m = (LineStyleAlphaModifier_AlongStroke *)modifier;
m->curve = newdataadr(fd, m->curve);
direct_link_curvemapping(fd, m->curve);
}
break;
case LS_MODIFIER_DISTANCE_FROM_CAMERA:
{
LineStyleAlphaModifier_DistanceFromCamera *m = (LineStyleAlphaModifier_DistanceFromCamera *)modifier;
m->curve = newdataadr(fd, m->curve);
direct_link_curvemapping(fd, m->curve);
}
break;
case LS_MODIFIER_DISTANCE_FROM_OBJECT:
{
LineStyleAlphaModifier_DistanceFromObject *m = (LineStyleAlphaModifier_DistanceFromObject *)modifier;
m->curve = newdataadr(fd, m->curve);
direct_link_curvemapping(fd, m->curve);
}
break;
case LS_MODIFIER_MATERIAL:
{
LineStyleAlphaModifier_Material *m = (LineStyleAlphaModifier_Material *)modifier;
m->curve = newdataadr(fd, m->curve);
direct_link_curvemapping(fd, m->curve);
}
break;
}
}
static void direct_link_linestyle_thickness_modifier(FileData *fd, LineStyleModifier *modifier)
{
switch (modifier->type) {
case LS_MODIFIER_ALONG_STROKE:
{
LineStyleThicknessModifier_AlongStroke *m = (LineStyleThicknessModifier_AlongStroke *)modifier;
m->curve = newdataadr(fd, m->curve);
direct_link_curvemapping(fd, m->curve);
}
break;
case LS_MODIFIER_DISTANCE_FROM_CAMERA:
{
LineStyleThicknessModifier_DistanceFromCamera *m = (LineStyleThicknessModifier_DistanceFromCamera *)modifier;
m->curve = newdataadr(fd, m->curve);
direct_link_curvemapping(fd, m->curve);
}
break;
case LS_MODIFIER_DISTANCE_FROM_OBJECT:
{
LineStyleThicknessModifier_DistanceFromObject *m = (LineStyleThicknessModifier_DistanceFromObject *)modifier;
m->curve = newdataadr(fd, m->curve);
direct_link_curvemapping(fd, m->curve);
}
break;
case LS_MODIFIER_MATERIAL:
{
LineStyleThicknessModifier_Material *m = (LineStyleThicknessModifier_Material *)modifier;
m->curve = newdataadr(fd, m->curve);
direct_link_curvemapping(fd, m->curve);
}
break;
}
}
static void direct_link_linestyle_geometry_modifier(FileData *UNUSED(fd), LineStyleModifier *UNUSED(modifier))
{
}
static void direct_link_linestyle(FileData *fd, FreestyleLineStyle *linestyle)
{
int a;
LineStyleModifier *modifier;
linestyle->adt= newdataadr(fd, linestyle->adt);
direct_link_animdata(fd, linestyle->adt);
link_list(fd, &linestyle->color_modifiers);
for (modifier = linestyle->color_modifiers.first; modifier; modifier = modifier->next)
direct_link_linestyle_color_modifier(fd, modifier);
link_list(fd, &linestyle->alpha_modifiers);
for (modifier = linestyle->alpha_modifiers.first; modifier; modifier = modifier->next)
direct_link_linestyle_alpha_modifier(fd, modifier);
link_list(fd, &linestyle->thickness_modifiers);
for (modifier = linestyle->thickness_modifiers.first; modifier; modifier = modifier->next)
direct_link_linestyle_thickness_modifier(fd, modifier);
link_list(fd, &linestyle->geometry_modifiers);
for (modifier = linestyle->geometry_modifiers.first; modifier; modifier = modifier->next)
direct_link_linestyle_geometry_modifier(fd, modifier);
for (a = 0; a < MAX_MTEX; a++) {
linestyle->mtex[a] = newdataadr(fd, linestyle->mtex[a]);
}
linestyle->nodetree = newdataadr(fd, linestyle->nodetree);
if (linestyle->nodetree) {
direct_link_id(fd, &linestyle->nodetree->id);
direct_link_nodetree(fd, linestyle->nodetree);
}
}
/* ************** GENERAL & MAIN ******************** */
static const 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_SPK: return "Data from SPK";
case ID_SO: return "Data from SO";
case ID_NT: return "Data from NT";
case ID_BR: return "Data from BR";
case ID_PA: return "Data from PA";
case ID_PAL: return "Data from PAL";
case ID_PC: return "Data from PCRV";
case ID_GD: return "Data from GD";
case ID_WM: return "Data from WM";
case ID_MC: return "Data from MC";
case ID_MSK: return "Data from MSK";
case ID_LS: return "Data from LS";
}
return "Data from Lib Block";
}
static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *allocname)
{
bhead = blo_nextbhead(fd, bhead);
while (bhead && bhead->code==DATA) {
void *data;
#if 0
/* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */
short *sp = fd->filesdna->structs[bhead->SDNAnr];
char *tmp = malloc(100);
allocname = fd->filesdna->types[ sp[0] ];
strcpy(tmp, allocname);
data = read_struct(fd, bhead, tmp);
#else
data = read_struct(fd, bhead, allocname);
#endif
if (data) {
oldnewmap_insert(fd->datamap, bhead->old, data, 0);
}
bhead = blo_nextbhead(fd, bhead);
}
return bhead;
}
static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **r_id)
{
/* this routine reads a libblock and its direct data. Use link functions
* to connect it all
*/
ID *id;
ListBase *lb;
const char *allocname;
bool wrong_id = false;
/* read libblock */
id = read_struct(fd, bhead, "lib block");
if (r_id)
*r_id = 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 = which_libbase(main, GS(id->name));
}
else {
lb = which_libbase(main, bhead->code);
}
BLI_addtail(lb, id);
/* clear first 8 bits */
id->flag = (id->flag & 0xFF00) | flag | LIB_NEED_LINK;
id->lib = main->curlib;
if (id->flag & LIB_FAKEUSER) id->us= 1;
else id->us = 0;
id->icon_id = 0;
id->flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA|LIB_DOIT);
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_ID) {
return 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 into fd->datamap */
bhead = read_data_into_oldnewmap(fd, bhead, allocname);
/* init pointers direct data */
direct_link_id(fd, id);
switch (GS(id->name)) {
case ID_WM:
direct_link_windowmanager(fd, (wmWindowManager *)id);
break;
case ID_SCR:
wrong_id = 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_SPK:
direct_link_speaker(fd, (Speaker *)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;
case ID_PA:
direct_link_particlesettings(fd, (ParticleSettings*)id);
break;
case ID_SCRIPT:
direct_link_script(fd, (Script*)id);
break;
case ID_GD:
direct_link_gpencil(fd, (bGPdata *)id);
break;
case ID_MC:
direct_link_movieclip(fd, (MovieClip *)id);
break;
case ID_MSK:
direct_link_mask(fd, (Mask *)id);
break;
case ID_LS:
direct_link_linestyle(fd, (FreestyleLineStyle *)id);
break;
case ID_PAL:
direct_link_palette(fd, (Palette *)id);
break;
case ID_PC:
direct_link_paint_curve(fd, (PaintCurve *)id);
break;
}
oldnewmap_free_unused(fd->datamap);
oldnewmap_clear(fd->datamap);
if (wrong_id) {
BKE_libblock_free(main, id);
}
return (bhead);
}
/* note, this has to be kept for reading older files... */
/* also version info is written here */
static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
{
FileGlobal *fg = read_struct(fd, bhead, "Global");
/* copy to bfd handle */
bfd->main->subversionfile = fg->subversion;
bfd->main->minversionfile = fg->minversion;
bfd->main->minsubversionfile = fg->minsubversion;
bfd->main->build_commit_timestamp = fg->build_commit_timestamp;
BLI_strncpy(bfd->main->build_hash, fg->build_hash, sizeof(bfd->main->build_hash));
bfd->winpos = fg->winpos;
bfd->fileflags = fg->fileflags;
bfd->displaymode = fg->displaymode;
bfd->globalf = fg->globalf;
BLI_strncpy(bfd->filename, fg->filename, sizeof(bfd->filename));
/* error in 2.65 and older: main->name was not set if you save from startup (not after loading file) */
if (bfd->filename[0] == 0) {
if (fd->fileversion < 265 || (fd->fileversion == 265 && fg->subversion < 1))
if ((G.fileflags & G_FILE_RECOVER)==0)
BLI_strncpy(bfd->filename, bfd->main->name, sizeof(bfd->filename));
/* early 2.50 version patch - filename not in FileGlobal struct at all */
if (fd->fileversion <= 250)
BLI_strncpy(bfd->filename, bfd->main->name, sizeof(bfd->filename));
}
if (G.fileflags & G_FILE_RECOVER)
BLI_strncpy(fd->relabase, fg->filename, sizeof(fd->relabase));
bfd->curscreen = fg->curscreen;
bfd->curscene = fg->curscene;
MEM_freeN(fg);
fd->globalf = bfd->globalf;
fd->fileflags = bfd->fileflags;
return blo_nextbhead(fd, bhead);
}
/* note, this has to be kept for reading older files... */
static void link_global(FileData *fd, BlendFileData *bfd)
{
bfd->curscreen = newlibadr(fd, NULL, bfd->curscreen);
bfd->curscene = newlibadr(fd, NULL, bfd->curscene);
// this happens in files older than 2.35
if (bfd->curscene == NULL) {
if (bfd->curscreen) bfd->curscene = bfd->curscreen->scene;
}
}
static void convert_tface_mt(FileData *fd, Main *main)
{
Main *gmain;
/* this is a delayed do_version (so it can create new materials) */
if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 3)) {
//XXX hack, material.c uses G.main all over the place, instead of main
// temporarily set G.main to the current main
gmain = G.main;
G.main = main;
if (!(do_version_tface(main))) {
BKE_report(fd->reports, RPT_WARNING, "Texface conversion problem (see error in console)");
}
//XXX hack, material.c uses G.main allover the place, instead of main
G.main = gmain;
}
}
/* initialize userdef with non-UI dependency stuff */
/* other initializers (such as theme color defaults) go to resources.c */
static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
{
Main *bmain = bfd->main;
UserDef *user = bfd->user;
if (user == NULL) return;
if (MAIN_VERSION_OLDER(bmain, 266, 4)) {
bTheme *btheme;
/* themes for Node and Sequence editor were not using grid color, but back. we copy this over then */
for (btheme = user->themes.first; btheme; btheme = btheme->next) {
copy_v4_v4_char(btheme->tnode.grid, btheme->tnode.back);
copy_v4_v4_char(btheme->tseq.grid, btheme->tseq.back);
}
}
if (!DNA_struct_elem_find(fd->filesdna, "UserDef", "WalkNavigation", "walk_navigation")) {
user->walk_navigation.mouse_speed = 1.0f;
user->walk_navigation.walk_speed = 2.5f; /* m/s */
user->walk_navigation.walk_speed_factor = 5.0f;
user->walk_navigation.view_height = 1.6f; /* m */
user->walk_navigation.jump_height = 0.4f; /* m */
user->walk_navigation.teleport_time = 0.2f; /* s */
}
}
static void do_versions(FileData *fd, Library *lib, Main *main)
{
/* WATCH IT!!!: pointers from libdata have not been converted */
if (G.debug & G_DEBUG) {
char build_commit_datetime[32];
time_t temp_time = main->build_commit_timestamp;
struct tm *tm = gmtime(&temp_time);
if (LIKELY(tm)) {
strftime(build_commit_datetime, sizeof(build_commit_datetime), "%Y-%m-%d %H:%M", tm);
}
else {
BLI_strncpy(build_commit_datetime, "date-unknown", sizeof(build_commit_datetime));
}
printf("read file %s\n Version %d sub %d date %s hash %s\n",
fd->relabase, main->versionfile, main->subversionfile,
build_commit_datetime, main->build_hash);
}
blo_do_versions_pre250(fd, lib, main);
blo_do_versions_250(fd, lib, main);
blo_do_versions_260(fd, lib, main);
blo_do_versions_270(fd, lib, main);
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */
/* don't forget to set version number in BKE_blender.h! */
}
#if 0 // XXX: disabled for now... we still don't have this in the right place in the loading code for it to work
static void do_versions_after_linking(FileData *fd, Library *lib, Main *main)
{
/* old Animation System (using IPO's) needs to be converted to the new Animato system */
if (main->versionfile < 250)
do_versions_ipos_to_animato(main);
}
#endif
static void lib_link_all(FileData *fd, Main *main)
{
oldnewmap_sort(fd);
/* No load UI for undo memfiles */
if (fd->memfile == NULL) {
lib_link_windowmanager(fd, main);
}
/* DO NOT skip screens here, 3Dview may contains pointers to other ID data (like bgpic)! See T41411. */
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); // XXX deprecated... still needs to be maintained for version patches still
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_speaker(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_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
lib_link_brush(fd, main);
lib_link_palette(fd, main);
lib_link_paint_curve(fd, main);
lib_link_particlesettings(fd, main);
lib_link_movieclip(fd, main);
lib_link_mask(fd, main);
lib_link_linestyle(fd, main);
lib_link_gpencil(fd, main);
lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
lib_link_library(fd, main); /* only init users */
}
static void direct_link_keymapitem(FileData *fd, wmKeyMapItem *kmi)
{
kmi->properties = newdataadr(fd, kmi->properties);
IDP_DirectLinkGroup_OrFree(&kmi->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
kmi->ptr = NULL;
kmi->flag &= ~KMI_UPDATE;
}
static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
{
UserDef *user;
wmKeyMap *keymap;
wmKeyMapItem *kmi;
wmKeyMapDiffItem *kmdi;
bAddon *addon;
bfd->user = user= read_struct(fd, bhead, "user def");
/* User struct has separate do-version handling */
user->versionfile = bfd->main->versionfile;
user->subversionfile = bfd->main->subversionfile;
/* read all data into fd->datamap */
bhead = read_data_into_oldnewmap(fd, bhead, "user def");
if (user->keymaps.first) {
/* backwards compatibility */
user->user_keymaps= user->keymaps;
user->keymaps.first= user->keymaps.last= NULL;
}
link_list(fd, &user->themes);
link_list(fd, &user->user_keymaps);
link_list(fd, &user->addons);
link_list(fd, &user->autoexec_paths);
for (keymap=user->user_keymaps.first; keymap; keymap=keymap->next) {
keymap->modal_items= NULL;
keymap->poll = NULL;
keymap->flag &= ~KEYMAP_UPDATE;
link_list(fd, &keymap->diff_items);
link_list(fd, &keymap->items);
for (kmdi=keymap->diff_items.first; kmdi; kmdi=kmdi->next) {
kmdi->remove_item= newdataadr(fd, kmdi->remove_item);
kmdi->add_item= newdataadr(fd, kmdi->add_item);
if (kmdi->remove_item)
direct_link_keymapitem(fd, kmdi->remove_item);
if (kmdi->add_item)
direct_link_keymapitem(fd, kmdi->add_item);
}
for (kmi=keymap->items.first; kmi; kmi=kmi->next)
direct_link_keymapitem(fd, kmi);
}
for (addon = user->addons.first; addon; addon = addon->next) {
addon->prop = newdataadr(fd, addon->prop);
IDP_DirectLinkGroup_OrFree(&addon->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
// XXX
user->uifonts.first = user->uifonts.last= NULL;
link_list(fd, &user->uistyles);
/* free fd->datamap again */
oldnewmap_free_unused(fd->datamap);
oldnewmap_clear(fd->datamap);
return bhead;
}
BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
{
BHead *bhead = blo_firstbhead(fd);
BlendFileData *bfd;
ListBase mainlist = {NULL, NULL};
bfd = MEM_callocN(sizeof(BlendFileData), "blendfiledata");
bfd->main = BKE_main_new();
BLI_addtail(&mainlist, bfd->main);
fd->mainlist = &mainlist;
bfd->main->versionfile = fd->fileversion;
bfd->type = BLENFILETYPE_BLEND;
BLI_strncpy(bfd->main->name, filepath, sizeof(bfd->main->name));
while (bhead) {
switch (bhead->code) {
case DATA:
case DNA1:
case TEST: /* used as preview since 2.5x */
case REND:
bhead = blo_nextbhead(fd, bhead);
break;
case GLOB:
bhead = read_global(bfd, fd, bhead);
break;
case USER:
bhead = read_userdef(bfd, fd, bhead);
break;
case ENDB:
bhead = NULL;
break;
case ID_LI:
/* skip library datablocks in undo, this works together with
* BLO_read_from_memfile, where the old main->library is restored
* overwriting the libraries from the memory file. previously
* it did not save ID_LI/ID_ID blocks in this case, but they are
* needed to make quit.blend recover them correctly. */
if (fd->memfile)
bhead = blo_nextbhead(fd, bhead);
else
bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
break;
case ID_ID:
/* same as above */
if (fd->memfile)
bhead = blo_nextbhead(fd, bhead);
else
/* always adds to the most recently loaded
* ID_LI block, see direct_link_library.
* this is part of the file format definition. */
bhead = read_libblock(fd, mainlist.last, bhead, LIB_READ+LIB_EXTERN, NULL);
break;
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
case ID_SCRN:
bhead->code = ID_SCR;
/* deliberate pass on to default */
default:
bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
}
}
/* do before read_libraries, but skip undo case */
if (fd->memfile==NULL)
do_versions(fd, NULL, bfd->main);
do_versions_userdef(fd, bfd);
read_libraries(fd, &mainlist);
blo_join_main(&mainlist);
lib_link_all(fd, bfd->main);
//do_versions_after_linking(fd, NULL, bfd->main); // XXX: not here (or even in this function at all)! this causes crashes on many files - Aligorith (July 04, 2010)
lib_verify_nodetree(bfd->main, true);
fix_relpaths_library(fd->relabase, bfd->main); /* make all relative paths, relative to the open blend file */
link_global(fd, bfd); /* as last */
return bfd;
}
/* ************* APPEND LIBRARY ************** */
struct BHeadSort {
BHead *bhead;
void *old;
};
static int verg_bheadsort(const void *v1, const void *v2)
{
const struct BHeadSort *x1=v1, *x2=v2;
if (x1->old > x2->old) return 1;
else if (x1->old < x2->old) return -1;
return 0;
}
static void sort_bhead_old_map(FileData *fd)
{
BHead *bhead;
struct BHeadSort *bhs;
int tot = 0;
for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead))
tot++;
fd->tot_bheadmap = tot;
if (tot == 0) return;
bhs = fd->bheadmap = MEM_mallocN(tot * sizeof(struct BHeadSort), "BHeadSort");
for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead), bhs++) {
bhs->bhead = bhead;
bhs->old = bhead->old;
}
qsort(fd->bheadmap, tot, sizeof(struct BHeadSort), verg_bheadsort);
}
static BHead *find_previous_lib(FileData *fd, BHead *bhead)
{
/* skip library datablocks in undo, see comment in read_libblock */
if (fd->memfile)
return NULL;
for (; bhead; bhead = blo_prevbhead(fd, bhead)) {
if (bhead->code == ID_LI)
break;
}
return bhead;
}
static BHead *find_bhead(FileData *fd, void *old)
{
#if 0
BHead *bhead;
#endif
struct BHeadSort *bhs, bhs_s;
if (!old)
return NULL;
if (fd->bheadmap == NULL)
sort_bhead_old_map(fd);
bhs_s.old = old;
bhs = bsearch(&bhs_s, fd->bheadmap, fd->tot_bheadmap, sizeof(struct BHeadSort), verg_bheadsort);
if (bhs)
return bhs->bhead;
#if 0
for (bhead = blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
if (bhead->old == old)
return bhead;
}
#endif
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)
{
const char *idname= bhead_id_name(fd, bhead);
/* which_libbase can be NULL, intentionally not using idname+2 */
return BLI_findstring(which_libbase(mainvar, GS(idname)), idname, offsetof(ID, name));
}
static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
{
BHead *bhead;
FileData *fd = fdhandle;
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, lib->name, fd->relabase);
if (ptr->curlib == NULL) {
const char *idname= bhead_id_name(fd, bhead);
blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB ERROR: Data refers to main .blend file: '%s' from %s"),
idname, mainvar->curlib->filepath);
return;
}
else
id = is_yet_read(fd, ptr, bhead);
if (id == NULL) {
read_libblock(fd, ptr, bhead, LIB_READ+LIB_INDIRECT, NULL);
// commented because this can print way too much
// if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name);
/* for outliner dependency only */
ptr->curlib->parent = mainvar->curlib;
}
else {
/* The line below was commented by Ton (I assume), when Hos did the merge from the orange branch. rev 6568
* This line is NEEDED, the case is that you have 3 blend files...
* user.blend, lib.blend and lib_indirect.blend - if user.blend already references a "tree" from
* lib_indirect.blend but lib.blend does too, linking in a Scene or Group from lib.blend can result in an
* empty without the dupli group referenced. Once you save and reload the group would appear. - Campbell */
/* This crashes files, must look further into it */
/* Update: the issue is that in file reading, the oldnewmap is OK, but for existing data, it has to be
* inserted in the map to be found! */
/* Update: previously it was checking for id->flag & LIB_PRE_EXISTING, however that does not affect file
* reading. For file reading we may need to insert it into the libmap as well, because you might have
* two files indirectly linking the same datablock, and in that case we need this in the libmap for the
* fd of both those files.
*
* The crash that this check avoided earlier was because bhead->code wasn't properly passed in, making
* change_idid_adr not detect the mapping was for an ID_ID datablock. */
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
change_idid_adr_fd(fd, bhead->old, id);
// commented because this can print way too much
// if (G.debug & 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, bhead->code);
// commented because this can print way too much
// if (G.debug & G_DEBUG) printf("expand: already read %s\n", id->name);
}
}
}
}
static void (*expand_doit)(void *, Main *, void *);
// XXX deprecated - old animation system
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);
}
}
// XXX deprecated - old animation system
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_fmodifiers(FileData *fd, Main *mainvar, ListBase *list)
{
FModifier *fcm;
for (fcm = list->first; fcm; fcm = fcm->next) {
/* library data for specific F-Modifier types */
switch (fcm->type) {
case FMODIFIER_TYPE_PYTHON:
{
FMod_Python *data = (FMod_Python *)fcm->data;
expand_doit(fd, mainvar, data->script);
}
break;
}
}
}
static void expand_fcurves(FileData *fd, Main *mainvar, ListBase *list)
{
FCurve *fcu;
for (fcu = list->first; fcu; fcu = fcu->next) {
/* Driver targets if there is a driver */
if (fcu->driver) {
ChannelDriver *driver = fcu->driver;
DriverVar *dvar;
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
DRIVER_TARGETS_LOOPER(dvar)
{
// TODO: only expand those that are going to get used?
expand_doit(fd, mainvar, dtar->id);
}
DRIVER_TARGETS_LOOPER_END
}
}
/* F-Curve Modifiers */
expand_fmodifiers(fd, mainvar, &fcu->modifiers);
}
}
static void expand_action(FileData *fd, Main *mainvar, bAction *act)
{
bActionChannel *chan;
// XXX deprecated - old animation system --------------
for (chan=act->chanbase.first; chan; chan=chan->next) {
expand_doit(fd, mainvar, chan->ipo);
expand_constraint_channels(fd, mainvar, &chan->constraintChannels);
}
// ---------------------------------------------------
/* F-Curves in Action */
expand_fcurves(fd, mainvar, &act->curves);
}
static void expand_keyingsets(FileData *fd, Main *mainvar, ListBase *list)
{
KeyingSet *ks;
KS_Path *ksp;
/* expand the ID-pointers in KeyingSets's paths */
for (ks = list->first; ks; ks = ks->next) {
for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
expand_doit(fd, mainvar, ksp->id);
}
}
}
static void expand_animdata_nlastrips(FileData *fd, Main *mainvar, ListBase *list)
{
NlaStrip *strip;
for (strip= list->first; strip; strip= strip->next) {
/* check child strips */
expand_animdata_nlastrips(fd, mainvar, &strip->strips);
/* check F-Curves */
expand_fcurves(fd, mainvar, &strip->fcurves);
/* check F-Modifiers */
expand_fmodifiers(fd, mainvar, &strip->modifiers);
/* relink referenced action */
expand_doit(fd, mainvar, strip->act);
}
}
static void expand_animdata(FileData *fd, Main *mainvar, AnimData *adt)
{
NlaTrack *nlt;
/* own action */
expand_doit(fd, mainvar, adt->action);
expand_doit(fd, mainvar, adt->tmpact);
/* drivers - assume that these F-Curves have driver data to be in this list... */
expand_fcurves(fd, mainvar, &adt->drivers);
/* nla-data - referenced actions */
for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next)
expand_animdata_nlastrips(fd, mainvar, &nlt->strips);
}
static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSettings *part)
{
int a;
expand_doit(fd, mainvar, part->dup_ob);
expand_doit(fd, mainvar, part->dup_group);
expand_doit(fd, mainvar, part->eff_group);
expand_doit(fd, mainvar, part->bb_ob);
if (part->adt)
expand_animdata(fd, mainvar, part->adt);
for (a = 0; a < MAX_MTEX; a++) {
if (part->mtex[a]) {
expand_doit(fd, mainvar, part->mtex[a]->tex);
expand_doit(fd, mainvar, part->mtex[a]->object);
}
}
}
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); // XXX deprecated - old animation system
if (key->adt)
expand_animdata(fd, mainvar, key->adt);
}
static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
{
bNode *node;
if (ntree->adt)
expand_animdata(fd, mainvar, ntree->adt);
if (ntree->gpd)
expand_doit(fd, mainvar, ntree->gpd);
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_texture(FileData *fd, Main *mainvar, Tex *tex)
{
expand_doit(fd, mainvar, tex->ima);
expand_doit(fd, mainvar, tex->ipo); // XXX deprecated - old animation system
if (tex->adt)
expand_animdata(fd, mainvar, tex->adt);
if (tex->nodetree)
expand_nodetree(fd, mainvar, tex->nodetree);
}
static void expand_brush(FileData *fd, Main *mainvar, Brush *brush)
{
expand_doit(fd, mainvar, brush->mtex.tex);
expand_doit(fd, mainvar, brush->mask_mtex.tex);
expand_doit(fd, mainvar, brush->clone.image);
expand_doit(fd, mainvar, brush->paint_curve);
}
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); // XXX deprecated - old animation system
if (ma->adt)
expand_animdata(fd, mainvar, ma->adt);
if (ma->nodetree)
expand_nodetree(fd, mainvar, ma->nodetree);
if (ma->group)
expand_doit(fd, mainvar, ma->group);
}
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); // XXX deprecated - old animation system
if (la->adt)
expand_animdata(fd, mainvar, la->adt);
if (la->nodetree)
expand_nodetree(fd, mainvar, la->nodetree);
}
static void expand_lattice(FileData *fd, Main *mainvar, Lattice *lt)
{
expand_doit(fd, mainvar, lt->ipo); // XXX deprecated - old animation system
expand_doit(fd, mainvar, lt->key);
if (lt->adt)
expand_animdata(fd, mainvar, lt->adt);
}
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); // XXX deprecated - old animation system
if (wrld->adt)
expand_animdata(fd, mainvar, wrld->adt);
if (wrld->nodetree)
expand_nodetree(fd, mainvar, wrld->nodetree);
}
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]);
}
if (mb->adt)
expand_animdata(fd, mainvar, mb->adt);
}
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); // XXX deprecated - old animation system
expand_doit(fd, mainvar, cu->bevobj);
expand_doit(fd, mainvar, cu->taperobj);
expand_doit(fd, mainvar, cu->textoncurve);
if (cu->adt)
expand_animdata(fd, mainvar, cu->adt);
}
static void expand_mesh(FileData *fd, Main *mainvar, Mesh *me)
{
CustomDataLayer *layer;
TFace *tf;
int a, i;
if (me->adt)
expand_animdata(fd, mainvar, me->adt);
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);
}
}
if (me->mface && !me->mpoly) {
MTFace *mtf;
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);
}
}
}
}
else {
MTexPoly *mtp;
for (a = 0; a < me->pdata.totlayer; a++) {
layer = &me->pdata.layers[a];
if (layer->type == CD_MTEXPOLY) {
mtp = (MTexPoly *) layer->data;
for (i = 0; i < me->totpoly; i++, mtp++) {
if (mtp->tpage)
expand_doit(fd, mainvar, mtp->tpage);
}
}
}
}
}
/* temp struct used to transport needed info to expand_constraint_cb() */
typedef struct tConstraintExpandData {
FileData *fd;
Main *mainvar;
} tConstraintExpandData;
/* callback function used to expand constraint ID-links */
static void expand_constraint_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *userdata)
{
tConstraintExpandData *ced = (tConstraintExpandData *)userdata;
expand_doit(ced->fd, ced->mainvar, *idpoin);
}
static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb)
{
tConstraintExpandData ced;
bConstraint *curcon;
/* relink all ID-blocks used by the constraints */
ced.fd = fd;
ced.mainvar = mainvar;
BKE_constraints_id_loop(lb, expand_constraint_cb, &ced);
/* deprecated manual expansion stuff */
for (curcon = lb->first; curcon; curcon = curcon->next) {
if (curcon->ipo)
expand_doit(fd, mainvar, curcon->ipo); // XXX deprecated - old animation system
}
}
#if 0 /* Disabled as it doesn't actually do anything except recurse... */
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);
}
}
#endif
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)
{
if (arm->adt)
expand_animdata(fd, mainvar, arm->adt);
#if 0 /* Disabled as this currently only recurses down the chain doing nothing */
{
Bone *curBone;
for (curBone = arm->bonebase.first; curBone; curBone=curBone->next) {
expand_bones(fd, mainvar, curBone);
}
}
#endif
}
static void expand_object_expandModifiers(void *userData, Object *UNUSED(ob),
ID **idpoin)
{
struct { FileData *fd; Main *mainvar; } *data= userData;
FileData *fd = data->fd;
Main *mainvar = data->mainvar;
expand_doit(fd, mainvar, *idpoin);
}
static void expand_object(FileData *fd, Main *mainvar, Object *ob)
{
ParticleSystem *psys;
bSensor *sens;
bController *cont;
bActuator *act;
bActionStrip *strip;
PartEff *paf;
int a;
expand_doit(fd, mainvar, ob->data);
/* expand_object_expandModifier() */
if (ob->modifiers.first) {
struct { FileData *fd; Main *mainvar; } data;
data.fd = fd;
data.mainvar = mainvar;
modifiers_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data);
}
expand_pose(fd, mainvar, ob->pose);
expand_doit(fd, mainvar, ob->poselib);
expand_constraints(fd, mainvar, &ob->constraints);
expand_doit(fd, mainvar, ob->gpd);
// XXX deprecated - old animation system (for version patching only)
expand_doit(fd, mainvar, ob->ipo);
expand_doit(fd, mainvar, ob->action);
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);
}
// XXX deprecated - old animation system (for version patching only)
if (ob->adt)
expand_animdata(fd, mainvar, ob->adt);
for (a = 0; a < ob->totcol; a++) {
expand_doit(fd, mainvar, ob->mat[a]);
}
paf = blo_do_version_give_parteff_245(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);
for (psys = ob->particlesystem.first; psys; psys = psys->next)
expand_doit(fd, mainvar, psys->part);
for (sens = ob->sensors.first; sens; sens = sens->next) {
if (sens->type == SENS_MESSAGE) {
bMessageSensor *ms = sens->data;
expand_doit(fd, mainvar, ms->fromObject);
}
}
for (cont = ob->controllers.first; cont; cont = cont->next) {
if (cont->type == CONT_PYTHON) {
bPythonCont *pc = cont->data;
expand_doit(fd, mainvar, pc->text);
}
}
for (act = ob->actuators.first; act; act = act->next) {
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_OBJECT) {
bObjectActuator *oa = act->data;
expand_doit(fd, mainvar, oa->reference);
}
else if (act->type == ACT_ADD_OBJECT) {
bAddObjectActuator *aoa = act->data;
expand_doit(fd, mainvar, aoa->ob);
}
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_2DFILTER) {
bTwoDFilterActuator *tdfa = act->data;
expand_doit(fd, mainvar, tdfa->text);
}
else if (act->type == ACT_ACTION) {
bActionActuator *aa = act->data;
expand_doit(fd, mainvar, aa->act);
}
else if (act->type == ACT_SHAPEACTION) {
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);
}
else if (act->type==ACT_PARENT) {
bParentActuator *pa = act->data;
expand_doit(fd, mainvar, pa->ob);
}
else if (act->type == ACT_ARMATURE) {
bArmatureActuator *arma = act->data;
expand_doit(fd, mainvar, arma->target);
}
else if (act->type == ACT_STEERING) {
bSteeringActuator *sta = act->data;
expand_doit(fd, mainvar, sta->target);
expand_doit(fd, mainvar, sta->navmesh);
}
}
if (ob->pd && ob->pd->tex)
expand_doit(fd, mainvar, ob->pd->tex);
if (ob->rigidbody_constraint) {
expand_doit(fd, mainvar, ob->rigidbody_constraint->ob1);
expand_doit(fd, mainvar, ob->rigidbody_constraint->ob2);
}
if (ob->currentlod) {
LodLevel *level;
for (level = ob->lodlevels.first; level; level = level->next) {
expand_doit(fd, mainvar, level->source);
}
}
}
static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
{
Base *base;
SceneRenderLayer *srl;
FreestyleModuleConfig *module;
FreestyleLineSet *lineset;
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->adt)
expand_animdata(fd, mainvar, sce->adt);
expand_keyingsets(fd, mainvar, &sce->keyingsets);
if (sce->set)
expand_doit(fd, mainvar, sce->set);
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);
for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
if (module->script)
expand_doit(fd, mainvar, module->script);
}
for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
if (lineset->group)
expand_doit(fd, mainvar, lineset->group);
expand_doit(fd, mainvar, lineset->linestyle);
}
}
if (sce->r.dometext)
expand_doit(fd, mainvar, sce->gm.dome.warptext);
if (sce->gpd)
expand_doit(fd, mainvar, sce->gpd);
if (sce->ed) {
Sequence *seq;
SEQ_BEGIN (sce->ed, seq)
{
if (seq->scene) expand_doit(fd, mainvar, seq->scene);
if (seq->scene_camera) expand_doit(fd, mainvar, seq->scene_camera);
if (seq->clip) expand_doit(fd, mainvar, seq->clip);
if (seq->mask) expand_doit(fd, mainvar, seq->mask);
if (seq->sound) expand_doit(fd, mainvar, seq->sound);
}
SEQ_END
}
if (sce->rigidbody_world) {
expand_doit(fd, mainvar, sce->rigidbody_world->group);
expand_doit(fd, mainvar, sce->rigidbody_world->constraints);
}
#ifdef DURIAN_CAMERA_SWITCH
{
TimeMarker *marker;
for (marker = sce->markers.first; marker; marker = marker->next) {
if (marker->camera) {
expand_doit(fd, mainvar, marker->camera);
}
}
}
#endif
expand_doit(fd, mainvar, sce->clip);
}
static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
{
expand_doit(fd, mainvar, ca->ipo); // XXX deprecated - old animation system
if (ca->adt)
expand_animdata(fd, mainvar, ca->adt);
}
static void expand_speaker(FileData *fd, Main *mainvar, Speaker *spk)
{
expand_doit(fd, mainvar, spk->sound);
if (spk->adt)
expand_animdata(fd, mainvar, spk->adt);
}
static void expand_sound(FileData *fd, Main *mainvar, bSound *snd)
{
expand_doit(fd, mainvar, snd->ipo); // XXX deprecated - old animation system
}
static void expand_movieclip(FileData *fd, Main *mainvar, MovieClip *clip)
{
if (clip->adt)
expand_animdata(fd, mainvar, clip->adt);
}
static void expand_mask_parent(FileData *fd, Main *mainvar, MaskParent *parent)
{
if (parent->id) {
expand_doit(fd, mainvar, parent->id);
}
}
static void expand_mask(FileData *fd, Main *mainvar, Mask *mask)
{
MaskLayer *mask_layer;
if (mask->adt)
expand_animdata(fd, mainvar, mask->adt);
for (mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
MaskSpline *spline;
for (spline = mask_layer->splines.first; spline; spline = spline->next) {
int i;
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
expand_mask_parent(fd, mainvar, &point->parent);
}
expand_mask_parent(fd, mainvar, &spline->parent);
}
}
}
static void expand_linestyle(FileData *fd, Main *mainvar, FreestyleLineStyle *linestyle)
{
int a;
LineStyleModifier *m;
for (a = 0; a < MAX_MTEX; a++) {
if (linestyle->mtex[a]) {
expand_doit(fd, mainvar, linestyle->mtex[a]->tex);
expand_doit(fd, mainvar, linestyle->mtex[a]->object);
}
}
if (linestyle->nodetree)
expand_nodetree(fd, mainvar, linestyle->nodetree);
if (linestyle->adt)
expand_animdata(fd, mainvar, linestyle->adt);
for (m = linestyle->color_modifiers.first; m; m = m->next) {
if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT)
expand_doit(fd, mainvar, ((LineStyleColorModifier_DistanceFromObject *)m)->target);
}
for (m = linestyle->alpha_modifiers.first; m; m = m->next) {
if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT)
expand_doit(fd, mainvar, ((LineStyleAlphaModifier_DistanceFromObject *)m)->target);
}
for (m = linestyle->thickness_modifiers.first; m; m = m->next) {
if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT)
expand_doit(fd, mainvar, ((LineStyleThicknessModifier_DistanceFromObject *)m)->target);
}
}
static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
{
if (gpd->adt)
expand_animdata(fd, mainvar, gpd->adt);
}
void BLO_main_expander(void (*expand_doit_func)(void *, Main *, void *))
{
expand_doit = expand_doit_func;
}
void BLO_expand_main(void *fdhandle, Main *mainvar)
{
ListBase *lbarray[MAX_LIBARRAY];
FileData *fd = fdhandle;
ID *id;
int a;
bool do_it = true;
while (do_it) {
do_it = false;
a = set_listbasepointers(mainvar, lbarray);
while (a--) {
id = lbarray[a]->first;
while (id) {
if (id->flag & LIB_NEED_EXPAND) {
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_SPK:
expand_speaker(fd, mainvar, (Speaker *)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); // XXX deprecated - old animation system
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); // XXX deprecated - old animation system
break;
case ID_PA:
expand_particlesettings(fd, mainvar, (ParticleSettings *)id);
break;
case ID_MC:
expand_movieclip(fd, mainvar, (MovieClip *)id);
break;
case ID_MSK:
expand_mask(fd, mainvar, (Mask *)id);
break;
case ID_LS:
expand_linestyle(fd, mainvar, (FreestyleLineStyle *)id);
break;
case ID_GD:
expand_gpencil(fd, mainvar, (bGPdata *)id);
break;
}
do_it = true;
id->flag -= LIB_NEED_EXPAND;
}
id = id->next;
}
}
}
}
/* ***************************** */
static bool object_in_any_scene(Main *mainvar, Object *ob)
{
Scene *sce;
for (sce= mainvar->scene.first; sce; sce= sce->id.next) {
if (BKE_scene_base_find(sce, ob))
return 1;
}
return 0;
}
static void give_base_to_objects(Main *mainvar, Scene *sce, Library *lib, const short idcode, const bool is_link, const short active_lay)
{
Object *ob;
Base *base;
const bool is_group_append = (is_link == false && idcode == ID_GR);
/* give all objects which are LIB_INDIRECT a base, or for a group when *lib has been set */
for (ob = mainvar->object.first; ob; ob = ob->id.next) {
if (ob->id.flag & LIB_INDIRECT) {
/* IF below is quite confusing!
* if we are appending, but this object wasnt just added along with a group,
* then this is already used indirectly in the scene somewhere else and we didnt just append it.
*
* (ob->id.flag & LIB_PRE_EXISTING)==0 means that this is a newly appended object - Campbell */
if (is_group_append==0 || (ob->id.flag & LIB_PRE_EXISTING)==0) {
bool do_it = false;
if (ob->id.us == 0) {
do_it = true;
}
else if (idcode==ID_GR) {
if (ob->id.us == 1 && is_link == false && ob->id.lib == lib) {
if ((ob->flag & OB_FROMGROUP) && object_in_any_scene(mainvar, ob)==0) {
do_it = true;
}
}
}
else {
/* when appending, make sure any indirectly loaded objects
* get a base else they cant be accessed at all [#27437] */
if (ob->id.us==1 && is_link == false && ob->id.lib == lib) {
/* we may be appending from a scene where we already
* have a linked object which is not in any scene [#27616] */
if ((ob->id.flag & LIB_PRE_EXISTING)==0) {
if (object_in_any_scene(mainvar, ob)==0) {
do_it = true;
}
}
}
}
if (do_it) {
base = MEM_callocN(sizeof(Base), "add_ext_base");
BLI_addtail(&sce->base, base);
if (active_lay) ob->lay = sce->lay;
base->lay = ob->lay;
base->object = ob;
base->flag = ob->flag;
ob->id.us = 1;
ob->id.flag -= LIB_INDIRECT;
ob->id.flag |= LIB_EXTERN;
}
}
}
}
}
static void give_base_to_groups(Main *mainvar, Scene *scene)
{
Group *group;
/* give all objects which are tagged a base */
for (group = mainvar->group.first; group; group = group->id.next) {
if (group->id.flag & LIB_DOIT) {
Base *base;
Object *ob;
/* any indirect group should not have been tagged */
BLI_assert((group->id.flag & LIB_INDIRECT)==0);
/* BKE_object_add(...) messes with the selection */
ob = BKE_object_add_only_object(mainvar, OB_EMPTY, group->id.name + 2);
ob->type = OB_EMPTY;
ob->lay = scene->lay;
/* assign the base */
base = BKE_scene_base_add(scene, ob);
base->flag |= SELECT;
base->object->flag= base->flag;
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
scene->basact = base;
/* assign the group */
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
rename_id(&ob->id, group->id.name + 2);
copy_v3_v3(ob->loc, scene->cursor);
}
}
}
/* returns true if the item was found
* but it may already have already been appended/linked */
static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, const short idcode)
{
BHead *bhead;
ID *id = NULL;
int found = 0;
for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
if (bhead->code == idcode) {
const char *idname_test= bhead_id_name(fd, bhead);
if (strcmp(idname_test + 2, idname) == 0) {
found = 1;
id = is_yet_read(fd, mainl, bhead);
if (id == NULL) {
/* not read yet */
read_libblock(fd, mainl, bhead, LIB_TESTEXT, &id);
if (id) {
/* sort by name in list */
ListBase *lb = which_libbase(mainl, idcode);
id_sort_by_name(lb, id);
}
}
else {
/* already linked */
if (G.debug)
printf("append: already linked\n");
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
if (id->flag & LIB_INDIRECT) {
id->flag -= LIB_INDIRECT;
id->flag |= LIB_EXTERN;
}
}
break;
}
}
else if (bhead->code == ENDB) {
break;
}
}
/* if we found the id but the id is NULL, this is really bad */
BLI_assert((found != 0) == (id != NULL));
return (found) ? id : NULL;
}
/* simple reader for copy/paste buffers */
void BLO_library_append_all(Main *mainl, BlendHandle *bh)
{
FileData *fd = (FileData *)(bh);
BHead *bhead;
ID *id = NULL;
for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
if (bhead->code == ENDB)
break;
if (bhead->code == ID_OB)
read_libblock(fd, mainl, bhead, LIB_TESTIND, &id);
if (id) {
/* sort by name in list */
ListBase *lb = which_libbase(mainl, GS(id->name));
id_sort_by_name(lb, id);
}
}
}
static ID *append_named_part_ex(const bContext *C, Main *mainl, FileData *fd, const char *idname, const int idcode, const int flag)
{
ID *id= append_named_part(mainl, fd, idname, idcode);
if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */
Scene *scene = CTX_data_scene(C); /* can be NULL */
if (scene) {
Base *base;
Object *ob;
base= MEM_callocN(sizeof(Base), "app_nam_part");
BLI_addtail(&scene->base, base);
ob = (Object *)id;
/* link at active layer (view3d if available in context, else scene one */
if ((flag & FILE_ACTIVELAY)) {
View3D *v3d = CTX_wm_view3d(C);
ob->lay = BKE_screen_view3d_layer_active(v3d, scene);
}
ob->mode = OB_MODE_OBJECT;
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 */
}
}
}
else if (id && (GS(id->name) == ID_GR)) {
/* tag as needing to be instanced */
if (flag & FILE_GROUP_INSTANCE)
id->flag |= LIB_DOIT;
}
return id;
}
ID *BLO_library_append_named_part(Main *mainl, BlendHandle **bh, const char *idname, const int idcode)
{
FileData *fd = (FileData*)(*bh);
return append_named_part(mainl, fd, idname, idcode);
}
ID *BLO_library_append_named_part_ex(const bContext *C, Main *mainl, BlendHandle **bh, const char *idname, const int idcode, const short flag)
{
FileData *fd = (FileData*)(*bh);
return append_named_part_ex(C, mainl, fd, idname, idcode, flag);
}
static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **r_id)
{
BHead *bhead;
for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
if (bhead->code == GS(id->name)) {
if (strcmp(id->name, bhead_id_name(fd, bhead))==0) {
id->flag &= ~LIB_READ;
id->flag |= LIB_NEED_EXPAND;
// printf("read lib block %s\n", id->name);
read_libblock(fd, mainvar, bhead, id->flag, r_id);
break;
}
}
else if (bhead->code==ENDB)
break;
}
}
/* common routine to append/link something from a library */
static Main *library_append_begin(Main *mainvar, FileData **fd, const char *filepath)
{
Main *mainl;
(*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
/* clear for group instancing tag */
BKE_main_id_tag_listbase(&(mainvar->group), false);
/* make mains */
blo_split_main((*fd)->mainlist, mainvar);
/* which one do we need? */
mainl = blo_find_main(*fd, filepath, G.main->name);
/* needed for do_version */
mainl->versionfile = (*fd)->fileversion;
read_file_version(*fd, mainl);
return mainl;
}
Main *BLO_library_append_begin(Main *mainvar, BlendHandle **bh, const char *filepath)
{
FileData *fd = (FileData*)(*bh);
return library_append_begin(mainvar, &fd, filepath);
}
/* Context == NULL signifies not to do any scene manipulation */
static void library_append_end(const bContext *C, Main *mainl, FileData **fd, int idcode, short flag)
{
Main *mainvar;
Library *curlib;
/* expander now is callback function */
BLO_main_expander(expand_doit_library);
/* make main consistent */
BLO_expand_main(*fd, mainl);
/* do this when expand found other libs */
read_libraries(*fd, (*fd)->mainlist);
curlib = mainl->curlib;
/* make the lib path relative if required */
if (flag & FILE_RELPATH) {
/* use the full path, this could have been read by other library even */
BLI_strncpy(curlib->name, curlib->filepath, sizeof(curlib->name));
/* uses current .blend file as reference */
BLI_path_rel(curlib->name, G.main->name);
}
blo_join_main((*fd)->mainlist);
mainvar = (*fd)->mainlist->first;
MEM_freeN((*fd)->mainlist);
mainl = NULL; /* blo_join_main free's mainl, cant use anymore */
lib_link_all(*fd, mainvar);
lib_verify_nodetree(mainvar, false);
fix_relpaths_library(G.main->name, mainvar); /* make all relative paths, relative to the open blend file */
if (C) {
Scene *scene = CTX_data_scene(C);
/* give a base to loose objects. If group append, do it for objects too */
if (scene) {
const bool is_link = (flag & FILE_LINK) != 0;
if (idcode == ID_SCE) {
/* don't instance anything when linking in scenes, assume the scene its self instances the data */
}
else {
give_base_to_objects(mainvar, scene, curlib, idcode, is_link, flag & FILE_ACTIVELAY);
if (flag & FILE_GROUP_INSTANCE) {
give_base_to_groups(mainvar, scene);
}
}
}
else {
printf("library_append_end, scene is NULL (objects wont get bases)\n");
}
}
/* clear group instancing tag */
BKE_main_id_tag_listbase(&(mainvar->group), false);
/* has been removed... erm, why? s..ton) */
/* 20040907: looks like they are give base already in append_named_part(); -Nathan L */
/* 20041208: put back. It only linked direct, not indirect objects (ton) */
/* patch to prevent switch_endian happens twice */
if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
blo_freefiledata(*fd);
*fd = NULL;
}
}
void BLO_library_append_end(const bContext *C, struct Main *mainl, BlendHandle **bh, int idcode, short flag)
{
FileData *fd = (FileData*)(*bh);
library_append_end(C, mainl, &fd, idcode, flag);
*bh = (BlendHandle*)fd;
}
void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
{
return read_struct(fd, bh, blockname);
}
/* ************* 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;
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;
bool do_it = true;
/* expander now is callback function */
BLO_main_expander(expand_doit_library);
while (do_it) {
do_it = false;
/* 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) {
/* printf and reports for now... its important users know this */
/* if packed file... */
if (mainptr->curlib->packedfile) {
PackedFile *pf = mainptr->curlib->packedfile;
blo_reportf_wrap(
basefd->reports, RPT_INFO, TIP_("Read packed library: '%s', parent '%s'"),
mainptr->curlib->name,
library_parent_filepath(mainptr->curlib));
fd = blo_openblendermemory(pf->data, pf->size, basefd->reports);
/* needed for library_append and read_libraries */
BLI_strncpy(fd->relabase, mainptr->curlib->filepath, sizeof(fd->relabase));
}
else {
blo_reportf_wrap(
basefd->reports, RPT_INFO, TIP_("Read library: '%s', '%s', parent '%s'"),
mainptr->curlib->filepath,
mainptr->curlib->name,
library_parent_filepath(mainptr->curlib));
fd = blo_openblenderfile(mainptr->curlib->filepath, basefd->reports);
}
/* allow typing in a new lib path */
if (G.debug_value == -666) {
while (fd == NULL) {
char newlib_path[FILE_MAX] = {0};
printf("Missing library...'\n");
printf(" current file: %s\n", G.main->name);
printf(" absolute lib: %s\n", mainptr->curlib->filepath);
printf(" relative lib: %s\n", mainptr->curlib->name);
printf(" enter a new path:\n");
if (scanf("%s", newlib_path) > 0) {
BLI_strncpy(mainptr->curlib->name, newlib_path, sizeof(mainptr->curlib->name));
BLI_strncpy(mainptr->curlib->filepath, newlib_path, sizeof(mainptr->curlib->filepath));
BLI_cleanup_path(G.main->name, mainptr->curlib->filepath);
fd = blo_openblenderfile(mainptr->curlib->filepath, basefd->reports);
if (fd) {
fd->mainlist = mainlist;
printf("found: '%s', party on macuno!\n", mainptr->curlib->filepath);
}
}
}
}
if (fd) {
/* share the mainlist, so all libraries are added immediately in a
* single list. it used to be that all FileData's had their own list,
* but with indirectly linking this meant we didn't catch duplicate
* libraries properly */
fd->mainlist = mainlist;
fd->reports = basefd->reports;
if (fd->libmap)
oldnewmap_free(fd->libmap);
fd->libmap = oldnewmap_new();
mainptr->curlib->filedata = fd;
mainptr->versionfile= fd->fileversion;
/* subversion */
read_file_version(fd, mainptr);
}
else {
mainptr->curlib->filedata = NULL;
}
if (fd == NULL) {
blo_reportf_wrap(basefd->reports, RPT_WARNING, TIP_("Cannot find lib '%s'"),
mainptr->curlib->filepath);
}
}
if (fd) {
do_it = true;
a = set_listbasepointers(mainptr, lbarray);
while (a--) {
ID *id = lbarray[a]->first;
while (id) {
ID *idn = id->next;
if (id->flag & LIB_READ) {
ID *realid = NULL;
BLI_remlink(lbarray[a], id);
append_id_part(fd, mainptr, id, &realid);
if (!realid) {
blo_reportf_wrap(
fd->reports, RPT_WARNING,
TIP_("LIB ERROR: %s: '%s' missing from '%s', parent '%s'"),
BKE_idcode_to_name(GS(id->name)),
id->name + 2,
mainptr->curlib->filepath,
library_parent_filepath(mainptr->curlib));
}
change_idid_adr(mainlist, basefd, id, realid);
MEM_freeN(id);
}
id = idn;
}
}
BLO_expand_main(fd, mainptr);
}
}
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, *idn = NULL;
for (id = lbarray[a]->first; id; id = idn) {
idn = id->next;
if (id->flag & LIB_READ) {
BLI_remlink(lbarray[a], id);
blo_reportf_wrap(
basefd->reports, RPT_WARNING,
TIP_("LIB ERROR: %s: '%s' unread lib block missing from '%s', parent '%s'"),
BKE_idcode_to_name(GS(id->name)),
id->name + 2,
mainptr->curlib->filepath,
library_parent_filepath(mainptr->curlib));
change_idid_adr(mainlist, basefd, id, NULL);
MEM_freeN(id);
}
}
}
}
/* 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, const char *name, int actualsize, ReportList *reports)
{
BlendFileData *bfd = NULL;
FileData *fd = filedata_new();
fd->filedes = file;
fd->buffersize = actualsize;
fd->read = fd_read_from_file;
/* needed for library_append and read_libraries */
BLI_strncpy(fd->relabase, name, sizeof(fd->relabase));
fd = blo_decode_and_check(fd, reports);
if (!fd)
return NULL;
fd->reports = reports;
bfd = blo_read_file_internal(fd, "");
blo_freefiledata(fd);
return bfd;
}