Merged changes in the trunk up to revision 54802.
[blender.git] / source / blender / blenloader / intern / writefile.c
index 74287f0e6935e697c53e29097600aea98e474bd4..50e1e229ebac89449eafb47f9e1ab5542be33568 100644 (file)
 
 
 /*
-FILEFORMAT: IFF-style structure  (but not IFF compatible!)
-
-start file:
      BLENDER_V100    12 bytes  (versie 1.00)
                                      V = big endian, v = little endian
                                      _ = 4 byte pointer, - = 8 byte pointer
-
-datablocks:            also see struct BHead
      <bh.code>                       4 chars
      <bh.len>                        int,  len data after BHead
      <bh.old>                        void,  old pointer
      <bh.SDNAnr>                     int
      <bh.nr>                         int, in case of array: amount of structs
      data
      ...
      ...
-
-Almost all data in Blender are structures. Each struct saved
-gets a BHead header.  With BHead the struct can be linked again
-and compared with StructDNA .
-
-WRITE
-
-Preferred writing order: (not really a must, but why would you do it random?)
-Any case: direct data is ALWAYS after the lib block
-
-(Local file data)
-- for each LibBlock
      - write LibBlock
      - write associated direct data
-(External file data)
-- per library
      - write library block
      - per LibBlock
              - write the ID of LibBlock
-- write TEST (128x128, blend file preview, optional)
-- write FileGlobal (some global vars)
-- write SDNA
-- write USER if filename is ~/X.XX/config/startup.blend
-*/
+ * FILEFORMAT: IFF-style structure  (but not IFF compatible!)
+ *
+ * start file:
*     BLENDER_V100    12 bytes  (versie 1.00)
*                     V = big endian, v = little endian
*                     _ = 4 byte pointer, - = 8 byte pointer
+ *
+ * datablocks:     also see struct BHead
*     <bh.code>           4 chars
*     <bh.len>            int,  len data after BHead
*     <bh.old>            void,  old pointer
*     <bh.SDNAnr>         int
*     <bh.nr>             int, in case of array: amount of structs
*     data
*     ...
*     ...
+ *
+ * Almost all data in Blender are structures. Each struct saved
+ * gets a BHead header.  With BHead the struct can be linked again
+ * and compared with StructDNA .
+ *
+ * WRITE
+ *
+ * Preferred writing order: (not really a must, but why would you do it random?)
+ * Any case: direct data is ALWAYS after the lib block
+ *
+ * (Local file data)
+ * - for each LibBlock
*     - write LibBlock
*     - write associated direct data
+ * (External file data)
+ * - per library
*     - write library block
*     - per LibBlock
*         - write the ID of LibBlock
+ * - write TEST (128x128, blend file preview, optional)
+ * - write FileGlobal (some global vars)
+ * - write SDNA
+ * - write USER if filename is ~/X.XX/config/startup.blend
+ */
 
 
 #include <math.h>
@@ -89,6 +89,8 @@ Any case: direct data is ALWAYS after the lib block
 #  include "BLI_winstuff.h"
 #endif
 
+#include "BLI_utildefines.h"
+
 /* allow writefile to use deprecated functionality (for forward compatibility code) */
 #define DNA_DEPRECATED_ALLOW
 
@@ -108,6 +110,9 @@ Any case: direct data is ALWAYS after the lib block
 #include "DNA_key_types.h"
 #include "DNA_lattice_types.h"
 #include "DNA_lamp_types.h"
+#ifdef WITH_FREESTYLE
+#  include "DNA_linestyle_types.h"
+#endif
 #include "DNA_meta_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
@@ -118,6 +123,7 @@ Any case: direct data is ALWAYS after the lib block
 #include "DNA_packedFile_types.h"
 #include "DNA_particle_types.h"
 #include "DNA_property_types.h"
+#include "DNA_rigidbody_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_sdna_types.h"
 #include "DNA_sequence_types.h"
@@ -139,7 +145,7 @@ Any case: direct data is ALWAYS after the lib block
 #include "BLI_bitmap.h"
 #include "BLI_blenlib.h"
 #include "BLI_linklist.h"
-#include "BLI_bpath.h"
+#include "BKE_bpath.h"
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
 
@@ -154,7 +160,6 @@ Any case: direct data is ALWAYS after the lib block
 #include "BKE_report.h"
 #include "BKE_sequencer.h"
 #include "BKE_subsurf.h"
-#include "BKE_utildefines.h"
 #include "BKE_modifier.h"
 #include "BKE_fcurve.h"
 #include "BKE_pointcache.h"
@@ -163,6 +168,7 @@ Any case: direct data is ALWAYS after the lib block
 #include "BLO_writefile.h"
 #include "BLO_readfile.h"
 #include "BLO_undofile.h"
+#include "BLO_blend_defs.h"
 
 #include "readfile.h"
 
@@ -197,7 +203,7 @@ static WriteData *writedata_new(int file)
 
        if (wd == NULL) return NULL;
 
-       wd->sdna= DNA_sdna_from_data(DNAstr, DNAlen, 0);
+       wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
 
        wd->file= file;
 
@@ -511,7 +517,7 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves)
                writestruct(wd, DATA, "FCurve", 1, fcu);
                
                /* curve data */
