diff options
Diffstat (limited to 'source/blender/compositor')
30 files changed, 758 insertions, 109 deletions
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 048c974423f..c23aa4ec734 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -119,6 +119,8 @@ set(SRC nodes/COM_TimeNode.h nodes/COM_SwitchNode.cpp nodes/COM_SwitchNode.h + nodes/COM_SwitchViewNode.cpp + nodes/COM_SwitchViewNode.h nodes/COM_MovieClipNode.cpp nodes/COM_MovieClipNode.h nodes/COM_OutputFileNode.cpp @@ -370,6 +372,8 @@ set(SRC operations/COM_CompositorOperation.cpp operations/COM_OutputFileOperation.h operations/COM_OutputFileOperation.cpp + operations/COM_OutputFileMultiViewOperation.h + operations/COM_OutputFileMultiViewOperation.cpp operations/COM_ViewerOperation.h operations/COM_ViewerOperation.cpp operations/COM_PreviewOperation.h diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h index 9b22444cf7f..8b0a617f889 100644 --- a/source/blender/compositor/COM_compositor.h +++ b/source/blender/compositor/COM_compositor.h @@ -316,7 +316,8 @@ extern "C" { * generation in display space */ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering, - const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings); + const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, + const char *viewName); /** * @brief Deinitialize the compositor caches and allocated memory. diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h index 3fbafa0a029..d7ec653f480 100644 --- a/source/blender/compositor/intern/COM_CompositorContext.h +++ b/source/blender/compositor/intern/COM_CompositorContext.h @@ -87,6 +87,11 @@ private: const ColorManagedViewSettings *m_viewSettings; const ColorManagedDisplaySettings *m_displaySettings; + /** + * @brief active rendering view name + */ + const char *m_viewName; + public: /** * @brief constructor initializes the context with default values. @@ -180,7 +185,17 @@ public: * @brief set has this system active openclDevices? */ void setHasActiveOpenCLDevices(bool hasAvtiveOpenCLDevices) { this->m_hasActiveOpenCLDevices = hasAvtiveOpenCLDevices; } - + + /** + * @brief get the active rendering view + */ + const char *getViewName() const { return this->m_viewName; } + + /** + * @brief set the active rendering view + */ + void setViewName(const char *viewName) { this->m_viewName = viewName; } + int getChunksize() const { return this->getbNodeTree()->chunksize; } void setFastCalculation(bool fastCalculation) {this->m_fastCalculation = fastCalculation;} diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index 99f66bcb5b4..9de22612bdc 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -101,6 +101,7 @@ extern "C" { #include "COM_Stabilize2dNode.h" #include "COM_SunBeamsNode.h" #include "COM_SwitchNode.h" +#include "COM_SwitchViewNode.h" #include "COM_TextureNode.h" #include "COM_TimeNode.h" #include "COM_TonemapNode.h" @@ -328,6 +329,9 @@ Node *Converter::convert(bNode *b_node) case CMP_NODE_SWITCH: node = new SwitchNode(b_node); break; + case CMP_NODE_SWITCH_VIEW: + node = new SwitchViewNode(b_node); + break; case CMP_NODE_GLARE: node = new GlareNode(b_node); break; diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp index 2ed9e6187ba..caeaa07d9f9 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp @@ -43,8 +43,10 @@ extern "C" { #endif ExecutionSystem::ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editingtree, bool rendering, bool fastcalculation, - const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings) + const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, + const char *viewName) { + this->m_context.setViewName(viewName); this->m_context.setScene(scene); this->m_context.setbNodeTree(editingtree); this->m_context.setPreviewHash(editingtree->previews); diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index 555964f7b0c..41d63fb3a72 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -151,7 +151,8 @@ public: * @param rendering [true false] */ ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editingtree, bool rendering, bool fastcalculation, - const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings); + const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, + const char *viewName); /** * Destructor diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp index ff601e6f58e..7f7fc141aca 100644 --- a/source/blender/compositor/intern/COM_compositor.cpp +++ b/source/blender/compositor/intern/COM_compositor.cpp @@ -45,7 +45,8 @@ static void intern_freeCompositorCaches() void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering, const ColorManagedViewSettings *viewSettings, - const ColorManagedDisplaySettings *displaySettings) + const ColorManagedDisplaySettings *displaySettings, + const char *viewName) { /* initialize mutex, TODO this mutex init is actually not thread safe and * should be done somewhere as part of blender startup, all the other @@ -82,7 +83,7 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende bool twopass = (editingtree->flag & NTREE_TWO_PASS) > 0 && !rendering; /* initialize execution system */ if (twopass) { - ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, twopass, viewSettings, displaySettings); + ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, twopass, viewSettings, displaySettings, viewName); system->execute(); delete system; @@ -95,7 +96,7 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende } ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, false, - viewSettings, displaySettings); + viewSettings, displaySettings, viewName); system->execute(); delete system; diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cpp index 933b8d0282b..9e8b40d8af4 100644 --- a/source/blender/compositor/nodes/COM_CompositorNode.cpp +++ b/source/blender/compositor/nodes/COM_CompositorNode.cpp @@ -43,6 +43,7 @@ void CompositorNode::convertToOperations(NodeConverter &converter, const Composi CompositorOperation *compositorOperation = new CompositorOperation(); compositorOperation->setSceneName(context.getScene()->id.name); compositorOperation->setRenderData(context.getRenderData()); + compositorOperation->setViewName(context.getViewName()); compositorOperation->setbNodeTree(context.getbNodeTree()); /* alpha socket gives either 1 or a custom alpha value if "use alpha" is enabled */ compositorOperation->setUseAlphaInput(ignore_alpha || alphaSocket->isLinked()); diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp index cb7ccfaedf9..93ab6dd765a 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.cpp +++ b/source/blender/compositor/nodes/COM_ImageNode.cpp @@ -40,19 +40,19 @@ ImageNode::ImageNode(bNode *editorNode) : Node(editorNode) } NodeOperation *ImageNode::doMultilayerCheck(NodeConverter &converter, RenderLayer *rl, Image *image, ImageUser *user, - int framenumber, int outputsocketIndex, int passindex, DataType datatype) const + int framenumber, int outputsocketIndex, int passtype, int view, DataType datatype) const { NodeOutput *outputSocket = this->getOutputSocket(outputsocketIndex); MultilayerBaseOperation *operation = NULL; switch (datatype) { case COM_DT_VALUE: - operation = new MultilayerValueOperation(passindex); + operation = new MultilayerValueOperation(passtype, view); break; case COM_DT_VECTOR: - operation = new MultilayerVectorOperation(passindex); + operation = new MultilayerVectorOperation(passtype, view); break; case COM_DT_COLOR: - operation = new MultilayerColorOperation(passindex); + operation = new MultilayerColorOperation(passtype, view); break; default: break; @@ -96,6 +96,10 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo NodeOperation *operation = NULL; socket = this->getOutputSocket(index); bNodeSocket *bnodeSocket = socket->getbNodeSocket(); + RenderPass *rpass = (RenderPass *)BLI_findstring(&rl->passes, bnodeSocket->identifier, offsetof(RenderPass, internal_name)); + + int view = (rpass ? rpass->view_id : 0); + /* Passes in the file can differ from passes stored in sockets (#36755). * Look up the correct file pass using the socket identifier instead. */ @@ -104,8 +108,22 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo int passindex = storage->pass_index;*/ RenderPass *rpass = (RenderPass *)BLI_findlink(&rl->passes, passindex); #endif - int passindex; - RenderPass *rpass; + + /* returns the image view to use for the current active view */ + if (BLI_listbase_count_ex(&image->rr->views, 2) > 1) { + const int view_image = imageuser->view; + const bool is_allview = (view_image == 0); /* if view selected == All (0) */ + + if (is_allview) { + /* heuristic to match image name with scene names + * check if the view name exists in the image */ + view = BLI_findstringindex(&image->rr->views, context.getViewName(), offsetof(RenderView, name)); + } + else { + view = view_image - 1; + } + } + if (STREQ(bnodeSocket->identifier, "Alpha")) { BLI_assert(combined_operation != NULL); NodeOutput *outputSocket = this->getOutputSocket(index); @@ -118,22 +136,21 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo operation = separate_operation; } else { - for (rpass = (RenderPass *)rl->passes.first, passindex = 0; rpass; rpass = rpass->next, ++passindex) - if (STREQ(rpass->name, bnodeSocket->identifier)) - break; if (rpass) { - imageuser->pass = passindex; switch (rpass->channels) { case 1: - operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_VALUE); + operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, + rpass->passtype, view, COM_DT_VALUE); break; /* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */ /* XXX any way to detect actual vector images? */ case 3: - operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_VECTOR); + operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, + rpass->passtype, view, COM_DT_VECTOR); break; case 4: - operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_COLOR); + operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, + rpass->passtype, view, COM_DT_COLOR); break; default: /* dummy operation is added below */ @@ -168,6 +185,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo operation->setImage(image); operation->setImageUser(imageuser); operation->setFramenumber(framenumber); + operation->setRenderData(context.getRenderData()); + operation->setViewName(context.getViewName()); converter.addOperation(operation); if (outputStraightAlpha) { @@ -190,6 +209,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo alphaOperation->setImage(image); alphaOperation->setImageUser(imageuser); alphaOperation->setFramenumber(framenumber); + alphaOperation->setRenderData(context.getRenderData()); + alphaOperation->setViewName(context.getViewName()); converter.addOperation(alphaOperation); converter.mapOutputSocket(alphaImage, alphaOperation->getOutputSocket()); @@ -200,6 +221,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo depthOperation->setImage(image); depthOperation->setImageUser(imageuser); depthOperation->setFramenumber(framenumber); + depthOperation->setRenderData(context.getRenderData()); + depthOperation->setViewName(context.getViewName()); converter.addOperation(depthOperation); converter.mapOutputSocket(depthImage, depthOperation->getOutputSocket()); @@ -239,6 +262,7 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo } if (operation) { + /* not supporting multiview for this generic case */ converter.addOperation(operation); converter.mapOutputSocket(output, operation->getOutputSocket()); } diff --git a/source/blender/compositor/nodes/COM_ImageNode.h b/source/blender/compositor/nodes/COM_ImageNode.h index 1daa39a2a1f..267794510e1 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.h +++ b/source/blender/compositor/nodes/COM_ImageNode.h @@ -36,7 +36,7 @@ extern "C" { class ImageNode : public Node { private: NodeOperation *doMultilayerCheck(NodeConverter &converter, RenderLayer *rl, Image *image, ImageUser *user, - int framenumber, int outputsocketIndex, int passindex, DataType datatype) const; + int framenumber, int outputsocketIndex, int passtype, int view, DataType datatype) const; public: ImageNode(bNode *editorNode); void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cpp b/source/blender/compositor/nodes/COM_OutputFileNode.cpp index 92fa74b9a2e..acd2602e216 100644 --- a/source/blender/compositor/nodes/COM_OutputFileNode.cpp +++ b/source/blender/compositor/nodes/COM_OutputFileNode.cpp @@ -23,8 +23,11 @@ #include "COM_OutputFileNode.h" #include "COM_OutputFileOperation.h" +#include "COM_OutputFileMultiViewOperation.h" #include "COM_ExecutionSystem.h" +#include "BKE_scene.h" + #include "BLI_path_util.h" OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode) @@ -35,6 +38,7 @@ OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode) void OutputFileNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const { NodeImageMultiFile *storage = (NodeImageMultiFile *)this->getbNode()->storage; + const bool is_multiview = (context.getRenderData()->scemode & R_MULTIVIEW) != 0; if (!context.isRendering()) { /* only output files when rendering a sequence - @@ -46,10 +50,18 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, const Composi if (storage->format.imtype == R_IMF_IMTYPE_MULTILAYER) { /* single output operation for the multilayer file */ - OutputOpenExrMultiLayerOperation *outputOperation = new OutputOpenExrMultiLayerOperation( - context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec); + OutputOpenExrMultiLayerOperation *outputOperation; + + if (is_multiview && storage->format.views_format == R_IMF_VIEWS_MULTIVIEW) { + outputOperation = new OutputOpenExrMultiLayerMultiViewOperation( + context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec, context.getViewName()); + } + else { + outputOperation = new OutputOpenExrMultiLayerOperation( + context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec, context.getViewName()); + } converter.addOperation(outputOperation); - + int num_inputs = getNumberOfInputSockets(); bool previewAdded = false; for (int i = 0; i < num_inputs; ++i) { @@ -76,17 +88,31 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, const Composi NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage; ImageFormatData *format = (sockdata->use_node_format ? &storage->format : &sockdata->format); char path[FILE_MAX]; - + /* combine file path for the input */ BLI_join_dirfile(path, FILE_MAX, storage->base_path, sockdata->path); - - OutputSingleLayerOperation *outputOperation = new OutputSingleLayerOperation( - context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path, - context.getViewSettings(), context.getDisplaySettings()); + + NodeOperation *outputOperation = NULL; + + if (is_multiview && format->views_format == R_IMF_VIEWS_MULTIVIEW) { + outputOperation = new OutputOpenExrSingleLayerMultiViewOperation( + context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path, + context.getViewSettings(), context.getDisplaySettings(), context.getViewName()); + } + else if ((!is_multiview) || (format->views_format == R_IMF_VIEWS_INDIVIDUAL)) { + outputOperation = new OutputSingleLayerOperation( + context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path, + context.getViewSettings(), context.getDisplaySettings(), context.getViewName()); + } + else { /* R_IMF_VIEWS_STEREO_3D */ + outputOperation = new OutputStereoOperation( + context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path, + sockdata->layer, context.getViewSettings(), context.getDisplaySettings(), context.getViewName()); + } + converter.addOperation(outputOperation); - converter.mapInputSocket(input, outputOperation->getInputSocket(0)); - + if (!previewAdded) { converter.addNodeInputPreview(input); previewAdded = true; diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp index cc66c688379..02bf1ec8cfb 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp @@ -42,7 +42,8 @@ void RenderLayersNode::testSocketLink(NodeConverter &converter, const Compositor operation->setScene(scene); operation->setLayerId(layerId); operation->setRenderData(context.getRenderData()); - + operation->setViewName(context.getViewName()); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); converter.addOperation(operation); diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp b/source/blender/compositor/nodes/COM_SplitViewerNode.cpp index 15eca0a97e5..0f917d317f9 100644 --- a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp +++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cpp @@ -22,6 +22,8 @@ #include "COM_SplitViewerNode.h" #include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_scene.h" #include "COM_SplitOperation.h" #include "COM_ViewerOperation.h" @@ -55,6 +57,8 @@ void SplitViewerNode::convertToOperations(NodeConverter &converter, const Compos viewerOperation->setImageUser(imageUser); viewerOperation->setViewSettings(context.getViewSettings()); viewerOperation->setDisplaySettings(context.getDisplaySettings()); + viewerOperation->setRenderData(context.getRenderData()); + viewerOperation->setViewName(context.getViewName()); /* defaults - the viewer node has these options but not exposed for split view * we could use the split to define an area of interest on one axis at least */ diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp b/source/blender/compositor/nodes/COM_SwitchViewNode.cpp new file mode 100644 index 00000000000..5a23b8b4d9e --- /dev/null +++ b/source/blender/compositor/nodes/COM_SwitchViewNode.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2015, Blender Foundation. + * + * 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. + * + * Contributor: + * Dalai Felinto + */ + +#include "COM_SwitchViewNode.h" +#include "BLI_listbase.h" + +SwitchViewNode::SwitchViewNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void SwitchViewNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const +{ + NodeOperationOutput *result; + const char *viewName = context.getViewName(); + bNode *bnode = this->getbNode(); + + /* get the internal index of the socket with a matching name */ + int nr = BLI_findstringindex(&bnode->inputs, viewName, offsetof(bNodeSocket, name)); + nr = max(nr, 0); + + result = converter.addInputProxy(getInputSocket(nr), false); + converter.mapOutputSocket(getOutputSocket(0), result); +} diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.h b/source/blender/compositor/nodes/COM_SwitchViewNode.h new file mode 100644 index 00000000000..6ab5145bed5 --- /dev/null +++ b/source/blender/compositor/nodes/COM_SwitchViewNode.h @@ -0,0 +1,37 @@ +/* + * Copyright 2015, Blender Foundation. + * + * 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. + * + * Contributor: + * Dalai Felinto + */ + +#ifndef _COM_SwitchViewNode_h_ +#define _COM_SwitchViewNode_h_ + +#include "COM_Node.h" +#include "COM_NodeOperation.h" +#include "DNA_node_types.h" +/** + * @brief SwitchViewNode + * @ingroup Node + */ +class SwitchViewNode : public Node { +public: + SwitchViewNode(bNode *editorNode); + void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; +}; +#endif diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cpp b/source/blender/compositor/nodes/COM_ViewerNode.cpp index ff0b8fb1706..ab819ce6e30 100644 --- a/source/blender/compositor/nodes/COM_ViewerNode.cpp +++ b/source/blender/compositor/nodes/COM_ViewerNode.cpp @@ -22,6 +22,9 @@ #include "COM_ViewerNode.h" #include "BKE_global.h" +#include "BKE_image.h" +#include "BLI_listbase.h" +#include "BKE_scene.h" #include "COM_ViewerOperation.h" #include "COM_ExecutionSystem.h" @@ -51,6 +54,8 @@ void ViewerNode::convertToOperations(NodeConverter &converter, const CompositorC viewerOperation->setCenterY(editorNode->custom4); /* alpha socket gives either 1 or a custom alpha value if "use alpha" is enabled */ viewerOperation->setUseAlphaInput(ignore_alpha || alphaSocket->isLinked()); + viewerOperation->setRenderData(context.getRenderData()); + viewerOperation->setViewName(context.getViewName()); viewerOperation->setViewSettings(context.getViewSettings()); viewerOperation->setDisplaySettings(context.getDisplaySettings()); diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp index ffef81d0323..eacbdf91be2 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cpp +++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp @@ -52,6 +52,7 @@ CompositorOperation::CompositorOperation() : NodeOperation() this->m_active = false; this->m_sceneName[0] = '\0'; + this->m_viewName = NULL; } void CompositorOperation::initExecution() @@ -81,14 +82,16 @@ void CompositorOperation::deinitExecution() RenderResult *rr = RE_AcquireResultWrite(re); if (rr) { - if (rr->rectf != NULL) { - MEM_freeN(rr->rectf); + RenderView *rv = (RenderView *)BLI_findstring(&rr->views, this->m_viewName, offsetof(RenderView, name)); + + if (rv->rectf != NULL) { + MEM_freeN(rv->rectf); } - rr->rectf = this->m_outputBuffer; - if (rr->rectz != NULL) { - MEM_freeN(rr->rectz); + rv->rectf = this->m_outputBuffer; + if (rv->rectz != NULL) { + MEM_freeN(rv->rectz); } - rr->rectz = this->m_depthBuffer; + rv->rectz = this->m_depthBuffer; } else { if (this->m_outputBuffer) { diff --git a/source/blender/compositor/operations/COM_CompositorOperation.h b/source/blender/compositor/operations/COM_CompositorOperation.h index 447d74131b3..e81ba520695 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.h +++ b/source/blender/compositor/operations/COM_CompositorOperation.h @@ -75,11 +75,17 @@ private: * @brief operation is active for calculating final compo result */ bool m_active; + + /** + * @brief View name, used for multiview + */ + const char *m_viewName; public: CompositorOperation(); const bool isActiveCompositorOutput() const { return this->m_active; } void executeRegion(rcti *rect, unsigned int tileNumber); void setSceneName(const char *sceneName) { BLI_strncpy(this->m_sceneName, sceneName, sizeof(this->m_sceneName)); } + void setViewName(const char *viewName) { this->m_viewName = viewName; } void setRenderData(const RenderData *rd) { this->m_rd = rd; } bool isOutputOperation(bool /*rendering*/) const { return this->isActiveCompositorOutput(); } void initExecution(); diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp index 624fdf8b626..c140b7afbd7 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.cpp +++ b/source/blender/compositor/operations/COM_ImageOperation.cpp @@ -25,6 +25,7 @@ #include "BLI_listbase.h" #include "DNA_image_types.h" #include "BKE_image.h" +#include "BKE_scene.h" #include "BLI_math.h" extern "C" { @@ -48,6 +49,8 @@ BaseImageOperation::BaseImageOperation() : NodeOperation() this->m_framenumber = 0; this->m_depthBuffer = NULL; this->m_numberOfChannels = 0; + this->m_rd = NULL; + this->m_viewName = NULL; } ImageOperation::ImageOperation() : BaseImageOperation() { @@ -65,8 +68,12 @@ ImageDepthOperation::ImageDepthOperation() : BaseImageOperation() ImBuf *BaseImageOperation::getImBuf() { ImBuf *ibuf; - - ibuf = BKE_image_acquire_ibuf(this->m_image, this->m_imageUser, NULL); + ImageUser iuser = *this->m_imageUser; + + /* local changes to the original ImageUser */ + iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName); + + ibuf = BKE_image_acquire_ibuf(this->m_image, &iuser, NULL); if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) { BKE_image_release_ibuf(this->m_image, ibuf, NULL); return NULL; diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h index 206f1509f60..75222559810 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.h +++ b/source/blender/compositor/operations/COM_ImageOperation.h @@ -49,7 +49,9 @@ protected: int m_imagewidth; int m_framenumber; int m_numberOfChannels; - + const RenderData *m_rd; + const char *m_viewName; + BaseImageOperation(); /** * Determine the output resolution. The resolution is retrieved from the Renderer @@ -64,7 +66,8 @@ public: void deinitExecution(); void setImage(Image *image) { this->m_image = image; } void setImageUser(ImageUser *imageuser) { this->m_imageUser = imageuser; } - + void setRenderData(const RenderData *rd) { this->m_rd = rd; } + void setViewName(const char *viewName) { this->m_viewName = viewName; } void setFramenumber(int framenumber) { this->m_framenumber = framenumber; } }; class ImageOperation : public BaseImageOperation { diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp index 513140e2f62..00be3b1cdde 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp @@ -27,18 +27,27 @@ extern "C" { # include "IMB_imbuf_types.h" } -MultilayerBaseOperation::MultilayerBaseOperation(int passindex) : BaseImageOperation() +MultilayerBaseOperation::MultilayerBaseOperation(int passtype, int view) : BaseImageOperation() { - this->m_passId = passindex; + this->m_passtype = passtype; + this->m_view = view; } + ImBuf *MultilayerBaseOperation::getImBuf() { - RenderPass *rpass = (RenderPass *)BLI_findlink(&this->m_renderlayer->passes, this->m_passId); - if (rpass) { - this->m_imageUser->pass = m_passId; - BKE_image_multilayer_index(this->m_image->rr, this->m_imageUser); - return BaseImageOperation::getImBuf(); + /* temporarily changes the view to get the right ImBuf */ + int view = this->m_imageUser->view; + + this->m_imageUser->view = this->m_view; + this->m_imageUser->passtype = this->m_passtype; + + if (BKE_image_multilayer_index(this->m_image->rr, this->m_imageUser)) { + ImBuf *ibuf = BaseImageOperation::getImBuf(); + this->m_imageUser->view = view; + return ibuf; } + + this->m_imageUser->view = view; return NULL; } diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h index 37bee1b6a8c..2e140577d74 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h @@ -29,7 +29,8 @@ class MultilayerBaseOperation : public BaseImageOperation { private: - int m_passId; + int m_passtype; + int m_view; RenderLayer *m_renderlayer; protected: ImBuf *getImBuf(); @@ -37,13 +38,13 @@ public: /** * Constructor */ - MultilayerBaseOperation(int passindex); + MultilayerBaseOperation(int passtype, int view); void setRenderLayer(RenderLayer *renderlayer) { this->m_renderlayer = renderlayer; } }; class MultilayerColorOperation : public MultilayerBaseOperation { public: - MultilayerColorOperation(int passindex) : MultilayerBaseOperation(passindex) { + MultilayerColorOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) { this->addOutputSocket(COM_DT_COLOR); } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); @@ -51,7 +52,7 @@ public: class MultilayerValueOperation : public MultilayerBaseOperation { public: - MultilayerValueOperation(int passindex) : MultilayerBaseOperation(passindex) { + MultilayerValueOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) { this->addOutputSocket(COM_DT_VALUE); } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); @@ -59,7 +60,7 @@ public: class MultilayerVectorOperation : public MultilayerBaseOperation { public: - MultilayerVectorOperation(int passindex) : MultilayerBaseOperation(passindex) { + MultilayerVectorOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) { this->addOutputSocket(COM_DT_VECTOR); } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp new file mode 100644 index 00000000000..c927dfa89a1 --- /dev/null +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp @@ -0,0 +1,317 @@ +/* + * Copyright 2015, Blender Foundation. + * + * 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. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Lukas Tönne + * Dalai Felinto + */ + +#include "COM_OutputFileOperation.h" +#include "COM_OutputFileMultiViewOperation.h" + +#include <string.h> +#include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BKE_image.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "DNA_color_types.h" +#include "MEM_guardedalloc.h" + +extern "C" { +#include "IMB_imbuf.h" +#include "IMB_colormanagement.h" +#include "IMB_imbuf_types.h" +} + +/************************************ OpenEXR Singlelayer Multiview *****************************************/ + +OutputOpenExrSingleLayerMultiViewOperation::OutputOpenExrSingleLayerMultiViewOperation( + const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path, + const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, + const char *viewName) + : OutputSingleLayerOperation(rd, tree, datatype, format, path, viewSettings, displaySettings, viewName) +{ +} + +void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filename) +{ + size_t width = this->getWidth(); + size_t height = this->getHeight(); + SceneRenderView *srv; + + if (width != 0 && height != 0) { + void *exrhandle; + + exrhandle = IMB_exr_get_handle_name(filename); + + if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) + return exrhandle; + + IMB_exr_clear_channels(exrhandle); + + for (srv = (SceneRenderView *)this->m_rd->views.first; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false) + continue; + + IMB_exr_add_view(exrhandle, srv->name); + add_exr_channels(exrhandle, NULL, this->m_datatype, srv->name, width, NULL); + } + + BLI_make_existing_file(filename); + + /* prepare the file with all the channels */ + + if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_format->exr_codec) == 0) { + printf("Error Writing Singlelayer Multiview Openexr\n"); + IMB_exr_close(exrhandle); + } + else { + IMB_exr_clear_channels(exrhandle); + return exrhandle; + } + } + return NULL; +} + +void OutputOpenExrSingleLayerMultiViewOperation::deinitExecution() +{ + unsigned int width = this->getWidth(); + unsigned int height = this->getHeight(); + + if (width != 0 && height != 0) { + void *exrhandle; + Main *bmain = G.main; /* TODO, have this passed along */ + char filename[FILE_MAX]; + + BKE_image_path_from_imtype( + filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_OPENEXR, + (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL); + + exrhandle = this->get_handle(filename); + add_exr_channels(exrhandle, NULL, this->m_datatype, this->m_viewName, width, this->m_outputBuffer); + + /* memory can only be freed after we write all views to the file */ + this->m_outputBuffer = NULL; + this->m_imageInput = NULL; + + /* ready to close the file */ + if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) { + IMB_exr_write_channels(exrhandle); + + /* free buffer memory for all the views */ + free_exr_channels(exrhandle, this->m_rd, NULL, this->m_datatype); + + /* remove exr handle and data */ + IMB_exr_close(exrhandle); + } + } +} + +/************************************ OpenEXR Multilayer Multiview *****************************************/ + +OutputOpenExrMultiLayerMultiViewOperation::OutputOpenExrMultiLayerMultiViewOperation( + const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName) + : OutputOpenExrMultiLayerOperation(rd, tree, path, exr_codec, viewName) +{ +} + +void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename) +{ + unsigned int width = this->getWidth(); + unsigned int height = this->getHeight(); + + if (width != 0 && height != 0) { + + void *exrhandle; + SceneRenderView *srv; + + /* get a new global handle */ + exrhandle = IMB_exr_get_handle_name(filename); + + if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) + return exrhandle; + + IMB_exr_clear_channels(exrhandle); + + /* check renderdata for amount of views */ + for (srv = (SceneRenderView *) this->m_rd->views.first; srv; srv = srv->next) { + + if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false) + continue; + + IMB_exr_add_view(exrhandle, srv->name); + + for (unsigned int i = 0; i < this->m_layers.size(); ++i) + add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, srv->name, width, NULL); + } + + BLI_make_existing_file(filename); + + /* prepare the file with all the channels for the header */ + if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec) == 0) { + printf("Error Writing Multilayer Multiview Openexr\n"); + IMB_exr_close(exrhandle); + } + else { + IMB_exr_clear_channels(exrhandle); + return exrhandle; + } + } + return NULL; +} + +void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution() +{ + unsigned int width = this->getWidth(); + unsigned int height = this->getHeight(); + + if (width != 0 && height != 0) { + void *exrhandle; + Main *bmain = G.main; /* TODO, have this passed along */ + char filename[FILE_MAX]; + + BKE_image_path_from_imtype( + filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER, + (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL); + + exrhandle = this->get_handle(filename); + + for (unsigned int i = 0; i < this->m_layers.size(); ++i) + add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, this->m_viewName, width, this->m_layers[i].outputBuffer); + + for (unsigned int i = 0; i < this->m_layers.size(); ++i) { + /* memory can only be freed after we write all views to the file */ + this->m_layers[i].outputBuffer = NULL; + this->m_layers[i].imageInput = NULL; + } + + /* ready to close the file */ + if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) { + IMB_exr_write_channels(exrhandle); + + /* free buffer memory for all the views */ + for (unsigned int i = 0; i < this->m_layers.size(); ++i) { + free_exr_channels(exrhandle, this->m_rd, this->m_layers[i].name, this->m_layers[i].datatype); + } + + IMB_exr_close(exrhandle); + } + } +} + + +/******************************** Stereo3D ******************************/ + +OutputStereoOperation::OutputStereoOperation( + const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path, + const char *name, const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, + const char *viewName) + : OutputSingleLayerOperation(rd, tree, datatype, format, path, viewSettings, displaySettings, viewName) +{ + BLI_strncpy(this->m_name, name, sizeof(this->m_name)); + this->m_channels = get_datatype_size(datatype); +} + +void *OutputStereoOperation::get_handle(const char *filename) +{ + size_t width = this->getWidth(); + size_t height = this->getHeight(); + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; + size_t i; + + if (width != 0 && height != 0) { + void *exrhandle; + + exrhandle = IMB_exr_get_handle_name(filename); + + if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) + return exrhandle; + + IMB_exr_clear_channels(exrhandle); + + for (i = 0; i < 2; i++) + IMB_exr_add_view(exrhandle, names[i]); + + return exrhandle; + } + return NULL; +} + +void OutputStereoOperation::deinitExecution() +{ + unsigned int width = this->getWidth(); + unsigned int height = this->getHeight(); + + if (width != 0 && height != 0) { + void *exrhandle; + + exrhandle = this->get_handle(this->m_path); + float *buf = this->m_outputBuffer; + + /* populate single EXR channel with view data */ + IMB_exr_add_channel(exrhandle, NULL, this->m_name, this->m_viewName, 1, this->m_channels * width * height, buf); + + this->m_imageInput = NULL; + this->m_outputBuffer = NULL; + + /* create stereo ibuf */ + if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) { + ImBuf *ibuf[3] = {NULL}; + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; + Main *bmain = G.main; /* TODO, have this passed along */ + char filename[FILE_MAX]; + int i; + + /* get rectf from EXR */ + for (i = 0; i < 2; i++) { + float *rectf = IMB_exr_channel_rect(exrhandle, NULL, this->m_name, names[i]); + ibuf[i] = IMB_allocImBuf(width, height, this->m_format->planes, 0); + + ibuf[i]->channels = this->m_channels; + ibuf[i]->rect_float = rectf; + ibuf[i]->mall |= IB_rectfloat; + ibuf[i]->dither = this->m_rd->dither_intensity; + + /* do colormanagement in the individual views, so it doesn't need to do in the stereo */ + IMB_colormanagement_imbuf_for_write(ibuf[i], true, false, this->m_viewSettings, + this->m_displaySettings, this->m_format); + IMB_prepare_write_ImBuf(IMB_isfloat(ibuf[i]), ibuf[i]); + } + + /* create stereo buffer */ + ibuf[2] = IMB_stereo3d_ImBuf(this->m_format, ibuf[0], ibuf[1]); + + BKE_image_path_from_imformat( + filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format, + (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL); + + BKE_imbuf_write(ibuf[2], filename, this->m_format); + + /* imbuf knows which rects are not part of ibuf */ + for (i = 0; i < 3; i++) + IMB_freeImBuf(ibuf[i]); + + IMB_exr_close(exrhandle); + } + } +} diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h new file mode 100644 index 00000000000..25716fdb9e1 --- /dev/null +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h @@ -0,0 +1,74 @@ +/* + * Copyright 2015, Blender Foundation. + * + * 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. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Lukas Tönne + * Dalai Felinto + */ + +#ifndef _COM_OutputFileMultiViewOperation_h +#define _COM_OutputFileMultiViewOperation_h +#include "COM_NodeOperation.h" + +#include "BLI_rect.h" +#include "BLI_path_util.h" + +#include "DNA_color_types.h" +#include "DNA_userdef_types.h" + +#include "intern/openexr/openexr_multi.h" + +class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOperation { +private: +public: + OutputOpenExrSingleLayerMultiViewOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype, + ImageFormatData *format, const char *path, + const ColorManagedViewSettings *viewSettings, + const ColorManagedDisplaySettings *displaySettings, + const char *viewName); + + void *get_handle(const char *filename); + void deinitExecution(); +}; + +/* Writes inputs into OpenEXR multilayer channels. */ +class OutputOpenExrMultiLayerMultiViewOperation : public OutputOpenExrMultiLayerOperation { +private: +public: + OutputOpenExrMultiLayerMultiViewOperation(const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName); + + void *get_handle(const char *filename); + void deinitExecution(); +}; + +/**/ +class OutputStereoOperation : public OutputSingleLayerOperation { +private: + char m_name[FILE_MAX]; + size_t m_channels; +public: + OutputStereoOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype, + struct ImageFormatData *format, const char *path, const char *name, + const ColorManagedViewSettings *viewSettings, + const ColorManagedDisplaySettings *displaySettings, const char *viewName); + void *get_handle(const char *filename); + void deinitExecution(); +}; + +#endif diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp index b1c90a6355f..1a7a356f5b4 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp @@ -29,6 +29,7 @@ #include "BKE_image.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_scene.h" #include "DNA_color_types.h" @@ -39,7 +40,60 @@ extern "C" { # include "IMB_imbuf_types.h" } -static int get_datatype_size(DataType datatype) +void add_exr_channels(void *exrhandle, const char *layerName, const DataType datatype, const char *viewName, const size_t width, float *buf) +{ + /* create channels */ + switch (datatype) { + case COM_DT_VALUE: + IMB_exr_add_channel(exrhandle, layerName, "V", viewName, 1, width, buf ? buf : NULL); + break; + case COM_DT_VECTOR: + IMB_exr_add_channel(exrhandle, layerName, "X", viewName, 3, 3 * width, buf ? buf : NULL); + IMB_exr_add_channel(exrhandle, layerName, "Y", viewName, 3, 3 * width, buf ? buf + 1 : NULL); + IMB_exr_add_channel(exrhandle, layerName, "Z", viewName, 3, 3 * width, buf ? buf + 2 : NULL); + break; + case COM_DT_COLOR: + IMB_exr_add_channel(exrhandle, layerName, "R", viewName, 4, 4 * width, buf ? buf : NULL); + IMB_exr_add_channel(exrhandle, layerName, "G", viewName, 4, 4 * width, buf ? buf + 1 : NULL); + IMB_exr_add_channel(exrhandle, layerName, "B", viewName, 4, 4 * width, buf ? buf + 2 : NULL); + IMB_exr_add_channel(exrhandle, layerName, "A", viewName, 4, 4 * width, buf ? buf + 3 : NULL); + break; + default: + break; + } +} + +void free_exr_channels(void *exrhandle, const RenderData *rd, const char *layerName, const DataType datatype) +{ + SceneRenderView *srv; + + /* check renderdata for amount of views */ + for (srv = (SceneRenderView *) rd->views.first; srv; srv = srv->next) { + float *rect = NULL; + + if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) + continue; + + /* the pointer is stored in the first channel of each datatype */ + switch (datatype) { + case COM_DT_VALUE: + rect = IMB_exr_channel_rect(exrhandle, layerName, "V", srv->name); + break; + case COM_DT_VECTOR: + rect = IMB_exr_channel_rect(exrhandle, layerName, "X", srv->name); + break; + case COM_DT_COLOR: + rect = IMB_exr_channel_rect(exrhandle, layerName, "R", srv->name); + break; + default: + break; + } + if (rect) + MEM_freeN(rect); + } +} + +int get_datatype_size(DataType datatype) { switch (datatype) { case COM_DT_VALUE: return 1; @@ -94,7 +148,7 @@ static void write_buffer_rect(rcti *rect, const bNodeTree *tree, OutputSingleLayerOperation::OutputSingleLayerOperation( const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path, - const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings) + const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, const char *viewName) { this->m_rd = rd; this->m_tree = tree; @@ -110,6 +164,7 @@ OutputSingleLayerOperation::OutputSingleLayerOperation( this->m_viewSettings = viewSettings; this->m_displaySettings = displaySettings; + this->m_viewName = viewName; } void OutputSingleLayerOperation::initExecution() @@ -131,6 +186,7 @@ void OutputSingleLayerOperation::deinitExecution() ImBuf *ibuf = IMB_allocImBuf(this->getWidth(), this->getHeight(), this->m_format->planes, 0); Main *bmain = G.main; /* TODO, have this passed along */ char filename[FILE_MAX]; + const char *suffix; ibuf->channels = size; ibuf->rect_float = this->m_outputBuffer; @@ -140,10 +196,12 @@ void OutputSingleLayerOperation::deinitExecution() IMB_colormanagement_imbuf_for_write(ibuf, true, false, m_viewSettings, m_displaySettings, this->m_format); + suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName); + BKE_image_path_from_imformat( - filename, this->m_path, bmain->name, this->m_rd->cfra, - this->m_format, (this->m_rd->scemode & R_EXTENSION) != 0, true); - + filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format, + (this->m_rd->scemode & R_EXTENSION) != 0, true, suffix); + if (0 == BKE_imbuf_write(ibuf, filename, this->m_format)) printf("Cannot save Node File Output to %s\n", filename); else @@ -155,6 +213,7 @@ void OutputSingleLayerOperation::deinitExecution() this->m_imageInput = NULL; } +/******************************* MultiLayer *******************************/ OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bool use_layer_) { @@ -168,13 +227,14 @@ OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bo } OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation( - const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec) + const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName) { this->m_rd = rd; this->m_tree = tree; BLI_strncpy(this->m_path, path, sizeof(this->m_path)); this->m_exr_codec = exr_codec; + this->m_viewName = viewName; } void OutputOpenExrMultiLayerOperation::add_layer(const char *name, DataType datatype, bool use_layer) @@ -210,52 +270,21 @@ void OutputOpenExrMultiLayerOperation::deinitExecution() if (width != 0 && height != 0) { Main *bmain = G.main; /* TODO, have this passed along */ char filename[FILE_MAX]; + const char *suffix; void *exrhandle = IMB_exr_get_handle(); - + + suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName); BKE_image_path_from_imtype( filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER, - (this->m_rd->scemode & R_EXTENSION) != 0, true); + (this->m_rd->scemode & R_EXTENSION) != 0, true, suffix); BLI_make_existing_file(filename); - + for (unsigned int i = 0; i < this->m_layers.size(); ++i) { OutputOpenExrLayer &layer = this->m_layers[i]; if (!layer.imageInput) continue; /* skip unconnected sockets */ - char channelname[EXR_TOT_MAXNAME]; - BLI_strncpy(channelname, this->m_layers[i].name, sizeof(channelname) - 2); - char *channelname_ext = channelname + strlen(channelname); - - float *buf = this->m_layers[i].outputBuffer; - - /* create channels */ - switch (this->m_layers[i].datatype) { - case COM_DT_VALUE: - strcpy(channelname_ext, ".V"); - IMB_exr_add_channel(exrhandle, 0, channelname, 1, width, buf); - break; - case COM_DT_VECTOR: - strcpy(channelname_ext, ".X"); - IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf); - strcpy(channelname_ext, ".Y"); - IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 1); - strcpy(channelname_ext, ".Z"); - IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 2); - break; - case COM_DT_COLOR: - strcpy(channelname_ext, ".R"); - IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf); - strcpy(channelname_ext, ".G"); - IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 1); - strcpy(channelname_ext, ".B"); - IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 2); - strcpy(channelname_ext, ".A"); - IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 3); - break; - default: - break; - } - + add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, "", width, this->m_layers[i].outputBuffer); } /* when the filename has no permissions, this can fail */ @@ -279,3 +308,4 @@ void OutputOpenExrMultiLayerOperation::deinitExecution() } } } + diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h index af16f186d9d..58ebf055583 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.h +++ b/source/blender/compositor/operations/COM_OutputFileOperation.h @@ -34,7 +34,7 @@ /* Writes the image to a single-layer file. */ class OutputSingleLayerOperation : public NodeOperation { -private: +protected: const RenderData *m_rd; const bNodeTree *m_tree; @@ -47,9 +47,11 @@ private: const ColorManagedViewSettings *m_viewSettings; const ColorManagedDisplaySettings *m_displaySettings; + + const char *m_viewName; public: OutputSingleLayerOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path, - const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings); + const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, const char *viewName); void executeRegion(rcti *rect, unsigned int tileNumber); bool isOutputOperation(bool /*rendering*/) const { return true; } @@ -75,7 +77,7 @@ struct OutputOpenExrLayer { /* Writes inputs into OpenEXR multilayer channels. */ class OutputOpenExrMultiLayerOperation : public NodeOperation { -private: +protected: typedef std::vector<OutputOpenExrLayer> LayerList; const RenderData *m_rd; @@ -84,9 +86,10 @@ private: char m_path[FILE_MAX]; char m_exr_codec; LayerList m_layers; + const char *m_viewName; public: - OutputOpenExrMultiLayerOperation(const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec); + OutputOpenExrMultiLayerOperation(const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName); void add_layer(const char *name, DataType datatype, bool use_layer); @@ -99,4 +102,8 @@ public: bool isFileOutputOperation() const { return true; } }; +void add_exr_channels(void *exrhandle, const char *layerName, const DataType datatype, const char *viewName, const size_t width, float *buf); +void free_exr_channels(void *exrhandle, const RenderData *rd, const char *layerName, const DataType datatype); +int get_datatype_size(DataType datatype); + #endif diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp index defbc2ab57f..af176a766ff 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp @@ -23,6 +23,7 @@ #include "COM_RenderLayersProg.h" #include "BLI_listbase.h" +#include "BKE_scene.h" #include "DNA_scene_types.h" extern "C" { @@ -57,11 +58,10 @@ void RenderLayersBaseProg::initExecution() if (srl) { RenderLayer *rl = RE_GetRenderLayer(rr, srl->name); - if (rl && rl->rectf) { - this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_renderpass); - + if (rl) { + this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_renderpass, this->m_viewName); if (this->m_inputBuffer == NULL && this->m_renderpass == SCE_PASS_COMBINED) { - this->m_inputBuffer = rl->rectf; + this->m_inputBuffer = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, this->m_viewName); } } } @@ -195,7 +195,7 @@ void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsig SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&sce->r.layers, getLayerId()); if (srl) { RenderLayer *rl = RE_GetRenderLayer(rr, srl->name); - if (rl && rl->rectf) { + if (rl) { resolution[0] = rl->rectx; resolution[1] = rl->recty; } diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h index f73d9de3e27..2ddbc968c01 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.h +++ b/source/blender/compositor/operations/COM_RenderLayersProg.h @@ -51,7 +51,12 @@ private: * layerId of the layer where this operation needs to get its data from */ short m_layerId; - + + /** + * viewName of the view to use (unless another view is specified by the node + */ + const char *m_viewName; + /** * cached instance to the float buffer inside the layer */ @@ -97,6 +102,8 @@ public: void setRenderData(const RenderData *rd) { this->m_rd = rd; } void setLayerId(short layerId) { this->m_layerId = layerId; } short getLayerId() { return this->m_layerId; } + void setViewName(const char *viewName) { this->m_viewName = viewName; } + const char *getViewName() { return this->m_viewName; } void initExecution(); void deinitExecution(); void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cpp index da2706a2244..96ee5ecbb03 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.cpp +++ b/source/blender/compositor/operations/COM_ViewerOperation.cpp @@ -23,6 +23,7 @@ #include "COM_ViewerOperation.h" #include "BLI_listbase.h" #include "BKE_image.h" +#include "BKE_scene.h" #include "WM_api.h" #include "WM_types.h" #include "PIL_time.h" @@ -57,6 +58,8 @@ ViewerOperation::ViewerOperation() : NodeOperation() this->m_imageInput = NULL; this->m_alphaInput = NULL; this->m_depthInput = NULL; + this->m_rd = NULL; + this->m_viewName = NULL; } void ViewerOperation::initExecution() @@ -123,8 +126,18 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) void ViewerOperation::initImage() { Image *ima = this->m_image; + ImageUser iuser = *this->m_imageUser; void *lock; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, this->m_imageUser, &lock); + ImBuf *ibuf; + + /* make sure the image has the correct number of views */ + if (ima && BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) { + BKE_image_verify_viewer_views(this->m_rd, ima, this->m_imageUser); + } + + /* local changes to the original ImageUser */ + iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName); + ibuf = BKE_image_acquire_ibuf(ima, &iuser, &lock); if (!ibuf) return; BLI_lock_thread(LOCK_DRAW_IMAGE); diff --git a/source/blender/compositor/operations/COM_ViewerOperation.h b/source/blender/compositor/operations/COM_ViewerOperation.h index a17375c2de9..107aee3a82f 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.h +++ b/source/blender/compositor/operations/COM_ViewerOperation.h @@ -40,7 +40,9 @@ private: bool m_doDepthBuffer; ImBuf *m_ibuf; bool m_useAlphaInput; - + const RenderData *m_rd; + const char *m_viewName; + const ColorManagedViewSettings *m_viewSettings; const ColorManagedDisplaySettings *m_displaySettings; @@ -67,6 +69,8 @@ public: const CompositorPriority getRenderPriority() const; bool isViewerOperation() const { return true; } void setUseAlphaInput(bool value) { this->m_useAlphaInput = value; } + void setRenderData(const RenderData *rd) { this->m_rd = rd; } + void setViewName(const char *viewName) { this->m_viewName = viewName; } void setViewSettings(const ColorManagedViewSettings *viewSettings) { this->m_viewSettings = viewSettings; } void setDisplaySettings(const ColorManagedDisplaySettings *displaySettings) { this->m_displaySettings = displaySettings; } |