Blender V2.61 - r43446

writefile.c

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