-               if (fcu->bezt)          
+               if (fcu->bezt)
                        writestruct(wd, DATA, "BezTriple", fcu->totvert, fcu->bezt);
                if (fcu->fpt)
                        writestruct(wd, DATA, "FPoint", fcu->totvert, fcu->fpt);
@@ -646,15 +652,21 @@ static void write_animdata(WriteData *wd, AnimData *adt)
        write_nladata(wd, &adt->nla_tracks);
 }
 
-static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
+static void write_curvemapping_curves(WriteData *wd, CurveMapping *cumap)
 {
        int a;
-       
-       writestruct(wd, DATA, "CurveMapping", 1, cumap);
-       for (a=0; a<CM_TOT; a++)
+
+       for (a = 0; a < CM_TOT; a++)
                writestruct(wd, DATA, "CurveMapPoint", cumap->cm[a].totpoint, cumap->cm[a].curve);
 }
 
+static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
+{
+       writestruct(wd, DATA, "CurveMapping", 1, cumap);
+
+       write_curvemapping_curves(wd, cumap);
+}
+
 static void write_node_socket(WriteData *wd, bNodeSocket *sock)
 {
        bNodeSocketType *stype= ntreeGetSocketType(sock->type);
@@ -714,18 +726,31 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
                        write_node_socket(wd, sock);
                for (sock= node->outputs.first; sock; sock= sock->next)
                        write_node_socket(wd, sock);
-
+               
+               for (link = node->internal_links.first; link; link = link->next)
+                       writestruct(wd, DATA, "bNodeLink", 1, link);
                
                if (node->storage) {
                        /* could be handlerized at some point, now only 1 exception still */
                        if (ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
                                write_curvemapping(wd, node->storage);
+                       else if (ntree->type==NTREE_SHADER && node->type==SH_NODE_SCRIPT) {
+                               NodeShaderScript *nss = (NodeShaderScript *)node->storage;
+                               if (nss->bytecode)
+                                       writedata(wd, DATA, strlen(nss->bytecode)+1, nss->bytecode);
+                               /* Write ID Properties -- and copy this comment EXACTLY for easy finding
+                                * of library blocks that implement this.*/
+                               if (nss->prop)
+                                       IDP_WriteProperty(nss->prop, wd);
+                               writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+                       }
                        else if (ntree->type==NTREE_COMPOSIT && ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
                                write_curvemapping(wd, node->storage);
                        else if (ntree->type==NTREE_TEXTURE && (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME) )
                                write_curvemapping(wd, node->storage);
-                       else if (ntree->type==NTREE_COMPOSIT && node->type==CMP_NODE_MOVIEDISTORTION)
-                               /* pass */;
+                       else if (ntree->type==NTREE_COMPOSIT && node->type==CMP_NODE_MOVIEDISTORTION) {
+                               /* pass */
+                       }
                        else
                                writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
                }
@@ -770,13 +795,16 @@ typedef struct RenderInfo {
        char scene_name[MAX_ID_NAME - 2];
 } RenderInfo;
 
-static void write_renderinfo(WriteData *wd, Main *mainvar)             /* for renderdeamon */
+/* was for historic render-deamon feature,
+ * now write because it can be easily extracted without
+ * reading the whole blend file */
+static void write_renderinfo(WriteData *wd, Main *mainvar)
 {
        bScreen *curscreen;
        Scene *sce;
        RenderInfo data;
 
-       /* XXX in future, handle multiple windows with multiple screnes? */
+       /* XXX in future, handle multiple windows with multiple screens? */
        current_screen_compat(mainvar, &curscreen);
 
        for (sce= mainvar->scene.first; sce; sce= sce->id.next) {
@@ -828,8 +856,12 @@ static void write_userdef(WriteData *wd)
                        write_keymapitem(wd, kmi);
        }
 
-       for (bext= U.addons.first; bext; bext=bext->next)
+       for (bext= U.addons.first; bext; bext=bext->next) {
                writestruct(wd, DATA, "bAddon", 1, bext);
+               if (bext->prop) {
+                       IDP_WriteProperty(bext->prop, wd);
+               }
+       }
        
        for (style= U.uistyles.first; style; style= style->next) {
                writestruct(wd, DATA, "uiStyle", 1, style);
@@ -878,7 +910,7 @@ static const char *ptcache_data_struct[] = {
        "", // BPHYS_DATA_ROTATION
        "", // BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST */
        "", // BPHYS_DATA_SIZE:
-       "", // BPHYS_DATA_TIMES:        
+       "", // BPHYS_DATA_TIMES:
        "BoidData" // case BPHYS_DATA_BOIDS:
 };
 static const char *ptcache_extra_struct[] = {
@@ -1206,7 +1238,7 @@ static void write_constraints(WriteData *wd, ListBase *conlist)
        bConstraint *con;
 
        for (con=conlist->first; con; con=con->next) {
-               bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+               bConstraintTypeInfo *cti= BKE_constraint_get_typeinfo(con);
                
                /* Write the specific data */
                if (cti && con->data) {
@@ -1231,7 +1263,7 @@ static void write_constraints(WriteData *wd, ListBase *conlist)
                                        break;
                                case CONSTRAINT_TYPE_SPLINEIK: 
                                {
-                                       bSplineIKConstraint *data= (bSplineIKConstraint*)con->data;
+                                       bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
                                        
                                        /* write points array */
                                        writedata(wd, DATA, sizeof(float)*(data->numpoints), data->points);
@@ -1319,7 +1351,7 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
                        writestruct(wd, DATA, "ClothCollSettings", 1, clmd->coll_parms);
                        writestruct(wd, DATA, "EffectorWeights", 1, clmd->sim_parms->effector_weights);
                        write_pointcaches(wd, &clmd->ptcaches);
-               } 
+               }
                else if (md->type==eModifierType_Smoke) {
                        SmokeModifierData *smd = (SmokeModifierData*) md;
                        
@@ -1349,7 +1381,7 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
                                writestruct(wd, DATA, "SmokeFlowSettings", 1, smd->flow);
                        else if (smd->type & MOD_SMOKE_TYPE_COLL)
                                writestruct(wd, DATA, "SmokeCollSettings", 1, smd->coll);
-               } 
+               }
                else if (md->type==eModifierType_Fluidsim) {
                        FluidsimModifierData *fluidmd = (FluidsimModifierData*) md;
                        
@@ -1377,25 +1409,25 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
                                writestruct(wd, DATA, "ColorBand", 1, pmd->brush->paint_ramp);
                                writestruct(wd, DATA, "ColorBand", 1, pmd->brush->vel_ramp);
                        }
-               } 
+               }
                else if (md->type==eModifierType_Collision) {
                        
-                       /*
+#if 0
                        CollisionModifierData *collmd = (CollisionModifierData*) md;
                        // TODO: CollisionModifier should use pointcache 
                        // + have proper reset events before enabling this
                        writestruct(wd, DATA, "MVert", collmd->numverts, collmd->x);
                        writestruct(wd, DATA, "MVert", collmd->numverts, collmd->xnew);
                        writestruct(wd, DATA, "MFace", collmd->numfaces, collmd->mfaces);
-                       */
+#endif
                }
                else if (md->type==eModifierType_MeshDeform) {
                        MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
                        int size = mmd->dyngridsize;
 
                        writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->bindinfluences);
-                       writedata(wd, DATA, sizeof(int)*(mmd->totvert+1), mmd->bindoffsets);
-                       writedata(wd, DATA, sizeof(float)*3*mmd->totcagevert,
+                       writedata(wd, DATA, sizeof(int) * (mmd->totvert + 1), mmd->bindoffsets);
+                       writedata(wd, DATA, sizeof(float) * 3 * mmd->totcagevert,
                                mmd->bindcagecos);
                        writestruct(wd, DATA, "MDefCell", size*size*size, mmd->dyngrid);
                        writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->dyninfluences);
@@ -1461,6 +1493,14 @@ static void write_objects(WriteData *wd, ListBase *idbase)
                        }
                        writestruct(wd, DATA, "BulletSoftBody", 1, ob->bsoft);
                        
+                       if (ob->rigidbody_object) {
+                               // TODO: if any extra data is added to handle duplis, will need separate function then
+                               writestruct(wd, DATA, "RigidBodyOb", 1, ob->rigidbody_object);
+                       }
+                       if (ob->rigidbody_constraint) {
+                               writestruct(wd, DATA, "RigidBodyCon", 1, ob->rigidbody_constraint);
+                       }
+
                        write_particlesystems(wd, &ob->particlesystem);
                        write_modifiers(wd, &ob->modifiers);
                }
@@ -1597,7 +1637,7 @@ static void write_curves(WriteData *wd, ListBase *idbase)
                        if (cu->vfont) {
                                writedata(wd, DATA, amount_of_chars(cu->str)+1, cu->str);
                                writestruct(wd, DATA, "CharInfo", cu->len+1, cu->strinfo);
-                               writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb);                           
+                               writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb);
                        }
                        else {
                                /* is also the order of reading */
@@ -1652,7 +1692,7 @@ static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external)
                        MDisps *md = &mdlist[i];
                        if (md->disps) {
                                if (!external)
-                                       writedata(wd, DATA, sizeof(float)*3*md->totdisp, md->disps);
+                                       writedata(wd, DATA, sizeof(float) * 3 * md->totdisp, md->disps);
                        }
                        
                        if (md->hidden)
