diff options
Diffstat (limited to 'source/blender/imbuf/intern/stereoimbuf.c')
-rw-r--r-- | source/blender/imbuf/intern/stereoimbuf.c | 1292 |
1 files changed, 1292 insertions, 0 deletions
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; + } +} |