/* * ***** 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 #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; } }