Index: source/blender/imbuf/intern/openexr/openexr_api.cpp =================================================================== --- source/blender/imbuf/intern/openexr/openexr_api.cpp (révision 29193) +++ source/blender/imbuf/intern/openexr/openexr_api.cpp (copie de travail) @@ -30,7 +30,6 @@ #include #include - #include extern "C" @@ -147,6 +146,15 @@ extern "C" { + +static void openexr_thread_init() +{ + static int exr_thread_init= 0; + if(exr_thread_init == 0) { + Imf::staticInitialize(); + exr_thread_init= 1; + } +} int imb_is_a_openexr(unsigned char *mem) { @@ -339,6 +347,8 @@ int imb_save_openexr(struct ImBuf *ibuf, char *name, int flags) { + openexr_thread_init(); + if (flags & IB_mem) { printf("OpenEXR-save: Create EXR in memory CURRENTLY NOT SUPPORTED !\n"); @@ -452,6 +462,8 @@ ExrHandle *data= (ExrHandle *)handle; Header header (width, height); ExrChannel *echan; + + openexr_thread_init(); data->width= width; data->height= height; @@ -462,18 +474,33 @@ openexr_header_compression(&header, compress); // openexr_header_metadata(&header, ibuf); // no imbuf. cant write /* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */ + + header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.52.5")); - 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 mipmap, int width, int height, int tilex, int tiley) { ExrHandle *data= (ExrHandle *)handle; - Header header (width, height); + Header *header; ExrChannel *echan; + openexr_thread_init(); + + /* open exr specify tiles must allign with top left frame coord but blender + render with tiles alligned to the bottom left. We work around this by saving + the whole area covered by the tyles (the data window) and defining a display + window that cover only the rendered area */ + + int ntx = ceil((float)width/tilex); + int nty = ceil((float)height/tiley); + Box2i dispw(V2i( 0, 0), V2i(width-1, height-1) ); + Box2i dataw(V2i( 0 , height -(nty*tiley) ), V2i(ntx*tilex-1, height-1) ); + V2f swc(0.0f, 0.0f); + header = new Header(dispw, dataw, 1.0, swc, 1, RANDOM_Y, RLE_COMPRESSION); + + data->tilex= tilex; data->tiley= tiley; data->width= width; @@ -481,26 +508,30 @@ data->mipmap= mipmap; for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) - header.channels().insert (echan->name, Channel (FLOAT)); + header->channels().insert (echan->name, Channel (FLOAT)); - header.setTileDescription (TileDescription (tilex, tiley, (mipmap)? MIPMAP_LEVELS: ONE_LEVEL)); - header.lineOrder() = RANDOM_Y; - header.compression() = RLE_COMPRESSION; + header->setTileDescription (TileDescription (tilex, tiley, (mipmap)? MIPMAP_LEVELS: ONE_LEVEL)); + header->lineOrder() = RANDOM_Y; + header->compression() = RLE_COMPRESSION; - header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43")); - - data->tofile = new TiledOutputFile(filename, header); + header->insert ("BlenderMultiChannel", StringAttribute ("Blender V2.52.5")); + + data->tofile = new TiledOutputFile(filename, *header); + + delete header; } /* read from file */ int IMB_exr_begin_read(void *handle, char *filename, int *width, int *height) { ExrHandle *data= (ExrHandle *)handle; - + + openexr_thread_init(); + 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(); + Box2i dw = data->ifile->header().displayWindow(); data->width= *width = dw.max.x - dw.min.x + 1; data->height= *height = dw.max.y - dw.min.y + 1; @@ -554,19 +585,41 @@ ExrHandle *data= (ExrHandle *)handle; FrameBuffer frameBuffer; ExrChannel *echan; - + float *rect; + int xs, ys; + int x, y; + + openexr_thread_init(); + for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) { - float *rect= echan->rect - echan->xstride*partx - echan->ystride*party; - frameBuffer.insert (echan->name, Slice (FLOAT, (char *)rect, - echan->xstride*sizeof(float), echan->ystride*sizeof(float))); + /* coordinates for relative tile coordinates, starting from top of tile, + striding left->right, top->bottom */ + rect= echan->rect + (data->tiley-1)*echan->ystride; + xs = echan->xstride*sizeof(float); + ys = -echan->ystride*sizeof(float); + + /* for accessing the buffer with tile relative coords */ +// frameBuffer.insert (echan->name, Slice (FLOAT, (char *)rect, +// xs, ys, //xStride, yStride +// 1, 1, 0.0, // xSampling, ySampling, fillValue +// true, true) ); // xTileCoords, yTileCoords (use relative tile coords) + + /* for accesing the buffer with image global coords */ + rect= rect - echan->xstride*partx + echan->ystride*(data->height-party-data->tiley); + frameBuffer.insert (echan->name, Slice (FLOAT, (char *)rect, + xs, ys) ); //xStride, yStride + } data->tofile->setFrameBuffer (frameBuffer); + x = partx/data->tilex ; + /* flip tile grid vertically to conform to EXR coordinate system */ + y = ceil((float)data->height/data->tiley) - (party/data->tiley) -1; + try { - // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley); - data->tofile->writeTile (partx/data->tilex, party/data->tiley, level); + data->tofile->writeTile (x, y, level); } catch (const std::exception &exc) { std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl; @@ -578,11 +631,16 @@ ExrHandle *data= (ExrHandle *)handle; FrameBuffer frameBuffer; ExrChannel *echan; - + + openexr_thread_init(); + if(data->channels.first) { - for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) - frameBuffer.insert (echan->name, Slice (FLOAT, (char *)echan->rect, - echan->xstride*sizeof(float), echan->ystride*sizeof(float))); + for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) { + float *rect = echan->rect + echan->xstride*(data->height-1)*data->width; + + frameBuffer.insert (echan->name, Slice (FLOAT, (char *)rect, + echan->xstride*sizeof(float), -echan->ystride*sizeof(float))); + } data->ofile->setFrameBuffer (frameBuffer); try { @@ -602,12 +660,23 @@ ExrHandle *data= (ExrHandle *)handle; FrameBuffer frameBuffer; ExrChannel *echan; - + + openexr_thread_init(); + + /* check if exr was save with previous version of blender which flipped images */ + const StringAttribute *ta = data->ifile->header().findTypedAttribute ("BlenderMultiChannel"); + short flip = (ta && strncmp(ta->value().c_str(), "Blender V2.43", 13)==0); /* 'Blender V2.43 and newer' is covered too */ + for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) { /* no datawindow correction needed */ - if(echan->rect) - frameBuffer.insert (echan->name, Slice (FLOAT, (char *)echan->rect, + if(echan->rect) { + if(flip) + frameBuffer.insert (echan->name, Slice (FLOAT, (char *)echan->rect, echan->xstride*sizeof(float), echan->ystride*sizeof(float))); + else + frameBuffer.insert (echan->name, Slice (FLOAT, (char *)(echan->rect + echan->xstride*(data->height-1)*data->width), + echan->xstride*sizeof(float), -echan->ystride*sizeof(float))); + } else printf("warning, channel with no rect set %s\n", echan->name); } @@ -631,6 +700,8 @@ ExrLayer *lay; ExrPass *pass; + openexr_thread_init(); + if(data->layers.first==NULL) { printf("cannot convert multilayer, no layers in handle\n"); return; @@ -685,6 +756,8 @@ { int plen, len= strlen(echan->name); + openexr_thread_init(); + if(len < 4) { printf("multilayer read: name too short: %s\n", echan->name); return 0; @@ -760,6 +833,8 @@ int a; char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME]; + openexr_thread_init(); + data->ifile= file; data->width= width; data->height= height; @@ -912,6 +987,8 @@ { struct ImBuf *ibuf = NULL; InputFile *file = NULL; + + openexr_thread_init(); if (imb_is_a_openexr(mem) == 0) return(NULL);