diff options
author | Ton Roosendaal <ton@blender.org> | 2006-12-20 20:57:56 +0300 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2006-12-20 20:57:56 +0300 |
commit | 253432bfc7c2a1dae224a03fb3055de19743ec67 (patch) | |
tree | 2cea30606f9f29be51d5366ddf0d3747b9649b90 /source/blender/imbuf | |
parent | 0a0753b409221b66f5003d8c257426043ada227e (diff) |
The Big Image refactor!
Please read:
http://www.blender3d.org/cms/Imaging.834.0.html
Or in short:
- adding MultiLayer Image support
- recoded entire Image API
- better integration of movie/sequence Images
Was a whole load of work... went down for a week to do this. So, will need
a lot of testing! Will be in irc all evening.
Diffstat (limited to 'source/blender/imbuf')
-rw-r--r-- | source/blender/imbuf/IMB_imbuf.h | 2 | ||||
-rw-r--r-- | source/blender/imbuf/IMB_imbuf_types.h | 34 | ||||
-rw-r--r-- | source/blender/imbuf/intern/allocimbuf.c | 23 | ||||
-rw-r--r-- | source/blender/imbuf/intern/divers.c | 30 | ||||
-rw-r--r-- | source/blender/imbuf/intern/filter.c | 25 | ||||
-rw-r--r-- | source/blender/imbuf/intern/openexr/openexr_api.cpp | 402 | ||||
-rw-r--r-- | source/blender/imbuf/intern/openexr/openexr_multi.h | 23 | ||||
-rw-r--r-- | source/blender/imbuf/intern/readimage.c | 2 | ||||
-rw-r--r-- | source/blender/imbuf/intern/rectop.c | 2 |
9 files changed, 449 insertions, 94 deletions
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 02b3557c094..60177f2c996 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -315,6 +315,7 @@ void IMB_antialias(struct ImBuf * ibuf); void IMB_filter(struct ImBuf *ibuf); void IMB_filterN(struct ImBuf *out, struct ImBuf *in); void IMB_filter_extend(struct ImBuf *ibuf); +void IMB_makemipmap(struct ImBuf *ibuf, int use_filter); /** * @@ -537,6 +538,7 @@ void imb_freerectImBuf(struct ImBuf * ibuf); short imb_addrectfloatImBuf(struct ImBuf * ibuf); void imb_freerectfloatImBuf(struct ImBuf * ibuf); +void imb_freemipmapImBuf(struct ImBuf * ibuf); #ifdef WITH_QUICKTIME /** diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 586dedc54e8..f5487bb9ac0 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -56,6 +56,8 @@ struct _AviMovie; struct Mdec; +#define IB_MIPMAP_LEVELS 10 + /** * \brief The basic imbuf type * \ingroup imbuf @@ -70,36 +72,41 @@ struct Mdec; * * Also, that iff.h needs to be in the final release "plugins/include" dir, too! */ -typedef struct ImBuf{ - short x, y; /**< width and Height of our image buffer */ - short skipx; /**< Width in ints to get to the next scanline */ +typedef struct ImBuf { + struct ImBuf *next, *prev; /**< allow lists of ImBufs, for caches or flipbooks */ + short x, y; /**< width and Height of our image buffer */ + short skipx; /**< Width in ints to get to the next scanline */ unsigned char depth; /**< Active amount of bits/bitplanes */ unsigned char cbits; /**< Amount of active bits in cmap */ unsigned short mincol; /**< smallest color in colormap */ unsigned short maxcol; /**< Largest color in colormap */ - int type; /**< 0=abgr, 1=bitplanes */ - int ftype; /**< File type we are going to save as */ + int type; /**< 0=abgr, 1=bitplanes */ + int ftype; /**< File type we are going to save as */ unsigned int *cmap; /**< Color map data. */ unsigned int *rect; /**< pixel values stored here */ unsigned int **planes; /**< bitplanes */ - int flags; /**< Controls which components should exist. */ - int mall; /**< what is malloced internal, and can be freed */ + int flags; /**< Controls which components should exist. */ + int mall; /**< what is malloced internal, and can be freed */ short xorig, yorig; /**< Cordinates of first pixel of an image used in some formats (example: targa) */ char name[1023]; /**< The file name assocated with this image */ char namenull; /**< Unused don't want to remove it thought messes things up */ - int userflags; /**< Used to set imbuf to Dirty and other stuff */ - int *zbuf; /**< z buffer data, original zbuffer */ - float *zbuf_float; /**< z buffer data, camera coordinates */ + int userflags; /**< Used to set imbuf to Dirty and other stuff */ + int *zbuf; /**< z buffer data, original zbuffer */ + float *zbuf_float; /**< z buffer data, camera coordinates */ void *userdata; unsigned char *encodedbuffer; /**< Compressed image only used with png currently */ unsigned int encodedsize; /**< Size of data written to encodedbuffer */ unsigned int encodedbuffersize; /**< Size of encodedbuffer */ float *rect_float; /**< floating point Rect equivilant */ + int channels; /**< amount of channels in rect_float (0 = 4 channel default) */ float dither; /**< random dither value, for conversion from float -> byte rect */ struct MEM_CacheLimiterHandle_s * c_handle; /**< handle for cache limiter */ - int refcounter; /**< Refcounter for multiple users */ + int refcounter; /**< Refcounter for multiple users */ + int index; /**< reference index for ImBuf lists */ + + struct ImBuf *mipmap[IB_MIPMAP_LEVELS]; /**< MipMap levels, a series of halved images */ } ImBuf; /* Moved from BKE_bmfont_types.h because it is a userflag bit mask. */ @@ -138,8 +145,9 @@ typedef enum { #define IB_zbuf (1 << 13) #define IB_mem (1 << 14) -#define IB_rectfloat (1 << 15) -#define IB_zbuffloat (1 << 16) +#define IB_rectfloat (1 << 15) +#define IB_zbuffloat (1 << 16) +#define IB_multilayer (1 << 17) /* * The bit flag is stored in the ImBuf.ftype variable. diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 30e97328e7c..003d377389b 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -62,6 +62,17 @@ void imb_freeplanesImBuf(struct ImBuf * ibuf) ibuf->mall &= ~IB_planes; } +void imb_freemipmapImBuf(struct ImBuf * ibuf) +{ + int a; + + for(a=0; a<IB_MIPMAP_LEVELS; a++) { + if(ibuf->mipmap[a]) IMB_freeImBuf(ibuf->mipmap[a]); + ibuf->mipmap[a]= NULL; + } +} + +/* any free rect frees mipmaps to be sure, creation is in render on first request */ void imb_freerectfloatImBuf(struct ImBuf * ibuf) { if (ibuf==NULL) return; @@ -73,10 +84,13 @@ void imb_freerectfloatImBuf(struct ImBuf * ibuf) } } + imb_freemipmapImBuf(ibuf); + ibuf->rect_float= NULL; ibuf->mall &= ~IB_rectfloat; } +/* any free rect frees mipmaps to be sure, creation is in render on first request */ void imb_freerectImBuf(struct ImBuf * ibuf) { if (ibuf==NULL) return; @@ -87,6 +101,8 @@ void imb_freerectImBuf(struct ImBuf * ibuf) } } + imb_freemipmapImBuf(ibuf); + ibuf->rect= NULL; ibuf->mall &= ~IB_rect; } @@ -363,7 +379,8 @@ struct ImBuf *IMB_allocImBuf(short x, short y, uchar d, unsigned int flags, ucha ibuf->y= y; ibuf->depth= d; ibuf->ftype= TGA; - + ibuf->channels= 4; /* float option, is set to other values when buffers get assigned */ + if (flags & IB_rect){ if (imb_addrectImBuf(ibuf)==FALSE){ IMB_freeImBuf(ibuf); @@ -407,7 +424,7 @@ struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1) { struct ImBuf *ibuf2, tbuf; int flags = 0; - int x, y; + int a, x, y; if (ibuf1 == NULL) return NULL; @@ -452,6 +469,8 @@ struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1) tbuf.encodedbuffer = ibuf2->encodedbuffer; tbuf.zbuf= NULL; tbuf.zbuf_float= NULL; + for(a=0; a<IB_MIPMAP_LEVELS; a++) + tbuf.mipmap[a]= NULL; // set malloc flag tbuf.mall = ibuf2->mall; diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index c0018d0b336..a4fab4a3572 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -181,7 +181,7 @@ void IMB_rect_from_float(struct ImBuf *ibuf) /* quick method to convert floatbuf to byte */ float *tof = ibuf->rect_float; float dither= ibuf->dither; - int i; + int i, channels= ibuf->channels; unsigned char *to = (unsigned char *) ibuf->rect; if(tof==NULL) return; @@ -190,14 +190,26 @@ void IMB_rect_from_float(struct ImBuf *ibuf) to = (unsigned char *) ibuf->rect; } - if(dither==0.0f) { - for (i = ibuf->x * ibuf->y; i > 0; i--) { - to[0] = FTOCHAR(tof[0]); - to[1] = FTOCHAR(tof[1]); - to[2] = FTOCHAR(tof[2]); - to[3] = FTOCHAR(tof[3]); - to += 4; - tof += 4; + if(dither==0.0f || channels!=4) { + if(channels==1) { + for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof++) + to[1]= to[2]= to[3]= to[0] = FTOCHAR(tof[0]); + } + else if(channels==3) { + for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) { + to[0] = FTOCHAR(tof[0]); + to[1] = FTOCHAR(tof[1]); + to[2] = FTOCHAR(tof[2]); + to[3] = 255; + } + } + else { + for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) { + to[0] = FTOCHAR(tof[0]); + to[1] = FTOCHAR(tof[1]); + to[2] = FTOCHAR(tof[2]); + to[3] = FTOCHAR(tof[3]); + } } } else { diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c index 343211eb6b0..fd9dac1af2b 100644 --- a/source/blender/imbuf/intern/filter.c +++ b/source/blender/imbuf/intern/filter.c @@ -302,3 +302,28 @@ void IMB_filter_extend(struct ImBuf *ibuf) } } +void IMB_makemipmap(ImBuf *ibuf, int use_filter) +{ + ImBuf *hbuf= ibuf; + int minsize, curmap=0; + + minsize= ibuf->x<ibuf->y?ibuf->x:ibuf->y; + + while(minsize>10 && curmap<IB_MIPMAP_LEVELS) { + if(use_filter) { + ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect, 0); + IMB_filterN(nbuf, hbuf); + ibuf->mipmap[curmap]= IMB_onehalf(nbuf); + IMB_freeImBuf(nbuf); + } + else { + ibuf->mipmap[curmap]= IMB_onehalf(hbuf); + } + hbuf= ibuf->mipmap[curmap]; + + curmap++; + minsize= hbuf->x<hbuf->y?hbuf->x:hbuf->y; + } +} + + diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 3027f9508cf..25ca958afdb 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -343,37 +343,69 @@ short imb_save_openexr(struct ImBuf *ibuf, char *name, int flags) } } -/* ********************* Tile file support ************************************ */ +/* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */ + +/* naming rules: + - parse name from right to left + - last character is channel ID, 1 char like 'A' 'R' 'G' 'B' 'X' 'Y' 'Z' 'W' 'U' 'V' + - separated with a dot; the Pass name (like "Depth", "Color", "Diffuse" or "Combined") + - separated with a dot: the Layer name (like "Lamp1" or "Walls" or "Characters") +*/ + +static ListBase exrhandles= {NULL, NULL}; typedef struct ExrHandle { + struct ExrHandle *next, *prev; + InputFile *ifile; TiledOutputFile *tofile; OutputFile *ofile; int tilex, tiley; int width, height; - ListBase channels; + + ListBase channels; /* flattened out, ExrChannel */ + ListBase layers; /* hierarchical, pointing in end to ExrChannel */ } ExrHandle; -#define CHANMAXNAME 64 +/* flattened out channel */ typedef struct ExrChannel { struct ExrChannel *next, *prev; - char name[2*CHANMAXNAME + 1]; - int xstride, ystride; - float *rect; + + char name[EXR_TOT_MAXNAME+1]; /* full name of layer+pass */ + int xstride, ystride; /* step to next pixel, to next scanline */ + float *rect; /* first pointer to write in */ + char chan_id; /* quick lookup of channel char */ } ExrChannel; -/* not threaded! write one tiled file at a time */ + +/* hierarchical; layers -> passes -> channels[] */ +typedef struct ExrPass { + struct ExrPass *next, *prev; + char name[EXR_PASS_MAXNAME]; + int totchan; + float *rect; + struct ExrChannel *chan[EXR_PASS_MAXCHAN]; + char chan_id[EXR_PASS_MAXCHAN]; +} ExrPass; + +typedef struct ExrLayer { + struct ExrLayer *next, *prev; + char name[EXR_LAY_MAXNAME+1]; + ListBase passes; +} ExrLayer; + +/* ********************** */ + void *IMB_exr_get_handle(void) { - static ExrHandle data; - - memset(&data, sizeof(ExrHandle), 0); - - return &data; + ExrHandle *data= (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle"); + BLI_addtail(&exrhandles, data); + return data; } -/* still clumsy name handling, layers/channels can be ordered as list in list later */ -void IMB_exr_add_channel(void *handle, const char *layname, const char *channame) +/* adds flattened ExrChannels */ +/* xstride, ystride and rect can be done in set_channel too, for tile writing */ +void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect) { ExrHandle *data= (ExrHandle *)handle; ExrChannel *echan; @@ -381,14 +413,19 @@ void IMB_exr_add_channel(void *handle, const char *layname, const char *channame echan= (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel"); if(layname) { - char lay[CHANMAXNAME], chan[CHANMAXNAME]; - strncpy(lay, layname, CHANMAXNAME-1); - strncpy(chan, channame, CHANMAXNAME-1); + char lay[EXR_LAY_MAXNAME+1], pass[EXR_PASS_MAXNAME+1]; + BLI_strncpy(lay, layname, EXR_LAY_MAXNAME); + BLI_strncpy(pass, passname, EXR_PASS_MAXNAME); - sprintf(echan->name, "%s.%s", lay, chan); + sprintf(echan->name, "%s.%s", lay, pass); } else - strncpy(echan->name, channame, 2*CHANMAXNAME); + BLI_strncpy(echan->name, passname, EXR_TOT_MAXNAME-1); + + echan->xstride= xstride; + echan->ystride= ystride; + echan->rect= rect; + // printf("added channel %s\n", echan->name); BLI_addtail(&data->channels, echan); } @@ -405,7 +442,9 @@ void IMB_exr_begin_write(void *handle, char *filename, int width, int height) for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) header.channels().insert (echan->name, Channel (FLOAT)); - header.insert ("comments", StringAttribute ("Blender MultiChannel")); + header.compression() = RLE_COMPRESSION; + + header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43")); data->ofile = new OutputFile(filename, header); } @@ -426,13 +465,14 @@ void IMB_exrtile_begin_write(void *handle, char *filename, int width, int height header.setTileDescription (TileDescription (tilex, tiley, ONE_LEVEL)); header.lineOrder() = RANDOM_Y, - header.compression() = NO_COMPRESSION; + header.compression() = RLE_COMPRESSION; - header.insert ("comments", StringAttribute ("Blender MultiChannel")); + header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43")); data->tofile = new TiledOutputFile(filename, header); } +/* read from file */ int IMB_exr_begin_read(void *handle, char *filename, int *width, int *height) { ExrHandle *data= (ExrHandle *)handle; @@ -447,7 +487,7 @@ int IMB_exr_begin_read(void *handle, char *filename, int *width, int *height) const ChannelList &channels = data->ifile->header().channels(); for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) - IMB_exr_add_channel(data, NULL, i.name()); + IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL); return 1; } @@ -456,21 +496,21 @@ int IMB_exr_begin_read(void *handle, char *filename, int *width, int *height) } /* still clumsy name handling, layers/channels can be ordered as list in list later */ -void IMB_exr_set_channel(void *handle, char *layname, char *channame, int xstride, int ystride, float *rect) +void IMB_exr_set_channel(void *handle, char *layname, char *passname, int xstride, int ystride, float *rect) { ExrHandle *data= (ExrHandle *)handle; ExrChannel *echan; - char name[2*CHANMAXNAME + 1]; + char name[EXR_TOT_MAXNAME + 1]; if(layname) { - char lay[CHANMAXNAME], chan[CHANMAXNAME]; - strncpy(lay, layname, CHANMAXNAME-1); - strncpy(chan, channame, CHANMAXNAME-1); + char lay[EXR_LAY_MAXNAME+1], pass[EXR_PASS_MAXNAME+1]; + BLI_strncpy(lay, layname, EXR_LAY_MAXNAME); + BLI_strncpy(pass, passname, EXR_PASS_MAXNAME); - sprintf(name, "%s.%s", lay, chan); + sprintf(name, "%s.%s", lay, pass); } else - strncpy(name, channame, 2*CHANMAXNAME); + BLI_strncpy(name, passname, EXR_TOT_MAXNAME-1); for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) @@ -540,11 +580,38 @@ void IMB_exr_read_channels(void *handle) data->ifile->readPixels (0, data->height-1); } +void IMB_exr_multilayer_convert(void *handle, void *base, + void * (*addlayer)(void *base, char *str), + void (*addpass)(void *base, void *lay, char *str, + float *rect, int totchan, char *chan_id)) +{ + ExrHandle *data= (ExrHandle *)handle; + ExrLayer *lay; + ExrPass *pass; + + if(data->layers.first==NULL) { + printf("cannot convert multilayer, no layers in handle\n"); + return; + } + + for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) { + void *laybase= addlayer(base, lay->name); + if(laybase) { + for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) { + addpass(base, laybase, pass->name, pass->rect, pass->totchan, pass->chan_id); + pass->rect= NULL; + } + } + } +} + void IMB_exr_close(void *handle) { ExrHandle *data= (ExrHandle *)handle; ExrChannel *echan; + ExrLayer *lay; + ExrPass *pass; if(data->ifile) delete data->ifile; @@ -558,6 +625,191 @@ void IMB_exr_close(void *handle) data->tofile= NULL; BLI_freelistN(&data->channels); + + for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) { + for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) + if(pass->rect) + MEM_freeN(pass->rect); + BLI_freelistN(&lay->passes); + } + BLI_freelistN(&data->layers); + + BLI_remlink(&exrhandles, data); + MEM_freeN(data); +} + +/* ********* */ + +static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname) +{ + int plen, len= strlen(echan->name); + + if(len < 4) { + printf("multilayer read: name too short: %s\n", echan->name); + return 0; + } + if(echan->name[len-2]!='.') { + printf("multilayer read: name has no Channel: %s\n", echan->name); + return 0; + } + echan->chan_id= echan->name[len-1]; + + len-= 3; + while(len>=0) { + if(echan->name[len]=='.') + break; + len--; + } + BLI_strncpy(passname, echan->name+len+1, EXR_PASS_MAXNAME); + plen= strlen(passname); + if(plen < 3) { + printf("multilayer read: should not happen: %s\n", echan->name); + return 0; + } + passname[plen-2]= 0; + + if(len<1) + layname[0]= 0; + else { + BLI_strncpy(layname, echan->name, EXR_LAY_MAXNAME); + layname[len]= 0; + } + // printf("found lay %s pass %s chan %c\n", layname, passname, echan->chan_id); +} + +static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname) +{ + ExrLayer *lay; + + for(lay= (ExrLayer *)lb->first; lay; lay= lay->next) { + if( strcmp(lay->name, layname)==0 ) + return lay; + } + lay= (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer"); + BLI_addtail(lb, lay); + BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME); + + return lay; +} + +static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname) +{ + ExrPass *pass; + + for(pass= (ExrPass *)lb->first; pass; pass= pass->next) { + if( strcmp(pass->name, passname)==0 ) + return pass; + } + + pass= (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass"); + + if(strcmp(passname, "Combined")==0) + BLI_addhead(lb, pass); + else + BLI_addtail(lb, pass); + + BLI_strncpy(pass->name, passname, EXR_LAY_MAXNAME); + + return pass; +} + +/* creates channels, makes a hierarchy and assigns memory to channels */ +static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height) +{ + ExrLayer *lay; + ExrPass *pass; + ExrChannel *echan; + ExrHandle *data= (ExrHandle *)IMB_exr_get_handle(); + int a; + char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME]; + + data->ifile= file; + data->width= width; + data->height= height; + + const ChannelList &channels = data->ifile->header().channels(); + + for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) + IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL); + + /* now try to sort out how to assign memory to the channels */ + /* first build hierarchical layer list */ + for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) { + if( imb_exr_split_channel_name(echan, layname, passname) ) { + ExrLayer *lay= imb_exr_get_layer(&data->layers, layname); + ExrPass *pass= imb_exr_get_pass(&lay->passes, passname); + + pass->chan[pass->totchan]= echan; + pass->totchan++; + if(pass->totchan>=EXR_PASS_MAXCHAN) + break; + } + } + if(echan) { + printf("error, too many channels in one pass: %s\n", echan->name); + IMB_exr_close(data); + return NULL; + } + + /* with some heuristics, try to merge the channels in buffers */ + for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) { + for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) { + if(pass->totchan) { + pass->rect= (float *)MEM_mapallocN(width*height*pass->totchan*sizeof(float), "pass rect"); + if(pass->totchan==1) { + echan= pass->chan[0]; + echan->rect= pass->rect; + echan->xstride= 1; + echan->ystride= width; + pass->chan_id[0]= echan->chan_id; + } + else { + char lookup[256]; + + memset(lookup, 0, sizeof(lookup)); + + /* we can have RGB(A), XYZ(W), UVA */ + if(pass->totchan==3 || pass->totchan==4) { + if(pass->chan[0]->chan_id=='B' || pass->chan[1]->chan_id=='B' || pass->chan[2]->chan_id=='B') { + lookup['R']= 0; + lookup['G']= 1; + lookup['B']= 2; + lookup['A']= 3; + } + else if(pass->chan[0]->chan_id=='Y' || pass->chan[1]->chan_id=='Y' || pass->chan[2]->chan_id=='Y') { + lookup['X']= 0; + lookup['Y']= 1; + lookup['Z']= 2; + lookup['W']= 3; + } + else { + lookup['U']= 0; + lookup['V']= 1; + lookup['A']= 2; + } + for(a=0; a<pass->totchan; a++) { + echan= pass->chan[a]; + echan->rect= pass->rect + lookup[echan->chan_id]; + echan->xstride= pass->totchan; + echan->ystride= width*pass->totchan; + pass->chan_id[ lookup[echan->chan_id] ]= echan->chan_id; + } + } + else { /* unknown */ + for(a=0; a<pass->totchan; a++) { + echan= pass->chan[a]; + echan->rect= pass->rect + a; + echan->xstride= pass->totchan; + echan->ystride= width*pass->totchan; + pass->chan_id[a]= echan->chan_id; + } + } + } + } + } + } + + return data; } @@ -598,9 +850,9 @@ static int exr_has_zbuffer(InputFile *file) static int exr_is_renderresult(InputFile *file) { - const StringAttribute *comments= file->header().findTypedAttribute<StringAttribute>("comments"); + const StringAttribute *comments= file->header().findTypedAttribute<StringAttribute>("BlenderMultiChannel"); if(comments) - if(comments->value() == "Blender MultiChannel") +// if(comments->value() == "Blender MultiChannel") return 1; return 0; } @@ -615,6 +867,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags) try { Mem_IStream membuf(mem, size); + int is_multi; file = new InputFile(membuf); Box2i dw = file->header().dataWindow(); @@ -625,53 +878,70 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags) // dw.min.x, dw.min.y, dw.max.x, dw.max.y); //exr_print_filecontents(file); - int flipped= exr_is_renderresult(file); - ibuf = IMB_allocImBuf(width, height, 32, 0, 0); + is_multi= exr_is_renderresult(file); - if (ibuf) + /* do not make an ibuf when */ + if(is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) { + printf("Error: can't process EXR multilayer file\n"); + } + else { + + ibuf = IMB_allocImBuf(width, height, 32, 0, 0); ibuf->ftype = OPENEXR; if (!(flags & IB_test)) { - FrameBuffer frameBuffer; - float *first; - int xstride = sizeof(float) * 4; - int ystride = flipped ? xstride*width : - xstride*width; - - imb_addrectfloatImBuf(ibuf); - - /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */ - first= ibuf->rect_float - 4*(dw.min.x - dw.min.y*width); - /* but, since we read y-flipped (negative y stride) we move to last scanline */ - if(!flipped) first+= 4*(height-1)*width; - - frameBuffer.insert ("R", Slice (FLOAT, (char *) first, xstride, ystride)); - frameBuffer.insert ("G", Slice (FLOAT, (char *) (first+1), xstride, ystride)); - frameBuffer.insert ("B", Slice (FLOAT, (char *) (first+2), xstride, ystride)); - /* 1.0 is fill value */ - frameBuffer.insert ("A", Slice (FLOAT, (char *) (first+3), xstride, ystride, 1, 1, 1.0f)); - - if(exr_has_zbuffer(file)) + if(is_multi) /* only enters with IB_multilayer flag set */ { - float *firstz; + /* constructs channels for reading, allocates memory in channels */ + ExrHandle *handle= imb_exr_begin_read_mem(file, width, height); + if(handle) { + IMB_exr_read_channels(handle); + ibuf->userdata= handle; /* potential danger, the caller has to check for this! */ + return ibuf; + } + } + else { + FrameBuffer frameBuffer; + float *first; + int xstride = sizeof(float) * 4; + int ystride = - xstride*width; + + imb_addrectfloatImBuf(ibuf); + + /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */ + first= ibuf->rect_float - 4*(dw.min.x - dw.min.y*width); + /* but, since we read y-flipped (negative y stride) we move to last scanline */ + first+= 4*(height-1)*width; + + frameBuffer.insert ("R", Slice (FLOAT, (char *) first, xstride, ystride)); + frameBuffer.insert ("G", Slice (FLOAT, (char *) (first+1), xstride, ystride)); + frameBuffer.insert ("B", Slice (FLOAT, (char *) (first+2), xstride, ystride)); + /* 1.0 is fill value */ + frameBuffer.insert ("A", Slice (FLOAT, (char *) (first+3), xstride, ystride, 1, 1, 1.0f)); + + if(exr_has_zbuffer(file)) + { + float *firstz; + + addzbuffloatImBuf(ibuf); + firstz= ibuf->zbuf_float - (dw.min.x - dw.min.y*width); + firstz+= (height-1)*width; + frameBuffer.insert ("Z", Slice (FLOAT, (char *)firstz , sizeof(float), -width*sizeof(float))); + } - addzbuffloatImBuf(ibuf); - firstz= ibuf->zbuf_float - (dw.min.x - dw.min.y*width); - if(!flipped) firstz+= (height-1)*width; - frameBuffer.insert ("Z", Slice (FLOAT, (char *)firstz , sizeof(float), -width*sizeof(float))); + file->setFrameBuffer (frameBuffer); + file->readPixels (dw.min.y, dw.max.y); + + IMB_rect_from_float(ibuf); } - - file->setFrameBuffer (frameBuffer); - file->readPixels (dw.min.y, dw.max.y); - - IMB_rect_from_float(ibuf); } + + delete file; } - delete file; - return(ibuf); } diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h index ff71aab5f3c..feceb227e4b 100644 --- a/source/blender/imbuf/intern/openexr/openexr_multi.h +++ b/source/blender/imbuf/intern/openexr/openexr_multi.h @@ -32,28 +32,41 @@ /* experiment with more advanced exr api */ +/* Note: as for now openexr only supports 32 chars in channel names. + This api also supports max 8 channels per pass now. easy to fix! */ +#define EXR_LAY_MAXNAME 19 +#define EXR_PASS_MAXNAME 11 +#define EXR_TOT_MAXNAME 32 +#define EXR_PASS_MAXCHAN 8 + + #ifdef WITH_OPENEXR void * IMB_exr_get_handle (void); -void IMB_exr_add_channel (void *handle, const char *layname, const char *channame); +void IMB_exr_add_channel (void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect); int IMB_exr_begin_read (void *handle, char *filename, int *width, int *height); void IMB_exr_begin_write (void *handle, char *filename, int width, int height); void IMB_exrtile_begin_write (void *handle, char *filename, int width, int height, int tilex, int tiley); -void IMB_exr_set_channel (void *handle, char *layname, char *channame, int xstride, int ystride, float *rect); +void IMB_exr_set_channel (void *handle, char *layname, char *passname, int xstride, int ystride, float *rect); void IMB_exr_read_channels (void *handle); void IMB_exr_write_channels (void *handle); void IMB_exrtile_write_channels (void *handle, int partx, int party); +void IMB_exr_multilayer_convert (void *handle, void *base, + void * (*addlayer)(void *base, char *str), + void (*addpass)(void *base, void *lay, char *str, float *rect, int totchan, char *chan_id)); + void IMB_exr_close (void *handle); + #else /* ugly... but we only use it on pipeline.c, render module, now */ void * IMB_exr_get_handle (void) {return NULL;} -void IMB_exr_add_channel (void *handle, const char *layname, const char *channame) {} +void IMB_exr_add_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) {} int IMB_exr_begin_read (void *handle, char *filename, int *width, int *height) {return 0;} void IMB_exr_begin_write (void *handle, char *filename, int width, int height) {} @@ -65,6 +78,10 @@ void IMB_exr_read_channels (void *handle) {} void IMB_exr_write_channels (void *handle) {} void IMB_exrtile_write_channels (void *handle, int partx, int party) {} +void IMB_exr_multilayer_convert (void *handle, void *base, + void * (*addlayer)(void *base, char *str), + void (*addpass)(void *base, void *lay, char *str, float *rect, int totchan, char *chan_id)) {} + void IMB_exr_close (void *handle) {} #endif diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index 45ef191277b..bfa6200d23b 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -270,7 +270,7 @@ struct ImBuf *IMB_loadiffname(char *naam, int flags) { ibuf= IMB_loadifffile(file, flags); - if (ibuf == 0) { + if (ibuf == NULL) { if (read(file, buf, 4) != 4) buf[0] = 0; if ((BIG_LONG(buf[0]) & 0xfffffff0) == 0xffd8ffe0) ibuf = imb_ibJpegImageFromFilename(naam, flags); diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 41183ce91da..429fcb109ea 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -332,6 +332,8 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx, IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &width, &height); if (width == 0 || height == 0) return; + if (sbuf && sbuf->channels!=4) return; + if (dbuf->channels!=4) return; do_char = (sbuf && sbuf->rect && dbuf->rect); do_float = (sbuf && sbuf->rect_float && dbuf->rect_float); |