Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/imbuf/intern')
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h1
-rw-r--r--source/blender/imbuf/intern/anim_movie.c5
-rw-r--r--source/blender/imbuf/intern/indexer.c12
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp1030
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h39
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_stub.cpp46
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c1292
-rw-r--r--source/blender/imbuf/intern/thumbs.c2
-rw-r--r--source/blender/imbuf/intern/util.c12
-rw-r--r--source/blender/imbuf/intern/writeimage.c30
10 files changed, 2231 insertions, 238 deletions
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index ed349e8f7eb..1fc43e22f68 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -194,6 +194,7 @@ struct anim {
struct anim_index *curr_idx[IMB_TC_MAX_SLOT];
char colorspace[64];
+ char suffix[64]; /* MAX_NAME - multiview */
};
#endif
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index ffdecb793aa..0bb9f0fce51 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -288,6 +288,11 @@ struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char
return(anim);
}
+void IMB_suffix_anim(struct anim *anim, const char *suffix)
+{
+ BLI_strncpy(anim->suffix, suffix, sizeof(anim->suffix));
+}
+
#ifdef WITH_AVI
static int startavi(struct anim *anim)
{
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 183159f7d6c..150ea0995ac 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -398,7 +398,7 @@ static void get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size,
}
BLI_snprintf(proxy_name, sizeof(proxy_name), name,
- (int) (proxy_fac[i] * 100), stream_suffix);
+ (int) (proxy_fac[i] * 100), stream_suffix, anim->suffix);
get_index_dir(anim, index_dir, sizeof(index_dir));
@@ -411,10 +411,10 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
char index_dir[FILE_MAXDIR];
int i = IMB_timecode_to_array_index(tc);
const char *index_names[] = {
- "record_run%s.blen_tc",
- "free_run%s.blen_tc",
- "interp_free_run%s.blen_tc",
- "record_run_no_gaps%s.blen_tc"
+ "record_run%s%s.blen_tc",
+ "free_run%s%s.blen_tc",
+ "interp_free_run%s%s.blen_tc",
+ "record_run_no_gaps%s%s.blen_tc"
};
char stream_suffix[20];
@@ -426,7 +426,7 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
BLI_snprintf(stream_suffix, 20, "_st%d", anim->streamindex);
}
- BLI_snprintf(index_name, 256, index_names[i], stream_suffix);
+ BLI_snprintf(index_name, 256, index_names[i], stream_suffix, anim->suffix);
get_index_dir(anim, index_dir, sizeof(index_dir));
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 45eae89ad9d..1262f0af95d 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -92,9 +92,32 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include <ImfStringAttribute.h>
#include <ImfStandardAttributes.h>
+/* multiview/multipart */
+#include <ImfMultiView.h>
+#include <ImfMultiPartInputFile.h>
+#include <ImfInputPart.h>
+#include <ImfOutputPart.h>
+#include <ImfMultiPartOutputFile.h>
+#include <ImfTiledOutputPart.h>
+#include <ImfPartType.h>
+#include <ImfPartHelper.h>
+
using namespace Imf;
using namespace Imath;
+extern "C"
+{
+/* prototype */
+static struct ExrPass *imb_exr_get_pass(ListBase *lb, char *passname);
+static bool exr_has_multiview(MultiPartInputFile& file);
+static bool exr_has_multipart_file(MultiPartInputFile& file);
+static int exr_has_alpha(MultiPartInputFile& file);
+static int exr_has_zbuffer(MultiPartInputFile& file);
+static void exr_printf(const char *__restrict format, ...);
+static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
+ bool *r_singlelayer, bool *r_multilayer, bool *r_multiview);
+}
+
/* Memory Input Stream */
class Mem_IStream : public Imf::IStream
@@ -340,13 +363,21 @@ static void openexr_header_metadata(Header *header, struct ImBuf *ibuf)
addXDensity(*header, ibuf->ppm[0] / 39.3700787); /* 1 meter = 39.3700787 inches */
}
-static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags)
+static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
{
const int channels = ibuf->channels;
const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
const int width = ibuf->x;
const int height = ibuf->y;
+ const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
+
+ BLI_assert((!is_multiview) || (getview && getbuffer));
+
+ std::vector <string> views;
+ size_t view_id;
try
{
@@ -355,13 +386,22 @@ static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags
openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
openexr_header_metadata(&header, ibuf);
- header.channels().insert("R", Channel(HALF));
- header.channels().insert("G", Channel(HALF));
- header.channels().insert("B", Channel(HALF));
- if (is_alpha)
- header.channels().insert("A", Channel(HALF));
- if (is_zbuf) // z we do as float always
- header.channels().insert("Z", Channel(Imf::FLOAT));
+ /* create views when possible */
+ for (view_id = 0; view_id < totviews; view_id ++)
+ views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
+
+ if (is_multiview)
+ addMultiView(header, views);
+
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ header.channels().insert(insertViewName("R", views, view_id), Channel(HALF));
+ header.channels().insert(insertViewName("G", views, view_id), Channel(HALF));
+ header.channels().insert(insertViewName("B", views, view_id), Channel(HALF));
+ if (is_alpha)
+ header.channels().insert(insertViewName("A", views, view_id), Channel(HALF));
+ if (is_zbuf) // z we do as float always
+ header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
+ }
FrameBuffer frameBuffer;
@@ -370,75 +410,91 @@ static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags
OutputFile file(file_stream, header);
/* we store first everything in half array */
- RGBAZ *pixels = new RGBAZ[height * width];
- RGBAZ *to = pixels;
+ RGBAZ *pixels = new RGBAZ[height * width * totviews];
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 (is_alpha)
- frameBuffer.insert("A", Slice(HALF, (char *) &pixels[0].a, xstride, ystride));
- if (is_zbuf)
- frameBuffer.insert("Z", Slice(Imf::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 + channels * i * width;
-
- for (int j = ibuf->x; j > 0; j--) {
- to->r = from[0];
- to->g = (channels >= 2) ? from[1] : from[0];
- to->b = (channels >= 3) ? from[2] : from[0];
- to->a = (channels >= 4) ? from[3] : 1.0f;
- to++; from += channels;
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
+ const size_t offset = view_id * width * height;
+ RGBAZ *to = pixels + offset;
+
+ /* indicate used buffers */
+ frameBuffer.insert(insertViewName("R", views, view_id), Slice(HALF, (char *) &pixels[offset].r, xstride, ystride));
+ frameBuffer.insert(insertViewName("G", views, view_id), Slice(HALF, (char *) &pixels[offset].g, xstride, ystride));
+ frameBuffer.insert(insertViewName("B", views, view_id), Slice(HALF, (char *) &pixels[offset].b, xstride, ystride));
+ if (is_alpha)
+ frameBuffer.insert(insertViewName("A", views, view_id), Slice(HALF, (char *) &pixels[offset].a, xstride, ystride));
+ if (is_zbuf)
+ frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *)(view_ibuf->zbuf_float + (height - 1) * width),
+ sizeof(float), sizeof(float) * -width));
+ if (view_ibuf->rect_float) {
+ float *from;
+
+ for (int i = view_ibuf->y - 1; i >= 0; i--) {
+ from = view_ibuf->rect_float + channels * i * width;
+
+ for (int j = view_ibuf->x; j > 0; j--) {
+ to->r = from[0];
+ to->g = (channels >= 2) ? from[1] : from[0];
+ to->b = (channels >= 3) ? from[2] : from[0];
+ to->a = (channels >= 4) ? from[3] : 1.0f;
+ to++; from += channels;
+ }
}
}
- }
- else {
- unsigned char *from;
-
- for (int i = ibuf->y - 1; i >= 0; i--) {
- from = (unsigned char *)ibuf->rect + 4 * i * width;
-
- for (int j = ibuf->x; j > 0; j--) {
- to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
- to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
- to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
- to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
- to++; from += 4;
+ else {
+ unsigned char *from;
+
+ for (int i = view_ibuf->y - 1; i >= 0; i--) {
+ from = (unsigned char *)view_ibuf->rect + 4 * i * width;
+
+ for (int j = view_ibuf->x; j > 0; j--) {
+ to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
+ to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
+ to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
+ to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
+ to++; from += 4;
+ }
}
}
+
+ if (is_multiview)
+ IMB_freeImBuf(view_ibuf);
}
-// printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
+ exr_printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
file.setFrameBuffer(frameBuffer);
file.writePixels(height);
delete[] pixels;
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
printf("OpenEXR-save: ERROR: %s\n", exc.what());
- return (0);
+ return false;
}
- return (1);
+ return true;
}
-static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flags)
+static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, const size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
{
const int channels = ibuf->channels;
const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
const int width = ibuf->x;
const int height = ibuf->y;
+ const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
+
+ BLI_assert((!is_multiview) || (getview && getbuffer));
+
+ std::vector <string> views;
+ size_t view_id;
try
{
@@ -447,13 +503,22 @@ static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flag
openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
openexr_header_metadata(&header, ibuf);
- header.channels().insert("R", Channel(Imf::FLOAT));
- header.channels().insert("G", Channel(Imf::FLOAT));
- header.channels().insert("B", Channel(Imf::FLOAT));
- if (is_alpha)
- header.channels().insert("A", Channel(Imf::FLOAT));
- if (is_zbuf)
- header.channels().insert("Z", Channel(Imf::FLOAT));
+ /* create views when possible */
+ for (view_id = 0; view_id < totviews; view_id ++)
+ views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
+
+ if (is_multiview)
+ addMultiView(header, views);
+
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ header.channels().insert(insertViewName("R", views, view_id), Channel(Imf::FLOAT));
+ header.channels().insert(insertViewName("G", views, view_id), Channel(Imf::FLOAT));
+ header.channels().insert(insertViewName("B", views, view_id), Channel(Imf::FLOAT));
+ if (is_alpha)
+ header.channels().insert(insertViewName("A", views, view_id), Channel(Imf::FLOAT));
+ if (is_zbuf)
+ header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
+ }
FrameBuffer frameBuffer;
@@ -463,37 +528,41 @@ static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flag
int xstride = sizeof(float) * channels;
int ystride = -xstride * width;
- float *rect[4] = {NULL, NULL, NULL, NULL};
- /* last scanline, stride negative */
- 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]; /* red as alpha, is this needed since alpha isn't written? */
-
- frameBuffer.insert("R", Slice(Imf::FLOAT, (char *)rect[0], xstride, ystride));
- frameBuffer.insert("G", Slice(Imf::FLOAT, (char *)rect[1], xstride, ystride));
- frameBuffer.insert("B", Slice(Imf::FLOAT, (char *)rect[2], xstride, ystride));
- if (is_alpha)
- frameBuffer.insert("A", Slice(Imf::FLOAT, (char *)rect[3], xstride, ystride));
- if (is_zbuf)
- frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *) (ibuf->zbuf_float + (height - 1) * width),
- sizeof(float), sizeof(float) * -width));
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ float *rect[4] = {NULL, NULL, NULL, NULL};
+ ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
+
+ /* last scanline, stride negative */
+ rect[0] = view_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]; /* red as alpha, is this needed since alpha isn't written? */
+
+ frameBuffer.insert(insertViewName("R", views, view_id), Slice(Imf::FLOAT, (char *)rect[0], xstride, ystride));
+ frameBuffer.insert(insertViewName("G", views, view_id), Slice(Imf::FLOAT, (char *)rect[1], xstride, ystride));
+ frameBuffer.insert(insertViewName("B", views, view_id), Slice(Imf::FLOAT, (char *)rect[2], xstride, ystride));
+ if (is_alpha)
+ frameBuffer.insert(insertViewName("A", views, view_id), Slice(Imf::FLOAT, (char *)rect[3], xstride, ystride));
+ if (is_zbuf)
+ frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *) (view_ibuf->zbuf_float + (height - 1) * width),
+ sizeof(float), sizeof(float) * -width));
+
+ if (is_multiview)
+ IMB_freeImBuf(view_ibuf);
+ }
file.setFrameBuffer(frameBuffer);
file.writePixels(height);
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
printf("OpenEXR-save: ERROR: %s\n", exc.what());
-
- return (0);
+ return false;
}
- return (1);
- // printf("OpenEXR-save: Done.\n");
+ return true;
}
-
int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
{
if (flags & IB_mem) {
@@ -504,16 +573,48 @@ int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
}
if (ibuf->ftype & OPENEXR_HALF)
- return imb_save_openexr_half(ibuf, name, flags);
+ return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
+ else {
+ /* when no float rect, we save as half (16 bits is sufficient) */
+ if (ibuf->rect_float == NULL)
+ return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
+ else
+ return (int) imb_save_openexr_float(ibuf, name, flags, 1, NULL, NULL);
+ }
+}
+
+static bool imb_save_openexr_multiview(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, const size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
+{
+ if (flags & IB_mem) {
+ printf("OpenEXR-save: Create multiview EXR in memory CURRENTLY NOT SUPPORTED !\n");
+ imb_addencodedbufferImBuf(ibuf);
+ ibuf->encodedsize = 0;
+ return false;
+ }
+
+ if (ibuf->ftype & OPENEXR_HALF)
+ return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
else {
/* when no float rect, we save as half (16 bits is sufficient) */
if (ibuf->rect_float == NULL)
- return imb_save_openexr_half(ibuf, name, flags);
+ return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
else
- return imb_save_openexr_float(ibuf, name, flags);
+ return imb_save_openexr_float(ibuf, name, flags, totviews, getview, getbuffer);
}
}
+/* Save single-layer multiview OpenEXR
+ * If we have more multiview formats in the future, the function below could be incorporated
+ * in our ImBuf write functions, meanwhile this is an OpenEXR special case only */
+bool IMB_exr_multiview_save(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
+{
+ return imb_save_openexr_multiview(ibuf, name, flags, totviews, getview, getbuffer);
+}
+
/* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */
/* naming rules:
@@ -527,18 +628,22 @@ static ListBase exrhandles = {NULL, NULL};
typedef struct ExrHandle {
struct ExrHandle *next, *prev;
+ char name[FILE_MAX];
IFileStream *ifile_stream;
- InputFile *ifile;
+ MultiPartInputFile *ifile;
OFileStream *ofile_stream;
- TiledOutputFile *tofile;
+ MultiPartOutputFile *mpofile;
OutputFile *ofile;
int tilex, tiley;
int width, height;
int mipmap;
+ StringVector *multiView; /* it needs to be a pointer due to Windows release builds of EXR2.0 segfault when opening EXR bug */
+ int parts;
+
ListBase channels; /* flattened out, ExrChannel */
ListBase layers; /* hierarchical, pointing in end to ExrChannel */
} ExrHandle;
@@ -547,10 +652,12 @@ typedef struct ExrHandle {
typedef struct ExrChannel {
struct ExrChannel *next, *prev;
- char name[EXR_TOT_MAXNAME + 1]; /* full name of layer+pass */
+ char name[EXR_TOT_MAXNAME + 1]; /* full name with everything */
+ struct MultiViewChannelName *m; /* struct to store all multipart channel info */
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 */
+ int view_id; /* quick lookup of channel view */
} ExrChannel;
@@ -562,6 +669,10 @@ typedef struct ExrPass {
float *rect;
struct ExrChannel *chan[EXR_PASS_MAXCHAN];
char chan_id[EXR_PASS_MAXCHAN];
+
+ char internal_name[EXR_PASS_MAXNAME]; /* name with no view */
+ char view[EXR_VIEW_MAXNAME];
+ int view_id;
} ExrPass;
typedef struct ExrLayer {
@@ -575,39 +686,141 @@ typedef struct ExrLayer {
void *IMB_exr_get_handle(void)
{
ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
+ data->multiView = new StringVector();
+
BLI_addtail(&exrhandles, data);
return data;
}
+void *IMB_exr_get_handle_name(const char *name)
+{
+ ExrHandle *data = (ExrHandle *) BLI_rfindstring(&exrhandles, name, offsetof(ExrHandle, name));
+
+ if (data == NULL) {
+ data = (ExrHandle *)IMB_exr_get_handle();
+ BLI_strncpy(data->name, name, strlen(name) + 1);
+ }
+ return data;
+}
+
+/* multiview functions */
+} // extern "C"
+
+extern "C"
+{
+
+void IMB_exr_add_view(void *handle, const char *name)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ data->multiView->push_back(name);
+}
+
+static int imb_exr_get_multiView_id(StringVector& views, const std::string& name)
+{
+ int count = 0;
+ for (StringVector::const_iterator i = views.begin(); count < views.size(); ++i) {
+ if (name == *i)
+ return count;
+ else
+ count ++;
+ }
+
+ /* no views or wrong name */
+ return -1;
+}
+
+static void imb_exr_get_views(MultiPartInputFile& file, StringVector& views)
+{
+ if (exr_has_multipart_file(file) == false) {
+ if (exr_has_multiview(file)) {
+ StringVector sv = multiView(file.header(0));
+ for (StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i)
+ views.push_back(*i);
+ }
+ }
+
+ else {
+ for (int p = 0; p < file.parts(); p++) {
+ std::string view = "";
+ if (file.header(p).hasView())
+ view = file.header(p).view();
+
+ if (imb_exr_get_multiView_id(views, view) == -1)
+ views.push_back(view);
+ }
+ }
+}
+
+/* Multilayer Blender files have the view name in all the passes (even the default view one) */
+static const char *imb_exr_insert_view_name(const char *passname, const char *viewname)
+{
+ if (viewname == NULL || viewname[0] == '\0')
+ return passname;
+
+ static char retstr[EXR_PASS_MAXNAME];
+ const char *end = passname + strlen(passname);
+ const char *token;
+
+ int len = IMB_exr_split_token(passname, end, &token);
+
+ if (len == 0)
+ BLI_snprintf(retstr, sizeof(retstr), "%s.%s", passname, viewname);
+ else
+ BLI_snprintf(retstr, sizeof(retstr), "%.*s%s.%s",
+ (int)(end - passname) - len, passname, viewname, token);
+
+ return retstr;
+}
+
/* 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)
+/* passname does not include view */
+void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, const char *viewname, int xstride, int ystride, float *rect)
{
ExrHandle *data = (ExrHandle *)handle;
ExrChannel *echan;
- echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel");
+ echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel");
+ echan->m = new MultiViewChannelName ();
- if (layname) {
- 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);
+ if (layname && layname[0] != '\0') {
+ echan->m->name = layname;
+ echan->m->name.append(".");
+ echan->m->name.append(passname);
+ }
+ else {
+ echan->m->name.assign(passname);
+ }
- BLI_snprintf(echan->name, sizeof(echan->name), "%s.%s", lay, pass);
+ echan->m->internal_name = echan->m->name;
+
+ echan->m->view.assign(viewname ? viewname : "");
+
+ /* quick look up */
+ echan->view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, echan->m->view));
+
+ /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
+ if (layname && layname[0] != '\0') {
+ std::string raw_name = imb_exr_insert_view_name(echan->m->name.c_str(), echan->m->view.c_str());
+ BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name));
+ }
+ else if (data->multiView->size() > 1) {
+ std::string raw_name = insertViewName(echan->m->name, *data->multiView, echan->view_id);
+ BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name));
}
else {
- BLI_strncpy(echan->name, passname, EXR_TOT_MAXNAME - 1);
+ BLI_strncpy(echan->name, echan->m->name.c_str(), sizeof(echan->name));
}
echan->xstride = xstride;
echan->ystride = ystride;
echan->rect = rect;
- // printf("added channel %s\n", echan->name);
+ exr_printf("added channel %s\n", echan->name);
BLI_addtail(&data->channels, echan);
}
-/* only used for writing temp. render results (not image files) */
+/* used for output files (from RenderResult) (single and multilayer, single and multiview) */
int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress)
{
ExrHandle *data = (ExrHandle *)handle;
@@ -617,6 +830,8 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
data->width = width;
data->height = height;
+ bool is_singlelayer, is_multilayer, is_multiview;
+
for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
header.channels().insert(echan->name, Channel(Imf::FLOAT));
@@ -624,7 +839,13 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
// 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.55.1 and newer"));
+ imb_exr_type_by_channels(header.channels(), *data->multiView, &is_singlelayer, &is_multilayer, &is_multiview);
+
+ if (is_multilayer)
+ header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
+
+ if (is_multiview)
+ addMultiView(header, *data->multiView);
/* avoid crash/abort when we don't have permission to write here */
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
@@ -632,7 +853,7 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
data->ofile_stream = new OFileStream(filename);
data->ofile = new OutputFile(*(data->ofile_stream), header);
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "IMB_exr_begin_write: ERROR: " << exc.what() << std::endl;
delete data->ofile;
@@ -645,10 +866,13 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
return (data->ofile != NULL);
}
+/* only used for writing temp. render results (not image files)
+ * (FSA and Save Buffers) */
void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
{
ExrHandle *data = (ExrHandle *)handle;
Header header(width, height);
+ std::vector<Header> headers;
ExrChannel *echan;
data->tilex = tilex;
@@ -657,26 +881,47 @@ void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int
data->height = height;
data->mipmap = mipmap;
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
- header.channels().insert(echan->name, Channel(Imf::FLOAT));
-
header.setTileDescription(TileDescription(tilex, tiley, (mipmap) ? MIPMAP_LEVELS : ONE_LEVEL));
- header.lineOrder() = RANDOM_Y;
header.compression() = RLE_COMPRESSION;
+ header.setType(TILEDIMAGE);
header.insert("BlenderMultiChannel", StringAttribute("Blender V2.43"));
+ int numparts = data->multiView->size();
+
+ /* copy header from all parts of input to our header array
+ * those temporary files have one part per view */
+ for (int i = 0; i < numparts; i++) {
+ headers.push_back (header);
+ headers[headers.size() - 1].setView((*(data->multiView))[i]);
+ headers[headers.size() - 1].setName((*(data->multiView))[i]);
+ }
+
+ exr_printf("\nIMB_exrtile_begin_write\n");
+ exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
+ exr_printf("---------------------------------------------------------------\n");
+
+ /* assign channels */
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+
+ echan->m->internal_name = echan->m->name;
+ echan->m->part_number = echan->view_id;
+
+ headers[echan->view_id].channels().insert(echan->m->internal_name, Channel(Imf::FLOAT));
+ exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
+ }
+
/* avoid crash/abort when we don't have permission to write here */
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
try {
data->ofile_stream = new OFileStream(filename);
- data->tofile = new TiledOutputFile(*(data->ofile_stream), header);
+ data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
}
catch (const std::exception &) {
- delete data->tofile;
+ delete data->mpofile;
delete data->ofile_stream;
- data->tofile = NULL;
+ data->mpofile = NULL;
data->ofile_stream = NULL;
}
}
@@ -685,12 +930,13 @@ void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int
int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height)
{
ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *echan;
if (BLI_exists(filename) && BLI_file_size(filename) > 32) { /* 32 is arbitrary, but zero length files crashes exr */
/* avoid crash/abort when we don't have permission to write here */
try {
data->ifile_stream = new IFileStream(filename);
- data->ifile = new InputFile(*(data->ifile_stream));
+ data->ifile = new MultiPartInputFile(*(data->ifile_stream));
}
catch (const std::exception &) {
delete data->ifile;
@@ -701,14 +947,24 @@ int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *heig
}
if (data->ifile) {
- Box2i dw = data->ifile->header().dataWindow();
+ Box2i dw = data->ifile->header(0).dataWindow();
data->width = *width = dw.max.x - dw.min.x + 1;
data->height = *height = dw.max.y - dw.min.y + 1;
- const ChannelList &channels = data->ifile->header().channels();
+ imb_exr_get_views(*data->ifile, *data->multiView);
+
+ std::vector<MultiViewChannelName> channels;
+ GetChannelsInMultiPartFile(*data->ifile, channels);
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
- IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
+ for (size_t i = 0; i < channels.size(); i++) {
+ IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL);
+
+ echan = (ExrChannel *)data->channels.last;
+ echan->m->name = channels[i].name;
+ echan->m->view = channels[i].view;
+ echan->m->part_number = channels[i].part_number;
+ echan->m->internal_name = channels[i].internal_name;
+ }
return 1;
}
@@ -717,6 +973,7 @@ int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *heig
}
/* still clumsy name handling, layers/channels can be ordered as list in list later */
+/* passname here is the raw channel name without the layer */
void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
{
ExrHandle *data = (ExrHandle *)handle;
@@ -741,37 +998,53 @@ void IMB_exr_set_channel(void *handle, const char *layname, const char *passname
echan->rect = rect;
}
else
- printf("IMB_exrtile_set_channel error %s\n", name);
-}
-
-void IMB_exrtile_clear_channels(void *handle)
-{
- ExrHandle *data = (ExrHandle *)handle;
- BLI_freelistN(&data->channels);
+ printf("IMB_exr_set_channel error %s\n", name);
}
-void IMB_exrtile_write_channels(void *handle, int partx, int party, int level)
+float *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *viewname)
{
ExrHandle *data = (ExrHandle *)handle;
- FrameBuffer frameBuffer;
ExrChannel *echan;
+ char name[EXR_TOT_MAXNAME + 1];
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
- float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
+ if (layname) {
+ 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);
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)rect,
- echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
+ BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
}
+ else
+ BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
- data->tofile->setFrameBuffer(frameBuffer);
-
- try {
- // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
- data->tofile->writeTile(partx / data->tilex, party / data->tiley, level);
+ /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
+ if (layname && layname[0] != '\0') {
+ std::string raw_name = imb_exr_insert_view_name(name, viewname);
+ BLI_strncpy(name, raw_name.c_str(), sizeof(name));
}
- catch (const std::exception &exc) {
- std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
+ else if (data->multiView->size() > 1) {
+ size_t view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, viewname));
+ std::string raw_name = insertViewName(name, *data->multiView, view_id);
+ BLI_strncpy(name, raw_name.c_str(), sizeof(name));
}
+
+ echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
+
+ if (echan)
+ return echan->rect;
+
+ return NULL;
+}
+
+void IMB_exr_clear_channels(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *chan;
+
+ for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next)
+ delete chan->m;
+
+ BLI_freelistN(&data->channels);
}
void IMB_exr_write_channels(void *handle)
@@ -793,7 +1066,7 @@ void IMB_exr_write_channels(void *handle)
try {
data->ofile->writePixels(data->height);
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
}
}
@@ -802,49 +1075,171 @@ void IMB_exr_write_channels(void *handle)
}
}
-void IMB_exr_read_channels(void *handle)
+/* temporary function, used for FSA and Save Buffers */
+/* called once per tile * view */
+void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname)
{
ExrHandle *data = (ExrHandle *)handle;
FrameBuffer frameBuffer;
ExrChannel *echan;
+ std::string view(viewname);
+ const size_t view_id = imb_exr_get_multiView_id(*data->multiView, view);
+
+ exr_printf("\nIMB_exrtile_write_channels(view: %s)\n", viewname);
+ exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
+ exr_printf("---------------------------------------------------------------------\n");
+
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+
+ /* eventually we can make the parts' channels to include
+ only the current view TODO */
+ if (strcmp(viewname, echan->m->view.c_str()) != 0)
+ continue;
+
+ exr_printf("%d %-6s %-22s \"%s\"\n",
+ echan->m->part_number,
+ echan->m->view.c_str(),
+ echan->m->name.c_str(),
+ echan->m->internal_name.c_str()
+ );
+
+ float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
+ frameBuffer.insert(echan->m->internal_name,
+ Slice(Imf::FLOAT,
+ (char *)rect,
+ echan->xstride * sizeof(float),
+ echan->ystride * sizeof(float)
+ )
+ );
+ }
+
+ TiledOutputPart out (*data->mpofile, view_id);
+ out.setFrameBuffer(frameBuffer);
+
+ try {
+ // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
+ out.writeTile(partx / data->tilex, party / data->tiley, level);
+ }
+ catch (const std::exception& exc) {
+ std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
+ }
+}
+
+/* called only when handle has all views */
+void IMB_exrmultiview_write_channels(void *handle, const char *viewname)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ const size_t view_id = viewname ? imb_exr_get_multiView_id(*data->multiView, viewname) : -1;
+ int numparts = (view_id == -1 ? data->parts : view_id + 1);
+ std::vector <FrameBuffer> frameBuffers(numparts);
+ std::vector <OutputPart> outputParts;
+ ExrChannel *echan;
+ int i, part;
+
+ if (data->channels.first == NULL)
+ return;
+
+ exr_printf("\nIMB_exrmultiview_write_channels()\n");
+
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ if (view_id != -1 && echan->view_id != view_id)
+ continue;
+
+ part = (view_id == -1 ? echan->m->part_number : echan->view_id);
+
+ /* last scanline, stride negative */
+ float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
+ frameBuffers[part].insert(echan->m->internal_name,
+ Slice(Imf::FLOAT,
+ (char *)rect,
+ echan->xstride * sizeof(float),
+ -echan->ystride * sizeof(float))
+ );
+ }
+
+ for (i = 0; i < numparts; i++) {
+ OutputPart out(*data->mpofile, i);
+ out.setFrameBuffer(frameBuffers[i]);
+ outputParts.push_back(out);
+ }
+
+ try {
+ for (i = 0; i < numparts; i++) {
+ if (view_id != -1 && i != view_id)
+ continue;
+
+ outputParts[i].writePixels(data->height);
+ }
+ }
+ catch (const std::exception& exc) {
+ std::cerr << "OpenEXR-write Multi Part: ERROR: " << exc.what() << std::endl;
+ }
+}
+
+void IMB_exr_read_channels(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *echan;
+ int numparts = data->ifile->parts();
+ std::vector<FrameBuffer> frameBuffers(numparts);
+ std::vector<InputPart> inputParts;
/* check if exr was saved with previous versions of blender which flipped images */
- const StringAttribute *ta = data->ifile->header().findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
+ const StringAttribute *ta = data->ifile->header(0).findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
short flip = (ta && STREQLEN(ta->value().c_str(), "Blender V2.43", 13)); /* 'previous multilayer attribute, flipped */
+ exr_printf("\nIMB_exr_read_channels\n%s %-6s %-22s \"%s\"\n---------------------------------------------------------------------\n", "p", "view", "name", "internal_name");
+
for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
if (echan->rect) {
if (flip)
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)echan->rect,
+ frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT, (char *)echan->rect,
echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
else
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width),
+ frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::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);
+ printf("warning, channel with no rect set %s\n", echan->m->internal_name.c_str());
}
- data->ifile->setFrameBuffer(frameBuffer);
+ for (int i = 0; i < numparts; i++) {
+ InputPart in (*data->ifile, i);
+ in.setFrameBuffer(frameBuffers[i]);
+ inputParts.push_back(in);
+ }
try {
- data->ifile->readPixels(0, data->height - 1);
+ for (int i = 0; i < numparts; i++) {
+ Header header = inputParts[i].header();
+ exr_printf("readPixels:readPixels[%d]: min.y: %d, max.y: %d\n", i, header.dataWindow().min.y, header.dataWindow().max.y);
+ inputParts[i].readPixels(header.dataWindow().min.y, header.dataWindow().max.y);
+ inputParts[i].readPixels(0, data->height - 1);
+ }
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
}
}
void IMB_exr_multilayer_convert(void *handle, void *base,
+ void * (*addview)(void *base, const char *str),
void * (*addlayer)(void *base, const char *str),
void (*addpass)(void *base, void *lay, const char *str,
- float *rect, int totchan, const char *chan_id))
+ float *rect, int totchan, const char *chan_id,
+ const char *view))
{
ExrHandle *data = (ExrHandle *)handle;
ExrLayer *lay;
ExrPass *pass;
+ /* add views to RenderResult */
+ for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
+ addview(base, (*i).c_str());
+ }
+
if (BLI_listbase_is_empty(&data->layers)) {
printf("cannot convert multilayer, no layers in handle\n");
return;
@@ -854,32 +1249,98 @@ void IMB_exr_multilayer_convert(void *handle, void *base,
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);
+ addpass(base, laybase, pass->internal_name, pass->rect, pass->totchan, pass->chan_id, pass->view);
pass->rect = NULL;
}
}
}
}
+void IMB_exr_multiview_convert(void *handle, void *base,
+ void (*addview)(void *base, const char *str),
+ void (*addbuffer)(void *base, const char *str, ImBuf *ibuf, const int frame),
+ const int frame)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ MultiPartInputFile *file = data->ifile;
+ ExrLayer *lay;
+ ExrPass *pass;
+ ImBuf *ibuf = NULL;
+ const int is_alpha = exr_has_alpha(*file);
+ Box2i dw = file->header(0).dataWindow();
+ const size_t width = dw.max.x - dw.min.x + 1;
+ const size_t height = dw.max.y - dw.min.y + 1;
+ const bool is_depth = exr_has_zbuffer(*file);
+
+ /* add views to RenderResult */
+ for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
+ addview(base, (*i).c_str());
+ }
+
+ if (BLI_listbase_is_empty(&data->layers)) {
+ printf("cannot convert multiviews, no views in handle\n");
+ return;
+ }
+
+ /* there is one float/pass per layer (layer here is a view) */
+ BLI_assert(BLI_listbase_count_ex(&data->layers, 2) == 1);
+ lay = (ExrLayer *)data->layers.first;
+ for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
+ if (STREQ(pass->chan_id, "RGB") || STREQ(pass->chan_id, "RGBA")) {
+ ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, IB_rectfloat);
+
+ if (!ibuf) {
+ printf("error creating multiview buffer\n");
+ return;
+ }
+
+ IMB_buffer_float_from_float(
+ ibuf->rect_float, pass->rect, pass->totchan,
+ IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
+ ibuf->x, ibuf->y, ibuf->x, ibuf->x);
+
+ if (hasXDensity(file->header(0))) {
+ ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
+ ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
+ }
+
+ if (is_depth) {
+ ExrPass *zpass;
+ for (zpass = (ExrPass *)lay->passes.first; zpass; zpass = zpass->next) {
+ if (STREQ(zpass->chan_id, "Z") && STREQ(zpass->view, pass->view)) {
+ addzbuffloatImBuf(ibuf);
+ memcpy(ibuf->zbuf_float, zpass->rect, sizeof(float) * ibuf->x * ibuf->y);
+ }
+ }
+ }
+
+ addbuffer(base, pass->view, ibuf, frame);
+ }
+ }
+}
void IMB_exr_close(void *handle)
{
ExrHandle *data = (ExrHandle *)handle;
ExrLayer *lay;
ExrPass *pass;
+ ExrChannel *chan;
delete data->ifile;
delete data->ifile_stream;
delete data->ofile;
- delete data->tofile;
+ delete data->mpofile;
delete data->ofile_stream;
data->ifile = NULL;
data->ifile_stream = NULL;
data->ofile = NULL;
- data->tofile = NULL;
+ data->mpofile = NULL;
data->ofile_stream = NULL;
+ for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next) {
+ delete chan->m;
+ }
BLI_freelistN(&data->channels);
for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
@@ -897,7 +1358,7 @@ void IMB_exr_close(void *handle)
/* ********* */
/* get a substring from the end of the name, separated by '.' */
-static int imb_exr_split_token(const char *str, const char *end, const char **token)
+int IMB_exr_split_token(const char *str, const char *end, const char **token)
{
ptrdiff_t maxlen = end - str;
int len = 0;
@@ -911,7 +1372,7 @@ static int imb_exr_split_token(const char *str, const char *end, const char **to
static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
{
- const char *name = echan->name;
+ const char *name = echan->m->name.c_str();
const char *end = name + strlen(name);
const char *token;
char tokenbuf[EXR_TOT_MAXNAME];
@@ -933,7 +1394,7 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
}
/* last token is single character channel identifier */
- len = imb_exr_split_token(name, end, &token);
+ len = IMB_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
return 0;
@@ -971,7 +1432,7 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
end -= len + 1; /* +1 to skip '.' separator */
/* second token is pass name */
- len = imb_exr_split_token(name, end, &token);
+ len = IMB_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
return 0;
@@ -1020,7 +1481,7 @@ static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
}
/* creates channels, makes a hierarchy and assigns memory to channels */
-static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
+static ExrHandle *imb_exr_begin_read_mem(MultiPartInputFile& file, int width, int height)
{
ExrLayer *lay;
ExrPass *pass;
@@ -1029,30 +1490,57 @@ static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
int a;
char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
- data->ifile = file;
+ data->ifile = &file;
data->width = width;
data->height = height;
- const ChannelList &channels = data->ifile->header().channels();
+ std::vector<MultiViewChannelName> channels;
+ GetChannelsInMultiPartFile(*data->ifile, channels);
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
- IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
+ data->multiView = new StringVector();
+ imb_exr_get_views(*data->ifile, *data->multiView);
+
+ for (size_t i = 0; i < channels.size(); i++) {
+ IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL);
+
+ echan = (ExrChannel *)data->channels.last;
+ echan->m->name = channels[i].name;
+ echan->m->view = channels[i].view;
+ echan->m->part_number = channels[i].part_number;
+ echan->m->internal_name = channels[i].internal_name;
+ }
/* 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) ) {
+ if (imb_exr_split_channel_name(echan, layname, passname)) {
+
+ const char *view = echan->m->view.c_str();
+ char internal_name[EXR_PASS_MAXNAME];
+
+ BLI_strncpy(internal_name, passname, EXR_PASS_MAXNAME);
+
+ if (view[0] != '\0') {
+ char tmp_pass[EXR_PASS_MAXNAME];
+ BLI_snprintf(tmp_pass, sizeof(tmp_pass), "%s.%s", passname, view);
+ BLI_strncpy(passname, tmp_pass, sizeof(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++;
+ pass->view_id = echan->view_id;
+ BLI_strncpy(pass->view, view, sizeof(pass->view));
+ BLI_strncpy(pass->internal_name, internal_name, EXR_PASS_MAXNAME);
+
if (pass->totchan >= EXR_PASS_MAXCHAN)
break;
}
}
if (echan) {
- printf("error, too many channels in one pass: %s\n", echan->name);
+ printf("error, too many channels in one pass: %s\n", echan->m->name.c_str());
IMB_exr_close(data);
return NULL;
}
@@ -1122,20 +1610,52 @@ static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
/* ********************************************************* */
/* debug only */
-static void exr_print_filecontents(InputFile *file)
+static void exr_printf(const char *fmt, ...)
{
- const ChannelList &channels = file->header().channels();
+#if 0
+ char output[1024];
+ va_list args;
+ va_start(args, fmt);
+ std::vsprintf(output, fmt, args);
+ va_end(args);
+ printf("%s", output);
+#else
+ (void)fmt;
+#endif
+}
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
- const Channel &channel = i.channel();
- printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
+static void exr_print_filecontents(MultiPartInputFile& file)
+{
+ int numparts = file.parts();
+ if (numparts == 1 && hasMultiView(file.header(0))) {
+ const StringVector views = multiView(file.header(0));
+ printf("OpenEXR-load: MultiView file\n");
+ printf("OpenEXR-load: Default view: %s\n", defaultViewName(views).c_str());
+ for (StringVector::const_iterator i = views.begin(); i != views.end(); ++i) {
+ printf("OpenEXR-load: Found view %s\n", (*i).c_str());
+ }
+ }
+ else if (numparts > 1) {
+ printf("OpenEXR-load: MultiPart file\n");
+ for (int i = 0; i < numparts; i++) {
+ if (file.header(i).hasView())
+ printf("OpenEXR-load: Part %d: view = \"%s\"\n", i, file.header(i).view().c_str());
+ }
+ }
+
+ for (int j = 0; j < numparts; j++) {
+ const ChannelList& channels = file.header(j).channels();
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
+ const Channel& channel = i.channel();
+ printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
+ }
}
}
/* 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)
+static const char *exr_rgba_channelname(MultiPartInputFile& file, const char *chan)
{
- const ChannelList &channels = file->header().channels();
+ const ChannelList& channels = file.header(0).channels();
for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
/* const Channel &channel = i.channel(); */ /* Not used yet */
@@ -1150,48 +1670,48 @@ static const char *exr_rgba_channelname(InputFile *file, const char *chan)
return chan;
}
-static bool exr_has_rgb(InputFile *file)
+static bool exr_has_rgb(MultiPartInputFile& file)
{
- return file->header().channels().findChannel("R") != NULL &&
- file->header().channels().findChannel("G") != NULL &&
- file->header().channels().findChannel("B") != NULL;
+ return file.header(0).channels().findChannel("R") != NULL &&
+ file.header(0).channels().findChannel("G") != NULL &&
+ file.header(0).channels().findChannel("B") != NULL;
}
-static bool exr_has_luma(InputFile *file)
+static bool exr_has_luma(MultiPartInputFile& file)
{
/* Y channel is the luma and should always present fir luma space images,
* optionally it could be also channels for chromas called BY and RY.
*/
- return file->header().channels().findChannel("Y") != NULL;
+ return file.header(0).channels().findChannel("Y") != NULL;
}
-static bool exr_has_chroma(InputFile *file)
+static bool exr_has_chroma(MultiPartInputFile& file)
{
- return file->header().channels().findChannel("BY") != NULL &&
- file->header().channels().findChannel("RY") != NULL;
+ return file.header(0).channels().findChannel("BY") != NULL &&
+ file.header(0).channels().findChannel("RY") != NULL;
}
-static int exr_has_zbuffer(InputFile *file)
+static int exr_has_zbuffer(MultiPartInputFile& file)
{
- return !(file->header().channels().findChannel("Z") == NULL);
+ return !(file.header(0).channels().findChannel("Z") == NULL);
}
-static int exr_has_alpha(InputFile *file)
+static int exr_has_alpha(MultiPartInputFile& file)
{
- return !(file->header().channels().findChannel("A") == NULL);
+ return !(file.header(0).channels().findChannel("A") == NULL);
}
-static bool exr_is_multilayer(InputFile *file)
+static bool imb_exr_is_multilayer_file(MultiPartInputFile& file)
{
- const StringAttribute *comments = file->header().findTypedAttribute<StringAttribute>("BlenderMultiChannel");
- const ChannelList &channels = file->header().channels();
+ const StringAttribute *comments = file.header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
+ const ChannelList& channels = file.header(0).channels();
std::set <std::string> layerNames;
/* will not include empty layer names */
channels.layers(layerNames);
if (comments || layerNames.size() > 1)
- return 1;
+ return true;
if (layerNames.size()) {
/* if layerNames is not empty, it means at least one layer is non-empty,
@@ -1206,17 +1726,122 @@ static bool exr_is_multilayer(InputFile *file)
size_t pos = layerName.rfind ('.');
if (pos == std::string::npos)
- return 1;
+ return true;
}
}
- return 0;
+ return false;
+}
+
+static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
+ bool *r_singlelayer, bool *r_multilayer, bool *r_multiview)
+{
+ std::set <std::string> layerNames;
+
+ *r_singlelayer = true;
+ *r_multilayer = *r_multiview = false;
+
+ /* will not include empty layer names */
+ channels.layers(layerNames);
+
+ if (views.size() && views[0] != "")
+ *r_multiview = true;
+
+ if (layerNames.size()) {
+ /* if layerNames is not empty, it means at least one layer is non-empty,
+ * but it also could be layers without names in the file and such case
+ * shall be considered a multilayer exr
+ *
+ * that's what we do here: test whether there're empty layer names together
+ * with non-empty ones in the file
+ */
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++)
+ for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
+ /* see if any layername differs from a viewname */
+ if (imb_exr_get_multiView_id(views, *i) == -1) {
+ std::string layerName = *i;
+ size_t pos = layerName.rfind ('.');
+
+ if (pos != std::string::npos) {
+ *r_multilayer = true;
+ *r_singlelayer = false;
+ return;
+ }
+ }
+ }
+ else {
+ *r_singlelayer = true;
+ *r_multilayer = false;
+ *r_multiview = false;
+ }
+
+ BLI_assert(r_singlelayer != r_multilayer);
+}
+
+bool IMB_exr_has_singlelayer_multiview(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ MultiPartInputFile *file = data->ifile;
+ std::set <std::string> layerNames;
+ const ChannelList& channels = file->header(0).channels();
+ const StringAttribute *comments;
+
+ if (exr_has_multiview(*file) == false)
+ return false;
+
+ comments = file->header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
+
+ if (comments)
+ return false;
+
+ /* will not include empty layer names */
+ channels.layers(layerNames);
+
+ /* returns false if any layer differs from views list */
+ if (layerNames.size())
+ for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
+ if (imb_exr_get_multiView_id(*data->multiView, *i) == -1)
+ return false;
+
+ return true;
+}
+
+bool IMB_exr_has_multilayer(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ return imb_exr_is_multilayer_file(*data->ifile);
+}
+
+static bool exr_has_multiview(MultiPartInputFile& file)
+{
+ return hasMultiView(file.header(0));
+}
+
+static bool exr_has_multipart_file(MultiPartInputFile& file)
+{
+ return file.parts() > 1;
+}
+
+/* it returns true if the file is multilayer or multiview */
+static bool imb_exr_is_multi(MultiPartInputFile& file)
+{
+ /* multipart files are treated as multilayer in blender - even if they are single layer openexr with multiview */
+ if (exr_has_multipart_file(file))
+ return true;
+
+ if (exr_has_multiview(file))
+ return true;
+
+ if (imb_exr_is_multilayer_file(file))
+ return true;
+
+ return false;
}
struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
struct ImBuf *ibuf = NULL;
- InputFile *file = NULL;
+ MultiPartInputFile *file = NULL;
if (imb_is_a_openexr(mem) == 0) return(NULL);
@@ -1226,9 +1851,9 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
{
Mem_IStream *membuf = new Mem_IStream(mem, size);
bool is_multi;
- file = new InputFile(*membuf);
+ file = new MultiPartInputFile(*membuf);
- Box2i dw = file->header().dataWindow();
+ Box2i dw = file->header(0).dataWindow();
const int width = dw.max.x - dw.min.x + 1;
const int height = dw.max.y - dw.min.y + 1;
@@ -1236,38 +1861,38 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
// dw.min.x, dw.min.y, dw.max.x, dw.max.y);
if (0) // debug
- exr_print_filecontents(file);
+ exr_print_filecontents(*file);
- is_multi = exr_is_multilayer(file);
+ is_multi = imb_exr_is_multi(*file);
/* 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 {
- const int is_alpha = exr_has_alpha(file);
+ const int is_alpha = exr_has_alpha(*file);
ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, 0);
- if (hasXDensity(file->header())) {
- ibuf->ppm[0] = xDensity(file->header()) * 39.3700787f;
- ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header().pixelAspectRatio();
+ if (hasXDensity(file->header(0))) {
+ ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
+ ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
}
ibuf->ftype = OPENEXR;
if (!(flags & IB_test)) {
- if (is_multi) { /* only enters with IB_multilayer flag set */
+ if (is_multi && ((flags & IB_thumbnail) == 0)) { /* only enters with IB_multilayer flag set */
/* constructs channels for reading, allocates memory in channels */
- ExrHandle *handle = imb_exr_begin_read_mem(file, width, height);
+ 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! */
}
}
else {
- const bool has_rgb = exr_has_rgb(file);
- const bool has_luma = exr_has_luma(file);
+ const bool has_rgb = exr_has_rgb(*file);
+ const bool has_luma = exr_has_luma(*file);
FrameBuffer frameBuffer;
float *first;
int xstride = sizeof(float) * 4;
@@ -1281,27 +1906,27 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
first += 4 * (height - 1) * width;
if (has_rgb) {
- frameBuffer.insert(exr_rgba_channelname(file, "R"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "R"),
Slice(Imf::FLOAT, (char *) first, xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "G"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "G"),
Slice(Imf::FLOAT, (char *) (first + 1), xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "B"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "B"),
Slice(Imf::FLOAT, (char *) (first + 2), xstride, ystride));
}
else if (has_luma) {
- frameBuffer.insert(exr_rgba_channelname(file, "Y"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "Y"),
Slice(Imf::FLOAT, (char *) first, xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "BY"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "BY"),
Slice(Imf::FLOAT, (char *) (first + 1), xstride, ystride, 1, 1, 0.5f));
- frameBuffer.insert(exr_rgba_channelname(file, "RY"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "RY"),
Slice(Imf::FLOAT, (char *) (first + 2), xstride, ystride, 1, 1, 0.5f));
}
/* 1.0 is fill value, this still needs to be assigned even when (is_alpha == 0) */
- frameBuffer.insert(exr_rgba_channelname(file, "A"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "A"),
Slice(Imf::FLOAT, (char *) (first + 3), xstride, ystride, 1, 1, 1.0f));
- if (exr_has_zbuffer(file)) {
+ if (exr_has_zbuffer(*file)) {
float *firstz;
addzbuffloatImBuf(ibuf);
@@ -1310,8 +1935,9 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *)firstz, sizeof(float), -width * sizeof(float)));
}
- file->setFrameBuffer(frameBuffer);
- file->readPixels(dw.min.y, dw.max.y);
+ InputPart in (*file, 0);
+ in.setFrameBuffer(frameBuffer);
+ in.readPixels(dw.min.y, dw.max.y);
// XXX, ImBuf has no nice way to deal with this.
// ideally IM_rect would be used when the caller wants a rect BUT
@@ -1325,7 +1951,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
if (!has_rgb && has_luma) {
size_t a;
- if (exr_has_chroma(file)) {
+ if (exr_has_chroma(*file)) {
for (a = 0; a < (size_t) ibuf->x * ibuf->y; ++a) {
float *color = ibuf->rect_float + a * 4;
ycc_to_rgb(color[0] * 255.0f, color[1] * 255.0f, color[2] * 255.0f,
@@ -1351,7 +1977,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
}
return(ibuf);
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
std::cerr << exc.what() << std::endl;
if (ibuf) IMB_freeImBuf(ibuf);
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
index 376d2401b1c..45ab0ed37c7 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -39,8 +39,9 @@
/* This api also supports max 8 channels per pass now. easy to fix! */
#define EXR_LAY_MAXNAME 64
#define EXR_PASS_MAXNAME 64
+#define EXR_VIEW_MAXNAME 64
#define EXR_TOT_MAXNAME 64
-#define EXR_PASS_MAXCHAN 8
+#define EXR_PASS_MAXCHAN 24
#ifdef __cplusplus
@@ -48,25 +49,49 @@ extern "C" {
#endif
void *IMB_exr_get_handle(void);
-void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect);
+void *IMB_exr_get_handle_name(const char *name);
+void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, const char *view, int xstride, int ystride, float *rect);
int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height);
int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress);
void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley);
void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect);
+float *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *view);
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, int level);
-void IMB_exrtile_clear_channels(void *handle);
+void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname);
+void IMB_exrmultiview_write_channels(void *handle, const char *viewname);
+void IMB_exr_clear_channels(void *handle);
-void IMB_exr_multilayer_convert(void *handle, void *base,
- void * (*addlayer)(void *base, const char *str),
- void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id));
+void IMB_exr_multilayer_convert(
+ void *handle, void *base,
+ void * (*addview)(void *base, const char *str),
+ void * (*addlayer)(void *base, const char *str),
+ void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan,
+ const char *chan_id, const char *view));
+
+void IMB_exr_multiview_convert(
+ void *handle, void *base,
+ void (*addview)(void *base, const char *str),
+ void (*addbuffer)(void *base, const char *str, struct ImBuf *ibuf, const int frame),
+ const int frame);
+
+bool IMB_exr_multiview_save(
+ struct ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ struct ImBuf * (*getbuffer)(void *base, const size_t view_id));
void IMB_exr_close(void *handle);
+void IMB_exr_add_view(void *handle, const char *name);
+
+int IMB_exr_split_token(const char *str, const char *end, const char **token);
+
+bool IMB_exr_has_multilayer(void *handle);
+bool IMB_exr_has_singlelayer_multiview(void *handle);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
index 21fa878c08a..c326efd2427 100644
--- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
@@ -31,27 +31,55 @@
#include "openexr_api.h"
#include "openexr_multi.h"
-
+#include "BLI_utildefines.h" /* UNUSED_VARS */
void *IMB_exr_get_handle (void) {return NULL;}
-void IMB_exr_add_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; }
+void *IMB_exr_get_handle_name (const char *name) {(void)name; return NULL;}
+void IMB_exr_add_channel (void *handle, const char *layname, const char *passname, const char *view, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)passname; (void)xstride; (void)ystride; (void)rect; }
int IMB_exr_begin_read (void *handle, const char *filename, int *width, int *height) { (void)handle; (void)filename; (void)width; (void)height; return 0;}
int IMB_exr_begin_write (void *handle, const char *filename, int width, int height, int compress) { (void)handle; (void)filename; (void)width; (void)height; (void)compress; return 0;}
void IMB_exrtile_begin_write (void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley) { (void)handle; (void)filename; (void)mipmap; (void)width; (void)height; (void)tilex; (void)tiley; }
-void IMB_exr_set_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; }
+void IMB_exr_set_channel (void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)passname; (void)xstride; (void)ystride; (void)rect; }
+float *IMB_exr_channel_rect (void *handle, const char *layname, const char *passname, const char *view) { (void)handle; (void)layname; (void)passname; (void)view; return NULL; }
void IMB_exr_read_channels (void *handle) { (void)handle; }
void IMB_exr_write_channels (void *handle) { (void)handle; }
-void IMB_exrtile_write_channels (void *handle, int partx, int party, int level) { (void)handle; (void)partx; (void)party; (void)level; }
-void IMB_exrtile_clear_channels (void *handle) { (void)handle; }
+void IMB_exrtile_write_channels (void *handle, int partx, int party, int level, const char *viewname) { UNUSED_VARS(handle, partx, party, level, viewname); }
+void IMB_exrmultiview_write_channels(void *handle, const char *viewname) { UNUSED_VARS(handle, viewname); }
+void IMB_exr_clear_channels (void *handle) { (void)handle; }
+
+void IMB_exr_multilayer_convert(
+ void *handle, void *base,
+ void * (*addview)(void *base, const char *str),
+ void * (*addlayer)(void *base, const char *str),
+ void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan,
+ const char *chan_id, const char *view))
+{
+ UNUSED_VARS(handle, base, addview, addlayer, addpass);
+}
-void IMB_exr_multilayer_convert (void *handle, void *base,
- void * (*addlayer)(void *base, const char *str),
- void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id))
+void IMB_exr_multiview_convert(
+ void *handle, void *base,
+ void (*addview)(void *base, const char *str),
+ void (*addbuffer)(void *base, const char *str, struct ImBuf *ibuf, const int frame), const int frame)
{
- (void)handle; (void)base; (void)addlayer; (void)addpass;
+ UNUSED_VARS(handle, base, addview, addbuffer, frame);
+}
+
+bool IMB_exr_multiview_save(
+ struct ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ struct ImBuf * (*getbuffer)(void *base, const size_t view_id))
+{
+ UNUSED_VARS(ibuf, name, flags, totviews, getview, getbuffer);
+ return false;
}
void IMB_exr_close (void *handle) { (void)handle; }
+
+void IMB_exr_add_view(void *handle, const char *name) { UNUSED_VARS(handle, name); }
+int IMB_exr_split_token(const char *str, const char *end, const char **token) { UNUSED_VARS(str, end, token); return 1; }
+bool IMB_exr_has_multilayer(void *handle) { UNUSED_VARS(handle); return false; }
+bool IMB_exr_has_singlelayer_multiview(void *handle) { UNUSED_VARS(handle); return false; }
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
new file mode 100644
index 00000000000..cf9c6b388ff
--- /dev/null
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -0,0 +1,1292 @@
+/*
+ * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/imbuf/intern/stereoimbuf.c
+ * \ingroup imbuf
+ */
+
+#include <stddef.h>
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_filetype.h"
+#include "IMB_metadata.h"
+#include "IMB_colormanagement_intern.h"
+
+#include "imbuf.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "BLI_math.h"
+
+#include "DNA_userdef_types.h"
+#include "DNA_scene_types.h"
+
+/* prototypes */
+struct Stereo3DData;
+static void imb_stereo3d_write_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d);
+static void imb_stereo3d_read_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d);
+
+typedef struct Stereo3DData {
+ struct { float *left, *right, *stereo; } rectf;
+ struct { uchar *left, *right, *stereo; } rect;
+ size_t x, y, channels;
+ bool is_float;
+} Stereo3DData;
+
+static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ int anaglyph_encoding[3][3] = {
+ {0, 1, 1},
+ {1, 0, 1},
+ {0, 0, 1},
+ };
+
+ int r, g, b;
+
+ r = anaglyph_encoding[mode][0];
+ g = anaglyph_encoding[mode][1];
+ b = anaglyph_encoding[mode][2];
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 4;
+ float *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ to[3] = MAX2(from[0][2], from[0][2]);
+ }
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ to[3] = MAX2(from[0][2], from[0][2]);
+ }
+ }
+ }
+ }
+}
+
+static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterlaceType mode, const bool swap)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+ memcpy(to, from[i], sizeof(float) * channels * stride_from);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y;
+ const float *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[i][0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ const float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3(to, from[i]);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4(to, from[i]);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y;
+ const float *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[j][0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ const float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3(to, from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 4;
+ const float *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4(to, from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+ memcpy(to, from[i], sizeof(uchar) * channels * stride_from);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y;
+ const uchar *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[i][0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3_char((char *)to, (char *)from[i]);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4_char((char *)to, (char *)from[i]);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y;
+ const uchar *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[j][0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3_char((char *)to, (char *)from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4_char((char *)to, (char *)from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+/* stereo3d output (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_write_sidebyside(Stereo3DData *s3d, const bool crosseyed)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width * 2;
+
+ const int l = (int) crosseyed;
+ const int r = !l;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[l], sizeof(float) * channels * stride_from);
+ memcpy(to + channels * stride_from, from[r], sizeof(float) * channels * stride_from);
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[l], sizeof(uchar) * channels * stride_from);
+ memcpy(to + channels * stride_from, from[r], sizeof(uchar) * channels * stride_from);
+ }
+ }
+}
+
+/* stereo3d output (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_write_topbottom(Stereo3DData *s3d)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[1], sizeof(float) * channels * stride_from);
+ memcpy(to + channels * height * stride_from, from[0], sizeof(float) * channels * stride_from);
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[1], sizeof(uchar) * channels * stride_from);
+ memcpy(to + channels * height * stride_from, from[0], sizeof(uchar) * channels * stride_from);
+ }
+ }
+}
+
+/**************************** dimension utils ****************************************/
+
+void IMB_stereo3d_write_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height)
+{
+ switch (mode) {
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ *r_width = is_squeezed ? width : width * 2;
+ *r_height = height;
+ break;
+ }
+ case S3D_DISPLAY_TOPBOTTOM:
+ {
+ *r_width = width;
+ *r_height = is_squeezed ? height : height * 2;
+ break;
+ }
+ case S3D_DISPLAY_ANAGLYPH:
+ case S3D_DISPLAY_INTERLACE:
+ default:
+ {
+ *r_width = width;
+ *r_height = height;
+ break;
+ }
+ }
+}
+
+void IMB_stereo3d_read_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height)
+{
+ switch (mode) {
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ *r_width = is_squeezed ? width / 2 : width;
+ *r_height = height;
+ break;
+ }
+ case S3D_DISPLAY_TOPBOTTOM:
+ {
+ *r_width = width;
+ *r_height = is_squeezed ? height / 2 : height;
+ break;
+ }
+ case S3D_DISPLAY_ANAGLYPH:
+ case S3D_DISPLAY_INTERLACE:
+ default:
+ {
+ *r_width = width;
+ *r_height = height;
+ break;
+ }
+ }
+}
+
+/**************************** un/squeeze frame ****************************************/
+
+static void imb_stereo3d_squeeze_ImBuf(ImBuf *ibuf, Stereo3dFormat *s3d, const size_t x, const size_t y)
+{
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+}
+
+static void imb_stereo3d_unsqueeze_ImBuf(ImBuf *ibuf, Stereo3dFormat *s3d, const size_t x, const size_t y)
+{
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+}
+
+static void imb_stereo3d_squeeze_rectf(float *rectf, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
+{
+ ImBuf *ibuf;
+ size_t width, height;
+
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ /* creates temporary imbuf to store the rectf */
+ IMB_stereo3d_write_dimensions(s3d->display_mode, false, x, y, &width, &height);
+ ibuf = IMB_allocImBuf(width, height, channels, IB_rectfloat);
+
+ IMB_buffer_float_from_float(
+ ibuf->rect_float, rectf, channels,
+ IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
+ width, height, width, width);
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+ rectf = MEM_dupallocN(ibuf->rect_float);
+ IMB_freeImBuf(ibuf);
+}
+
+static void imb_stereo3d_squeeze_rect(int *rect, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
+{
+ ImBuf *ibuf;
+ size_t width, height;
+
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ /* creates temporary imbuf to store the rectf */
+ IMB_stereo3d_write_dimensions(s3d->display_mode, false, x, y, &width, &height);
+ ibuf = IMB_allocImBuf(width, height, channels, IB_rect);
+
+ IMB_buffer_byte_from_byte(
+ (unsigned char *)ibuf->rect, (unsigned char *)rect,
+ IB_PROFILE_SRGB, IB_PROFILE_SRGB, false,
+ width, height, width, width);
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+ rect = MEM_dupallocN(ibuf->rect);
+ IMB_freeImBuf(ibuf);
+}
+
+
+/*************************** preparing to call the write functions **************************/
+
+static void imb_stereo3d_data_initialize(
+ Stereo3DData *s3d_data, const bool is_float,
+ const size_t x, const size_t y, const size_t channels,
+ int *rect_left, int *rect_right, int *rect_stereo,
+ float *rectf_left, float *rectf_right, float *rectf_stereo)
+{
+ s3d_data->is_float = is_float;
+ s3d_data->x = x;
+ s3d_data->y = y;
+ s3d_data->channels = channels;
+ s3d_data->rect.left = (uchar *)rect_left;
+ s3d_data->rect.right = (uchar *)rect_right;
+ s3d_data->rect.stereo = (uchar *)rect_stereo;
+ s3d_data->rectf.left = rectf_left;
+ s3d_data->rectf.right = rectf_right;
+ s3d_data->rectf.stereo = rectf_stereo;
+}
+
+int *IMB_stereo3d_from_rect(
+ ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ int *rect_left, int *rect_right)
+{
+ int *r_rect;
+ Stereo3DData s3d_data = {{NULL}};
+ size_t width, height;
+ const bool is_float = im_format->depth > 8;
+
+ IMB_stereo3d_write_dimensions(im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
+ r_rect = MEM_mallocN(channels * sizeof(int) * width * height, __func__);
+
+ imb_stereo3d_data_initialize(&s3d_data, is_float, x, y, channels, rect_left, rect_right, r_rect, NULL, NULL, NULL);
+ imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
+ imb_stereo3d_squeeze_rect(r_rect, &im_format->stereo3d_format, x, y, channels);
+
+ return r_rect;
+}
+
+float *IMB_stereo3d_from_rectf(
+ ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ float *rectf_left, float *rectf_right)
+{
+ float *r_rectf;
+ Stereo3DData s3d_data = {{NULL}};
+ size_t width, height;
+ const bool is_float = im_format->depth > 8;
+
+ IMB_stereo3d_write_dimensions(im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
+ r_rectf = MEM_mallocN(channels * sizeof(float) * width * height, __func__);
+
+ imb_stereo3d_data_initialize(&s3d_data, is_float, x, y, channels, NULL, NULL, NULL, rectf_left, rectf_right, r_rectf);
+ imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
+ imb_stereo3d_squeeze_rectf(r_rectf, &im_format->stereo3d_format, x, y, channels);
+
+ return r_rectf;
+}
+
+/* left/right are always float */
+ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
+{
+ ImBuf *ibuf_stereo = NULL;
+ Stereo3DData s3d_data = {{NULL}};
+ size_t width, height;
+ const bool is_float = im_format->depth > 8;
+
+ IMB_stereo3d_write_dimensions(im_format->stereo3d_format.display_mode, false, ibuf_left->x, ibuf_left->y, &width, &height);
+ ibuf_stereo = IMB_allocImBuf(width, height, ibuf_left->planes, (is_float ? IB_rectfloat : IB_rect));
+
+ /* copy flags for IB_fields and other settings */
+ ibuf_stereo->flags = ibuf_left->flags;
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 4,
+ (int *)ibuf_left->rect, (int *)ibuf_right->rect, (int *)ibuf_stereo->rect,
+ ibuf_left->rect_float, ibuf_right->rect_float, ibuf_stereo->rect_float);
+
+ imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
+ imb_stereo3d_squeeze_ImBuf(ibuf_stereo, &im_format->stereo3d_format, ibuf_left->x, ibuf_left->y);
+
+ return ibuf_stereo;
+}
+
+static void imb_stereo3d_write_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d)
+{
+ switch (s3d->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ imb_stereo3d_write_anaglyph(s3d_data, s3d->anaglyph_type);
+ break;
+ case S3D_DISPLAY_INTERLACE:
+ imb_stereo3d_write_interlace(s3d_data, s3d->interlace_type, (s3d->flag & S3D_INTERLACE_SWAP) != 0);
+ break;
+ case S3D_DISPLAY_SIDEBYSIDE:
+ imb_stereo3d_write_sidebyside(s3d_data, (s3d->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0);
+ break;
+ case S3D_DISPLAY_TOPBOTTOM:
+ imb_stereo3d_write_topbottom(s3d_data);
+ break;
+ default:
+ break;
+ }
+}
+
+/******************************** reading stereo imbufs **********************/
+
+static void imb_stereo3d_read_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ int anaglyph_encoding[3][3] = {
+ {0, 1, 1},
+ {1, 0, 1},
+ {0, 0, 1},
+ };
+
+ int r, g, b;
+
+ r = anaglyph_encoding[mode][0];
+ g = anaglyph_encoding[mode][1];
+ b = anaglyph_encoding[mode][2];
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ float *rect_from = s3d->rectf.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *from = rect_from + stride_from * y * 4;
+ float *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ to[0][3] = to[1][3] = from[3];
+ }
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ uchar *rect_from = s3d->rect.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ to[0][3] = to[1][3] = from[3];
+ }
+ }
+ }
+ }
+}
+
+static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterlaceType mode, const bool swap)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+ memcpy(to[i], from, sizeof(float) * channels * stride_to);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y;
+ float *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[i][0] = from[0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3(to[i], from);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4(to[i], from);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y;
+ float *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[j][0] = from[0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3(to[j], from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 4;
+ float *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4(to[j], from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.right;
+ uchar *rect_right = s3d->rect.left;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+ memcpy(to[i], from, sizeof(uchar) * channels * stride_to);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y;
+ uchar *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[i][0] = from[0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3_char((char *)to[i], (char *)from);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4_char((char *)to[i], (char *)from);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y;
+ uchar *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[j][0] = from[0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3_char((char *)to[j], (char *)from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4_char((char *)to[j], (char *)from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+/* stereo input (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_read_sidebyside(Stereo3DData *s3d, const bool crosseyed)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width * 2;
+ const int stride_to = width;
+
+ const int l = (int) crosseyed;
+ const int r = !l;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[l], from, sizeof(float) * channels * stride_to);
+ memcpy(to[r], from + channels * stride_to, sizeof(float) * channels * stride_to);
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ /* always RGBA input/output */
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[l], from, sizeof(uchar) * channels * stride_to);
+ memcpy(to[r], from + channels * stride_to, sizeof(uchar) * channels * stride_to);
+ }
+ }
+}
+
+/* stereo input (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_read_topbottom(Stereo3DData *s3d)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[1], from, sizeof(float) * channels * stride_to);
+ memcpy(to[0], from + channels * height * stride_to, sizeof(float) * channels * stride_to);
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[1], from, sizeof(uchar) * channels * stride_to);
+ memcpy(to[0], from + channels * height * stride_to, sizeof(uchar) * channels * stride_to);
+ }
+ }
+}
+
+
+/*************************** preparing to call the read functions **************************/
+
+/* reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right) */
+void IMB_ImBufFromStereo3d(
+ Stereo3dFormat *s3d, ImBuf *ibuf_stereo3d,
+ ImBuf **r_ibuf_left, ImBuf **r_ibuf_right)
+{
+ Stereo3DData s3d_data = {{NULL}};
+ ImBuf *ibuf_left, *ibuf_right;
+ size_t width, height;
+ const bool is_float = (ibuf_stereo3d->rect_float != NULL);
+
+ IMB_stereo3d_read_dimensions(
+ s3d->display_mode, ((s3d->flag & S3D_SQUEEZED_FRAME) == 0), ibuf_stereo3d->x, ibuf_stereo3d->y,
+ &width, &height);
+
+ ibuf_left = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect));
+ ibuf_right = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect));
+
+ /* copy flags for IB_fields and other settings */
+ ibuf_left->flags = ibuf_stereo3d->flags;
+ ibuf_right->flags = ibuf_stereo3d->flags;
+
+ /* we always work with unsqueezed formats */
+ IMB_stereo3d_write_dimensions(
+ s3d->display_mode, ((s3d->flag & S3D_SQUEEZED_FRAME) == 0), ibuf_stereo3d->x, ibuf_stereo3d->y,
+ &width, &height);
+ imb_stereo3d_unsqueeze_ImBuf(ibuf_stereo3d, s3d, width, height);
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 4,
+ (int *)ibuf_left->rect, (int *)ibuf_right->rect, (int *)ibuf_stereo3d->rect,
+ ibuf_left->rect_float, ibuf_right->rect_float, ibuf_stereo3d->rect_float);
+
+ imb_stereo3d_read_doit(&s3d_data, s3d);
+
+ if (ibuf_stereo3d->flags & (IB_zbuf | IB_zbuffloat)) {
+ if (is_float) {
+ addzbuffloatImBuf(ibuf_left);
+ addzbuffloatImBuf(ibuf_right);
+ }
+ else {
+ addzbufImBuf(ibuf_left);
+ addzbufImBuf(ibuf_right);
+ }
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 1,
+ (int *)ibuf_left->zbuf, (int *)ibuf_right->zbuf, (int *)ibuf_stereo3d->zbuf,
+ ibuf_left->zbuf_float, ibuf_right->zbuf_float, ibuf_stereo3d->zbuf_float);
+
+ imb_stereo3d_read_doit(&s3d_data, s3d);
+ }
+
+ IMB_freeImBuf(ibuf_stereo3d);
+
+ *r_ibuf_left = ibuf_left;
+ *r_ibuf_right = ibuf_right;
+}
+
+static void imb_stereo3d_read_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d)
+{
+ switch (s3d->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ imb_stereo3d_read_anaglyph(s3d_data, s3d->anaglyph_type);
+ break;
+ case S3D_DISPLAY_INTERLACE:
+ imb_stereo3d_read_interlace(s3d_data, s3d->interlace_type, (s3d->flag & S3D_INTERLACE_SWAP) != 0);
+ break;
+ case S3D_DISPLAY_SIDEBYSIDE:
+ imb_stereo3d_read_sidebyside(s3d_data, (s3d->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0);
+ break;
+ case S3D_DISPLAY_TOPBOTTOM:
+ imb_stereo3d_read_topbottom(s3d_data);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 118f0405303..21f440a8232 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -338,7 +338,7 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
img = IMB_loadblend_thumb(path);
}
else {
- img = IMB_loadiffname(path, IB_rect | IB_metadata, NULL);
+ img = IMB_loadiffname(path, IB_rect | IB_metadata | IB_thumbnail, NULL);
}
}
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 32100aa2288..3fee6688014 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -439,3 +439,15 @@ bool IMB_isanim(const char *filename)
return (type && type != ANIM_SEQUENCE);
}
+
+bool IMB_isfloat(ImBuf *ibuf)
+{
+ ImFileType *type;
+
+ for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
+ if (type->ftype(type, ibuf)) {
+ return (type->flag & IM_FTYPE_FLOAT) != 0;
+ }
+ }
+ return false;
+}
diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c
index 087330d10d2..5e9ccf4437e 100644
--- a/source/blender/imbuf/intern/writeimage.c
+++ b/source/blender/imbuf/intern/writeimage.c
@@ -43,19 +43,7 @@
static ImBuf *prepare_write_imbuf(ImFileType *type, ImBuf *ibuf)
{
- ImBuf *write_ibuf = ibuf;
-
- if (type->flag & IM_FTYPE_FLOAT) {
- /* pass */
- }
- else {
- if (ibuf->rect == NULL && ibuf->rect_float) {
- ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE);
- IMB_rect_from_float(ibuf);
- }
- }
-
- return write_ibuf;
+ return IMB_prepare_write_ImBuf((type->flag & IM_FTYPE_FLOAT), ibuf);
}
short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
@@ -86,3 +74,19 @@ short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
return false;
}
+ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf)
+{
+ ImBuf *write_ibuf = ibuf;
+
+ if (isfloat) {
+ /* pass */
+ }
+ else {
+ if (ibuf->rect == NULL && ibuf->rect_float) {
+ ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE);
+ IMB_rect_from_float(ibuf);
+ }
+ }
+
+ return write_ibuf;
+}