@@ -1719,9 +1759,10 @@ static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data,
 
                                writestruct(wd, DATA, structname, datasize, layer->data);
                        }
-                       else
+                       else {
                                printf("%s error: layer '%s':%d - can't be written to file\n",
                                       __func__, structname, layer->type);
+                       }
                }
        }
 
@@ -1753,6 +1794,9 @@ static void write_meshs(WriteData *wd, ListBase *idbase)
                                backup_mesh.totface = mesh->totface;
                                mesh->totface = 0;
                                /* -- */
+                               backup_mesh.fdata = mesh->fdata;
+                               memset(&mesh->fdata, 0, sizeof(mesh->fdata));
+                               /* -- */
 #endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
 
                                writestruct(wd, ID_ME, "Mesh", 1, mesh);
@@ -1776,6 +1820,8 @@ static void write_meshs(WriteData *wd, ListBase *idbase)
                                mesh->mface = backup_mesh.mface;
                                /* -- */
                                mesh->totface = backup_mesh.totface;
+                               /* -- */
+                               mesh->fdata = backup_mesh.fdata;
 #endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
 
                        }
@@ -1802,20 +1848,20 @@ static void write_meshs(WriteData *wd, ListBase *idbase)
                                mesh->totloop = 0;
                                /* -- */
                                backup_mesh.fdata = mesh->fdata;
