Blender  V2.59
writefile.c
Go to the documentation of this file.
00001 /*
00002  * $Id: writefile.c 39084 2011-08-05 20:45:26Z blendix $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  *
00024  * Contributor(s): Blender Foundation
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 /*
00035 FILEFORMAT: IFF-style structure  (but not IFF compatible!)
00036 
00037 start file:
00038         BLENDER_V100    12 bytes  (versie 1.00)
00039                                         V = big endian, v = little endian
00040                                         _ = 4 byte pointer, - = 8 byte pointer
00041 
00042 datablocks:             also see struct BHead
00043         <bh.code>                       4 chars
00044         <bh.len>                        int,  len data after BHead
00045         <bh.old>                        void,  old pointer
00046         <bh.SDNAnr>                     int
00047         <bh.nr>                         int, in case of array: amount of structs
00048         data
00049         ...
00050         ...
00051 
00052 Almost all data in Blender are structures. Each struct saved
00053 gets a BHead header.  With BHead the struct can be linked again
00054 and compared with StructDNA .
00055 
00056 WRITE
00057 
00058 Preferred writing order: (not really a must, but why would you do it random?)
00059 Any case: direct data is ALWAYS after the lib block
00060 
00061 (Local file data)
00062 - for each LibBlock
00063         - write LibBlock
00064         - write associated direct data
00065 (External file data)
00066 - per library
00067         - write library block
00068         - per LibBlock
00069                 - write the ID of LibBlock
00070 - write TEST (128x128, blend file preview, optional)
00071 - write FileGlobal (some global vars)
00072 - write SDNA
00073 - write USER if filename is ~/X.XX/config/startup.blend
00074 */
00075 
00076 
00077 #include <math.h>
00078 #include <fcntl.h>
00079 #include <stdio.h>
00080 #include <string.h>
00081 #include <stdlib.h>
00082 
00083 #include "zlib.h"
00084 
00085 #ifndef WIN32
00086 #include <unistd.h>
00087 #else
00088 #include "winsock2.h"
00089 #include <io.h>
00090 #include <process.h> // for getpid
00091 #include "BLI_winstuff.h"
00092 #endif
00093 
00094 #include "DNA_anim_types.h"
00095 #include "DNA_armature_types.h"
00096 #include "DNA_actuator_types.h"
00097 #include "DNA_brush_types.h"
00098 #include "DNA_camera_types.h"
00099 #include "DNA_cloth_types.h"
00100 #include "DNA_constraint_types.h"
00101 #include "DNA_controller_types.h"
00102 #include "DNA_genfile.h"
00103 #include "DNA_group_types.h"
00104 #include "DNA_gpencil_types.h"
00105 #include "DNA_fileglobal_types.h"
00106 #include "DNA_key_types.h"
00107 #include "DNA_lattice_types.h"
00108 #include "DNA_lamp_types.h"
00109 #include "DNA_meta_types.h"
00110 #include "DNA_mesh_types.h"
00111 #include "DNA_meshdata_types.h"
00112 #include "DNA_material_types.h"
00113 #include "DNA_node_types.h"
00114 #include "DNA_object_types.h"
00115 #include "DNA_object_force.h"
00116 #include "DNA_packedFile_types.h"
00117 #include "DNA_particle_types.h"
00118 #include "DNA_property_types.h"
00119 #include "DNA_scene_types.h"
00120 #include "DNA_sdna_types.h"
00121 #include "DNA_sequence_types.h"
00122 #include "DNA_sensor_types.h"
00123 #include "DNA_smoke_types.h"
00124 #include "DNA_space_types.h"
00125 #include "DNA_screen_types.h"
00126 #include "DNA_sound_types.h"
00127 #include "DNA_text_types.h"
00128 #include "DNA_view3d_types.h"
00129 #include "DNA_vfont_types.h"
00130 #include "DNA_world_types.h"
00131 #include "DNA_windowmanager_types.h"
00132 
00133 #include "MEM_guardedalloc.h" // MEM_freeN
00134 #include "BLI_blenlib.h"
00135 #include "BLI_linklist.h"
00136 #include "BLI_bpath.h"
00137 #include "BLI_utildefines.h"
00138 
00139 #include "BKE_action.h"
00140 #include "BKE_blender.h"
00141 #include "BKE_curve.h"
00142 #include "BKE_constraint.h"
00143 #include "BKE_global.h" // for G
00144 #include "BKE_library.h" // for  set_listbasepointers
00145 #include "BKE_main.h"
00146 #include "BKE_node.h"
00147 #include "BKE_report.h"
00148 #include "BKE_sequencer.h"
00149 #include "BKE_utildefines.h"
00150 #include "BKE_modifier.h"
00151 #include "BKE_fcurve.h"
00152 #include "BKE_pointcache.h"
00153 
00154 #include "BLO_writefile.h"
00155 #include "BLO_readfile.h"
00156 #include "BLO_undofile.h"
00157 
00158 #include "readfile.h"
00159 
00160 #include <errno.h>
00161 
00162 /* ********* my write, buffered writing with minimum size chunks ************ */
00163 
00164 #define MYWRITE_BUFFER_SIZE     100000
00165 #define MYWRITE_MAX_CHUNK       32768
00166 
00167 typedef struct {
00168         struct SDNA *sdna;
00169 
00170         int file;
00171         unsigned char *buf;
00172         MemFile *compare, *current;
00173         
00174         int tot, count, error, memsize;
00175 } WriteData;
00176 
00177 static WriteData *writedata_new(int file)
00178 {
00179         WriteData *wd= MEM_callocN(sizeof(*wd), "writedata");
00180 
00181                 /* XXX, see note about this in readfile.c, remove
00182                  * once we have an xp lock - zr
00183                  */
00184 
00185         if (wd == NULL) return NULL;
00186 
00187         wd->sdna= DNA_sdna_from_data(DNAstr, DNAlen, 0);
00188 
00189         wd->file= file;
00190 
00191         wd->buf= MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf");
00192 
00193         return wd;
00194 }
00195 
00196 static void writedata_do_write(WriteData *wd, void *mem, int memlen)
00197 {
00198         if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) return;
00199         if (wd->error) return;
00200 
00201         /* memory based save */
00202         if(wd->current) {
00203                 add_memfilechunk(NULL, wd->current, mem, memlen);
00204         }
00205         else {
00206                 if (write(wd->file, mem, memlen) != memlen)
00207                         wd->error= 1;
00208                 
00209         }
00210 }
00211 
00212 static void writedata_free(WriteData *wd)
00213 {
00214         DNA_sdna_free(wd->sdna);
00215 
00216         MEM_freeN(wd->buf);
00217         MEM_freeN(wd);
00218 }
00219 
00220 /***/
00221 
00229 #define MYWRITE_FLUSH           NULL
00230 
00231 static void mywrite( WriteData *wd, void *adr, int len)
00232 {
00233         if (wd->error) return;
00234 
00235         /* flush helps compression for undo-save */
00236         if(adr==MYWRITE_FLUSH) {
00237                 if(wd->count) {
00238                         writedata_do_write(wd, wd->buf, wd->count);
00239                         wd->count= 0;
00240                 }
00241                 return;
00242         }
00243 
00244         wd->tot+= len;
00245         
00246         /* if we have a single big chunk, write existing data in
00247          * buffer and write out big chunk in smaller pieces */
00248         if(len>MYWRITE_MAX_CHUNK) {
00249                 if(wd->count) {
00250                         writedata_do_write(wd, wd->buf, wd->count);
00251                         wd->count= 0;
00252                 }
00253 
00254                 do {
00255                         int writelen= MIN2(len, MYWRITE_MAX_CHUNK);
00256                         writedata_do_write(wd, adr, writelen);
00257                         adr = (char*)adr + writelen;
00258                         len -= writelen;
00259                 } while(len > 0);
00260 
00261                 return;
00262         }
00263 
00264         /* if data would overflow buffer, write out the buffer */
00265         if(len+wd->count>MYWRITE_BUFFER_SIZE-1) {
00266                 writedata_do_write(wd, wd->buf, wd->count);
00267                 wd->count= 0;
00268         }
00269 
00270         /* append data at end of buffer */
00271         memcpy(&wd->buf[wd->count], adr, len);
00272         wd->count+= len;
00273 }
00274 
00281 static WriteData *bgnwrite(int file, MemFile *compare, MemFile *current)
00282 {
00283         WriteData *wd= writedata_new(file);
00284 
00285         if (wd == NULL) return NULL;
00286 
00287         wd->compare= compare;
00288         wd->current= current;
00289         /* this inits comparing */
00290         add_memfilechunk(compare, NULL, NULL, 0);
00291         
00292         return wd;
00293 }
00294 
00301 static int endwrite(WriteData *wd)
00302 {
00303         int err;
00304 
00305         if (wd->count) {
00306                 writedata_do_write(wd, wd->buf, wd->count);
00307                 wd->count= 0;
00308         }
00309         
00310         err= wd->error;
00311         writedata_free(wd);
00312 
00313         return err;
00314 }
00315 
00316 /* ********** WRITE FILE ****************** */
00317 
00318 static void writestruct(WriteData *wd, int filecode, const char *structname, int nr, void *adr)
00319 {
00320         BHead bh;
00321         short *sp;
00322 
00323         if(adr==NULL || nr==0) return;
00324 
00325         /* init BHead */
00326         bh.code= filecode;
00327         bh.old= adr;
00328         bh.nr= nr;
00329 
00330         bh.SDNAnr= DNA_struct_find_nr(wd->sdna, structname);
00331         if(bh.SDNAnr== -1) {
00332                 printf("error: can't find SDNA code <%s>\n", structname);
00333                 return;
00334         }
00335         sp= wd->sdna->structs[bh.SDNAnr];
00336 
00337         bh.len= nr*wd->sdna->typelens[sp[0]];
00338 
00339         if(bh.len==0) return;
00340 
00341         mywrite(wd, &bh, sizeof(BHead));
00342         mywrite(wd, adr, bh.len);
00343 }
00344 
00345 static void writedata(WriteData *wd, int filecode, int len, void *adr)  /* do not use for structs */
00346 {
00347         BHead bh;
00348 
00349         if(adr==NULL) return;
00350         if(len==0) return;
00351 
00352         len+= 3;
00353         len-= ( len % 4);
00354 
00355         /* init BHead */
00356         bh.code= filecode;
00357         bh.old= adr;
00358         bh.nr= 1;
00359         bh.SDNAnr= 0;
00360         bh.len= len;
00361 
00362         mywrite(wd, &bh, sizeof(BHead));
00363         if(len) mywrite(wd, adr, len);
00364 }
00365 
00366 /* *************** writing some direct data structs used in more code parts **************** */
00367 /*These functions are used by blender's .blend system for file saving/loading.*/
00368 void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd);
00369 void IDP_WriteProperty(IDProperty *prop, void *wd);
00370 
00371 static void IDP_WriteArray(IDProperty *prop, void *wd)
00372 {
00373         /*REMEMBER to set totalen to len in the linking code!!*/
00374         if (prop->data.pointer) {
00375                 writedata(wd, DATA, MEM_allocN_len(prop->data.pointer), prop->data.pointer);
00376 
00377                 if(prop->subtype == IDP_GROUP) {
00378                         IDProperty **array= prop->data.pointer;
00379                         int a;
00380 
00381                         for(a=0; a<prop->len; a++)
00382                                 IDP_WriteProperty(array[a], wd);
00383                 }
00384         }
00385 }
00386 
00387 static void IDP_WriteIDPArray(IDProperty *prop, void *wd)
00388 {
00389         /*REMEMBER to set totalen to len in the linking code!!*/
00390         if (prop->data.pointer) {
00391                 IDProperty *array = prop->data.pointer;
00392                 int a;
00393 
00394                 writestruct(wd, DATA, "IDProperty", prop->len, array);
00395 
00396                 for(a=0; a<prop->len; a++)
00397                         IDP_WriteProperty_OnlyData(&array[a], wd);
00398         }
00399 }
00400 
00401 static void IDP_WriteString(IDProperty *prop, void *wd)
00402 {
00403         /*REMEMBER to set totalen to len in the linking code!!*/
00404         writedata(wd, DATA, prop->len+1, prop->data.pointer);
00405 }
00406 
00407 static void IDP_WriteGroup(IDProperty *prop, void *wd)
00408 {
00409         IDProperty *loop;
00410 
00411         for (loop=prop->data.group.first; loop; loop=loop->next) {
00412                 IDP_WriteProperty(loop, wd);
00413         }
00414 }
00415 
00416 /* Functions to read/write ID Properties */
00417 void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd)
00418 {
00419         switch (prop->type) {
00420                 case IDP_GROUP:
00421                         IDP_WriteGroup(prop, wd);
00422                         break;
00423                 case IDP_STRING:
00424                         IDP_WriteString(prop, wd);
00425                         break;
00426                 case IDP_ARRAY:
00427                         IDP_WriteArray(prop, wd);
00428                         break;
00429                 case IDP_IDPARRAY:
00430                         IDP_WriteIDPArray(prop, wd);
00431                         break;
00432         }
00433 }
00434 
00435 void IDP_WriteProperty(IDProperty *prop, void *wd)
00436 {
00437         writestruct(wd, DATA, "IDProperty", 1, prop);
00438         IDP_WriteProperty_OnlyData(prop, wd);
00439 }
00440 
00441 static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers)
00442 {
00443         FModifier *fcm;
00444         
00445         /* Modifiers */
00446         for (fcm= fmodifiers->first; fcm; fcm= fcm->next) {
00447                 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
00448                 
00449                 /* Write the specific data */
00450                 if (fmi && fcm->data) {
00451                         /* firstly, just write the plain fmi->data struct */
00452                         writestruct(wd, DATA, fmi->structName, 1, fcm->data);
00453                         
00454                         /* do any modifier specific stuff */
00455                         switch (fcm->type) {
00456                                 case FMODIFIER_TYPE_GENERATOR:
00457                                 {
00458                                         FMod_Generator *data= (FMod_Generator *)fcm->data;
00459                                         
00460                                         /* write coefficients array */
00461                                         if (data->coefficients)
00462                                                 writedata(wd, DATA, sizeof(float)*(data->arraysize), data->coefficients);
00463                                 }
00464                                         break;
00465                                 case FMODIFIER_TYPE_ENVELOPE:
00466                                 {
00467                                         FMod_Envelope *data= (FMod_Envelope *)fcm->data;
00468                                         
00469                                         /* write envelope data */
00470                                         if (data->data)
00471                                                 writestruct(wd, DATA, "FCM_EnvelopeData", data->totvert, data->data);
00472                                 }
00473                                         break;
00474                                 case FMODIFIER_TYPE_PYTHON:
00475                                 {
00476                                         FMod_Python *data = (FMod_Python *)fcm->data;
00477                                         
00478                                         /* Write ID Properties -- and copy this comment EXACTLY for easy finding
00479                                          of library blocks that implement this.*/
00480                                         IDP_WriteProperty(data->prop, wd);
00481                                 }
00482                                         break;
00483                         }
00484                 }
00485                 
00486                 /* Write the modifier */
00487                 writestruct(wd, DATA, "FModifier", 1, fcm);
00488         }
00489 }
00490 
00491 static void write_fcurves(WriteData *wd, ListBase *fcurves)
00492 {
00493         FCurve *fcu;
00494         
00495         for (fcu=fcurves->first; fcu; fcu=fcu->next) {
00496                 /* F-Curve */
00497                 writestruct(wd, DATA, "FCurve", 1, fcu);
00498                 
00499                 /* curve data */
00500                 if (fcu->bezt)          
00501                         writestruct(wd, DATA, "BezTriple", fcu->totvert, fcu->bezt);
00502                 if (fcu->fpt)
00503                         writestruct(wd, DATA, "FPoint", fcu->totvert, fcu->fpt);
00504                         
00505                 if (fcu->rna_path)
00506                         writedata(wd, DATA, strlen(fcu->rna_path)+1, fcu->rna_path);
00507                 
00508                 /* driver data */
00509                 if (fcu->driver) {
00510                         ChannelDriver *driver= fcu->driver;
00511                         DriverVar *dvar;
00512                         
00513                         writestruct(wd, DATA, "ChannelDriver", 1, driver);
00514                         
00515                         /* variables */
00516                         for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
00517                                 writestruct(wd, DATA, "DriverVar", 1, dvar);
00518                                 
00519                                 DRIVER_TARGETS_USED_LOOPER(dvar)
00520                                 {
00521                                         if (dtar->rna_path)
00522                                                 writedata(wd, DATA, strlen(dtar->rna_path)+1, dtar->rna_path);
00523                                 }
00524                                 DRIVER_TARGETS_LOOPER_END
00525                         }
00526                 }
00527                 
00528                 /* write F-Modifiers */
00529                 write_fmodifiers(wd, &fcu->modifiers);
00530         }
00531 }
00532 
00533 static void write_actions(WriteData *wd, ListBase *idbase)
00534 {
00535         bAction *act;
00536         bActionGroup *grp;
00537         TimeMarker *marker;
00538         
00539         for(act=idbase->first; act; act= act->id.next) {
00540                 if (act->id.us>0 || wd->current) {
00541                         writestruct(wd, ID_AC, "bAction", 1, act);
00542                         if (act->id.properties) IDP_WriteProperty(act->id.properties, wd);
00543                         
00544                         write_fcurves(wd, &act->curves);
00545                         
00546                         for (grp=act->groups.first; grp; grp=grp->next) {
00547                                 writestruct(wd, DATA, "bActionGroup", 1, grp);
00548                         }
00549                         
00550                         for (marker=act->markers.first; marker; marker=marker->next) {
00551                                 writestruct(wd, DATA, "TimeMarker", 1, marker);
00552                         }
00553                 }
00554         }
00555         
00556         /* flush helps the compression for undo-save */
00557         mywrite(wd, MYWRITE_FLUSH, 0);
00558 }
00559 
00560 static void write_keyingsets(WriteData *wd, ListBase *list)
00561 {
00562         KeyingSet *ks;
00563         KS_Path *ksp;
00564         
00565         for (ks= list->first; ks; ks= ks->next) {
00566                 /* KeyingSet */
00567                 writestruct(wd, DATA, "KeyingSet", 1, ks);
00568                 
00569                 /* Paths */
00570                 for (ksp= ks->paths.first; ksp; ksp= ksp->next) {
00571                         /* Path */
00572                         writestruct(wd, DATA, "KS_Path", 1, ksp);
00573                         
00574                         if (ksp->rna_path)
00575                                 writedata(wd, DATA, strlen(ksp->rna_path)+1, ksp->rna_path);
00576                 }
00577         }
00578 }
00579 
00580 static void write_nlastrips(WriteData *wd, ListBase *strips)
00581 {
00582         NlaStrip *strip;
00583         
00584         for (strip= strips->first; strip; strip= strip->next) {
00585                 /* write the strip first */
00586                 writestruct(wd, DATA, "NlaStrip", 1, strip);
00587                 
00588                 /* write the strip's F-Curves and modifiers */
00589                 write_fcurves(wd, &strip->fcurves);
00590                 write_fmodifiers(wd, &strip->modifiers);
00591                 
00592                 /* write the strip's children */
00593                 write_nlastrips(wd, &strip->strips);
00594         }
00595 }
00596 
00597 static void write_nladata(WriteData *wd, ListBase *nlabase)
00598 {
00599         NlaTrack *nlt;
00600         
00601         /* write all the tracks */
00602         for (nlt= nlabase->first; nlt; nlt= nlt->next) {
00603                 /* write the track first */
00604                 writestruct(wd, DATA, "NlaTrack", 1, nlt);
00605                 
00606                 /* write the track's strips */
00607                 write_nlastrips(wd, &nlt->strips);
00608         }
00609 }
00610 
00611 static void write_animdata(WriteData *wd, AnimData *adt)
00612 {
00613         AnimOverride *aor;
00614         
00615         /* firstly, just write the AnimData block */
00616         writestruct(wd, DATA, "AnimData", 1, adt);
00617         
00618         /* write drivers */
00619         write_fcurves(wd, &adt->drivers);
00620         
00621         /* write overrides */
00622         // FIXME: are these needed?
00623         for (aor= adt->overrides.first; aor; aor= aor->next) {
00624                 /* overrides consist of base data + rna_path */
00625                 writestruct(wd, DATA, "AnimOverride", 1, aor);
00626                 writedata(wd, DATA, strlen(aor->rna_path)+1, aor->rna_path);
00627         }
00628         
00629         // TODO write the remaps (if they are needed)
00630         
00631         /* write NLA data */
00632         write_nladata(wd, &adt->nla_tracks);
00633 }
00634 
00635 static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
00636 {
00637         int a;
00638         
00639         writestruct(wd, DATA, "CurveMapping", 1, cumap);
00640         for(a=0; a<CM_TOT; a++)
00641                 writestruct(wd, DATA, "CurveMapPoint", cumap->cm[a].totpoint, cumap->cm[a].curve);
00642 }
00643 
00644 /* this is only direct data, tree itself should have been written */
00645 static void write_nodetree(WriteData *wd, bNodeTree *ntree)
00646 {
00647         bNode *node;
00648         bNodeSocket *sock;
00649         bNodeLink *link;
00650         
00651         /* for link_list() speed, we write per list */
00652         
00653         if(ntree->adt) write_animdata(wd, ntree->adt);
00654         
00655         for(node= ntree->nodes.first; node; node= node->next)
00656                 writestruct(wd, DATA, "bNode", 1, node);
00657 
00658         for(node= ntree->nodes.first; node; node= node->next) {
00659                 if(node->storage && node->type!=NODE_DYNAMIC) {
00660                         /* could be handlerized at some point, now only 1 exception still */
00661                         if(ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
00662                                 write_curvemapping(wd, node->storage);
00663                         else if(ntree->type==NTREE_COMPOSIT && ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
00664                                 write_curvemapping(wd, node->storage);
00665                         else if(ntree->type==NTREE_TEXTURE && (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME) )
00666                                 write_curvemapping(wd, node->storage);
00667                         else 
00668                                 writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
00669                 }
00670                 for(sock= node->inputs.first; sock; sock= sock->next)
00671                         writestruct(wd, DATA, "bNodeSocket", 1, sock);
00672                 for(sock= node->outputs.first; sock; sock= sock->next)
00673                         writestruct(wd, DATA, "bNodeSocket", 1, sock);
00674         }
00675         
00676         for(link= ntree->links.first; link; link= link->next)
00677                 writestruct(wd, DATA, "bNodeLink", 1, link);
00678         
00679         /* external sockets */
00680         for(sock= ntree->inputs.first; sock; sock= sock->next)
00681                 writestruct(wd, DATA, "bNodeSocket", 1, sock);
00682         for(sock= ntree->outputs.first; sock; sock= sock->next)
00683                 writestruct(wd, DATA, "bNodeSocket", 1, sock);
00684 }
00685 
00686 static void current_screen_compat(Main *mainvar, bScreen **screen)
00687 {
00688         wmWindowManager *wm;
00689         wmWindow *window;
00690 
00691         /* find a global current screen in the first open window, to have
00692          * a reasonable default for reading in older versions */
00693         wm= mainvar->wm.first;
00694         window= (wm)? wm->windows.first: NULL;
00695         *screen= (window)? window->screen: NULL;
00696 }
00697 
00698 static void write_renderinfo(WriteData *wd, Main *mainvar)              /* for renderdeamon */
00699 {
00700         bScreen *curscreen;
00701         Scene *sce;
00702         int data[8];
00703 
00704         /* XXX in future, handle multiple windows with multiple screnes? */
00705         current_screen_compat(mainvar, &curscreen);
00706 
00707         for(sce= mainvar->scene.first; sce; sce= sce->id.next) {
00708                 if(sce->id.lib==NULL  && ( sce==curscreen->scene || (sce->r.scemode & R_BG_RENDER)) ) {
00709                         data[0]= sce->r.sfra;
00710                         data[1]= sce->r.efra;
00711 
00712                         memset(data+2, 0, sizeof(int)*6);
00713                         BLI_strncpy((char *)(data+2), sce->id.name+2, sizeof(sce->id.name)-2);
00714 
00715                         writedata(wd, REND, 32, data);
00716                 }
00717         }
00718 }
00719 
00720 static void write_keymapitem(WriteData *wd, wmKeyMapItem *kmi)
00721 {
00722         writestruct(wd, DATA, "wmKeyMapItem", 1, kmi);
00723         if(kmi->properties)
00724                 IDP_WriteProperty(kmi->properties, wd);
00725 }
00726 
00727 static void write_userdef(WriteData *wd)
00728 {
00729         bTheme *btheme;
00730         wmKeyMap *keymap;
00731         wmKeyMapItem *kmi;
00732         wmKeyMapDiffItem *kmdi;
00733         bAddon *bext;
00734         uiStyle *style;
00735         
00736         writestruct(wd, USER, "UserDef", 1, &U);
00737 
00738         for(btheme= U.themes.first; btheme; btheme=btheme->next)
00739                 writestruct(wd, DATA, "bTheme", 1, btheme);
00740 
00741         for(keymap= U.user_keymaps.first; keymap; keymap=keymap->next) {
00742                 writestruct(wd, DATA, "wmKeyMap", 1, keymap);
00743 
00744                 for(kmdi=keymap->diff_items.first; kmdi; kmdi=kmdi->next) {
00745                         writestruct(wd, DATA, "wmKeyMapDiffItem", 1, kmdi);
00746                         if(kmdi->remove_item)
00747                                 write_keymapitem(wd, kmdi->remove_item);
00748                         if(kmdi->add_item)
00749                                 write_keymapitem(wd, kmdi->add_item);
00750                 }
00751 
00752                 for(kmi=keymap->items.first; kmi; kmi=kmi->next)
00753                         write_keymapitem(wd, kmi);
00754         }
00755 
00756         for(bext= U.addons.first; bext; bext=bext->next)
00757                 writestruct(wd, DATA, "bAddon", 1, bext);
00758         
00759         for(style= U.uistyles.first; style; style= style->next) {
00760                 writestruct(wd, DATA, "uiStyle", 1, style);
00761         }
00762 }
00763 
00764 static void write_boid_state(WriteData *wd, BoidState *state)
00765 {
00766         BoidRule *rule = state->rules.first;
00767         //BoidCondition *cond = state->conditions.first;
00768 
00769         writestruct(wd, DATA, "BoidState", 1, state);
00770 
00771         for(; rule; rule=rule->next) {
00772                 switch(rule->type) {
00773                         case eBoidRuleType_Goal:
00774                         case eBoidRuleType_Avoid:
00775                                 writestruct(wd, DATA, "BoidRuleGoalAvoid", 1, rule);
00776                                 break;
00777                         case eBoidRuleType_AvoidCollision:
00778                                 writestruct(wd, DATA, "BoidRuleAvoidCollision", 1, rule);
00779                                 break;
00780                         case eBoidRuleType_FollowLeader:
00781                                 writestruct(wd, DATA, "BoidRuleFollowLeader", 1, rule);
00782                                 break;
00783                         case eBoidRuleType_AverageSpeed:
00784                                 writestruct(wd, DATA, "BoidRuleAverageSpeed", 1, rule);
00785                                 break;
00786                         case eBoidRuleType_Fight:
00787                                 writestruct(wd, DATA, "BoidRuleFight", 1, rule);
00788                                 break;
00789                         default:
00790                                 writestruct(wd, DATA, "BoidRule", 1, rule);
00791                                 break;
00792                 }
00793         }
00794         //for(; cond; cond=cond->next)
00795         //      writestruct(wd, DATA, "BoidCondition", 1, cond);
00796 }
00797 
00798 /* update this also to readfile.c */
00799 static const char *ptcache_data_struct[] = {
00800         "", // BPHYS_DATA_INDEX
00801         "", // BPHYS_DATA_LOCATION
00802         "", // BPHYS_DATA_VELOCITY
00803         "", // BPHYS_DATA_ROTATION
00804         "", // BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST */
00805         "", // BPHYS_DATA_SIZE:
00806         "", // BPHYS_DATA_TIMES:        
00807         "BoidData" // case BPHYS_DATA_BOIDS:
00808 };
00809 static const char *ptcache_extra_struct[] = {
00810         "",
00811         "ParticleSpring"
00812 };
00813 static void write_pointcaches(WriteData *wd, ListBase *ptcaches)
00814 {
00815         PointCache *cache = ptcaches->first;
00816         int i;
00817 
00818         for(; cache; cache=cache->next) {
00819                 writestruct(wd, DATA, "PointCache", 1, cache);
00820 
00821                 if((cache->flag & PTCACHE_DISK_CACHE)==0) {
00822                         PTCacheMem *pm = cache->mem_cache.first;
00823 
00824                         for(; pm; pm=pm->next) {
00825                                 PTCacheExtra *extra = pm->extradata.first;
00826 
00827                                 writestruct(wd, DATA, "PTCacheMem", 1, pm);
00828                                 
00829                                 for(i=0; i<BPHYS_TOT_DATA; i++) {
00830                                         if(pm->data[i] && pm->data_types & (1<<i)) {
00831                                                 if(strcmp(ptcache_data_struct[i], "")==0)
00832                                                         writedata(wd, DATA, MEM_allocN_len(pm->data[i]), pm->data[i]);
00833                                                 else
00834                                                         writestruct(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]);
00835                                         }
00836                                 }
00837 
00838                                 for(; extra; extra=extra->next) {
00839                                         if(strcmp(ptcache_extra_struct[extra->type], "")==0)
00840                                                 continue;
00841                                         writestruct(wd, DATA, "PTCacheExtra", 1, extra);
00842                                         writestruct(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data);
00843                                 }
00844                         }
00845                 }
00846         }
00847 }
00848 static void write_particlesettings(WriteData *wd, ListBase *idbase)
00849 {
00850         ParticleSettings *part;
00851         ParticleDupliWeight *dw;
00852         GroupObject *go;
00853         int a;
00854 
00855         part= idbase->first;
00856         while(part) {
00857                 if(part->id.us>0 || wd->current) {
00858                         /* write LibData */
00859                         writestruct(wd, ID_PA, "ParticleSettings", 1, part);
00860                         if (part->id.properties) IDP_WriteProperty(part->id.properties, wd);
00861                         if (part->adt) write_animdata(wd, part->adt);
00862                         writestruct(wd, DATA, "PartDeflect", 1, part->pd);
00863                         writestruct(wd, DATA, "PartDeflect", 1, part->pd2);
00864                         writestruct(wd, DATA, "EffectorWeights", 1, part->effector_weights);
00865 
00866                         dw = part->dupliweights.first;
00867                         for(; dw; dw=dw->next) {
00868                                 /* update indices */
00869                                 dw->index = 0;
00870                                 go = part->dup_group->gobject.first;
00871                                 while(go && go->ob != dw->ob) {
00872                                         go=go->next;
00873                                         dw->index++;
00874                                 }
00875                                 writestruct(wd, DATA, "ParticleDupliWeight", 1, dw);
00876                         }
00877 
00878                         if(part->boids && part->phystype == PART_PHYS_BOIDS) {
00879                                 BoidState *state = part->boids->states.first;
00880 
00881                                 writestruct(wd, DATA, "BoidSettings", 1, part->boids);
00882 
00883                                 for(; state; state=state->next)
00884                                         write_boid_state(wd, state);
00885                         }
00886                         if(part->fluid && part->phystype == PART_PHYS_FLUID){
00887                                 writestruct(wd, DATA, "SPHFluidSettings", 1, part->fluid); 
00888                         }
00889 
00890                         for(a=0; a<MAX_MTEX; a++) {
00891                                 if(part->mtex[a]) writestruct(wd, DATA, "MTex", 1, part->mtex[a]);
00892                         }
00893                 }
00894                 part= part->id.next;
00895         }
00896 }
00897 static void write_particlesystems(WriteData *wd, ListBase *particles)
00898 {
00899         ParticleSystem *psys= particles->first;
00900         ParticleTarget *pt;
00901         int a;
00902 
00903         for(; psys; psys=psys->next) {
00904                 writestruct(wd, DATA, "ParticleSystem", 1, psys);
00905 
00906                 if(psys->particles) {
00907                         writestruct(wd, DATA, "ParticleData", psys->totpart ,psys->particles);
00908 
00909                         if(psys->particles->hair) {
00910                                 ParticleData *pa = psys->particles;
00911 
00912                                 for(a=0; a<psys->totpart; a++, pa++)
00913                                         writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair);
00914                         }
00915 
00916                         if(psys->particles->boid && psys->part->phystype == PART_PHYS_BOIDS)
00917                                 writestruct(wd, DATA, "BoidParticle", psys->totpart, psys->particles->boid);
00918 
00919                         if(psys->part->fluid && psys->part->phystype == PART_PHYS_FLUID && (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS))
00920                                 writestruct(wd, DATA, "ParticleSpring", psys->tot_fluidsprings, psys->fluid_springs);
00921                 }
00922                 pt = psys->targets.first;
00923                 for(; pt; pt=pt->next)
00924                         writestruct(wd, DATA, "ParticleTarget", 1, pt);
00925 
00926                 if(psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild ,psys->child);
00927 
00928                 if(psys->clmd) {
00929                         writestruct(wd, DATA, "ClothModifierData", 1, psys->clmd);
00930                         writestruct(wd, DATA, "ClothSimSettings", 1, psys->clmd->sim_parms);
00931                         writestruct(wd, DATA, "ClothCollSettings", 1, psys->clmd->coll_parms);
00932                 }
00933                 
00934                 write_pointcaches(wd, &psys->ptcaches);
00935         }
00936 }
00937 
00938 static void write_properties(WriteData *wd, ListBase *lb)
00939 {
00940         bProperty *prop;
00941 
00942         prop= lb->first;
00943         while(prop) {
00944                 writestruct(wd, DATA, "bProperty", 1, prop);
00945 
00946                 if(prop->poin && prop->poin != &prop->data)
00947                         writedata(wd, DATA, MEM_allocN_len(prop->poin), prop->poin);
00948 
00949                 prop= prop->next;
00950         }
00951 }
00952 
00953 static void write_sensors(WriteData *wd, ListBase *lb)
00954 {
00955         bSensor *sens;
00956 
00957         sens= lb->first;
00958         while(sens) {
00959                 writestruct(wd, DATA, "bSensor", 1, sens);
00960 
00961                 writedata(wd, DATA, sizeof(void *)*sens->totlinks, sens->links);
00962 
00963                 switch(sens->type) {
00964                 case SENS_NEAR:
00965                         writestruct(wd, DATA, "bNearSensor", 1, sens->data);
00966                         break;
00967                 case SENS_MOUSE:
00968                         writestruct(wd, DATA, "bMouseSensor", 1, sens->data);
00969                         break;
00970                 case SENS_TOUCH:
00971                         writestruct(wd, DATA, "bTouchSensor", 1, sens->data);
00972                         break;
00973                 case SENS_KEYBOARD:
00974                         writestruct(wd, DATA, "bKeyboardSensor", 1, sens->data);
00975                         break;
00976                 case SENS_PROPERTY:
00977                         writestruct(wd, DATA, "bPropertySensor", 1, sens->data);
00978                         break;
00979                 case SENS_ARMATURE:
00980                         writestruct(wd, DATA, "bArmatureSensor", 1, sens->data);
00981                         break;
00982                 case SENS_ACTUATOR:
00983                         writestruct(wd, DATA, "bActuatorSensor", 1, sens->data);
00984                         break;
00985                 case SENS_DELAY:
00986                         writestruct(wd, DATA, "bDelaySensor", 1, sens->data);
00987                         break;
00988                 case SENS_COLLISION:
00989                         writestruct(wd, DATA, "bCollisionSensor", 1, sens->data);
00990                         break;
00991                 case SENS_RADAR:
00992                         writestruct(wd, DATA, "bRadarSensor", 1, sens->data);
00993                         break;
00994                 case SENS_RANDOM:
00995                         writestruct(wd, DATA, "bRandomSensor", 1, sens->data);
00996                         break;
00997                 case SENS_RAY:
00998                         writestruct(wd, DATA, "bRaySensor", 1, sens->data);
00999                         break;
01000                 case SENS_MESSAGE:
01001                         writestruct(wd, DATA, "bMessageSensor", 1, sens->data);
01002                         break;
01003                 case SENS_JOYSTICK:
01004                         writestruct(wd, DATA, "bJoystickSensor", 1, sens->data);
01005                         break;
01006                 default:
01007                         ; /* error: don't know how to write this file */
01008                 }
01009 
01010                 sens= sens->next;
01011         }
01012 }
01013 
01014 static void write_controllers(WriteData *wd, ListBase *lb)
01015 {
01016         bController *cont;
01017 
01018         cont= lb->first;
01019         while(cont) {
01020                 writestruct(wd, DATA, "bController", 1, cont);
01021 
01022                 writedata(wd, DATA, sizeof(void *)*cont->totlinks, cont->links);
01023 
01024                 switch(cont->type) {
01025                 case CONT_EXPRESSION:
01026                         writestruct(wd, DATA, "bExpressionCont", 1, cont->data);
01027                         break;
01028                 case CONT_PYTHON:
01029                         writestruct(wd, DATA, "bPythonCont", 1, cont->data);
01030                         break;
01031                 default:
01032                         ; /* error: don't know how to write this file */
01033                 }
01034 
01035                 cont= cont->next;
01036         }
01037 }
01038 
01039 static void write_actuators(WriteData *wd, ListBase *lb)
01040 {
01041         bActuator *act;
01042 
01043         act= lb->first;
01044         while(act) {
01045                 writestruct(wd, DATA, "bActuator", 1, act);
01046 
01047                 switch(act->type) {
01048                 case ACT_ACTION:
01049                 case ACT_SHAPEACTION:
01050                         writestruct(wd, DATA, "bActionActuator", 1, act->data);
01051                         break;
01052                 case ACT_SOUND:
01053                         writestruct(wd, DATA, "bSoundActuator", 1, act->data);
01054                         break;
01055                 case ACT_OBJECT:
01056                         writestruct(wd, DATA, "bObjectActuator", 1, act->data);
01057                         break;
01058                 case ACT_IPO:
01059                         writestruct(wd, DATA, "bIpoActuator", 1, act->data);
01060                         break;
01061                 case ACT_PROPERTY:
01062                         writestruct(wd, DATA, "bPropertyActuator", 1, act->data);
01063                         break;
01064                 case ACT_CAMERA:
01065                         writestruct(wd, DATA, "bCameraActuator", 1, act->data);
01066                         break;
01067                 case ACT_CONSTRAINT:
01068                         writestruct(wd, DATA, "bConstraintActuator", 1, act->data);
01069                         break;
01070                 case ACT_EDIT_OBJECT:
01071                         writestruct(wd, DATA, "bEditObjectActuator", 1, act->data);
01072                         break;
01073                 case ACT_SCENE:
01074                         writestruct(wd, DATA, "bSceneActuator", 1, act->data);
01075                         break;
01076                 case ACT_GROUP:
01077                         writestruct(wd, DATA, "bGroupActuator", 1, act->data);
01078                         break;
01079                 case ACT_RANDOM:
01080                         writestruct(wd, DATA, "bRandomActuator", 1, act->data);
01081                         break;
01082                 case ACT_MESSAGE:
01083                         writestruct(wd, DATA, "bMessageActuator", 1, act->data);
01084                         break;
01085                 case ACT_GAME:
01086                         writestruct(wd, DATA, "bGameActuator", 1, act->data);
01087                         break;
01088                 case ACT_VISIBILITY:
01089                         writestruct(wd, DATA, "bVisibilityActuator", 1, act->data);
01090                         break;
01091                 case ACT_2DFILTER:
01092                         writestruct(wd, DATA, "bTwoDFilterActuator", 1, act->data);
01093                         break;
01094                 case ACT_PARENT:
01095                         writestruct(wd, DATA, "bParentActuator", 1, act->data);
01096                         break;
01097                 case ACT_STATE:
01098                         writestruct(wd, DATA, "bStateActuator", 1, act->data);
01099                         break;
01100                 case ACT_ARMATURE:
01101                         writestruct(wd, DATA, "bArmatureActuator", 1, act->data);
01102                         break;
01103                 default:
01104                         ; /* error: don't know how to write this file */
01105                 }
01106 
01107                 act= act->next;
01108         }
01109 }
01110 
01111 static void write_motionpath(WriteData *wd, bMotionPath *mpath)
01112 {
01113         /* sanity checks */
01114         if (mpath == NULL)
01115                 return;
01116         
01117         /* firstly, just write the motionpath struct */
01118         writestruct(wd, DATA, "bMotionPath", 1, mpath);
01119         
01120         /* now write the array of data */
01121         writestruct(wd, DATA, "bMotionPathVert", mpath->length, mpath->points);
01122 }
01123 
01124 static void write_constraints(WriteData *wd, ListBase *conlist)
01125 {
01126         bConstraint *con;
01127 
01128         for (con=conlist->first; con; con=con->next) {
01129                 bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
01130                 
01131                 /* Write the specific data */
01132                 if (cti && con->data) {
01133                         /* firstly, just write the plain con->data struct */
01134                         writestruct(wd, DATA, cti->structName, 1, con->data);
01135                         
01136                         /* do any constraint specific stuff */
01137                         switch (con->type) {
01138                                 case CONSTRAINT_TYPE_PYTHON:
01139                                 {
01140                                         bPythonConstraint *data = (bPythonConstraint *)con->data;
01141                                         bConstraintTarget *ct;
01142                                         
01143                                         /* write targets */
01144                                         for (ct= data->targets.first; ct; ct= ct->next)
01145                                                 writestruct(wd, DATA, "bConstraintTarget", 1, ct);
01146                                         
01147                                         /* Write ID Properties -- and copy this comment EXACTLY for easy finding
01148                                          of library blocks that implement this.*/
01149                                         IDP_WriteProperty(data->prop, wd);
01150                                 }
01151                                         break;
01152                                 case CONSTRAINT_TYPE_SPLINEIK: 
01153                                 {
01154                                         bSplineIKConstraint *data= (bSplineIKConstraint*)con->data;
01155                                         
01156                                         /* write points array */
01157                                         writedata(wd, DATA, sizeof(float)*(data->numpoints), data->points);
01158                                 }
01159                                         break;
01160                         }
01161                 }
01162                 
01163                 /* Write the constraint */
01164                 writestruct(wd, DATA, "bConstraint", 1, con);
01165         }
01166 }
01167 
01168 static void write_pose(WriteData *wd, bPose *pose)
01169 {
01170         bPoseChannel *chan;
01171         bActionGroup *grp;
01172 
01173         /* Write each channel */
01174         if (!pose)
01175                 return;
01176 
01177         /* Write channels */
01178         for (chan=pose->chanbase.first; chan; chan=chan->next) {
01179                 /* Write ID Properties -- and copy this comment EXACTLY for easy finding
01180                  of library blocks that implement this.*/
01181                 if (chan->prop)
01182                         IDP_WriteProperty(chan->prop, wd);
01183                 
01184                 write_constraints(wd, &chan->constraints);
01185                 
01186                 write_motionpath(wd, chan->mpath);
01187                 
01188                 /* prevent crashes with autosave, when a bone duplicated in editmode has not yet been assigned to its posechannel */
01189                 if (chan->bone) 
01190                         chan->selectflag= chan->bone->flag & BONE_SELECTED; /* gets restored on read, for library armatures */
01191                 
01192                 writestruct(wd, DATA, "bPoseChannel", 1, chan);
01193         }
01194         
01195         /* Write groups */
01196         for (grp=pose->agroups.first; grp; grp=grp->next) 
01197                 writestruct(wd, DATA, "bActionGroup", 1, grp);
01198 
01199         /* write IK param */
01200         if (pose->ikparam) {
01201                 char *structname = (char *)get_ikparam_name(pose);
01202                 if (structname)
01203                         writestruct(wd, DATA, structname, 1, pose->ikparam);
01204         }
01205 
01206         /* Write this pose */
01207         writestruct(wd, DATA, "bPose", 1, pose);
01208 
01209 }
01210 
01211 static void write_defgroups(WriteData *wd, ListBase *defbase)
01212 {
01213         bDeformGroup    *defgroup;
01214 
01215         for (defgroup=defbase->first; defgroup; defgroup=defgroup->next)
01216                 writestruct(wd, DATA, "bDeformGroup", 1, defgroup);
01217 }
01218 
01219 static void write_modifiers(WriteData *wd, ListBase *modbase)
01220 {
01221         ModifierData *md;
01222 
01223         if (modbase == NULL) return;
01224         for (md=modbase->first; md; md= md->next) {
01225                 ModifierTypeInfo *mti = modifierType_getInfo(md->type);
01226                 if (mti == NULL) return;
01227                 
01228                 writestruct(wd, DATA, mti->structName, 1, md);
01229                         
01230                 if (md->type==eModifierType_Hook) {
01231                         HookModifierData *hmd = (HookModifierData*) md;
01232                         
01233                         writedata(wd, DATA, sizeof(int)*hmd->totindex, hmd->indexar);
01234                 }
01235                 else if(md->type==eModifierType_Cloth) {
01236                         ClothModifierData *clmd = (ClothModifierData*) md;
01237                         
01238                         writestruct(wd, DATA, "ClothSimSettings", 1, clmd->sim_parms);
01239                         writestruct(wd, DATA, "ClothCollSettings", 1, clmd->coll_parms);
01240                         writestruct(wd, DATA, "EffectorWeights", 1, clmd->sim_parms->effector_weights);
01241                         write_pointcaches(wd, &clmd->ptcaches);
01242                 } 
01243                 else if(md->type==eModifierType_Smoke) {
01244                         SmokeModifierData *smd = (SmokeModifierData*) md;
01245                         
01246                         if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
01247                         {
01248                                 if(smd->domain)
01249                                 {
01250                                         write_pointcaches(wd, &(smd->domain->ptcaches[0]));
01251 
01252                                         /* create fake pointcache so that old blender versions can read it */
01253                                         smd->domain->point_cache[1] = BKE_ptcache_add(&smd->domain->ptcaches[1]);
01254                                         smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE|PTCACHE_FAKE_SMOKE;
01255                                         smd->domain->point_cache[1]->step = 1;
01256 
01257                                         write_pointcaches(wd, &(smd->domain->ptcaches[1]));
01258                                 }
01259                                 
01260                                 writestruct(wd, DATA, "SmokeDomainSettings", 1, smd->domain);
01261 
01262                                 if(smd->domain) {
01263                                         /* cleanup the fake pointcache */
01264                                         BKE_ptcache_free_list(&smd->domain->ptcaches[1]);
01265                                         smd->domain->point_cache[1] = NULL;
01266                                         
01267                                         writestruct(wd, DATA, "EffectorWeights", 1, smd->domain->effector_weights);
01268                                 }
01269                         }
01270                         else if(smd->type & MOD_SMOKE_TYPE_FLOW)
01271                                 writestruct(wd, DATA, "SmokeFlowSettings", 1, smd->flow);
01272                         else if(smd->type & MOD_SMOKE_TYPE_COLL)
01273                                 writestruct(wd, DATA, "SmokeCollSettings", 1, smd->coll);
01274                 } 
01275                 else if(md->type==eModifierType_Fluidsim) {
01276                         FluidsimModifierData *fluidmd = (FluidsimModifierData*) md;
01277                         
01278                         writestruct(wd, DATA, "FluidsimSettings", 1, fluidmd->fss);
01279                 } 
01280                 else if (md->type==eModifierType_Collision) {
01281                         
01282                         /*
01283                         CollisionModifierData *collmd = (CollisionModifierData*) md;
01284                         // TODO: CollisionModifier should use pointcache 
01285                         // + have proper reset events before enabling this
01286                         writestruct(wd, DATA, "MVert", collmd->numverts, collmd->x);
01287                         writestruct(wd, DATA, "MVert", collmd->numverts, collmd->xnew);
01288                         writestruct(wd, DATA, "MFace", collmd->numfaces, collmd->mfaces);
01289                         */
01290                 }
01291                 else if (md->type==eModifierType_MeshDeform) {
01292                         MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
01293                         int size = mmd->dyngridsize;
01294 
01295                         writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->bindinfluences);
01296                         writedata(wd, DATA, sizeof(int)*(mmd->totvert+1), mmd->bindoffsets);
01297                         writedata(wd, DATA, sizeof(float)*3*mmd->totcagevert,
01298                                 mmd->bindcagecos);
01299                         writestruct(wd, DATA, "MDefCell", size*size*size, mmd->dyngrid);
01300                         writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->dyninfluences);
01301                         writedata(wd, DATA, sizeof(int)*mmd->totvert, mmd->dynverts);
01302                 }
01303                 else if (md->type==eModifierType_Warp) {
01304                         WarpModifierData *tmd = (WarpModifierData*) md;
01305                         if(tmd->curfalloff) {
01306                                 write_curvemapping(wd, tmd->curfalloff);
01307                         }
01308                 }
01309         }
01310 }
01311 
01312 static void write_objects(WriteData *wd, ListBase *idbase)
01313 {
01314         Object *ob;
01315         
01316         ob= idbase->first;
01317         while(ob) {
01318                 if(ob->id.us>0 || wd->current) {
01319                         /* write LibData */
01320                         writestruct(wd, ID_OB, "Object", 1, ob);
01321                         
01322                         /*Write ID Properties -- and copy this comment EXACTLY for easy finding
01323                           of library blocks that implement this.*/
01324                         if (ob->id.properties) IDP_WriteProperty(ob->id.properties, wd);
01325                         
01326                         if (ob->adt) write_animdata(wd, ob->adt);
01327                         
01328                         /* direct data */
01329                         writedata(wd, DATA, sizeof(void *)*ob->totcol, ob->mat);
01330                         writedata(wd, DATA, sizeof(char)*ob->totcol, ob->matbits);
01331                         /* write_effects(wd, &ob->effect); */ /* not used anymore */
01332                         write_properties(wd, &ob->prop);
01333                         write_sensors(wd, &ob->sensors);
01334                         write_controllers(wd, &ob->controllers);
01335                         write_actuators(wd, &ob->actuators);
01336 
01337                         if (ob->type == OB_ARMATURE) {
01338                                 bArmature *arm = ob->data;
01339                                 if (arm && ob->pose && arm->act_bone) {
01340                                         BLI_strncpy(ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone));
01341                                 }
01342                         }
01343 
01344                         write_pose(wd, ob->pose);
01345                         write_defgroups(wd, &ob->defbase);
01346                         write_constraints(wd, &ob->constraints);
01347                         write_motionpath(wd, ob->mpath);
01348                         
01349                         writestruct(wd, DATA, "PartDeflect", 1, ob->pd);
01350                         writestruct(wd, DATA, "SoftBody", 1, ob->soft);
01351                         if(ob->soft) {
01352                                 write_pointcaches(wd, &ob->soft->ptcaches);
01353                                 writestruct(wd, DATA, "EffectorWeights", 1, ob->soft->effector_weights);
01354                         }
01355                         writestruct(wd, DATA, "BulletSoftBody", 1, ob->bsoft);
01356                         
01357                         write_particlesystems(wd, &ob->particlesystem);
01358                         write_modifiers(wd, &ob->modifiers);
01359                 }
01360                 ob= ob->id.next;
01361         }
01362 
01363         /* flush helps the compression for undo-save */
01364         mywrite(wd, MYWRITE_FLUSH, 0);
01365 }
01366 
01367 
01368 static void write_vfonts(WriteData *wd, ListBase *idbase)
01369 {
01370         VFont *vf;
01371         PackedFile * pf;
01372 
01373         vf= idbase->first;
01374         while(vf) {
01375                 if(vf->id.us>0 || wd->current) {
01376                         /* write LibData */
01377                         writestruct(wd, ID_VF, "VFont", 1, vf);
01378                         if (vf->id.properties) IDP_WriteProperty(vf->id.properties, wd);
01379 
01380                         /* direct data */
01381 
01382                         if (vf->packedfile) {
01383                                 pf = vf->packedfile;
01384                                 writestruct(wd, DATA, "PackedFile", 1, pf);
01385                                 writedata(wd, DATA, pf->size, pf->data);
01386                         }
01387                 }
01388 
01389                 vf= vf->id.next;
01390         }
01391 }
01392 
01393 
01394 static void write_keys(WriteData *wd, ListBase *idbase)
01395 {
01396         Key *key;
01397         KeyBlock *kb;
01398 
01399         key= idbase->first;
01400         while(key) {
01401                 if(key->id.us>0 || wd->current) {
01402                         /* write LibData */
01403                         writestruct(wd, ID_KE, "Key", 1, key);
01404                         if (key->id.properties) IDP_WriteProperty(key->id.properties, wd);
01405                         
01406                         if (key->adt) write_animdata(wd, key->adt);
01407                         
01408                         /* direct data */
01409                         kb= key->block.first;
01410                         while(kb) {
01411                                 writestruct(wd, DATA, "KeyBlock", 1, kb);
01412                                 if(kb->data) writedata(wd, DATA, kb->totelem*key->elemsize, kb->data);
01413                                 kb= kb->next;
01414                         }
01415                 }
01416 
01417                 key= key->id.next;
01418         }
01419         /* flush helps the compression for undo-save */
01420         mywrite(wd, MYWRITE_FLUSH, 0);
01421 }
01422 
01423 static void write_cameras(WriteData *wd, ListBase *idbase)
01424 {
01425         Camera *cam;
01426 
01427         cam= idbase->first;
01428         while(cam) {
01429                 if(cam->id.us>0 || wd->current) {
01430                         /* write LibData */
01431                         writestruct(wd, ID_CA, "Camera", 1, cam);
01432                         if (cam->id.properties) IDP_WriteProperty(cam->id.properties, wd);
01433                         
01434                         if (cam->adt) write_animdata(wd, cam->adt);
01435                 }
01436 
01437                 cam= cam->id.next;
01438         }
01439 }
01440 
01441 static void write_mballs(WriteData *wd, ListBase *idbase)
01442 {
01443         MetaBall *mb;
01444         MetaElem *ml;
01445 
01446         mb= idbase->first;
01447         while(mb) {
01448                 if(mb->id.us>0 || wd->current) {
01449                         /* write LibData */
01450                         writestruct(wd, ID_MB, "MetaBall", 1, mb);
01451                         if (mb->id.properties) IDP_WriteProperty(mb->id.properties, wd);
01452 
01453                         /* direct data */
01454                         writedata(wd, DATA, sizeof(void *)*mb->totcol, mb->mat);
01455                         if (mb->adt) write_animdata(wd, mb->adt);
01456 
01457                         ml= mb->elems.first;
01458                         while(ml) {
01459                                 writestruct(wd, DATA, "MetaElem", 1, ml);
01460                                 ml= ml->next;
01461                         }
01462                 }
01463                 mb= mb->id.next;
01464         }
01465 }
01466 
01467 static int amount_of_chars(char *str)
01468 {
01469         // Since the data is saved as UTF-8 to the cu->str
01470         // The cu->len is not same as the strlen(cu->str)
01471         return strlen(str);
01472 }
01473 
01474 static void write_curves(WriteData *wd, ListBase *idbase)
01475 {
01476         Curve *cu;
01477         Nurb *nu;
01478 
01479         cu= idbase->first;
01480         while(cu) {
01481                 if(cu->id.us>0 || wd->current) {
01482                         /* write LibData */
01483                         writestruct(wd, ID_CU, "Curve", 1, cu);
01484                         
01485                         /* direct data */
01486                         writedata(wd, DATA, sizeof(void *)*cu->totcol, cu->mat);
01487                         if (cu->id.properties) IDP_WriteProperty(cu->id.properties, wd);
01488                         if (cu->adt) write_animdata(wd, cu->adt);
01489                         
01490                         if(cu->vfont) {
01491                                 writedata(wd, DATA, amount_of_chars(cu->str)+1, cu->str);
01492                                 writestruct(wd, DATA, "CharInfo", cu->len+1, cu->strinfo);
01493                                 writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb);                           
01494                         }
01495                         else {
01496                                 /* is also the order of reading */
01497                                 nu= cu->nurb.first;
01498                                 while(nu) {
01499                                         writestruct(wd, DATA, "Nurb", 1, nu);
01500                                         nu= nu->next;
01501                                 }
01502                                 nu= cu->nurb.first;
01503                                 while(nu) {
01504                                         if(nu->type == CU_BEZIER)
01505                                                 writestruct(wd, DATA, "BezTriple", nu->pntsu, nu->bezt);
01506                                         else {
01507                                                 writestruct(wd, DATA, "BPoint", nu->pntsu*nu->pntsv, nu->bp);
01508                                                 if(nu->knotsu) writedata(wd, DATA, KNOTSU(nu)*sizeof(float), nu->knotsu);
01509                                                 if(nu->knotsv) writedata(wd, DATA, KNOTSV(nu)*sizeof(float), nu->knotsv);
01510                                         }
01511                                         nu= nu->next;
01512                                 }
01513                         }
01514                 }
01515                 cu= cu->id.next;
01516         }
01517 
01518         /* flush helps the compression for undo-save */
01519         mywrite(wd, MYWRITE_FLUSH, 0);
01520 }
01521 
01522 static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist)
01523 {
01524         if (dvlist) {
01525                 int i;
01526                 
01527                 /* Write the dvert list */
01528                 writestruct(wd, DATA, "MDeformVert", count, dvlist);
01529                 
01530                 /* Write deformation data for each dvert */
01531                 for (i=0; i<count; i++) {
01532                         if (dvlist[i].dw)
01533                                 writestruct(wd, DATA, "MDeformWeight", dvlist[i].totweight, dvlist[i].dw);
01534                 }
01535         }
01536 }
01537 
01538 static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external)
01539 {
01540         if(mdlist) {
01541                 int i;
01542                 
01543                 writestruct(wd, DATA, "MDisps", count, mdlist);
01544                 if(!external) {
01545                         for(i = 0; i < count; ++i) {
01546                                 if(mdlist[i].disps)
01547                                         writedata(wd, DATA, sizeof(float)*3*mdlist[i].totdisp, mdlist[i].disps);
01548                         }
01549                 }
01550         }
01551 }
01552 
01553 static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data, int partial_type, int partial_count)
01554 {
01555         int i;
01556 
01557         /* write external customdata (not for undo) */
01558         if(data->external && !wd->current)
01559                 CustomData_external_write(data, id, CD_MASK_MESH, count, 0);
01560 
01561         writestruct(wd, DATA, "CustomDataLayer", data->maxlayer, data->layers);
01562 
01563         for (i=0; i<data->totlayer; i++) {
01564                 CustomDataLayer *layer= &data->layers[i];
01565                 const char *structname;
01566                 int structnum, datasize;
01567 
01568                 if (layer->type == CD_MDEFORMVERT) {
01569                         /* layer types that allocate own memory need special handling */
01570                         write_dverts(wd, count, layer->data);
01571                 }
01572                 else if (layer->type == CD_MDISPS) {
01573                         write_mdisps(wd, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
01574                 }
01575                 else {
01576                         CustomData_file_write_info(layer->type, &structname, &structnum);
01577                         if (structnum) {
01578                                 /* when using partial visibility, the MEdge and MFace layers
01579                                    are smaller than the original, so their type and count is
01580                                    passed to make this work */
01581                                 if (layer->type != partial_type) datasize= structnum*count;
01582                                 else datasize= structnum*partial_count;
01583 
01584                                 writestruct(wd, DATA, structname, datasize, layer->data);
01585                         }
01586                         else
01587                                 printf("error: this CustomDataLayer must not be written to file\n");
01588                 }
01589         }
01590 
01591         if(data->external)
01592                 writestruct(wd, DATA, "CustomDataExternal", 1, data->external);
01593 }
01594 
01595 static void write_meshs(WriteData *wd, ListBase *idbase)
01596 {
01597         Mesh *mesh;
01598 
01599         mesh= idbase->first;
01600         while(mesh) {
01601                 if(mesh->id.us>0 || wd->current) {
01602                         /* write LibData */
01603                         writestruct(wd, ID_ME, "Mesh", 1, mesh);
01604 
01605                         /* direct data */
01606                         if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
01607                         if (mesh->adt) write_animdata(wd, mesh->adt);
01608 
01609                         writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
01610 
01611                         if(mesh->pv) {
01612                                 write_customdata(wd, &mesh->id, mesh->pv->totvert, &mesh->vdata, -1, 0);
01613                                 write_customdata(wd, &mesh->id, mesh->pv->totedge, &mesh->edata,
01614                                         CD_MEDGE, mesh->totedge);
01615                                 write_customdata(wd, &mesh->id, mesh->pv->totface, &mesh->fdata,
01616                                         CD_MFACE, mesh->totface);
01617                         }
01618                         else {
01619                                 write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, -1, 0);
01620                                 write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, -1, 0);
01621                                 write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, -1, 0);
01622                         }
01623 
01624                         /* PMV data */
01625                         if(mesh->pv) {
01626                                 writestruct(wd, DATA, "PartialVisibility", 1, mesh->pv);
01627                                 writedata(wd, DATA, sizeof(unsigned int)*mesh->pv->totvert, mesh->pv->vert_map);
01628                                 writedata(wd, DATA, sizeof(int)*mesh->pv->totedge, mesh->pv->edge_map);
01629                                 writestruct(wd, DATA, "MFace", mesh->pv->totface, mesh->pv->old_faces);
01630                                 writestruct(wd, DATA, "MEdge", mesh->pv->totedge, mesh->pv->old_edges);
01631                         }
01632                 }
01633                 mesh= mesh->id.next;
01634         }
01635 }
01636 
01637 static void write_lattices(WriteData *wd, ListBase *idbase)
01638 {
01639         Lattice *lt;
01640         
01641         lt= idbase->first;
01642         while(lt) {
01643                 if(lt->id.us>0 || wd->current) {
01644                         /* write LibData */
01645                         writestruct(wd, ID_LT, "Lattice", 1, lt);
01646                         if (lt->id.properties) IDP_WriteProperty(lt->id.properties, wd);
01647                         
01648                         /* write animdata */
01649                         if (lt->adt) write_animdata(wd, lt->adt);
01650                         
01651                         /* direct data */
01652                         writestruct(wd, DATA, "BPoint", lt->pntsu*lt->pntsv*lt->pntsw, lt->def);
01653                         
01654                         write_dverts(wd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert);
01655                         
01656                 }
01657                 lt= lt->id.next;
01658         }
01659 }
01660 
01661 static void write_previews(WriteData *wd, PreviewImage *prv)
01662 {
01663         if (prv) {
01664                 short w = prv->w[1];
01665                 short h = prv->h[1];
01666                 unsigned int *rect = prv->rect[1];
01667                 /* don't write out large previews if not requested */
01668                 if (!(U.flag & USER_SAVE_PREVIEWS) ) {
01669                         prv->w[1] = 0;
01670                         prv->h[1] = 0;
01671                         prv->rect[1] = NULL;
01672                 }
01673                 writestruct(wd, DATA, "PreviewImage", 1, prv);
01674                 if (prv->rect[0]) writedata(wd, DATA, prv->w[0]*prv->h[0]*sizeof(unsigned int), prv->rect[0]);
01675                 if (prv->rect[1]) writedata(wd, DATA, prv->w[1]*prv->h[1]*sizeof(unsigned int), prv->rect[1]);
01676 
01677                 /* restore preview, we still want to keep it in memory even if not saved to file */
01678                 if (!(U.flag & USER_SAVE_PREVIEWS) ) {
01679                         prv->w[1] = w;
01680                         prv->h[1] = h;
01681                         prv->rect[1] = rect;
01682                 }
01683         }
01684 }
01685 
01686 static void write_images(WriteData *wd, ListBase *idbase)
01687 {
01688         Image *ima;
01689         PackedFile * pf;
01690 
01691 
01692         ima= idbase->first;
01693         while(ima) {
01694                 if(ima->id.us>0 || wd->current) {
01695                         /* write LibData */
01696                         writestruct(wd, ID_IM, "Image", 1, ima);
01697                         if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd);
01698 
01699                         if (ima->packedfile) {
01700                                 pf = ima->packedfile;
01701                                 writestruct(wd, DATA, "PackedFile", 1, pf);
01702                                 writedata(wd, DATA, pf->size, pf->data);
01703                         }
01704 
01705                         write_previews(wd, ima->preview);
01706                 }
01707                 ima= ima->id.next;
01708         }
01709         /* flush helps the compression for undo-save */
01710         mywrite(wd, MYWRITE_FLUSH, 0);
01711 }
01712 
01713 static void write_textures(WriteData *wd, ListBase *idbase)
01714 {
01715         Tex *tex;
01716 
01717         tex= idbase->first;
01718         while(tex) {
01719                 if(tex->id.us>0 || wd->current) {
01720                         /* write LibData */
01721                         writestruct(wd, ID_TE, "Tex", 1, tex);
01722                         if (tex->id.properties) IDP_WriteProperty(tex->id.properties, wd);
01723 
01724                         if (tex->adt) write_animdata(wd, tex->adt);
01725 
01726                         /* direct data */
01727                         if(tex->type == TEX_PLUGIN && tex->plugin) writestruct(wd, DATA, "PluginTex", 1, tex->plugin);
01728                         if(tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba);
01729                         if(tex->type == TEX_ENVMAP && tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env);
01730                         if(tex->type == TEX_POINTDENSITY && tex->pd) {
01731                                 writestruct(wd, DATA, "PointDensity", 1, tex->pd);
01732                                 if(tex->pd->coba) writestruct(wd, DATA, "ColorBand", 1, tex->pd->coba);
01733                                 if(tex->pd->falloff_curve) write_curvemapping(wd, tex->pd->falloff_curve);
01734                         }
01735                         if(tex->type == TEX_VOXELDATA && tex->vd) writestruct(wd, DATA, "VoxelData", 1, tex->vd);
01736                         
01737                         /* nodetree is integral part of texture, no libdata */
01738                         if(tex->nodetree) {
01739                                 writestruct(wd, DATA, "bNodeTree", 1, tex->nodetree);
01740                                 write_nodetree(wd, tex->nodetree);
01741                         }
01742                         
01743                         write_previews(wd, tex->preview);
01744                 }
01745                 tex= tex->id.next;
01746         }
01747 
01748         /* flush helps the compression for undo-save */
01749         mywrite(wd, MYWRITE_FLUSH, 0);
01750 }
01751 
01752 static void write_materials(WriteData *wd, ListBase *idbase)
01753 {
01754         Material *ma;
01755         int a;
01756 
01757         ma= idbase->first;
01758         while(ma) {
01759                 if(ma->id.us>0 || wd->current) {
01760                         /* write LibData */
01761                         writestruct(wd, ID_MA, "Material", 1, ma);
01762                         
01763                         /*Write ID Properties -- and copy this comment EXACTLY for easy finding
01764                           of library blocks that implement this.*/
01765                         /*manually set head group property to IDP_GROUP, just in case it hadn't been
01766                           set yet :) */
01767                         if (ma->id.properties) IDP_WriteProperty(ma->id.properties, wd);
01768                         
01769                         if (ma->adt) write_animdata(wd, ma->adt);
01770 
01771                         for(a=0; a<MAX_MTEX; a++) {
01772                                 if(ma->mtex[a]) writestruct(wd, DATA, "MTex", 1, ma->mtex[a]);
01773                         }
01774                         
01775                         if(ma->ramp_col) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_col);
01776                         if(ma->ramp_spec) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_spec);
01777                         
01778                         /* nodetree is integral part of material, no libdata */
01779                         if(ma->nodetree) {
01780                                 writestruct(wd, DATA, "bNodeTree", 1, ma->nodetree);
01781                                 write_nodetree(wd, ma->nodetree);
01782                         }
01783 
01784                         write_previews(wd, ma->preview);                        
01785                 }
01786                 ma= ma->id.next;
01787         }
01788 }
01789 
01790 static void write_worlds(WriteData *wd, ListBase *idbase)
01791 {
01792         World *wrld;
01793         int a;
01794 
01795         wrld= idbase->first;
01796         while(wrld) {
01797                 if(wrld->id.us>0 || wd->current) {
01798                         /* write LibData */
01799                         writestruct(wd, ID_WO, "World", 1, wrld);
01800                         if (wrld->id.properties) IDP_WriteProperty(wrld->id.properties, wd);
01801                         
01802                         if (wrld->adt) write_animdata(wd, wrld->adt);
01803                         
01804                         for(a=0; a<MAX_MTEX; a++) {
01805                                 if(wrld->mtex[a]) writestruct(wd, DATA, "MTex", 1, wrld->mtex[a]);
01806                         }
01807                         
01808                         write_previews(wd, wrld->preview);
01809                 }
01810                 wrld= wrld->id.next;
01811         }
01812 }
01813 
01814 static void write_lamps(WriteData *wd, ListBase *idbase)
01815 {
01816         Lamp *la;
01817         int a;
01818 
01819         la= idbase->first;
01820         while(la) {
01821                 if(la->id.us>0 || wd->current) {
01822                         /* write LibData */
01823                         writestruct(wd, ID_LA, "Lamp", 1, la);
01824                         if (la->id.properties) IDP_WriteProperty(la->id.properties, wd);
01825                         
01826                         if (la->adt) write_animdata(wd, la->adt);
01827                         
01828                         /* direct data */
01829                         for(a=0; a<MAX_MTEX; a++) {
01830                                 if(la->mtex[a]) writestruct(wd, DATA, "MTex", 1, la->mtex[a]);
01831                         }
01832                         
01833                         if(la->curfalloff)
01834                                 write_curvemapping(wd, la->curfalloff); 
01835                         
01836                         write_previews(wd, la->preview);
01837                         
01838                 }
01839                 la= la->id.next;
01840         }
01841 }
01842 
01843 
01844 static void write_scenes(WriteData *wd, ListBase *scebase)
01845 {
01846         Scene *sce;
01847         Base *base;
01848         Editing *ed;
01849         Sequence *seq;
01850         MetaStack *ms;
01851         Strip *strip;
01852         TimeMarker *marker;
01853         TransformOrientation *ts;
01854         SceneRenderLayer *srl;
01855         ToolSettings *tos;
01856         
01857         sce= scebase->first;
01858         while(sce) {
01859                 /* write LibData */
01860                 writestruct(wd, ID_SCE, "Scene", 1, sce);
01861                 if (sce->id.properties) IDP_WriteProperty(sce->id.properties, wd);
01862                 
01863                 if (sce->adt) write_animdata(wd, sce->adt);
01864                 write_keyingsets(wd, &sce->keyingsets);
01865                 
01866                 /* direct data */
01867                 base= sce->base.first;
01868                 while(base) {
01869                         writestruct(wd, DATA, "Base", 1, base);
01870                         base= base->next;
01871                 }
01872                 
01873                 tos = sce->toolsettings;
01874                 writestruct(wd, DATA, "ToolSettings", 1, tos);
01875                 if(tos->vpaint) {
01876                         writestruct(wd, DATA, "VPaint", 1, tos->vpaint);
01877                 }
01878                 if(tos->wpaint) {
01879                         writestruct(wd, DATA, "VPaint", 1, tos->wpaint);
01880                 }
01881                 if(tos->sculpt) {
01882                         writestruct(wd, DATA, "Sculpt", 1, tos->sculpt);
01883                 }
01884 
01885                 // write_paint(wd, &tos->imapaint.paint);
01886 
01887                 ed= sce->ed;
01888                 if(ed) {
01889                         writestruct(wd, DATA, "Editing", 1, ed);
01890                         
01891                         /* reset write flags too */
01892                         
01893                         SEQ_BEGIN(ed, seq) {
01894                                 if(seq->strip) seq->strip->done= 0;
01895                                 writestruct(wd, DATA, "Sequence", 1, seq);
01896                         }
01897                         SEQ_END
01898                         
01899                         SEQ_BEGIN(ed, seq) {
01900                                 if(seq->strip && seq->strip->done==0) {
01901                                         /* write strip with 'done' at 0 because readfile */
01902                                         
01903                                         if(seq->plugin) writestruct(wd, DATA, "PluginSeq", 1, seq->plugin);
01904                                         if(seq->effectdata) {
01905                                                 switch(seq->type){
01906                                                 case SEQ_COLOR:
01907                                                         writestruct(wd, DATA, "SolidColorVars", 1, seq->effectdata);
01908                                                         break;
01909                                                 case SEQ_SPEED:
01910                                                         writestruct(wd, DATA, "SpeedControlVars", 1, seq->effectdata);
01911                                                         break;
01912                                                 case SEQ_WIPE:
01913                                                         writestruct(wd, DATA, "WipeVars", 1, seq->effectdata);
01914                                                         break;
01915                                                 case SEQ_GLOW:
01916                                                         writestruct(wd, DATA, "GlowVars", 1, seq->effectdata);
01917                                                         break;
01918                                                 case SEQ_TRANSFORM:
01919                                                         writestruct(wd, DATA, "TransformVars", 1, seq->effectdata);
01920                                                         break;
01921                                                 }
01922                                         }
01923                                         
01924                                         strip= seq->strip;
01925                                         writestruct(wd, DATA, "Strip", 1, strip);
01926                                         if(seq->flag & SEQ_USE_CROP && strip->crop) {
01927                                                 writestruct(wd, DATA, "StripCrop", 1, strip->crop);
01928                                         }
01929                                         if(seq->flag & SEQ_USE_TRANSFORM && strip->transform) {
01930                                                 writestruct(wd, DATA, "StripTransform", 1, strip->transform);
01931                                         }
01932                                         if(seq->flag & SEQ_USE_PROXY && strip->proxy) {
01933                                                 writestruct(wd, DATA, "StripProxy", 1, strip->proxy);
01934                                         }
01935                                         if(seq->flag & SEQ_USE_COLOR_BALANCE && strip->color_balance) {
01936                                                 writestruct(wd, DATA, "StripColorBalance", 1, strip->color_balance);
01937                                         }
01938                                         if(seq->type==SEQ_IMAGE)
01939                                                 writestruct(wd, DATA, "StripElem", MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem), strip->stripdata);
01940                                         else if(seq->type==SEQ_MOVIE || seq->type==SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND)
01941                                                 writestruct(wd, DATA, "StripElem", 1, strip->stripdata);
01942                                         
01943                                         strip->done= 1;
01944                                 }
01945                         }
01946                         SEQ_END
01947                                 
01948                         /* new; meta stack too, even when its nasty restore code */
01949                         for(ms= ed->metastack.first; ms; ms= ms->next) {
01950                                 writestruct(wd, DATA, "MetaStack", 1, ms);
01951                         }
01952                 }
01953                 
01954                 if (sce->r.avicodecdata) {
01955                         writestruct(wd, DATA, "AviCodecData", 1, sce->r.avicodecdata);
01956                         if (sce->r.avicodecdata->lpFormat) writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
01957                         if (sce->r.avicodecdata->lpParms) writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
01958                 }
01959 
01960                 if (sce->r.qtcodecdata) {
01961                         writestruct(wd, DATA, "QuicktimeCodecData", 1, sce->r.qtcodecdata);
01962                         if (sce->r.qtcodecdata->cdParms) writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms);
01963                 }
01964                 if (sce->r.ffcodecdata.properties) {
01965                         IDP_WriteProperty(sce->r.ffcodecdata.properties, wd);
01966                 }
01967 
01968                 /* writing dynamic list of TimeMarkers to the blend file */
01969                 for(marker= sce->markers.first; marker; marker= marker->next)
01970                         writestruct(wd, DATA, "TimeMarker", 1, marker);
01971                 
01972                 /* writing dynamic list of TransformOrientations to the blend file */
01973                 for(ts = sce->transform_spaces.first; ts; ts = ts->next)
01974                         writestruct(wd, DATA, "TransformOrientation", 1, ts);
01975                 
01976                 for(srl= sce->r.layers.first; srl; srl= srl->next)
01977                         writestruct(wd, DATA, "SceneRenderLayer", 1, srl);
01978                 
01979                 if(sce->nodetree) {
01980                         writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree);
01981                         write_nodetree(wd, sce->nodetree);
01982                 }
01983                 
01984                 sce= sce->id.next;
01985         }
01986         /* flush helps the compression for undo-save */
01987         mywrite(wd, MYWRITE_FLUSH, 0);
01988 }
01989 
01990 static void write_gpencils(WriteData *wd, ListBase *lb)
01991 {
01992         bGPdata *gpd;
01993         bGPDlayer *gpl;
01994         bGPDframe *gpf;
01995         bGPDstroke *gps;
01996         
01997         for (gpd= lb->first; gpd; gpd= gpd->id.next) {
01998                 if (gpd->id.us>0 || wd->current) {
01999                         /* write gpd data block to file */
02000                         writestruct(wd, ID_GD, "bGPdata", 1, gpd);
02001                         
02002                         /* write grease-pencil layers to file */
02003                         for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
02004                                 writestruct(wd, DATA, "bGPDlayer", 1, gpl);
02005                                 
02006                                 /* write this layer's frames to file */
02007                                 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
02008                                         writestruct(wd, DATA, "bGPDframe", 1, gpf);
02009                                         
02010                                         /* write strokes */
02011                                         for (gps= gpf->strokes.first; gps; gps= gps->next) {
02012                                                 writestruct(wd, DATA, "bGPDstroke", 1, gps);
02013                                                 writestruct(wd, DATA, "bGPDspoint", gps->totpoints, gps->points);                               
02014                                         }
02015                                 }
02016                         }
02017                 }
02018         }
02019 }
02020 
02021 static void write_windowmanagers(WriteData *wd, ListBase *lb)
02022 {
02023         wmWindowManager *wm;
02024         wmWindow *win;
02025         
02026         for(wm= lb->first; wm; wm= wm->id.next) {
02027                 writestruct(wd, ID_WM, "wmWindowManager", 1, wm);
02028                 
02029                 for(win= wm->windows.first; win; win= win->next)
02030                         writestruct(wd, DATA, "wmWindow", 1, win);
02031         }
02032 }
02033 
02034 static void write_region(WriteData *wd, ARegion *ar, int spacetype)
02035 {       
02036         writestruct(wd, DATA, "ARegion", 1, ar);
02037         
02038         if(ar->regiondata) {
02039                 switch(spacetype) {
02040                         case SPACE_VIEW3D:
02041                                 if(ar->regiontype==RGN_TYPE_WINDOW) {
02042                                         RegionView3D *rv3d= ar->regiondata;
02043                                         writestruct(wd, DATA, "RegionView3D", 1, rv3d);
02044                                         
02045                                         if(rv3d->localvd)
02046                                                 writestruct(wd, DATA, "RegionView3D", 1, rv3d->localvd);
02047                                         if(rv3d->clipbb) 
02048                                                 writestruct(wd, DATA, "BoundBox", 1, rv3d->clipbb);
02049 
02050                                 }
02051                                 else
02052                                         printf("regiondata write missing!\n");
02053                                 break;
02054                         default:
02055                                 printf("regiondata write missing!\n");
02056                 }
02057         }
02058 }
02059 
02060 static void write_screens(WriteData *wd, ListBase *scrbase)
02061 {
02062         bScreen *sc;
02063         ScrArea *sa;
02064         ScrVert *sv;
02065         ScrEdge *se;
02066 
02067         sc= scrbase->first;
02068         while(sc) {
02069                 
02070                 /* write LibData */
02071                 /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
02072                 writestruct(wd, ID_SCRN, "Screen", 1, sc);
02073                 if (sc->id.properties) 
02074                         IDP_WriteProperty(sc->id.properties, wd);
02075                 
02076                 /* direct data */
02077                 for(sv= sc->vertbase.first; sv; sv= sv->next)
02078                         writestruct(wd, DATA, "ScrVert", 1, sv);
02079                 
02080                 for(se= sc->edgebase.first; se; se= se->next) 
02081                         writestruct(wd, DATA, "ScrEdge", 1, se);
02082                 
02083                 for(sa= sc->areabase.first; sa; sa= sa->next) {
02084                         SpaceLink *sl;
02085                         Panel *pa;
02086                         ARegion *ar;
02087                         
02088                         writestruct(wd, DATA, "ScrArea", 1, sa);
02089                         
02090                         for(ar= sa->regionbase.first; ar; ar= ar->next) {
02091                                 write_region(wd, ar, sa->spacetype);
02092                                 
02093                                 for(pa= ar->panels.first; pa; pa= pa->next)
02094                                         writestruct(wd, DATA, "Panel", 1, pa);
02095                         }
02096                         
02097                         sl= sa->spacedata.first;
02098                         while(sl) {
02099                                 for(ar= sl->regionbase.first; ar; ar= ar->next)
02100                                         write_region(wd, ar, sl->spacetype);
02101                                 
02102                                 if(sl->spacetype==SPACE_VIEW3D) {
02103                                         View3D *v3d= (View3D *) sl;
02104                                         BGpic *bgpic;
02105                                         writestruct(wd, DATA, "View3D", 1, v3d);
02106                                         for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next)
02107                                                 writestruct(wd, DATA, "BGpic", 1, bgpic);
02108                                         if(v3d->localvd) writestruct(wd, DATA, "View3D", 1, v3d->localvd);
02109                                 }
02110                                 else if(sl->spacetype==SPACE_IPO) {
02111                                         SpaceIpo *sipo= (SpaceIpo *)sl;
02112                                         ListBase tmpGhosts = sipo->ghostCurves;
02113                                         
02114                                         /* temporarily disable ghost curves when saving */
02115                                         sipo->ghostCurves.first= sipo->ghostCurves.last= NULL;
02116                                         
02117                                         writestruct(wd, DATA, "SpaceIpo", 1, sl);
02118                                         if(sipo->ads) writestruct(wd, DATA, "bDopeSheet", 1, sipo->ads);
02119                                         
02120                                         /* reenable ghost curves */
02121                                         sipo->ghostCurves= tmpGhosts;
02122                                 }
02123                                 else if(sl->spacetype==SPACE_BUTS) {
02124                                         writestruct(wd, DATA, "SpaceButs", 1, sl);
02125                                 }
02126                                 else if(sl->spacetype==SPACE_FILE) {
02127                                         SpaceFile *sfile= (SpaceFile *)sl;
02128 
02129                                         writestruct(wd, DATA, "SpaceFile", 1, sl);
02130                                         if(sfile->params)
02131                                                 writestruct(wd, DATA, "FileSelectParams", 1, sfile->params);
02132                                 }
02133                                 else if(sl->spacetype==SPACE_SEQ) {
02134                                         writestruct(wd, DATA, "SpaceSeq", 1, sl);
02135                                 }
02136                                 else if(sl->spacetype==SPACE_OUTLINER) {
02137                                         SpaceOops *so= (SpaceOops *)sl;
02138                                         
02139                                         writestruct(wd, DATA, "SpaceOops", 1, so);
02140 
02141                                         /* outliner */
02142                                         if(so->treestore) {
02143                                                 writestruct(wd, DATA, "TreeStore", 1, so->treestore);
02144                                                 if(so->treestore->data)
02145                                                         writestruct(wd, DATA, "TreeStoreElem", so->treestore->usedelem, so->treestore->data);
02146                                         }
02147                                 }
02148                                 else if(sl->spacetype==SPACE_IMAGE) {
02149                                         SpaceImage *sima= (SpaceImage *)sl;
02150                                         
02151                                         writestruct(wd, DATA, "SpaceImage", 1, sl);
02152                                         if(sima->cumap)
02153                                                 write_curvemapping(wd, sima->cumap);
02154                                 }
02155                                 else if(sl->spacetype==SPACE_IMASEL) {
02156                                         // XXX: depreceated... do we still want to keep this?
02157                                         writestruct(wd, DATA, "SpaceImaSel", 1, sl);
02158                                 }
02159                                 else if(sl->spacetype==SPACE_TEXT) {
02160                                         writestruct(wd, DATA, "SpaceText", 1, sl);
02161                                 }
02162                                 else if(sl->spacetype==SPACE_SCRIPT) {
02163                                         SpaceScript *scr = (SpaceScript*)sl;
02164                                         scr->but_refs = NULL;
02165                                         writestruct(wd, DATA, "SpaceScript", 1, sl);
02166                                 }
02167                                 else if(sl->spacetype==SPACE_ACTION) {
02168                                         writestruct(wd, DATA, "SpaceAction", 1, sl);
02169                                 }
02170                                 else if(sl->spacetype==SPACE_SOUND) {
02171                                         writestruct(wd, DATA, "SpaceSound", 1, sl);
02172                                 }
02173                                 else if(sl->spacetype==SPACE_NLA){
02174                                         SpaceNla *snla= (SpaceNla *)sl;
02175                                         
02176                                         writestruct(wd, DATA, "SpaceNla", 1, snla);
02177                                         if(snla->ads) writestruct(wd, DATA, "bDopeSheet", 1, snla->ads);
02178                                 }
02179                                 else if(sl->spacetype==SPACE_TIME){
02180                                         writestruct(wd, DATA, "SpaceTime", 1, sl);
02181                                 }
02182                                 else if(sl->spacetype==SPACE_NODE){
02183                                         writestruct(wd, DATA, "SpaceNode", 1, sl);
02184                                 }
02185                                 else if(sl->spacetype==SPACE_LOGIC){
02186                                         writestruct(wd, DATA, "SpaceLogic", 1, sl);
02187                                 }
02188                                 else if(sl->spacetype==SPACE_CONSOLE) {
02189                                         SpaceConsole *con = (SpaceConsole*)sl;
02190                                         ConsoleLine *cl;
02191 
02192                                         for (cl=con->history.first; cl; cl=cl->next) {
02193                                                 /* 'len_alloc' is invalid on write, set from 'len' on read */
02194                                                 writestruct(wd, DATA, "ConsoleLine", 1, cl);
02195                                                 writedata(wd, DATA, cl->len+1, cl->line);
02196                                         }
02197                                         writestruct(wd, DATA, "SpaceConsole", 1, sl);
02198 
02199                                 }
02200                                 else if(sl->spacetype==SPACE_USERPREF) {
02201                                         writestruct(wd, DATA, "SpaceUserPref", 1, sl);
02202                                 }
02203 
02204                                 sl= sl->next;
02205                         }
02206                 }
02207 
02208                 sc= sc->id.next;
02209         }
02210 }
02211 
02212 static void write_libraries(WriteData *wd, Main *main)
02213 {
02214         ListBase *lbarray[30];
02215         ID *id;
02216         int a, tot, foundone;
02217 
02218         for(; main; main= main->next) {
02219 
02220                 a=tot= set_listbasepointers(main, lbarray);
02221 
02222                 /* test: is lib being used */
02223                 foundone= 0;
02224                 while(tot--) {
02225                         for(id= lbarray[tot]->first; id; id= id->next) {
02226                                 if(id->us>0 && (id->flag & LIB_EXTERN)) {
02227                                         foundone= 1;
02228                                         break;
02229                                 }
02230                         }
02231                         if(foundone) break;
02232                 }
02233 
02234                 if(foundone) {
02235                         writestruct(wd, ID_LI, "Library", 1, main->curlib);
02236 
02237                         while(a--) {
02238                                 for(id= lbarray[a]->first; id; id= id->next) {
02239                                         if(id->us>0 && (id->flag & LIB_EXTERN)) {
02240                                                 writestruct(wd, ID_ID, "ID", 1, id);
02241                                         }
02242                                 }
02243                         }
02244                 }
02245         }
02246 }
02247 
02248 static void write_bone(WriteData *wd, Bone* bone)
02249 {
02250         Bone*   cbone;
02251 
02252         // PATCH for upward compatibility after 2.37+ armature recode
02253         bone->size[0]= bone->size[1]= bone->size[2]= 1.0f;
02254                 
02255         // Write this bone
02256         writestruct(wd, DATA, "Bone", 1, bone);
02257 
02258         /* Write ID Properties -- and copy this comment EXACTLY for easy finding
02259          of library blocks that implement this.*/
02260         if (bone->prop)
02261                 IDP_WriteProperty(bone->prop, wd);
02262         
02263         // Write Children
02264         cbone= bone->childbase.first;
02265         while(cbone) {
02266                 write_bone(wd, cbone);
02267                 cbone= cbone->next;
02268         }
02269 }
02270 
02271 static void write_armatures(WriteData *wd, ListBase *idbase)
02272 {
02273         bArmature       *arm;
02274         Bone            *bone;
02275 
02276         arm=idbase->first;
02277         while (arm) {
02278                 if (arm->id.us>0 || wd->current) {
02279                         writestruct(wd, ID_AR, "bArmature", 1, arm);
02280                         if (arm->id.properties) IDP_WriteProperty(arm->id.properties, wd);
02281 
02282                         if (arm->adt) write_animdata(wd, arm->adt);
02283 
02284                         /* Direct data */
02285                         bone= arm->bonebase.first;
02286                         while(bone) {
02287                                 write_bone(wd, bone);
02288                                 bone=bone->next;
02289                         }
02290                 }
02291                 arm=arm->id.next;
02292         }
02293 
02294         /* flush helps the compression for undo-save */
02295         mywrite(wd, MYWRITE_FLUSH, 0);
02296 }
02297 
02298 static void write_texts(WriteData *wd, ListBase *idbase)
02299 {
02300         Text *text;
02301         TextLine *tmp;
02302         TextMarker *mrk;
02303 
02304         text= idbase->first;
02305         while(text) {
02306                 if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) text->flags &= ~TXT_ISEXT;
02307 
02308                 /* write LibData */
02309                 writestruct(wd, ID_TXT, "Text", 1, text);
02310                 if(text->name) writedata(wd, DATA, strlen(text->name)+1, text->name);
02311                 if (text->id.properties) IDP_WriteProperty(text->id.properties, wd);
02312 
02313                 if(!(text->flags & TXT_ISEXT)) {
02314                         /* now write the text data, in two steps for optimization in the readfunction */
02315                         tmp= text->lines.first;
02316                         while (tmp) {
02317                                 writestruct(wd, DATA, "TextLine", 1, tmp);
02318                                 tmp= tmp->next;
02319                         }
02320 
02321                         tmp= text->lines.first;
02322                         while (tmp) {
02323                                 writedata(wd, DATA, tmp->len+1, tmp->line);
02324                                 tmp= tmp->next;
02325                         }
02326 
02327                         /* write markers */
02328                         mrk= text->markers.first;
02329                         while (mrk) {
02330                                 writestruct(wd, DATA, "TextMarker", 1, mrk);
02331                                 mrk= mrk->next;
02332                         }
02333                 }
02334 
02335 
02336                 text= text->id.next;
02337         }
02338 
02339         /* flush helps the compression for undo-save */
02340         mywrite(wd, MYWRITE_FLUSH, 0);
02341 }
02342 
02343 static void write_sounds(WriteData *wd, ListBase *idbase)
02344 {
02345         bSound *sound;
02346 
02347         PackedFile * pf;
02348 
02349         sound= idbase->first;
02350         while(sound) {
02351                 if(sound->id.us>0 || wd->current) {
02352                         /* write LibData */
02353                         writestruct(wd, ID_SO, "bSound", 1, sound);
02354                         if (sound->id.properties) IDP_WriteProperty(sound->id.properties, wd);
02355 
02356                         if (sound->packedfile) {
02357                                 pf = sound->packedfile;
02358                                 writestruct(wd, DATA, "PackedFile", 1, pf);
02359                                 writedata(wd, DATA, pf->size, pf->data);
02360                         }
02361                 }
02362                 sound= sound->id.next;
02363         }
02364 
02365         /* flush helps the compression for undo-save */
02366         mywrite(wd, MYWRITE_FLUSH, 0);
02367 }
02368 
02369 static void write_groups(WriteData *wd, ListBase *idbase)
02370 {
02371         Group *group;
02372         GroupObject *go;
02373 
02374         for(group= idbase->first; group; group= group->id.next) {
02375                 if(group->id.us>0 || wd->current) {
02376                         /* write LibData */
02377                         writestruct(wd, ID_GR, "Group", 1, group);
02378                         if (group->id.properties) IDP_WriteProperty(group->id.properties, wd);
02379 
02380                         go= group->gobject.first;
02381                         while(go) {
02382                                 writestruct(wd, DATA, "GroupObject", 1, go);
02383                                 go= go->next;
02384                         }
02385                 }
02386         }
02387 }
02388 
02389 static void write_nodetrees(WriteData *wd, ListBase *idbase)
02390 {
02391         bNodeTree *ntree;
02392         
02393         for(ntree=idbase->first; ntree; ntree= ntree->id.next) {
02394                 if (ntree->id.us>0 || wd->current) {
02395                         writestruct(wd, ID_NT, "bNodeTree", 1, ntree);
02396                         write_nodetree(wd, ntree);
02397                         
02398                         if (ntree->id.properties) IDP_WriteProperty(ntree->id.properties, wd);
02399                         
02400                         if (ntree->adt) write_animdata(wd, ntree->adt);
02401                 }
02402         }
02403 }
02404 
02405 static void write_brushes(WriteData *wd, ListBase *idbase)
02406 {
02407         Brush *brush;
02408         
02409         for(brush=idbase->first; brush; brush= brush->id.next) {
02410                 if(brush->id.us>0 || wd->current) {
02411                         writestruct(wd, ID_BR, "Brush", 1, brush);
02412                         if (brush->id.properties) IDP_WriteProperty(brush->id.properties, wd);
02413                         
02414                         writestruct(wd, DATA, "MTex", 1, &brush->mtex);
02415                         
02416                         if(brush->curve)
02417                                 write_curvemapping(wd, brush->curve);
02418                 }
02419         }
02420 }
02421 
02422 static void write_scripts(WriteData *wd, ListBase *idbase)
02423 {
02424         Script *script;
02425         
02426         for(script=idbase->first; script; script= script->id.next) {
02427                 if(script->id.us>0 || wd->current) {
02428                         writestruct(wd, ID_SCRIPT, "Script", 1, script);
02429                         if (script->id.properties) IDP_WriteProperty(script->id.properties, wd);
02430                 }
02431         }
02432 }
02433 
02434 /* context is usually defined by WM, two cases where no WM is available:
02435  * - for forward compatibility, curscreen has to be saved
02436  * - for undofile, curscene needs to be saved */
02437 static void write_global(WriteData *wd, int fileflags, Main *mainvar)
02438 {
02439         FileGlobal fg;
02440         bScreen *screen;
02441         char subvstr[8];
02442         
02443         /* prevent mem checkers from complaining */
02444         fg.pads= fg.pad= 0;
02445         memset(fg.filename, 0, sizeof(fg.filename));
02446 
02447         current_screen_compat(mainvar, &screen);
02448 
02449         /* XXX still remap G */
02450         fg.curscreen= screen;
02451         fg.curscene= screen->scene;
02452         fg.displaymode= G.displaymode;
02453         fg.winpos= G.winpos;
02454         fg.fileflags= (fileflags & ~(G_FILE_NO_UI|G_FILE_RELATIVE_REMAP));      // prevent to save this, is not good convention, and feature with concerns...
02455         fg.globalf= G.f;
02456         BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
02457 
02458         sprintf(subvstr, "%4d", BLENDER_SUBVERSION);
02459         memcpy(fg.subvstr, subvstr, 4);
02460         
02461         fg.subversion= BLENDER_SUBVERSION;
02462         fg.minversion= BLENDER_MINVERSION;
02463         fg.minsubversion= BLENDER_MINSUBVERSION;
02464 #ifdef NAN_BUILDINFO
02465         {
02466                 extern char build_rev[];
02467                 fg.revision= atoi(build_rev);
02468         }
02469 #else
02470         fg.revision= 0;
02471 #endif
02472         writestruct(wd, GLOB, "FileGlobal", 1, &fg);
02473 }
02474 
02475 /* preview image, first 2 values are width and height
02476  * second are an RGBA image (unsigned char)
02477  * note, this uses 'TEST' since new types will segfault on file load for older blender versions.
02478  */
02479 static void write_thumb(WriteData *wd, int *img)
02480 {
02481         if(img)
02482                 writedata(wd, TEST, (2 + img[0] * img[1]) * sizeof(int), img);
02483 }
02484 
02485 /* if MemFile * there's filesave to memory */
02486 static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFile *current, 
02487                                                          int write_user_block, int write_flags, int *thumb)
02488 {
02489         BHead bhead;
02490         ListBase mainlist;
02491         char buf[16];
02492         WriteData *wd;
02493 
02494         blo_split_main(&mainlist, mainvar);
02495 
02496         wd= bgnwrite(handle, compare, current);
02497         
02498         sprintf(buf, "BLENDER%c%c%.3d", (sizeof(void*)==8)?'-':'_', (ENDIAN_ORDER==B_ENDIAN)?'V':'v', BLENDER_VERSION);
02499         mywrite(wd, buf, 12);
02500 
02501         write_renderinfo(wd, mainvar);
02502         write_thumb(wd, thumb);
02503         write_global(wd, write_flags, mainvar);
02504 
02505         /* no UI save in undo */
02506         if(current==NULL) {
02507                 write_windowmanagers(wd, &mainvar->wm);
02508                 write_screens  (wd, &mainvar->screen);
02509         }
02510         write_scenes   (wd, &mainvar->scene);
02511         write_curves   (wd, &mainvar->curve);
02512         write_mballs   (wd, &mainvar->mball);
02513         write_images   (wd, &mainvar->image);
02514         write_cameras  (wd, &mainvar->camera);
02515         write_lamps    (wd, &mainvar->lamp);
02516         write_lattices (wd, &mainvar->latt);
02517         write_vfonts   (wd, &mainvar->vfont);
02518         write_keys     (wd, &mainvar->key);
02519         write_worlds   (wd, &mainvar->world);
02520         write_texts    (wd, &mainvar->text);
02521         write_sounds   (wd, &mainvar->sound);
02522         write_groups   (wd, &mainvar->group);
02523         write_armatures(wd, &mainvar->armature);
02524         write_actions  (wd, &mainvar->action);
02525         write_objects  (wd, &mainvar->object);
02526         write_materials(wd, &mainvar->mat);
02527         write_textures (wd, &mainvar->tex);
02528         write_meshs    (wd, &mainvar->mesh);
02529         write_particlesettings(wd, &mainvar->particle);
02530         write_nodetrees(wd, &mainvar->nodetree);
02531         write_brushes  (wd, &mainvar->brush);
02532         write_scripts  (wd, &mainvar->script);
02533         write_gpencils (wd, &mainvar->gpencil);
02534         write_libraries(wd,  mainvar->next);
02535 
02536         if (write_user_block) {
02537                 write_userdef(wd);
02538         }
02539                                                         
02540         /* dna as last, because (to be implemented) test for which structs are written */
02541         writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data);
02542 
02543         /* end of file */
02544         memset(&bhead, 0, sizeof(BHead));
02545         bhead.code= ENDB;
02546         mywrite(wd, &bhead, sizeof(BHead));
02547 
02548         blo_join_main(&mainlist);
02549 
02550         return endwrite(wd);
02551 }
02552 
02553 /* do reverse file history: .blend1 -> .blend2, .blend -> .blend1 */
02554 /* return: success(0), failure(1) */
02555 static int do_history(const char *name, ReportList *reports)
02556 {
02557         char tempname1[FILE_MAXDIR+FILE_MAXFILE], tempname2[FILE_MAXDIR+FILE_MAXFILE];
02558         int hisnr= U.versions;
02559         
02560         if(U.versions==0) return 0;
02561         if(strlen(name)<2) {
02562                 BKE_report(reports, RPT_ERROR, "Unable to make version backup: filename too short");
02563                 return 1;
02564         }
02565                 
02566         while(hisnr > 1) {
02567                 BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr-1);
02568                 BLI_snprintf(tempname2, sizeof(tempname2), "%s%d", name, hisnr);
02569         
02570                 if(BLI_rename(tempname1, tempname2)) {
02571                         BKE_report(reports, RPT_ERROR, "Unable to make version backup");
02572                         return 1;
02573                 }       
02574                 hisnr--;
02575         }
02576 
02577         /* is needed when hisnr==1 */
02578         BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr);
02579 
02580         if(BLI_rename(name, tempname1)) {
02581                 BKE_report(reports, RPT_ERROR, "Unable to make version backup");
02582                 return 1;
02583         }
02584 
02585         return 0;
02586 }
02587 
02588 /* return: success (1) */
02589 int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportList *reports, int *thumb)
02590 {
02591         char userfilename[FILE_MAXDIR+FILE_MAXFILE];
02592         char tempname[FILE_MAXDIR+FILE_MAXFILE+1];
02593         int file, err, write_user_block;
02594 
02595         /* open temporary file, so we preserve the original in case we crash */
02596         BLI_snprintf(tempname, sizeof(tempname), "%s@", filepath);
02597 
02598         file = open(tempname,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666);
02599         if(file == -1) {
02600                 BKE_reportf(reports, RPT_ERROR, "Can't open file %s for writing: %s.", tempname, strerror(errno));
02601                 return 0;
02602         }
02603 
02604         /* remapping of relative paths to new file location */
02605         if(write_flags & G_FILE_RELATIVE_REMAP) {
02606                 char dir1[FILE_MAXDIR+FILE_MAXFILE];
02607                 char dir2[FILE_MAXDIR+FILE_MAXFILE];
02608                 BLI_split_dirfile(filepath, dir1, NULL);
02609                 BLI_split_dirfile(mainvar->name, dir2, NULL);
02610 
02611                 /* just incase there is some subtle difference */
02612                 BLI_cleanup_dir(mainvar->name, dir1);
02613                 BLI_cleanup_dir(mainvar->name, dir2);
02614 
02615                 if(BLI_path_cmp(dir1, dir2)==0) {
02616                         write_flags &= ~G_FILE_RELATIVE_REMAP;
02617                 }
02618                 else {
02619                         if(G.relbase_valid) {
02620                                 /* blend may not have been saved before. Tn this case
02621                                  * we should not have any relative paths, but if there
02622                                  * is somehow, an invalid or empty G.main->name it will
02623                                  * print an error, dont try make the absolute in this case. */
02624                                 makeFilesAbsolute(mainvar, G.main->name, NULL);
02625                         }
02626                 }
02627         }
02628 
02629         BLI_make_file_string(G.main->name, userfilename, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
02630         write_user_block= (BLI_path_cmp(filepath, userfilename) == 0);
02631 
02632         if(write_flags & G_FILE_RELATIVE_REMAP)
02633                 makeFilesRelative(mainvar, filepath, NULL); /* note, making relative to something OTHER then G.main->name */
02634 
02635         /* actual file writing */
02636         err= write_file_handle(mainvar, file, NULL,NULL, write_user_block, write_flags, thumb);
02637         close(file);
02638 
02639         if (err) {
02640                 BKE_report(reports, RPT_ERROR, strerror(errno));
02641                 remove(tempname);
02642 
02643                 return 0;
02644         }
02645 
02646         /* file save to temporary file was successful */
02647         /* now do reverse file history (move .blend1 -> .blend2, .blend -> .blend1) */
02648         if (write_flags & G_FILE_HISTORY) { 
02649                 int err_hist = do_history(filepath, reports);
02650                 if (err_hist) {
02651                         BKE_report(reports, RPT_ERROR, "Version backup failed. File saved with @");
02652                         return 0;
02653                 }
02654         }
02655 
02656         if(write_flags & G_FILE_COMPRESS) {
02657                 /* compressed files have the same ending as regular files... only from 2.4!!! */
02658                 char gzname[FILE_MAXDIR+FILE_MAXFILE+4];
02659                 int ret;
02660 
02661                 /* first write compressed to separate @.gz */
02662                 BLI_snprintf(gzname, sizeof(gzname), "%s@.gz", filepath);
02663                 ret = BLI_gzip(tempname, gzname);
02664                 
02665                 if(0==ret) {
02666                         /* now rename to real file name, and delete temp @ file too */
02667                         if(BLI_rename(gzname, filepath) != 0) {
02668                                 BKE_report(reports, RPT_ERROR, "Can't change old file. File saved with @.");
02669                                 return 0;
02670                         }
02671 
02672                         BLI_delete(tempname, 0, 0);
02673                 }
02674                 else if(-1==ret) {
02675                         BKE_report(reports, RPT_ERROR, "Failed opening .gz file.");
02676                         return 0;
02677                 }
02678                 else if(-2==ret) {
02679                         BKE_report(reports, RPT_ERROR, "Failed opening .blend file for compression.");
02680                         return 0;
02681                 }
02682         }
02683         else if(BLI_rename(tempname, filepath) != 0) {
02684                 BKE_report(reports, RPT_ERROR, "Can't change old file. File saved with @");
02685                 return 0;
02686         }
02687 
02688         return 1;
02689 }
02690 
02691 /* return: success (1) */
02692 int BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags)
02693 {
02694         int err;
02695 
02696         err= write_file_handle(mainvar, 0, compare, current, 0, write_flags, NULL);
02697         
02698         if(err==0) return 1;
02699         return 0;
02700 }