diff options
Diffstat (limited to 'source/blender/imbuf/intern/openexr')
-rw-r--r-- | source/blender/imbuf/intern/openexr/openexr_api.cpp | 143 | ||||
-rw-r--r-- | source/blender/imbuf/intern/openexr/openexr_multi.h | 8 |
2 files changed, 94 insertions, 57 deletions
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 3cbada812b9..3e618a483e3 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -180,7 +180,7 @@ static void openexr_header_compression(Header *header, int compression) static short imb_save_openexr_half(struct ImBuf *ibuf, char *name, int flags) { - + int channels = ibuf->channels; int width = ibuf->x; int height = ibuf->y; int write_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; // summarize @@ -194,7 +194,7 @@ static short imb_save_openexr_half(struct ImBuf *ibuf, char *name, int flags) header.channels().insert ("R", Channel (HALF)); header.channels().insert ("G", Channel (HALF)); header.channels().insert ("B", Channel (HALF)); - if (ibuf->depth==32) + if (ibuf->depth==32 && channels >= 4) header.channels().insert ("A", Channel (HALF)); if (write_zbuf) // z we do as float always header.channels().insert ("Z", Channel (FLOAT)); @@ -207,29 +207,29 @@ static short imb_save_openexr_half(struct ImBuf *ibuf, char *name, int flags) RGBAZ *to = pixels; int xstride= sizeof (RGBAZ); int ystride= xstride*width; - + /* indicate used buffers */ frameBuffer.insert ("R", Slice (HALF, (char *) &pixels[0].r, xstride, ystride)); frameBuffer.insert ("G", Slice (HALF, (char *) &pixels[0].g, xstride, ystride)); frameBuffer.insert ("B", Slice (HALF, (char *) &pixels[0].b, xstride, ystride)); - if (ibuf->depth==32) + if (ibuf->depth==32 && channels >= 4) frameBuffer.insert ("A", Slice (HALF, (char *) &pixels[0].a, xstride, ystride)); if (write_zbuf) - frameBuffer.insert ("Z", Slice (FLOAT, (char *) ibuf->zbuf_float + 4*(height-1)*width, + frameBuffer.insert ("Z", Slice (FLOAT, (char *)(ibuf->zbuf_float + (height-1)*width), sizeof(float), sizeof(float) * -width)); if(ibuf->rect_float) { float *from; for (int i = ibuf->y-1; i >= 0; i--) { - from= ibuf->rect_float + 4*i*width; + from= ibuf->rect_float + channels*i*width; for (int j = ibuf->x; j > 0; j--) { to->r = from[0]; - to->g = from[1]; - to->b = from[2]; - to->a = from[3]; + to->g = (channels >= 2)? from[1]: from[0]; + to->b = (channels >= 3)? from[2]: from[0]; + to->a = (channels >= 4)? from[3]: from[0]; to++; from += 4; } } @@ -239,14 +239,14 @@ static short imb_save_openexr_half(struct ImBuf *ibuf, char *name, int flags) for (int i = ibuf->y-1; i >= 0; i--) { - from= (unsigned char *)(ibuf->rect + i*width); + from= (unsigned char *)ibuf->rect + channels*i*width; for (int j = ibuf->x; j > 0; j--) { to->r = (float)(from[0])/255.0; - to->g = (float)(from[1])/255.0; - to->b = (float)(from[2])/255.0; - to->a = (float)(from[3])/255.0; + to->g = (float)((channels >= 2)? from[1]: from[0])/255.0; + to->b = (float)((channels >= 3)? from[2]: from[0])/255.0; + to->a = (float)((channels >= 4)? from[3]: from[0])/255.0; to++; from += 4; } } @@ -272,7 +272,7 @@ static short imb_save_openexr_half(struct ImBuf *ibuf, char *name, int flags) static short imb_save_openexr_float(struct ImBuf *ibuf, char *name, int flags) { - + int channels = ibuf->channels; int width = ibuf->x; int height = ibuf->y; int write_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; // summarize @@ -286,24 +286,29 @@ static short imb_save_openexr_float(struct ImBuf *ibuf, char *name, int flags) header.channels().insert ("R", Channel (FLOAT)); header.channels().insert ("G", Channel (FLOAT)); header.channels().insert ("B", Channel (FLOAT)); - if (ibuf->depth==32) + if (ibuf->depth==32 && channels >= 4) header.channels().insert ("A", Channel (FLOAT)); if (write_zbuf) header.channels().insert ("Z", Channel (FLOAT)); FrameBuffer frameBuffer; OutputFile *file = new OutputFile(name, header); - float *first= ibuf->rect_float + 4*(height-1)*width; - int xstride = sizeof(float) * 4; + int xstride = sizeof(float) * channels; int ystride = - xstride*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)); - if (ibuf->depth==32) - frameBuffer.insert ("A", Slice (FLOAT, (char *) (first+3), xstride, ystride)); + float *rect[4] = {NULL, NULL, NULL, NULL}; + + rect[0]= ibuf->rect_float + channels*(height-1)*width; + rect[1]= (channels >= 2)? rect[0]+1: rect[0]; + rect[2]= (channels >= 3)? rect[0]+2: rect[0]; + rect[3]= (channels >= 4)? rect[0]+3: rect[0]; + + frameBuffer.insert ("R", Slice (FLOAT, (char *)rect[0], xstride, ystride)); + frameBuffer.insert ("G", Slice (FLOAT, (char *)rect[1], xstride, ystride)); + frameBuffer.insert ("B", Slice (FLOAT, (char *)rect[2], xstride, ystride)); + if (ibuf->depth==32 && channels >= 4) + frameBuffer.insert ("A", Slice (FLOAT, (char *)rect[3], xstride, ystride)); if (write_zbuf) - frameBuffer.insert ("Z", Slice (FLOAT, (char *) ibuf->zbuf_float + 4*(height-1)*width, + frameBuffer.insert ("Z", Slice (FLOAT, (char *) (ibuf->zbuf_float + (height-1)*width), sizeof(float), sizeof(float) * -width)); file->setFrameBuffer (frameBuffer); file->writePixels (height); @@ -362,6 +367,7 @@ typedef struct ExrHandle { OutputFile *ofile; int tilex, tiley; int width, height; + int mipmap; ListBase channels; /* flattened out, ExrChannel */ ListBase layers; /* hierarchical, pointing in end to ExrChannel */ @@ -445,12 +451,12 @@ void IMB_exr_begin_write(void *handle, char *filename, int width, int height, in openexr_header_compression(&header, compress); /* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */ - header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43")); + header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43 and newer")); data->ofile = new OutputFile(filename, header); } -void IMB_exrtile_begin_write(void *handle, char *filename, int width, int height, int tilex, int tiley) +void IMB_exrtile_begin_write(void *handle, char *filename, int mipmap, int width, int height, int tilex, int tiley) { ExrHandle *data= (ExrHandle *)handle; Header header (width, height); @@ -460,11 +466,12 @@ void IMB_exrtile_begin_write(void *handle, char *filename, int width, int height data->tiley= tiley; data->width= width; data->height= height; + data->mipmap= mipmap; for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) header.channels().insert (echan->name, Channel (FLOAT)); - header.setTileDescription (TileDescription (tilex, tiley, ONE_LEVEL)); + header.setTileDescription (TileDescription (tilex, tiley, (mipmap)? MIPMAP_LEVELS: ONE_LEVEL)); header.lineOrder() = RANDOM_Y; header.compression() = RLE_COMPRESSION; @@ -478,7 +485,7 @@ int IMB_exr_begin_read(void *handle, char *filename, int *width, int *height) { ExrHandle *data= (ExrHandle *)handle; - if(BLI_exists(filename)) { + if(BLI_exists(filename) && BLI_filepathsize(filename)>32) { /* 32 is arbitrary, but zero length files crashes exr */ data->ifile = new InputFile(filename); if(data->ifile) { Box2i dw = data->ifile->header().dataWindow(); @@ -533,7 +540,7 @@ void IMB_exrtile_clear_channels(void *handle) BLI_freelistN(&data->channels); } -void IMB_exrtile_write_channels(void *handle, int partx, int party) +void IMB_exrtile_write_channels(void *handle, int partx, int party, int level) { ExrHandle *data= (ExrHandle *)handle; FrameBuffer frameBuffer; @@ -547,9 +554,14 @@ void IMB_exrtile_write_channels(void *handle, int partx, int party) } data->tofile->setFrameBuffer (frameBuffer); - // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley); - data->tofile->writeTile (partx/data->tilex, party/data->tiley); - + + try { + // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley); + data->tofile->writeTile (partx/data->tilex, party/data->tiley, level); + } + catch (const std::exception &exc) { + std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl; + } } void IMB_exr_write_channels(void *handle) @@ -615,7 +627,6 @@ void IMB_exr_multilayer_convert(void *handle, void *base, void IMB_exr_close(void *handle) { ExrHandle *data= (ExrHandle *)handle; - ExrChannel *echan; ExrLayer *lay; ExrPass *pass; @@ -778,28 +789,28 @@ static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height) /* 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; + lookup[(unsigned int)'R']= 0; + lookup[(unsigned int)'G']= 1; + lookup[(unsigned int)'B']= 2; + lookup[(unsigned int)'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; + lookup[(unsigned int)'X']= 0; + lookup[(unsigned int)'Y']= 1; + lookup[(unsigned int)'Z']= 2; + lookup[(unsigned int)'W']= 3; } else { - lookup['U']= 0; - lookup['V']= 1; - lookup['A']= 2; + lookup[(unsigned int)'U']= 0; + lookup[(unsigned int)'V']= 1; + lookup[(unsigned int)'A']= 2; } for(a=0; a<pass->totchan; a++) { echan= pass->chan[a]; - echan->rect= pass->rect + lookup[echan->chan_id]; + echan->rect= pass->rect + lookup[(unsigned int)echan->chan_id]; echan->xstride= pass->totchan; echan->ystride= width*pass->totchan; - pass->chan_id[ lookup[echan->chan_id] ]= echan->chan_id; + pass->chan_id[ (unsigned int)lookup[(unsigned int)echan->chan_id] ]= echan->chan_id; } } else { /* unknown */ @@ -831,6 +842,7 @@ typedef struct RGBA } RGBA; +/* debug only */ static void exr_print_filecontents(InputFile *file) { const ChannelList &channels = file->header().channels(); @@ -842,13 +854,33 @@ static void exr_print_filecontents(InputFile *file) } } -static int exr_has_zbuffer(InputFile *file) +/* for non-multilayer, map R G B A channel names to something that's in this file */ +static const char *exr_rgba_channelname(InputFile *file, const char *chan) { const ChannelList &channels = file->header().channels(); for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) { const Channel &channel = i.channel(); + const char *str= i.name(); + int len= strlen(str); + if(len) { + if(BLI_strcasecmp(chan, str+len-1)==0) { + return str; + } + } + } + return chan; +} + + + +static int exr_has_zbuffer(InputFile *file) +{ + const ChannelList &channels = file->header().channels(); + + for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) + { if(strcmp("Z", i.name())==0) return 1; } @@ -884,7 +916,8 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags) //printf("OpenEXR-load: image data window %d %d %d %d\n", // dw.min.x, dw.min.y, dw.max.x, dw.max.y); - // exr_print_filecontents(file); + if(0) // debug + exr_print_filecontents(file); is_multi= exr_is_renderresult(file); @@ -923,11 +956,15 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags) /* 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)); + frameBuffer.insert ( exr_rgba_channelname(file, "R"), + Slice (FLOAT, (char *) first, xstride, ystride)); + frameBuffer.insert ( exr_rgba_channelname(file, "G"), + Slice (FLOAT, (char *) (first+1), xstride, ystride)); + frameBuffer.insert ( exr_rgba_channelname(file, "B"), + Slice (FLOAT, (char *) (first+2), xstride, ystride)); + + frameBuffer.insert ( exr_rgba_channelname(file, "A"), + Slice (FLOAT, (char *) (first+3), xstride, ystride, 1, 1, 1.0f)); /* 1.0 is fill value */ if(exr_has_zbuffer(file)) { diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h index ca4f7405f44..be4d1314a80 100644 --- a/source/blender/imbuf/intern/openexr/openexr_multi.h +++ b/source/blender/imbuf/intern/openexr/openexr_multi.h @@ -46,13 +46,13 @@ void IMB_exr_add_channel (void *handle, const char *layname, const char *passn 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, int compress); -void IMB_exrtile_begin_write (void *handle, char *filename, int width, int height, int tilex, int tiley); +void IMB_exrtile_begin_write (void *handle, char *filename, int mipmap, int width, int height, int tilex, int tiley); 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_exrtile_write_channels (void *handle, int partx, int party, int level); void IMB_exrtile_clear_channels (void *handle); void IMB_exr_multilayer_convert (void *handle, void *base, @@ -71,13 +71,13 @@ void IMB_exr_add_channel (void *handle, const char *layname, const char *chann 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, int compress) {} -void IMB_exrtile_begin_write (void *handle, char *filename, int width, int height, int tilex, int tiley) {} +void IMB_exrtile_begin_write (void *handle, char *filename, int mipmap, 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_read_channels (void *handle) {} void IMB_exr_write_channels (void *handle) {} -void IMB_exrtile_write_channels (void *handle, int partx, int party) {} +void IMB_exrtile_write_channels (void *handle, int partx, int party, int level) {} void IMB_exrtile_clear_channels (void *handle) {} void IMB_exr_multilayer_convert (void *handle, void *base, |