diff options
Diffstat (limited to 'source/blender/blenloader/intern/writefile.c')
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 564 |
1 files changed, 463 insertions, 101 deletions
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index b010cae6893..3c6e646fe9c 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -74,6 +74,7 @@ #include <math.h> #include <fcntl.h> +#include <limits.h> #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -89,6 +90,8 @@ # 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 +111,7 @@ #include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_lamp_types.h" +#include "DNA_linestyle_types.h" #include "DNA_meta_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -118,6 +122,7 @@ #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 +144,7 @@ #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" @@ -148,6 +153,7 @@ #include "BKE_curve.h" #include "BKE_constraint.h" #include "BKE_global.h" // for G +#include "BKE_idprop.h" #include "BKE_library.h" // for set_listbasepointers #include "BKE_main.h" #include "BKE_node.h" @@ -159,6 +165,13 @@ #include "BKE_pointcache.h" #include "BKE_mesh.h" +#ifdef USE_NODE_COMPAT_CUSTOMNODES +#include "NOD_common.h" +#include "NOD_socket.h" /* for sock->default_value data */ +#endif + +#include "RNA_access.h" + #include "BLO_writefile.h" #include "BLO_readfile.h" #include "BLO_undofile.h" @@ -197,7 +210,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; @@ -377,6 +390,17 @@ static void writedata(WriteData *wd, int filecode, int len, const void *adr) /* if (len) mywrite(wd, adr, len); } +/* use this to force writing of lists in same order as reading (using link_list) */ +static void writelist(WriteData *wd, int filecode, const char *structname, ListBase *lb) +{ + Link *link = lb->first; + + while (link) { + writestruct(wd, filecode, structname, 1, link); + link = link->next; + } +} + /* *************** writing some direct data structs used in more code parts **************** */ /*These functions are used by blender's .blend system for file saving/loading.*/ void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd); @@ -456,6 +480,9 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) { FModifier *fcm; + /* Write all modifiers first (for faster reloading) */ + writelist(wd, DATA, "FModifier", fmodifiers); + /* Modifiers */ for (fcm= fmodifiers->first; fcm; fcm= fcm->next) { FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); @@ -496,9 +523,6 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) break; } } - - /* Write the modifier */ - writestruct(wd, DATA, "FModifier", 1, fcm); } } @@ -506,10 +530,8 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves) { FCurve *fcu; + writelist(wd, DATA, "FCurve", fcurves); for (fcu=fcurves->first; fcu; fcu=fcu->next) { - /* F-Curve */ - writestruct(wd, DATA, "FCurve", 1, fcu); - /* curve data */ if (fcu->bezt) writestruct(wd, DATA, "BezTriple", fcu->totvert, fcu->bezt); @@ -527,9 +549,8 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves) writestruct(wd, DATA, "ChannelDriver", 1, driver); /* variables */ - for (dvar= driver->variables.first; dvar; dvar= dvar->next) { - writestruct(wd, DATA, "DriverVar", 1, dvar); - + writelist(wd, DATA, "DriverVar", &driver->variables); + for (dvar= driver->variables.first; dvar; dvar= dvar->next) { DRIVER_TARGETS_USED_LOOPER(dvar) { if (dtar->rna_path) @@ -595,10 +616,8 @@ static void write_nlastrips(WriteData *wd, ListBase *strips) { NlaStrip *strip; + writelist(wd, DATA, "NlaStrip", strips); for (strip= strips->first; strip; strip= strip->next) { - /* write the strip first */ - writestruct(wd, DATA, "NlaStrip", 1, strip); - /* write the strip's F-Curves and modifiers */ write_fcurves(wd, &strip->fcurves); write_fmodifiers(wd, &strip->modifiers); @@ -661,46 +680,54 @@ static void write_curvemapping(WriteData *wd, CurveMapping *cumap) write_curvemapping_curves(wd, cumap); } -static void write_node_socket(WriteData *wd, bNodeSocket *sock) +static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *node, bNodeSocket *sock) { - bNodeSocketType *stype= ntreeGetSocketType(sock->type); - +#ifdef USE_NODE_COMPAT_CUSTOMNODES /* forward compatibility code, so older blenders still open */ sock->stack_type = 1; - if (sock->default_value) { - bNodeSocketValueFloat *valfloat; - bNodeSocketValueVector *valvector; - bNodeSocketValueRGBA *valrgba; - - switch (sock->type) { - case SOCK_FLOAT: - valfloat = sock->default_value; - sock->ns.vec[0] = valfloat->value; - sock->ns.min = valfloat->min; - sock->ns.max = valfloat->max; - break; - case SOCK_VECTOR: - valvector = sock->default_value; - copy_v3_v3(sock->ns.vec, valvector->value); - sock->ns.min = valvector->min; - sock->ns.max = valvector->max; - break; - case SOCK_RGBA: - valrgba = sock->default_value; - copy_v4_v4(sock->ns.vec, valrgba->value); - sock->ns.min = 0.0f; - sock->ns.max = 1.0f; - break; + if (node->type == NODE_GROUP) { + bNodeTree *ngroup = (bNodeTree *)node->id; + if (ngroup) { + /* for node groups: look up the deprecated groupsock pointer */ + sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier); + BLI_assert(sock->groupsock != NULL); + + /* node group sockets now use the generic identifier string to verify group nodes, + * old blender uses the own_index. + */ + sock->own_index = sock->groupsock->own_index; } } +#endif /* actual socket writing */ writestruct(wd, DATA, "bNodeSocket", 1, sock); + + if (sock->prop) + IDP_WriteProperty(sock->prop, wd); + if (sock->default_value) - writestruct(wd, DATA, stype->value_structname, 1, sock->default_value); + writedata(wd, DATA, MEM_allocN_len(sock->default_value), sock->default_value); } +static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree), bNodeSocket *sock) +{ +#ifdef USE_NODE_COMPAT_CUSTOMNODES + /* forward compatibility code, so older blenders still open */ + sock->stack_type = 1; + + /* Reconstruct the deprecated default_value structs in socket interface DNA. */ + if (sock->default_value == NULL && sock->typeinfo) { + node_socket_init_default_value(sock); + } +#endif + + /* actual socket writing */ + writestruct(wd, DATA, "bNodeSocket", 1, sock); + if (sock->prop) + IDP_WriteProperty(sock->prop, wd); +} /* this is only direct data, tree itself should have been written */ static void write_nodetree(WriteData *wd, bNodeTree *ntree) { @@ -712,18 +739,19 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) if (ntree->adt) write_animdata(wd, ntree->adt); - for (node= ntree->nodes.first; node; node= node->next) + for (node = ntree->nodes.first; node; node = node->next) { writestruct(wd, DATA, "bNode", 1, node); - for (node= ntree->nodes.first; node; node= node->next) { + if (node->prop) + IDP_WriteProperty(node->prop, wd); + for (sock= node->inputs.first; sock; sock= sock->next) - write_node_socket(wd, sock); + write_node_socket(wd, ntree, node, sock); for (sock= node->outputs.first; sock; sock= sock->next) - write_node_socket(wd, sock); + write_node_socket(wd, ntree, node, 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)) @@ -732,10 +760,6 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) 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)) @@ -751,12 +775,12 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) if (node->type==CMP_NODE_OUTPUT_FILE) { /* inputs have own storage data */ - for (sock=node->inputs.first; sock; sock=sock->next) + for (sock = node->inputs.first; sock; sock = sock->next) writestruct(wd, DATA, "NodeImageMultiFileSocket", 1, sock->storage); } if (node->type==CMP_NODE_IMAGE) { /* write extra socket info */ - for (sock=node->outputs.first; sock; sock=sock->next) + for (sock = node->outputs.first; sock; sock = sock->next) writestruct(wd, DATA, "NodeImageLayer", 1, sock->storage); } } @@ -764,11 +788,10 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) for (link= ntree->links.first; link; link= link->next) writestruct(wd, DATA, "bNodeLink", 1, link); - /* external sockets */ - for (sock= ntree->inputs.first; sock; sock= sock->next) - write_node_socket(wd, sock); - for (sock= ntree->outputs.first; sock; sock= sock->next) - write_node_socket(wd, sock); + for (sock = ntree->inputs.first; sock; sock = sock->next) + write_node_socket_interface(wd, ntree, sock); + for (sock = ntree->outputs.first; sock; sock = sock->next) + write_node_socket_interface(wd, ntree, sock); } static void current_screen_compat(Main *mainvar, bScreen **screen) @@ -795,14 +818,15 @@ typedef struct RenderInfo { static void write_renderinfo(WriteData *wd, Main *mainvar) { bScreen *curscreen; - Scene *sce; + Scene *sce, *curscene = NULL; RenderInfo data; /* XXX in future, handle multiple windows with multiple screens? */ current_screen_compat(mainvar, &curscreen); - + if (curscreen) curscene = curscreen->scene; + for (sce= mainvar->scene.first; sce; sce= sce->id.next) { - if (sce->id.lib == NULL && (sce == curscreen->scene || (sce->r.scemode & R_BG_RENDER))) { + if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) { data.sfra = sce->r.sfra; data.efra = sce->r.efra; memset(data.scene_name, 0, sizeof(data.scene_name)); @@ -850,8 +874,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); @@ -1228,7 +1256,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) { @@ -1416,8 +1444,8 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) 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); @@ -1483,6 +1511,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); } @@ -1674,7 +1710,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) @@ -1768,7 +1804,7 @@ static void write_meshs(WriteData *wd, ListBase *idbase) if (!save_for_old_blender) { #ifdef USE_BMESH_SAVE_WITHOUT_MFACE - Mesh backup_mesh = {{0}}; + Mesh backup_mesh = {{NULL}}; /* cache only - don't write */ backup_mesh.mface = mesh->mface; mesh->mface = NULL; @@ -1811,7 +1847,7 @@ static void write_meshs(WriteData *wd, ListBase *idbase) #ifdef USE_BMESH_SAVE_AS_COMPAT - Mesh backup_mesh = {{0}}; + Mesh backup_mesh = {{NULL}}; /* backup */ backup_mesh.mpoly = mesh->mpoly; @@ -1847,7 +1883,7 @@ static void write_meshs(WriteData *wd, ListBase *idbase) mesh->totface = BKE_mesh_mpoly_to_mface(&mesh->fdata, &backup_mesh.ldata, &backup_mesh.pdata, mesh->totface, backup_mesh.totloop, backup_mesh.totpoly); - mesh_update_customdata_pointers(mesh, FALSE); + BKE_mesh_update_customdata_pointers(mesh, false); writestruct(wd, ID_ME, "Mesh", 1, mesh); @@ -1884,7 +1920,7 @@ static void write_meshs(WriteData *wd, ListBase *idbase) mesh->totpoly = backup_mesh.totpoly; mesh->totloop = backup_mesh.totloop; /* -- */ - mesh_update_customdata_pointers(mesh, FALSE); + BKE_mesh_update_customdata_pointers(mesh, false); /* --*/ mesh->edit_btmesh = backup_mesh.edit_btmesh; /* keep this after updating custom pointers */ /* restore */ @@ -2160,6 +2196,8 @@ static void write_scenes(WriteData *wd, ListBase *scebase) TransformOrientation *ts; SceneRenderLayer *srl; ToolSettings *tos; + FreestyleModuleConfig *fmc; + FreestyleLineSet *fls; sce= scebase->first; while (sce) { @@ -2283,8 +2321,15 @@ 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); + 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); + } + } if (sce->nodetree) { writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree); @@ -2292,7 +2337,14 @@ static void write_scenes(WriteData *wd, ListBase *scebase) } 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; } /* flush helps the compression for undo-save */ @@ -2312,16 +2364,16 @@ static void write_gpencils(WriteData *wd, ListBase *lb) writestruct(wd, ID_GD, "bGPdata", 1, gpd); /* write grease-pencil layers to file */ + writelist(wd, DATA, "bGPDlayer", &gpd->layers); for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { - writestruct(wd, DATA, "bGPDlayer", 1, gpl); /* write this layer's frames to file */ + writelist(wd, DATA, "bGPDframe", &gpl->frames); for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { - writestruct(wd, DATA, "bGPDframe", 1, gpf); /* write strokes */ + writelist(wd, DATA, "bGPDstroke", &gpf->strokes); for (gps= gpf->strokes.first; gps; gps= gps->next) { - writestruct(wd, DATA, "bGPDstroke", 1, gps); writestruct(wd, DATA, "bGPDspoint", gps->totpoints, gps->points); } } @@ -2395,6 +2447,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); @@ -2404,6 +2457,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; @@ -2485,7 +2541,12 @@ static void write_screens(WriteData *wd, ListBase *scrbase) writestruct(wd, DATA, "SpaceTime", 1, sl); } else if (sl->spacetype==SPACE_NODE) { - writestruct(wd, DATA, "SpaceNode", 1, sl); + SpaceNode *snode = (SpaceNode *)sl; + bNodeTreePath *path; + writestruct(wd, DATA, "SpaceNode", 1, snode); + + for (path=snode->treepath.first; path; path=path->next) + writestruct(wd, DATA, "bNodeTreePath", 1, path); } else if (sl->spacetype==SPACE_LOGIC) { writestruct(wd, DATA, "SpaceLogic", 1, sl); @@ -2515,6 +2576,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) @@ -2528,20 +2592,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)) { @@ -2719,6 +2798,73 @@ static void write_nodetrees(WriteData *wd, ListBase *idbase) } } +#ifdef USE_NODE_COMPAT_CUSTOMNODES +static void customnodes_add_deprecated_data(Main *mainvar) +{ + FOREACH_NODETREE(mainvar, ntree, id) { + bNodeLink *link, *last_link = ntree->links.last; + + /* only do this for node groups */ + if (id != &ntree->id) + continue; + + /* Forward compatibility for group nodes: add links to node tree interface sockets. + * These links are invalid by new rules (missing node pointer)! + * They will be removed again in customnodes_free_deprecated_data, + * cannot do this directly lest bNodeLink pointer mapping becomes ambiguous. + * When loading files with such links in a new Blender version + * they will be removed as well. + */ + for (link = ntree->links.first; link; link = link->next) { + bNode *fromnode = link->fromnode, *tonode = link->tonode; + bNodeSocket *fromsock = link->fromsock, *tosock = link->tosock; + + /* check both sides of the link, to handle direct input-to-output links */ + if (fromnode->type == NODE_GROUP_INPUT) { + fromnode = NULL; + fromsock = ntreeFindSocketInterface(ntree, SOCK_IN, fromsock->identifier); + } + /* only the active output node defines links */ + if (tonode->type == NODE_GROUP_OUTPUT && (tonode->flag & NODE_DO_OUTPUT)) { + tonode = NULL; + tosock = ntreeFindSocketInterface(ntree, SOCK_OUT, tosock->identifier); + } + + if (!fromnode || !tonode) { + /* Note: not using nodeAddLink here, it asserts existing node pointers */ + bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "group node link"); + tlink->fromnode = fromnode; + tlink->fromsock = fromsock; + tlink->tonode = tonode; + tlink->tosock= tosock; + tosock->link = tlink; + tlink->flag |= NODE_LINK_VALID; + BLI_addtail(&ntree->links, tlink); + } + + /* don't check newly created compatibility links */ + if (link == last_link) + break; + } + } + FOREACH_NODETREE_END +} + +static void customnodes_free_deprecated_data(Main *mainvar) +{ + FOREACH_NODETREE(mainvar, ntree, id) { + bNodeLink *link, *next_link; + + for (link = ntree->links.first; link; link = next_link) { + next_link = link->next; + if (link->fromnode == NULL || link->tonode == NULL) + nodeRemLink(ntree, link); + } + } + FOREACH_NODETREE_END +} +#endif + static void write_brushes(WriteData *wd, ListBase *idbase) { Brush *brush; @@ -2860,6 +3006,207 @@ static void write_masks(WriteData *wd, ListBase *idbase) mywrite(wd, MYWRITE_FLUSH, 0); } +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); + } + } +} + /* 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 */ @@ -2877,7 +3224,7 @@ 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; @@ -2886,7 +3233,6 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) fg.globalf= G.f; BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename)); - sprintf(subvstr, "%4d", BLENDER_SUBVERSION); memcpy(fg.subvstr, subvstr, 4); @@ -2931,6 +3277,14 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil wd->use_mesh_compat = (write_flags & G_FILE_MESH_COMPAT) != 0; #endif +#ifdef USE_NODE_COMPAT_CUSTOMNODES + /* don't write compatibility data on undo */ + if (!current) { + /* deprecated forward compat data is freed again below */ + customnodes_add_deprecated_data(mainvar); + } +#endif + sprintf(buf, "BLENDER%c%c%.3d", (sizeof(void*)==8)?'-':'_', (ENDIAN_ORDER==B_ENDIAN)?'V':'v', BLENDER_VERSION); mywrite(wd, buf, 12); @@ -2938,11 +3292,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_windowmanagers(wd, &mainvar->wm); + write_screens (wd, &mainvar->screen); write_movieclips (wd, &mainvar->movieclip); write_masks (wd, &mainvar->mask); write_scenes (wd, &mainvar->scene); @@ -2970,6 +3321,7 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil write_brushes (wd, &mainvar->brush); write_scripts (wd, &mainvar->script); write_gpencils (wd, &mainvar->gpencil); + write_linestyles(wd, &mainvar->linestyle); write_libraries(wd, mainvar->next); if (write_user_block) { @@ -2979,6 +3331,17 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil /* dna as last, because (to be implemented) test for which structs are written */ writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data); +#ifdef USE_NODE_COMPAT_CUSTOMNODES + /* compatibility data not created on undo */ + if (!current) { + /* Ugly, forward compatibility code generates deprecated data during writing, + * this has to be freed again. Can not be done directly after writing, otherwise + * the data pointers could be reused and not be mapped correctly. + */ + customnodes_free_deprecated_data(mainvar); + } +#endif + /* end of file */ memset(&bhead, 0, sizeof(BHead)); bhead.code= ENDB; @@ -3027,13 +3390,12 @@ 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 = (BLI_BPATH_TRAVERSE_SKIP_LIBRARY | BLI_BPATH_TRAVERSE_SKIP_MULTIFILE); + 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); @@ -3046,7 +3408,7 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL /* 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 = BLI_bpath_list_backup(mainvar, path_list_flag); + path_list_backup = BKE_bpath_list_backup(mainvar, path_list_flag); } /* remapping of relative paths to new file location */ @@ -3069,24 +3431,23 @@ 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)) { - BLI_bpath_list_restore(mainvar, path_list_flag, path_list_backup); - BLI_bpath_list_free(path_list_backup); + BKE_bpath_list_restore(mainvar, path_list_flag, path_list_backup); + BKE_bpath_list_free(path_list_backup); } if (err) { @@ -3122,7 +3483,7 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL return 0; } - BLI_delete(tempname, 0, 0); + BLI_delete(tempname, false, false); } else if (-1==ret) { BKE_report(reports, RPT_ERROR, "Failed opening .gz file"); @@ -3151,3 +3512,4 @@ int BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int wr if (err==0) return 1; return 0; } + |