From 077edbb384e3845f27cc06618046a08c7101cc4c Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 25 Nov 2009 14:27:50 +0000 Subject: Sculpt: external file storage for multires * This is experimental, the file format may change still! * Helps reduce memory usage, keeps .blend files smaller, and makes saving quicker when not editing multires. * This is implemented at the customdata level, currently only the multires displacements can be stored externally. ToDo * Better integration with object duplication/removal/.. * Memory is not yet freed when exiting sculpt mode. * Loading only lower levels is not supported yet. --- source/blender/blenkernel/BKE_btex.h | 64 ++++ source/blender/blenkernel/BKE_customdata.h | 16 + source/blender/blenkernel/intern/btex.c | 482 +++++++++++++++++++++++++ source/blender/blenkernel/intern/customdata.c | 305 +++++++++++++++- source/blender/blenkernel/intern/multires.c | 8 +- source/blender/blenkernel/intern/pointcache.c | 9 +- source/blender/blenlib/BLI_string.h | 3 + source/blender/blenlib/intern/string.c | 15 + source/blender/blenloader/intern/readfile.c | 10 +- source/blender/blenloader/intern/writefile.c | 19 +- source/blender/editors/include/ED_sculpt.h | 2 +- source/blender/makesdna/DNA_customdata_types.h | 17 +- source/blender/makesrna/intern/rna_modifier.c | 8 +- source/blender/windowmanager/intern/wm_files.c | 2 + 14 files changed, 924 insertions(+), 36 deletions(-) create mode 100644 source/blender/blenkernel/BKE_btex.h create mode 100644 source/blender/blenkernel/intern/btex.c (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_btex.h b/source/blender/blenkernel/BKE_btex.h new file mode 100644 index 00000000000..cb73fd160d7 --- /dev/null +++ b/source/blender/blenkernel/BKE_btex.h @@ -0,0 +1,64 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_BTEX_H +#define BKE_BTEX_H + +#define BTEX_TYPE_IMAGE 0 +#define BTEX_TYPE_MESH 1 + +#define BTEX_LAYER_NAME_MAX 64 + +typedef struct BTex BTex; +typedef struct BTexLayer BTexLayer; + +/* Create/Free */ + +BTex *btex_create(int type); +void btex_free(BTex *btex); + +/* File read/write/remove */ + +int btex_read_open(BTex *btex, char *filename); +int btex_read_layer(BTex *btex, BTexLayer *blay); +int btex_read_data(BTex *btex, int size, void *data); +void btex_read_close(BTex *btex); + +int btex_write_open(BTex *btex, char *filename); +int btex_write_layer(BTex *btex, BTexLayer *blay); +int btex_write_data(BTex *btex, int size, void *data); +void btex_write_close(BTex *btex); + +void btex_remove(char *filename); + +/* Layers */ + +BTexLayer *btex_layer_find(BTex *btex, int type, char *name); +BTexLayer *btex_layer_add(BTex *btex, int type, char *name); +void btex_layer_remove(BTex *btex, BTexLayer *blay); + +/* Mesh */ + +void btex_mesh_set_grids(BTex *btex, int totgrid, int gridsize, int datasize); + +#endif /* BKE_BTEX_H */ + diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 95ee918a888..5ce4b396f0e 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -278,4 +278,20 @@ int CustomData_verify_versions(struct CustomData *data, int index); void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata); void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata, int total); void CustomData_bmesh_init_pool(struct CustomData *data, int allocsize); + +/* External file storage */ + +void CustomData_external_add(struct CustomData *data, + int type, const char *name, int totelem); +void CustomData_external_remove(struct CustomData *data, + int type, int totelem); +void CustomData_external_remove_object(struct CustomData *data); +int CustomData_external_test(struct CustomData *data, int type); + +void CustomData_external_write(struct CustomData *data, + CustomDataMask mask, int totelem, int free); +void CustomData_external_read(struct CustomData *data, + CustomDataMask mask, int totelem); + #endif + diff --git a/source/blender/blenkernel/intern/btex.c b/source/blender/blenkernel/intern/btex.c new file mode 100644 index 00000000000..363e515f6e2 --- /dev/null +++ b/source/blender/blenkernel/intern/btex.c @@ -0,0 +1,482 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_fileops.h" +#include "BLI_string.h" + +#include "BKE_btex.h" +#include "BKE_global.h" +#include "BKE_utildefines.h" + +/************************* File Format Definitions ***************************/ + +#define BTEX_ENDIAN_LITTLE 0 +#define BTEX_ENDIAN_BIG 1 + +#define BTEX_DATA_FLOAT 0 + +typedef struct BTexHeader { + char ID[4]; /* "BTEX" */ + char endian; /* little, big */ + char version; /* non-compatible versions */ + char subversion; /* compatible sub versions */ + char pad; /* padding */ + + int structbytes; /* size of this struct in bytes */ + int type; /* image, mesh */ + int totlayer; /* number of layers in the file */ +} BTexHeader; + +typedef struct BTexImageHeader { + int structbytes; /* size of this struct in bytes */ + int width; /* image width */ + int height; /* image height */ + int tile_size; /* tile size (required power of 2) */ +} BTexImageHeader; + +typedef struct BTexMeshHeader { + int structbytes; /* size of this struct in bytes */ + int totgrid; /* number of grids */ + int gridsize; /* width of grids */ +} BTexMeshHeader; + +struct BTexLayer { + int structbytes; /* size of this struct in bytes */ + int datatype; /* only float for now */ + int datasize; /* size of data in layer */ + int type; /* layer type */ + char name[BTEX_LAYER_NAME_MAX]; /* layer name */ +}; + +/**************************** Other Definitions ******************************/ + +#define BTEX_VERSION 0 +#define BTEX_SUBVERSION 0 +#define BTEX_TILE_SIZE 64 + +struct BTex { + int type; + + BTexHeader header; + union { + BTexImageHeader image; + BTexMeshHeader mesh; + } btype; + + BTexLayer *layer; + int totlayer; + + FILE *readf; + FILE *writef; + int switchendian; + size_t dataoffset; +}; + +/********************************* Create/Free *******************************/ + +static int btex_endian(void) +{ + if(ENDIAN_ORDER == L_ENDIAN) + return BTEX_ENDIAN_LITTLE; + else + return BTEX_ENDIAN_BIG; +} + +/*static int btex_data_type_size(int datatype) +{ + if(datatype == BTEX_DATA_FLOAT) + return sizeof(float); + + return 0; +}*/ + +BTex *btex_create(int type) +{ + BTex *btex= MEM_callocN(sizeof(BTex), "BTex"); + + btex->type= type; + + return btex; +} + +void btex_free(BTex *btex) +{ + btex_read_close(btex); + btex_write_close(btex); + + if(btex->layer) + MEM_freeN(btex->layer); + + MEM_freeN(btex); +} + +/********************************* Read/Write ********************************/ + +static int btex_read_header(BTex *btex) +{ + BTexHeader *header; + BTexImageHeader *image; + BTexMeshHeader *mesh; + BTexLayer *layer; + FILE *f= btex->readf; + size_t offset = 0; + int a; + + header= &btex->header; + + if(!fread(header, sizeof(BTexHeader), 1, btex->readf)) + return 0; + + if(memcmp(header->ID, "BTEX", sizeof(header->ID)) != 0) + return 0; + if(header->version > BTEX_VERSION) + return 0; + + btex->switchendian= header->endian != btex_endian(); + header->endian= btex_endian(); + + if(btex->switchendian) { + SWITCH_INT(header->type); + SWITCH_INT(header->totlayer); + SWITCH_INT(header->structbytes); + } + + if(!ELEM(header->type, BTEX_TYPE_IMAGE, BTEX_TYPE_MESH)) + return 0; + + offset += header->structbytes; + header->structbytes= sizeof(BTexHeader); + + if(fseek(f, offset, SEEK_SET) != 0) + return 0; + + if(header->type == BTEX_TYPE_IMAGE) { + image= &btex->btype.image; + if(!fread(image, sizeof(BTexImageHeader), 1, f)) + return 0; + + if(btex->switchendian) { + SWITCH_INT(image->width); + SWITCH_INT(image->height); + SWITCH_INT(image->tile_size); + SWITCH_INT(image->structbytes); + } + + offset += image->structbytes; + image->structbytes= sizeof(BTexImageHeader); + } + else if(header->type == BTEX_TYPE_MESH) { + mesh= &btex->btype.mesh; + if(!fread(mesh, sizeof(BTexMeshHeader), 1, f)) + return 0; + + if(btex->switchendian) { + SWITCH_INT(mesh->totgrid); + SWITCH_INT(mesh->gridsize); + SWITCH_INT(mesh->structbytes); + } + + offset += mesh->structbytes; + mesh->structbytes= sizeof(BTexMeshHeader); + } + + if(fseek(f, offset, SEEK_SET) != 0) + return 0; + + btex->layer= MEM_callocN(sizeof(BTexLayer)*header->totlayer, "BTexLayer"); + btex->totlayer= header->totlayer; + + for(a=0; atotlayer; a++) { + layer= &btex->layer[a]; + + if(!fread(layer, sizeof(BTexLayer), 1, f)) + return 0; + + if(btex->switchendian) { + SWITCH_INT(layer->type); + SWITCH_INT(layer->datatype); + SWITCH_INT(layer->datasize); + SWITCH_INT(layer->structbytes); + } + + if(layer->datatype != BTEX_DATA_FLOAT) + return 0; + + offset += layer->structbytes; + layer->structbytes= sizeof(BTexLayer); + + if(fseek(f, offset, SEEK_SET) != 0) + return 0; + } + + btex->dataoffset= offset; + + return 1; +} + +static int btex_write_header(BTex *btex) +{ + BTexHeader *header; + BTexImageHeader *image; + BTexMeshHeader *mesh; + BTexLayer *layer; + FILE *f= btex->writef; + int a; + + header= &btex->header; + + if(!fwrite(header, sizeof(BTexHeader), 1, f)) + return 0; + + if(header->type == BTEX_TYPE_IMAGE) { + image= &btex->btype.image; + if(!fwrite(image, sizeof(BTexImageHeader), 1, f)) + return 0; + } + else if(header->type == BTEX_TYPE_MESH) { + mesh= &btex->btype.mesh; + if(!fwrite(mesh, sizeof(BTexMeshHeader), 1, f)) + return 0; + } + + for(a=0; atotlayer; a++) { + layer= &btex->layer[a]; + + if(!fwrite(layer, sizeof(BTexLayer), 1, f)) + return 0; + } + + return 1; +} + +int btex_read_open(BTex *btex, char *filename) +{ + FILE *f; + + f= fopen(filename, "rb"); + if(!f) + return 0; + + btex->readf= f; + + if(!btex_read_header(btex)) { + btex_read_close(btex); + return 0; + } + + if(btex->header.type != btex->type) { + btex_read_close(btex); + return 0; + } + + return 1; +} + +int btex_read_layer(BTex *btex, BTexLayer *blay) +{ + size_t offset; + int a; + + /* seek to right location in file */ + offset= btex->dataoffset; + for(a=0; atotlayer; a++) { + if(&btex->layer[a] == blay) + break; + else + offset += btex->layer[a].datasize; + } + + return (fseek(btex->readf, offset, SEEK_SET) == 0); +} + +int btex_read_data(BTex *btex, int size, void *data) +{ + float *fdata; + int a; + + /* read data */ + if(!fread(data, size, 1, btex->readf)) + return 0; + + /* switch endian if necessary */ + if(btex->switchendian) { + fdata= data; + + for(a=0; areadf) { + fclose(btex->readf); + btex->readf= NULL; + } +} + +int btex_write_open(BTex *btex, char *filename) +{ + BTexHeader *header; + BTexImageHeader *image; + BTexMeshHeader *mesh; + FILE *f; + + f= fopen(filename, "wb"); + if(!f) + return 0; + + btex->writef= f; + + /* fill header */ + header= &btex->header; + strcpy(header->ID, "BTEX"); + header->endian= btex_endian(); + header->version= BTEX_VERSION; + header->subversion= BTEX_SUBVERSION; + + header->structbytes= sizeof(BTexHeader); + header->type= btex->type; + header->totlayer= btex->totlayer; + + if(btex->type == BTEX_TYPE_IMAGE) { + /* fill image header */ + image= &btex->btype.image; + image->structbytes= sizeof(BTexImageHeader); + image->tile_size= BTEX_TILE_SIZE; + } + else if(btex->type == BTEX_TYPE_MESH) { + /* fill mesh header */ + mesh= &btex->btype.mesh; + mesh->structbytes= sizeof(BTexMeshHeader); + } + + btex_write_header(btex); + + return 1; +} + +int btex_write_layer(BTex *btex, BTexLayer *blay) +{ + return 1; +} + +int btex_write_data(BTex *btex, int size, void *data) +{ + /* write data */ + if(!fwrite(data, size, 1, btex->writef)) + return 0; + + return 1; +} + +void btex_write_close(BTex *btex) +{ + if(btex->writef) { + fclose(btex->writef); + btex->writef= NULL; + } +} + +void btex_remove(char *filename) +{ + BLI_delete(filename, 0, 0); +} + +/********************************** Layers ***********************************/ + +BTexLayer *btex_layer_find(BTex *btex, int type, char *name) +{ + BTexLayer *layer; + int a; + + for(a=0; atotlayer; a++) { + layer= &btex->layer[a]; + + if(layer->type == type && strcmp(layer->name, name) == 0) + return layer; + } + + return NULL; +} + +BTexLayer *btex_layer_add(BTex *btex, int type, char *name) +{ + BTexLayer *newlayer, *layer; + + /* expand array */ + newlayer= MEM_callocN(sizeof(BTexLayer)*(btex->totlayer+1), "BTexLayer"); + memcpy(newlayer, btex->layer, sizeof(BTexLayer)*btex->totlayer); + btex->layer= newlayer; + + btex->totlayer++; + + /* fill in new layer */ + layer= &btex->layer[btex->totlayer-1]; + layer->structbytes= sizeof(BTexLayer); + layer->datatype= BTEX_DATA_FLOAT; + layer->type= type; + BLI_strncpy(layer->name, name, BTEX_LAYER_NAME_MAX); + + return layer; +} + +void btex_layer_remove(BTex *btex, BTexLayer *layer) +{ + BTexLayer *newlayer; + int index= layer - btex->layer; + + /* expand array */ + newlayer= MEM_callocN(sizeof(BTexLayer)*(btex->totlayer-1), "BTexLayer"); + if(index > 0) + memcpy(newlayer, btex->layer, sizeof(BTexLayer)*index); + if(index+1 < btex->totlayer) + memcpy(newlayer+index, btex->layer+index+1, sizeof(BTexLayer)*(btex->totlayer-(index+1))); + btex->layer= newlayer; + + btex->totlayer--; +} + +/********************************* Mesh **************************************/ + +void btex_mesh_set_grids(BTex *btex, int totgrid, int gridsize, int datasize) +{ + BTexLayer *layer; + int a; + + btex->btype.mesh.totgrid= totgrid; + btex->btype.mesh.gridsize= gridsize; + + for(a=0; atotlayer; a++) { + layer= &btex->layer[a]; + layer->datasize= datasize; + } +} + diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 4844595513f..8f167310741 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -32,21 +32,26 @@ * */ -#include "BKE_customdata.h" -#include "BKE_utildefines.h" // CLAMP -#include "BLI_math.h" -#include "BLI_blenlib.h" -#include "BLI_linklist.h" -#include "BLI_mempool.h" +#include +#include + +#include "MEM_guardedalloc.h" #include "DNA_customdata_types.h" #include "DNA_listBase.h" #include "DNA_meshdata_types.h" +#include "DNA_ID.h" -#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "BLI_linklist.h" +#include "BLI_math.h" +#include "BLI_mempool.h" +#include "BLI_string.h" -#include -#include +#include "BKE_btex.h" +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_utildefines.h" /* number of layers to add when growing a CustomData object */ #define CUSTOMDATA_GROW 5 @@ -89,6 +94,12 @@ typedef struct LayerTypeInfo { /* a function to set a layer's data to default values. if NULL, the default is assumed to be all zeros */ void (*set_default)(void *data, int count); + + /* a function to read data from a btex file */ + int (*read)(BTex *btex, void *data, int count); + + /* a function to write data to a btex file */ + int (*write)(BTex *btex, void *data, int count); } LayerTypeInfo; static void layerCopy_mdeformvert(const void *source, void *dest, @@ -538,6 +549,39 @@ static void layerFree_mdisps(void *data, int count, int size) } } +static int layerRead_mdisps(BTex *btex, void *data, int count) +{ + MDisps *d = data; + int i; + + for(i = 0; i < count; ++i) { + if(!d[i].disps) + d[i].disps = MEM_callocN(sizeof(float)*3*d[i].totdisp, "mdisps read"); + + if(!btex_read_data(btex, d[i].totdisp*3*sizeof(float), d[i].disps)) { + printf("failed to read %d/%d %d\n", i, count, d[i].totdisp); + return 0; + } + } + + return 1; +} + +static int layerWrite_mdisps(BTex *btex, void *data, int count) +{ + MDisps *d = data; + int i; + + for(i = 0; i < count; ++i) { + if(!btex_write_data(btex, d[i].totdisp*3*sizeof(float), d[i].disps)) { + printf("failed to write %d/%d %d\n", i, count, d[i].totdisp); + return 0; + } + } + + return 1; +} + /* --------- */ static void layerDefault_mloopcol(void *data, int count) @@ -731,7 +775,7 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL, layerDefault_mloopcol}, {sizeof(float)*3*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, {sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps, - layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL}, + layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL, layerRead_mdisps, layerWrite_mdisps}, {sizeof(MCol)*4, "MCol", 4, "WeightCol", NULL, NULL, layerInterp_mcol, layerSwap_mcol, layerDefault_mcol}, {sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol, @@ -793,6 +837,8 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest, CustomDataLayer *layer, *newlayer; int i, type, number = 0, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0; + CustomData_external_read(dest, mask, totelem); + for(i = 0; i < source->totlayer; ++i) { layer = &source->layers[i]; typeInfo = layerType_getInfo(layer->type); @@ -853,6 +899,14 @@ static void customData_free_layer__internal(CustomDataLayer *layer, int totelem) } } +static void CustomData_external_free(CustomData *data) +{ + if(data->external) { + MEM_freeN(data->external); + data->external= NULL; + } +} + void CustomData_free(CustomData *data, int totelem) { int i; @@ -863,6 +917,8 @@ void CustomData_free(CustomData *data, int totelem) if(data->layers) MEM_freeN(data->layers); + CustomData_external_free(data); + memset(data, 0, sizeof(*data)); } @@ -2238,3 +2294,232 @@ int CustomData_verify_versions(struct CustomData *data, int index) return keeplayer; } +/****************************** External Files *******************************/ + +static void customdata_external_filename(char filename[FILE_MAX], CustomDataExternal *external) +{ + BLI_strncpy(filename, external->filename, FILE_MAX); + BLI_convertstringcode(filename, G.sce); +} + +void CustomData_external_read(CustomData *data, CustomDataMask mask, int totelem) +{ + CustomDataExternal *external= data->external; + CustomDataLayer *layer; + BTex *btex; + BTexLayer *blay; + char filename[FILE_MAX]; + const LayerTypeInfo *typeInfo; + int i, update = 0; + + if(!external) + return; + + for(i=0; itotlayer; i++) { + layer = &data->layers[i]; + typeInfo = layerType_getInfo(layer->type); + + if(!(mask & (1<type))); + else if(layer->flag & CD_FLAG_IN_MEMORY); + else if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) + update= 1; + } + + if(!update) + return; + + customdata_external_filename(filename, external); + + btex= btex_create(BTEX_TYPE_MESH); + if(!btex_read_open(btex, filename)) + return; + + for(i=0; itotlayer; i++) { + layer = &data->layers[i]; + typeInfo = layerType_getInfo(layer->type); + + if(!(mask & (1<type))); + else if(layer->flag & CD_FLAG_IN_MEMORY); + else if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) { + blay= btex_layer_find(btex, layer->type, layer->name); + + if(blay) { + if(btex_read_layer(btex, blay)) { + if(typeInfo->read(btex, layer->data, totelem)); + else break; + layer->flag |= CD_FLAG_IN_MEMORY; + } + else + break; + } + } + } + + btex_read_close(btex); + btex_free(btex); +} + +void CustomData_external_write(CustomData *data, CustomDataMask mask, int totelem, int free) +{ + CustomDataExternal *external= data->external; + CustomDataLayer *layer; + BTex *btex; + BTexLayer *blay; + const LayerTypeInfo *typeInfo; + int i, update = 0; + char filename[FILE_MAX]; + + if(!external) + return; + + for(i=0; itotlayer; i++) { + layer = &data->layers[i]; + typeInfo = layerType_getInfo(layer->type); + + if(!(mask & (1<type))); + else if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) + update= 1; + } + + if(!update) + return; + + CustomData_external_read(data, mask, totelem); + + btex= btex_create(BTEX_TYPE_MESH); + + for(i=0; itotlayer; i++) { + layer = &data->layers[i]; + typeInfo = layerType_getInfo(layer->type); + + if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) + btex_layer_add(btex, layer->type, layer->name); + } + + customdata_external_filename(filename, external); + if(!btex_write_open(btex, filename)) + return; + + for(i=0; itotlayer; i++) { + layer = &data->layers[i]; + typeInfo = layerType_getInfo(layer->type); + + if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) { + blay= btex_layer_find(btex, layer->type, layer->name); + + if(btex_write_layer(btex, blay)) { + if(typeInfo->write(btex, layer->data, totelem)); + else break; + } + else + break; + } + } + + if(i != data->totlayer) { + btex_free(btex); + return; + } + + for(i=0; itotlayer; i++) { + layer = &data->layers[i]; + typeInfo = layerType_getInfo(layer->type); + + if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) { + if(free) { + if(typeInfo->free) + typeInfo->free(layer->data, totelem, typeInfo->size); + layer->flag &= ~CD_FLAG_IN_MEMORY; + } + } + } + + btex_write_close(btex); + btex_free(btex); +} + +void CustomData_external_add(CustomData *data, int type, const char *name, int totelem) +{ + CustomDataExternal *external= data->external; + CustomDataLayer *layer; + int layer_index; + + layer_index = CustomData_get_active_layer_index(data, type); + if(layer_index < 0) return; + + layer = &data->layers[layer_index]; + + if(layer->flag & CD_FLAG_EXTERNAL) + return; + + if(!external) { + char hex[MAX_ID_NAME*2]; + + external= MEM_callocN(sizeof(CustomDataExternal), "CustomDataExternal"); + BLI_strhex(hex, sizeof(hex), name); + BLI_snprintf(external->filename, sizeof(external->filename), "//%s_mesh.btex", hex); + data->external= external; + } + + layer->flag |= CD_FLAG_EXTERNAL|CD_FLAG_IN_MEMORY; +} + +void CustomData_external_remove(CustomData *data, int type, int totelem) +{ + CustomDataExternal *external= data->external; + CustomDataLayer *layer; + char filename[FILE_MAX]; + int layer_index, i, remove_file; + + layer_index = CustomData_get_active_layer_index(data, type); + if(layer_index < 0) return; + + layer = &data->layers[layer_index]; + + if(!external) + return; + + if(layer->flag & CD_FLAG_EXTERNAL) { + if(!(layer->flag & CD_FLAG_IN_MEMORY)) + CustomData_external_read(data, (1<type), totelem); + + layer->flag &= ~CD_FLAG_EXTERNAL; + + remove_file= 1; + for(i=0; itotlayer; i++) + if(data->layers[i].flag & CD_FLAG_EXTERNAL) + remove_file= 0; + + if(remove_file) { + customdata_external_filename(filename, external); + btex_remove(filename); + CustomData_external_free(data); + } + } +} + +int CustomData_external_test(CustomData *data, int type) +{ + CustomDataLayer *layer; + int layer_index; + + layer_index = CustomData_get_active_layer_index(data, type); + if(layer_index < 0) return 0; + + layer = &data->layers[layer_index]; + return (layer->flag & CD_FLAG_EXTERNAL); +} + +void CustomData_external_remove_object(CustomData *data) +{ + CustomDataExternal *external= data->external; + char filename[FILE_MAX]; + + if(!external) + return; + + customdata_external_filename(filename, external); + btex_remove(filename); + CustomData_external_free(data); +} + diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 2518d4bc3ca..a709b45f60c 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -249,7 +249,7 @@ void multiresModifier_del_levels(struct MultiresModifierData *mmd, struct Object int levels = mmd->totlvl - lvl; MDisps *mdisps; - // XXX CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface); + CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface); mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS); multires_force_update(ob); @@ -595,7 +595,7 @@ static void multiresModifier_update(DerivedMesh *dm) ob = ccgdm->multires.ob; me = ccgdm->multires.ob->data; mmd = ccgdm->multires.mmd; - // XXX CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface); + CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface); mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS); if(mdisps) { @@ -692,7 +692,7 @@ void multires_force_update(Object *ob) struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int local_mmd, DerivedMesh *dm, Object *ob, int useRenderParams, int isFinalCalc) { - //Mesh *me= ob->data; + Mesh *me= ob->data; DerivedMesh *result; CCGDerivedMesh *ccgdm; DMGridData **gridData, **subGridData; @@ -727,7 +727,7 @@ struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, i memcpy(subGridData[i], gridData[i], sizeof(DMGridData)*gridSize*gridSize); } - // XXX CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface); + CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface); multiresModifier_disp_run(result, ob->data, 0, 0, subGridData, mmd->totlvl); for(i = 0; i < numGrids; i++) diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index c2798b4a746..e552f08f350 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1075,12 +1075,11 @@ static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, sho } if(strcmp(pid->cache->name, "")==0 && (pid->cache->flag & PTCACHE_EXTERNAL)==0) { idname = (pid->ob->id.name+2); + /* convert chars to hex so they are always a valid filename */ - while('\0' != *idname) { - snprintf(newname, MAX_PTCACHE_FILE, "%02X", (char)(*idname++)); - newname+=2; - len += 2; - } + BLI_strhex(newname, MAX_PTCACHE_FILE - len, idname); + len += strlen(newname); + newname = filename + len; } else { int temp = (int)strlen(pid->cache->name); diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index fb345de72e9..fad3c337355 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -123,6 +123,9 @@ int BLI_natstrcmp(const char *s1, const char *s2); void BLI_timestr(double _time, char *str); /* time var is global */ + /* Convert to hex string valid for file writing (2x length of original) */ +void BLI_strhex(char *hex, int maxlen, const char *str); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 405f8c6db97..2ecdda2de35 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -329,3 +329,18 @@ void BLI_timestr(double _time, char *str) str[11]=0; } + +void BLI_strhex(char *hex, int maxlen, const char *str) +{ + int len = 0; + + while('\0' != *str && len+3 < maxlen) { + snprintf(hex, maxlen, "%02X", *str++); + hex += 2; + len += 2; + } + + if(maxlen) + hex[0]= '\0'; +} + diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a9ceb77ad9f..c47ea8838c7 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3311,14 +3311,14 @@ static void direct_link_dverts(FileData *fd, int count, MDeformVert *mdverts) } } -static void direct_link_mdisps(FileData *fd, int count, MDisps *mdisps) +static void direct_link_mdisps(FileData *fd, int count, MDisps *mdisps, int external) { if(mdisps) { int i; for(i = 0; i < count; ++i) { mdisps[i].disps = newdataadr(fd, mdisps[i].disps); - if(!mdisps[i].disps) + if(!external && !mdisps[i].disps) mdisps[i].totdisp = 0; } } @@ -3329,14 +3329,18 @@ static void direct_link_customdata(FileData *fd, CustomData *data, int count) int i = 0; data->layers= newdataadr(fd, data->layers); + data->external= newdataadr(fd, data->external); while (i < data->totlayer) { CustomDataLayer *layer = &data->layers[i]; + if(layer->flag & CD_FLAG_EXTERNAL) + layer->flag &= ~CD_FLAG_IN_MEMORY; + if (CustomData_verify_versions(data, i)) { layer->data = newdataadr(fd, layer->data); if(layer->type == CD_MDISPS) - direct_link_mdisps(fd, count, layer->data); + direct_link_mdisps(fd, count, layer->data, layer->flag & CD_FLAG_EXTERNAL); i++; } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index b00cd10c6a7..0a4f22c1fd5 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1434,15 +1434,17 @@ static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist) } } -static void write_mdisps(WriteData *wd, int count, MDisps *mdlist) +static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external) { if(mdlist) { int i; writestruct(wd, DATA, "MDisps", count, mdlist); - for(i = 0; i < count; ++i) { - if(mdlist[i].disps) - writedata(wd, DATA, sizeof(float)*3*mdlist[i].totdisp, mdlist[i].disps); + if(!external) { + for(i = 0; i < count; ++i) { + if(mdlist[i].disps) + writedata(wd, DATA, sizeof(float)*3*mdlist[i].totdisp, mdlist[i].disps); + } } } } @@ -1451,6 +1453,10 @@ static void write_customdata(WriteData *wd, int count, CustomData *data, int par { int i; + /* write external customdata */ + if(data->external && !wd->current) + CustomData_external_write(data, CD_MASK_MESH, count, 0); + writestruct(wd, DATA, "CustomDataLayer", data->maxlayer, data->layers); for (i=0; itotlayer; i++) { @@ -1463,7 +1469,7 @@ static void write_customdata(WriteData *wd, int count, CustomData *data, int par write_dverts(wd, count, layer->data); } else if (layer->type == CD_MDISPS) { - write_mdisps(wd, count, layer->data); + write_mdisps(wd, count, layer->data, layer->flag & CD_FLAG_EXTERNAL); } else { CustomData_file_write_info(layer->type, &structname, &structnum); @@ -1480,6 +1486,9 @@ static void write_customdata(WriteData *wd, int count, CustomData *data, int par printf("error: this CustomDataLayer must not be written to file\n"); } } + + if(data->external) + writestruct(wd, DATA, "CustomDataExternal", 1, data->external); } static void write_meshs(WriteData *wd, ListBase *idbase) diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index 085c8e894f8..aae79e9a1de 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -39,7 +39,7 @@ struct wmWindowManager; void ED_operatortypes_sculpt(void); void sculpt_get_redraw_planes(float planes[4][4], struct ARegion *ar, struct RegionView3D *rv3d, struct Object *ob); - +void ED_sculpt_force_update(struct bContext *C); /* paint_ops.c */ void ED_operatortypes_paint(void); diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index ad686e37097..91e4cefce80 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -44,14 +44,19 @@ typedef struct CustomDataLayer { void *data; /* layer data */ } CustomDataLayer; +typedef struct CustomDataExternal { + char filename[240]; /* FILE_MAX */ +} CustomDataExternal; + /* structure which stores custom element data associated with mesh elements * (vertices, edges or faces). The custom data is organised into a series of * layers, each with a data type (e.g. MTFace, MDeformVert, etc.). */ typedef struct CustomData { - CustomDataLayer *layers; /* CustomDataLayers, ordered by type */ - int totlayer, maxlayer; /* number of layers, size of layers array */ - int totsize, pad; /* in editmode, total size of all data layers */ - void *pool; /* for Bmesh: Memory pool for allocation of blocks*/ + CustomDataLayer *layers; /* CustomDataLayers, ordered by type */ + int totlayer, maxlayer; /* number of layers, size of layers array */ + int totsize, pad; /* in editmode, total size of all data layers */ + void *pool; /* Bmesh: Memory pool for allocation of blocks */ + CustomDataExternal *external; /* external file storing customdata layers */ } CustomData; /* CustomData.type */ @@ -115,6 +120,10 @@ typedef struct CustomData { #define CD_FLAG_NOFREE (1<<1) /* indicates the layer is only temporary, also implies no copy */ #define CD_FLAG_TEMPORARY ((1<<2)|CD_FLAG_NOCOPY) +/* indicates the layer is stored in an external file */ +#define CD_FLAG_EXTERNAL (1<<3) +/* indicates external data is read into memory */ +#define CD_FLAG_IN_MEMORY (1<<4) /* Limits */ #define MAX_MTFACE 8 diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 689599c5cdf..208ba522502 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -340,7 +340,7 @@ static void rna_MultiresModifier_level_range(PointerRNA *ptr, int *min, int *max *max = mmd->totlvl; } -/*static int rna_MultiresModifier_external_get(PointerRNA *ptr) +static int rna_MultiresModifier_external_get(PointerRNA *ptr) { Object *ob= (Object*)ptr->id.data; Mesh *me= ob->data; @@ -364,7 +364,7 @@ static int rna_MultiresModifier_external_editable(PointerRNA *ptr) MultiresModifierData *mmd = ptr->data; return (G.save_over && mmd->totlvl > 0); -}*/ +} static void modifier_object_set(Object *self, Object **ob_p, int type, PointerRNA value) { @@ -570,10 +570,10 @@ static void rna_def_modifier_multires(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Total Levels", "Number of subdivisions for which displacements are stored."); - /*prop= RNA_def_property(srna, "external", PROP_BOOLEAN, PROP_NONE); + prop= RNA_def_property(srna, "external", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_MultiresModifier_external_get", "rna_MultiresModifier_external_set"); RNA_def_property_editable_func(prop, "rna_MultiresModifier_external_editable"); - RNA_def_property_ui_text(prop, "External", "Store multires displacements outside the .blend file, to save memory.");*/ + RNA_def_property_ui_text(prop, "External", "Store multires displacements outside the .blend file, to save memory."); } static void rna_def_modifier_lattice(BlenderRNA *brna) diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 6348e1a2717..21b894ee46b 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -81,6 +81,7 @@ #include "ED_datafiles.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_sculpt.h" #include "ED_util.h" #include "GHOST_C-api.h" @@ -492,6 +493,7 @@ void WM_write_file(bContext *C, char *target, int fileflags, ReportList *reports } ED_object_exit_editmode(C, EM_DO_UNDO); + ED_sculpt_force_update(C); do_history(di, reports); -- cgit v1.2.3