-                               memset(&mesh->fdata, 0, sizeof(CustomData));
+                               CustomData_reset(&mesh->fdata);
                                /* -- */
                                backup_mesh.pdata = mesh->pdata;
-                               memset(&mesh->pdata, 0, sizeof(CustomData));
+                               CustomData_reset(&mesh->pdata);
                                /* -- */
                                backup_mesh.ldata = mesh->ldata;
-                               memset(&mesh->ldata, 0, sizeof(CustomData));
+                               CustomData_reset(&mesh->ldata);
                                /* -- */
                                backup_mesh.edit_btmesh = mesh->edit_btmesh;
                                mesh->edit_btmesh = NULL;
                                /* backup */
 
 
-                               /* now fill in polys to mfaces*/
+                               /* now fill in polys to mfaces */
                                mesh->totface = BKE_mesh_mpoly_to_mface(&mesh->fdata, &backup_mesh.ldata, &backup_mesh.pdata,
                                                                        mesh->totface, backup_mesh.totloop, backup_mesh.totpoly);
 
@@ -2015,7 +2061,7 @@ static void write_materials(WriteData *wd, ListBase *idbase)
                                write_nodetree(wd, ma->nodetree);
                        }
 
-                       write_previews(wd, ma->preview);                        
+                       write_previews(wd, ma->preview);
                }
                ma= ma->id.next;
        }
@@ -2071,7 +2117,7 @@ static void write_lamps(WriteData *wd, ListBase *idbase)
                        }
                        
                        if (la->curfalloff)
-                               write_curvemapping(wd, la->curfalloff); 
+                               write_curvemapping(wd, la->curfalloff);
                        
                        /* nodetree is integral part of lamps, no libdata */
                        if (la->nodetree) {
@@ -2086,6 +2132,39 @@ static void write_lamps(WriteData *wd, ListBase *idbase)
        }
 }
 
+static void write_sequence_modifiers(WriteData *wd, ListBase *modbase)
+{
+       SequenceModifierData *smd;
+
+       for (smd = modbase->first; smd; smd = smd->next) {
+               SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+
+               if (smti) {
+                       writestruct(wd, DATA, smti->struct_name, 1, smd);
+
+                       if (smd->type == seqModifierType_Curves) {
+                               CurvesModifierData *cmd = (CurvesModifierData *) smd;
+
+                               write_curvemapping(wd, &cmd->curve_mapping);
+                       }
+                       else if (smd->type == seqModifierType_HueCorrect) {
+                               HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
+
+                               write_curvemapping(wd, &hcmd->curve_mapping);
+                       }
+               }
+               else {
+                       writestruct(wd, DATA, "SequenceModifierData", 1, smd);
+               }
+       }
+}
+
+static void write_view_settings(WriteData *wd, ColorManagedViewSettings *view_settings)
+{
+       if (view_settings->curve_mapping) {
+               write_curvemapping(wd, view_settings->curve_mapping);
+       }
+}
 
 static void write_scenes(WriteData *wd, ListBase *scebase)
 {
@@ -2153,19 +2232,19 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
                                        
                                        if (seq->effectdata) {
                                                switch (seq->type) {
-                                               case SEQ_COLOR:
+                                               case SEQ_TYPE_COLOR:
                                                        writestruct(wd, DATA, "SolidColorVars", 1, seq->effectdata);
                                                        break;
-                                               case SEQ_SPEED:
+                                               case SEQ_TYPE_SPEED:
                                                        writestruct(wd, DATA, "SpeedControlVars", 1, seq->effectdata);
                                                        break;
-                                               case SEQ_WIPE:
+                                               case SEQ_TYPE_WIPE:
                                                        writestruct(wd, DATA, "WipeVars", 1, seq->effectdata);
                                                        break;
-                                               case SEQ_GLOW:
+                                               case SEQ_TYPE_GLOW:
                                                        writestruct(wd, DATA, "GlowVars", 1, seq->effectdata);
                                                        break;
-                                               case SEQ_TRANSFORM:
+                                               case SEQ_TYPE_TRANSFORM:
                                                        writestruct(wd, DATA, "TransformVars", 1, seq->effectdata);
                                                        break;
                                                }
@@ -2182,16 +2261,15 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
                                        if (seq->flag & SEQ_USE_PROXY && strip->proxy) {
                                                writestruct(wd, DATA, "StripProxy", 1, strip->proxy);
                                        }
-                                       if (seq->flag & SEQ_USE_COLOR_BALANCE && strip->color_balance) {
-                                               writestruct(wd, DATA, "StripColorBalance", 1, strip->color_balance);
-                                       }
-                                       if (seq->type==SEQ_IMAGE)
+                                       if (seq->type==SEQ_TYPE_IMAGE)
                                                writestruct(wd, DATA, "StripElem", MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem), strip->stripdata);
-                                       else if (seq->type==SEQ_MOVIE || seq->type==SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND)
+                                       else if (seq->type==SEQ_TYPE_MOVIE || seq->type==SEQ_TYPE_SOUND_RAM || seq->type == SEQ_TYPE_SOUND_HD)
                                                writestruct(wd, DATA, "StripElem", 1, strip->stripdata);
                                        
                                        strip->done = TRUE;
                                }
+
+                               write_sequence_modifiers(wd, &seq->modifiers);
                        }
                        SEQ_END
                                
@@ -2223,13 +2301,39 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
                for (ts = sce->transform_spaces.first; ts; ts = ts->next)
                        writestruct(wd, DATA, "TransformOrientation", 1, ts);
                
-               for (srl= sce->r.layers.first; srl; srl= srl->next)
+               for (srl = sce->r.layers.first; srl; srl = srl->next) {
                        writestruct(wd, DATA, "SceneRenderLayer", 1, srl);
+                       
+#ifdef WITH_FREESTYLE
+                       {
+                               FreestyleModuleConfig *fmc;
+                               FreestyleLineSet *fls;
+
+                               for(fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
+                                       writestruct(wd, DATA, "FreestyleModuleConfig", 1, fmc);
+                               }
+                       
+                               for(fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
+                                       writestruct(wd, DATA, "FreestyleLineSet", 1, fls);
+                               }
+
+                       }
+#endif
+               }
                
                if (sce->nodetree) {
                        writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree);
                        write_nodetree(wd, sce->nodetree);
                }
+
+               write_view_settings(wd, &sce->view_settings);
+               
+               /* writing RigidBodyWorld data to the blend file */
+               if (sce->rigidbody_world) {
+                       writestruct(wd, DATA, "RigidBodyWorld", 1, sce->rigidbody_world);
+                       writestruct(wd, DATA, "EffectorWeights", 1, sce->rigidbody_world->effector_weights);
+                       write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
+               }
                
                sce= sce->id.next;
        }
@@ -2260,7 +2364,7 @@ static void write_gpencils(WriteData *wd, ListBase *lb)
                                        /* write strokes */
                                        for (gps= gpf->strokes.first; gps; gps= gps->next) {
                                                writestruct(wd, DATA, "bGPDstroke", 1, gps);
-                                               writestruct(wd, DATA, "bGPDspoint", gps->totpoints, gps->points);                               
+                                               writestruct(wd, DATA, "bGPDspoint", gps->totpoints, gps->points);
                                        }
                                }
                        }
@@ -2333,6 +2437,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
                for (sa= sc->areabase.first; sa; sa= sa->next) {
                        SpaceLink *sl;
                        Panel *pa;
+                       uiList *ui_list;
                        ARegion *ar;
                        
                        writestruct(wd, DATA, "ScrArea", 1, sa);
@@ -2342,6 +2447,9 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
                                
                                for (pa= ar->panels.first; pa; pa= pa->next)
                                        writestruct(wd, DATA, "Panel", 1, pa);
+                               
+                               for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next)
+                                       writestruct(wd, DATA, "uiList", 1, ui_list);
                        }
                        
                        sl= sa->spacedata.first;
@@ -2453,6 +2561,9 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
 
                sc= sc->id.next;
        }
+       
+       /* flush helps the compression for undo-save */
+       mywrite(wd, MYWRITE_FLUSH, 0);
 }
 
 static void write_libraries(WriteData *wd, Main *main)
@@ -2466,20 +2577,35 @@ static void write_libraries(WriteData *wd, Main *main)
                a=tot= set_listbasepointers(main, lbarray);
 
                /* test: is lib being used */
-               foundone = FALSE;
-               while (tot--) {
-                       for (id= lbarray[tot]->first; id; id= id->next) {
-                               if (id->us>0 && (id->flag & LIB_EXTERN)) {
-                                       foundone = TRUE;
-                                       break;
+               if (main->curlib && main->curlib->packedfile)
+                       foundone = TRUE;
+               else {
+                       foundone = FALSE;
+                       while (tot--) {
+                               for (id= lbarray[tot]->first; id; id= id->next) {
+                                       if (id->us>0 && (id->flag & LIB_EXTERN)) {
+                                               foundone = TRUE;
+                                               break;
+                                       }
                                }
+                               if (foundone) break;
                        }
-                       if (foundone) break;
                }
-
+               
+               /* to be able to restore quit.blend and temp saves, the packed blend has to be in undo buffers... */
+               /* XXX needs rethink, just like save UI in undo files now - would be nice to append things only for the]
+                  quit.blend and temp saves */
                if (foundone) {
                        writestruct(wd, ID_LI, "Library", 1, main->curlib);
 
+                       if (main->curlib->packedfile) {
+                               PackedFile *pf = main->curlib->packedfile;
+                               writestruct(wd, DATA, "PackedFile", 1, pf);
+                               writedata(wd, DATA, pf->size, pf->data);
+                               if (wd->current == NULL)
+                                       printf("write packed .blend: %s\n", main->curlib->name);
+                       }
+                       
                        while (a--) {
                                for (id= lbarray[a]->first; id; id= id->next) {
                                        if (id->us>0 && (id->flag & LIB_EXTERN)) {
@@ -2491,12 +2617,12 @@ static void write_libraries(WriteData *wd, Main *main)
        }
 }
 
-static void write_bone(WriteData *wd, Bonebone)
+static void write_bone(WriteData *wd, Bone *bone)
 {
        Bone*   cbone;
 
        // PATCH for upward compatibility after 2.37+ armature recode
-       bone->size[0]= bone->size[1]= bone->size[2]= 1.0f;
+       bone->size[0] = bone->size[1] = bone->size[2] = 1.0f;
                
        // Write this bone
        writestruct(wd, DATA, "Bone", 1, bone);
@@ -2545,7 +2671,6 @@ static void write_texts(WriteData *wd, ListBase *idbase)
 {
        Text *text;
        TextLine *tmp;
-       TextMarker *mrk;
 
        text= idbase->first;
        while (text) {
@@ -2569,13 +2694,6 @@ static void write_texts(WriteData *wd, ListBase *idbase)
                                writedata(wd, DATA, tmp->len+1, tmp->line);
                                tmp= tmp->next;
                        }
-
-                       /* write markers */
-                       mrk= text->markers.first;
-                       while (mrk) {
-                               writestruct(wd, DATA, "TextMarker", 1, mrk);
-                               mrk= mrk->next;
-                       }
                }
 
 
@@ -2806,6 +2924,209 @@ static void write_masks(WriteData *wd, ListBase *idbase)
        mywrite(wd, MYWRITE_FLUSH, 0);
 }
 
+#ifdef WITH_FREESTYLE
+static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers)
+{
+       LineStyleModifier *m;
+       const char *struct_name;
+
+       for (m = modifiers->first; m; m = m->next) {
+               switch (m->type) {
+               case LS_MODIFIER_ALONG_STROKE:
+                       struct_name = "LineStyleColorModifier_AlongStroke";
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+                       struct_name = "LineStyleColorModifier_DistanceFromCamera";
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+                       struct_name = "LineStyleColorModifier_DistanceFromObject";
+                       break;
+               case LS_MODIFIER_MATERIAL:
+                       struct_name = "LineStyleColorModifier_Material";
+                       break;
+               default:
+                       struct_name = "LineStyleColorModifier"; /* this should not happen */
+               }
+               writestruct(wd, DATA, struct_name, 1, m);
+       }
+       for (m = modifiers->first; m; m = m->next) {
+               switch (m->type) {
+               case LS_MODIFIER_ALONG_STROKE:
+                       writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_AlongStroke *)m)->color_ramp);
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+                       writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp);
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+                       writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp);
+                       break;
+               case LS_MODIFIER_MATERIAL:
+                       writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Material *)m)->color_ramp);
+                       break;
+               }
+       }
+}
+
+static void write_linestyle_alpha_modifiers(WriteData *wd, ListBase *modifiers)
+{
+       LineStyleModifier *m;
+       const char *struct_name;
+
+       for (m = modifiers->first; m; m = m->next) {
+               switch (m->type) {
+               case LS_MODIFIER_ALONG_STROKE:
+                       struct_name = "LineStyleAlphaModifier_AlongStroke";
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+                       struct_name = "LineStyleAlphaModifier_DistanceFromCamera";
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+                       struct_name = "LineStyleAlphaModifier_DistanceFromObject";
+                       break;
+               case LS_MODIFIER_MATERIAL:
+                       struct_name = "LineStyleAlphaModifier_Material";
+                       break;
+               default:
+                       struct_name = "LineStyleAlphaModifier"; /* this should not happen */
+               }
+               writestruct(wd, DATA, struct_name, 1, m);
+       }
+       for (m = modifiers->first; m; m = m->next) {
+               switch (m->type) {
+               case LS_MODIFIER_ALONG_STROKE:
+                       write_curvemapping(wd, ((LineStyleAlphaModifier_AlongStroke *)m)->curve);
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+                       write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve);
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+                       write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve);
+                       break;
+               case LS_MODIFIER_MATERIAL:
+                       write_curvemapping(wd, ((LineStyleAlphaModifier_Material *)m)->curve);
+                       break;
+               }
+       }
+}
+
+static void write_linestyle_thickness_modifiers(WriteData *wd, ListBase *modifiers)
+{
+       LineStyleModifier *m;
+       const char *struct_name;
+
+       for (m = modifiers->first; m; m = m->next) {
+               switch (m->type) {
+               case LS_MODIFIER_ALONG_STROKE:
+                       struct_name = "LineStyleThicknessModifier_AlongStroke";
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+                       struct_name = "LineStyleThicknessModifier_DistanceFromCamera";
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+                       struct_name = "LineStyleThicknessModifier_DistanceFromObject";
+                       break;
+               case LS_MODIFIER_MATERIAL:
+                       struct_name = "LineStyleThicknessModifier_Material";
+                       break;
+               case LS_MODIFIER_CALLIGRAPHY:
+                       struct_name = "LineStyleThicknessModifier_Calligraphy";
+                       break;
+               default:
+                       struct_name = "LineStyleThicknessModifier"; /* this should not happen */
+               }
+               writestruct(wd, DATA, struct_name, 1, m);
+       }
+       for (m = modifiers->first; m; m = m->next) {
+               switch (m->type) {
+               case LS_MODIFIER_ALONG_STROKE:
+                       write_curvemapping(wd, ((LineStyleThicknessModifier_AlongStroke *)m)->curve);
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+                       write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve);
+                       break;
+               case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+                       write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve);
+                       break;
+               case LS_MODIFIER_MATERIAL:
+                       write_curvemapping(wd, ((LineStyleThicknessModifier_Material *)m)->curve);
+                       break;
+               }
+       }
+}
+
+static void write_linestyle_geometry_modifiers(WriteData *wd, ListBase *modifiers)
+{
+       LineStyleModifier *m;
+       const char *struct_name;
+
+       for (m = modifiers->first; m; m = m->next) {
+               switch (m->type) {
+               case LS_MODIFIER_SAMPLING:
+                       struct_name = "LineStyleGeometryModifier_Sampling";
+                       break;
+               case LS_MODIFIER_BEZIER_CURVE:
+                       struct_name = "LineStyleGeometryModifier_BezierCurve";
+                       break;
+               case LS_MODIFIER_SINUS_DISPLACEMENT:
+                       struct_name = "LineStyleGeometryModifier_SinusDisplacement";
+                       break;
+               case LS_MODIFIER_SPATIAL_NOISE:
+                       struct_name = "LineStyleGeometryModifier_SpatialNoise";
+                       break;
+               case LS_MODIFIER_PERLIN_NOISE_1D:
+                       struct_name = "LineStyleGeometryModifier_PerlinNoise1D";
+                       break;
+               case LS_MODIFIER_PERLIN_NOISE_2D:
+                       struct_name = "LineStyleGeometryModifier_PerlinNoise2D";
+                       break;
+               case LS_MODIFIER_BACKBONE_STRETCHER:
+                       struct_name = "LineStyleGeometryModifier_BackboneStretcher";
+                       break;
+               case LS_MODIFIER_TIP_REMOVER:
+                       struct_name = "LineStyleGeometryModifier_TipRemover";
+                       break;
+               case LS_MODIFIER_POLYGONIZATION:
+                       struct_name = "LineStyleGeometryModifier_Polygonalization";
+                       break;
+               case LS_MODIFIER_GUIDING_LINES:
+                       struct_name = "LineStyleGeometryModifier_GuidingLines";
+                       break;
+               case LS_MODIFIER_BLUEPRINT:
+                       struct_name = "LineStyleGeometryModifier_Blueprint";
+                       break;
+               case LS_MODIFIER_2D_OFFSET:
+                       struct_name = "LineStyleGeometryModifier_2DOffset";
+                       break;
+               case LS_MODIFIER_2D_TRANSFORM:
+                       struct_name = "LineStyleGeometryModifier_2DTransform";
+                       break;
+               default:
+                       struct_name = "LineStyleGeometryModifier"; /* this should not happen */
+               }
+               writestruct(wd, DATA, struct_name, 1, m);
+       }
+}
+
+static void write_linestyles(WriteData *wd, ListBase *idbase)
+{
+       FreestyleLineStyle *linestyle;
+
+       for (linestyle = idbase->first; linestyle; linestyle = linestyle->id.next) {
+               if (linestyle->id.us>0 || wd->current) {
+                       writestruct(wd, ID_LS, "FreestyleLineStyle", 1, linestyle);
+                       if (linestyle->id.properties)
+                               IDP_WriteProperty(linestyle->id.properties, wd);
+                       if (linestyle->adt)
+                               write_animdata(wd, linestyle->adt);
+                       write_linestyle_color_modifiers(wd, &linestyle->color_modifiers);
+                       write_linestyle_alpha_modifiers(wd, &linestyle->alpha_modifiers);
+                       write_linestyle_thickness_modifiers(wd, &linestyle->thickness_modifiers);
+                       write_linestyle_geometry_modifiers(wd, &linestyle->geometry_modifiers);
+               }
+       }
+}
+#endif
+
 /* context is usually defined by WM, two cases where no WM is available:
  * - for forward compatibility, curscreen has to be saved
  * - for undofile, curscene needs to be saved */
@@ -2823,16 +3144,15 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
 
        /* XXX still remap G */
        fg.curscreen= screen;
-       fg.curscene= screen->scene;
+       fg.curscene= screen? screen->scene : NULL;
        fg.displaymode= G.displaymode;
        fg.winpos= G.winpos;
 
        /* prevent to save this, is not good convention, and feature with concerns... */
-       fg.fileflags= (fileflags & ~(G_FILE_NO_UI|G_FILE_RELATIVE_REMAP|G_FILE_MESH_COMPAT));
+       fg.fileflags= (fileflags & ~G_FILE_FLAGS_RUNTIME);
 
        fg.globalf= G.f;
        BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
-
        sprintf(subvstr, "%4d", BLENDER_SUBVERSION);
        memcpy(fg.subvstr, subvstr, 4);
        
@@ -2884,12 +3204,8 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil
        write_thumb(wd, thumb);
        write_global(wd, write_flags, mainvar);
 
-       /* no UI save in undo */
-       if (current==NULL) {
-               write_windowmanagers(wd, &mainvar->wm);
-               write_screens  (wd, &mainvar->screen);
-       }
-       write_gpencils (wd, &mainvar->gpencil);
+       write_windowmanagers(wd, &mainvar->wm);
+       write_screens  (wd, &mainvar->screen);
        write_movieclips (wd, &mainvar->movieclip);
        write_masks    (wd, &mainvar->mask);
        write_scenes   (wd, &mainvar->scene);
@@ -2916,6 +3232,10 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil
        write_nodetrees(wd, &mainvar->nodetree);
        write_brushes  (wd, &mainvar->brush);
        write_scripts  (wd, &mainvar->script);
+       write_gpencils (wd, &mainvar->gpencil);
+#ifdef WITH_FREESTYLE
+       write_linestyles(wd, &mainvar->linestyle);
+#endif
        write_libraries(wd,  mainvar->next);
 
        if (write_user_block) {
@@ -2955,7 +3275,7 @@ static int do_history(const char *name, ReportList *reports)
                if (BLI_rename(tempname1, tempname2)) {
                        BKE_report(reports, RPT_ERROR, "Unable to make version backup");
                        return 1;
-               }       
+               }
                hisnr--;
        }
 
@@ -2973,19 +3293,27 @@ static int do_history(const char *name, ReportList *reports)
 /* return: success (1) */
 int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportList *reports, const int *thumb)
 {
-       char userfilename[FILE_MAX];
        char tempname[FILE_MAX+1];
        int file, err, write_user_block;
 
+       /* path backup/restore */
+       void     *path_list_backup = NULL;
+       const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
+
        /* open temporary file, so we preserve the original in case we crash */
        BLI_snprintf(tempname, sizeof(tempname), "%s@", filepath);
 
        file = BLI_open(tempname, O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666);
        if (file == -1) {
-               BKE_reportf(reports, RPT_ERROR, "Can't open file %s for writing: %s.", tempname, strerror(errno));
+               BKE_reportf(reports, RPT_ERROR, "Cannot open file %s for writing: %s", tempname, strerror(errno));
                return 0;
        }
 
+       /* check if we need to backup and restore paths */
+       if (UNLIKELY((write_flags & G_FILE_RELATIVE_REMAP) && (G_FILE_SAVE_COPY & write_flags))) {
+               path_list_backup = BKE_bpath_list_backup(mainvar, path_list_flag);
+       }
+
        /* remapping of relative paths to new file location */
        if (write_flags & G_FILE_RELATIVE_REMAP) {
                char dir1[FILE_MAX];
@@ -3006,21 +3334,25 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL
                                 * we should not have any relative paths, but if there
                                 * is somehow, an invalid or empty G.main->name it will
                                 * print an error, don't try make the absolute in this case. */
-                               BLI_bpath_absolute_convert(mainvar, G.main->name, NULL);
+                               BKE_bpath_absolute_convert(mainvar, G.main->name, NULL);
                        }
                }
        }
 
-       BLI_make_file_string(G.main->name, userfilename, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
-       write_user_block= (BLI_path_cmp(filepath, userfilename) == 0);
+       write_user_block= write_flags & G_FILE_USERPREFS;
 
        if (write_flags & G_FILE_RELATIVE_REMAP)
-               BLI_bpath_relative_convert(mainvar, filepath, NULL); /* note, making relative to something OTHER then G.main->name */
+               BKE_bpath_relative_convert(mainvar, filepath, NULL); /* note, making relative to something OTHER then G.main->name */
 
        /* actual file writing */
        err= write_file_handle(mainvar, file, NULL, NULL, write_user_block, write_flags, thumb);
        close(file);
 
+       if (UNLIKELY(path_list_backup)) {
+               BKE_bpath_list_restore(mainvar, path_list_flag, path_list_backup);
+               BKE_bpath_list_free(path_list_backup);
+       }
+
        if (err) {
                BKE_report(reports, RPT_ERROR, strerror(errno));
                remove(tempname);
@@ -3030,10 +3362,10 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL
 
        /* file save to temporary file was successful */
        /* now do reverse file history (move .blend1 -> .blend2, .blend -> .blend1) */
-       if (write_flags & G_FILE_HISTORY) { 
+       if (write_flags & G_FILE_HISTORY) {
                int err_hist = do_history(filepath, reports);
                if (err_hist) {
-                       BKE_report(reports, RPT_ERROR, "Version backup failed. File saved with @");
+                       BKE_report(reports, RPT_ERROR, "Version backup failed (file saved with @)");
                        return 0;
                }
        }
@@ -3050,23 +3382,23 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL
                if (0==ret) {
                        /* now rename to real file name, and delete temp @ file too */
                        if (BLI_rename(gzname, filepath) != 0) {
-                               BKE_report(reports, RPT_ERROR, "Can't change old file. File saved with @.");
+                               BKE_report(reports, RPT_ERROR, "Cannot change old file (file saved with @)");
                                return 0;
                        }
 
                        BLI_delete(tempname, 0, 0);
                }
                else if (-1==ret) {
-                       BKE_report(reports, RPT_ERROR, "Failed opening .gz file.");
+                       BKE_report(reports, RPT_ERROR, "Failed opening .gz file");
                        return 0;
                }
                else if (-2==ret) {
-                       BKE_report(reports, RPT_ERROR, "Failed opening .blend file for compression.");
+                       BKE_report(reports, RPT_ERROR, "Failed opening .blend file for compression");
                        return 0;
                }
        }
        else if (BLI_rename(tempname, filepath) != 0) {
-               BKE_report(reports, RPT_ERROR, "Can't change old file. File saved with @");
+               BKE_report(reports, RPT_ERROR, "Cannot change old file (file saved with @)");
                return 0;
        }
 
@@ -3083,3 +3415,4 @@ int BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int wr
        if (err==0) return 1;
        return 0;
 }
+