From f3fb1df1922a938272a84209c55206255c687e31 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Fri, 5 Mar 2021 11:12:13 +0100 Subject: Fix T86293: crash undoing after executing the python console in certain scenarios In general, I could not find a reason executing from the python console should not do an Undo push. Running a script from the Text Editor does this as well and this seems generally useful. Without an Undo push, one can easily run into situations were IDs have been added or removed and undo on would then cause trouble (e.g. first selection then bpy.ops.object.duplicate() -- this crashed as reported in T86293 -- duplicate does not get its own undo push because it is not the last op in the list, wm->op_undo_depth is not zero). This has changed with the Undo refactor, so in essence the root cause is the same as T77557, Legacy Undo does not suffer from the crash (but misses the generally useful undo push from the console still) Now add Undo to CONSOLE_OT_execute bl_options ('UNDO_GROUPED' seems more appropriate than plain 'UNDO' since pasting multiple lines of code will call CONSOLE_OT_execute multiple times in a row). Maniphest Tasks: T86293 Differential Revision: https://developer.blender.org/D10625 --- release/scripts/startup/bl_operators/console.py | 1 + 1 file changed, 1 insertion(+) diff --git a/release/scripts/startup/bl_operators/console.py b/release/scripts/startup/bl_operators/console.py index 231dade820d..cd6728d56b2 100644 --- a/release/scripts/startup/bl_operators/console.py +++ b/release/scripts/startup/bl_operators/console.py @@ -37,6 +37,7 @@ class ConsoleExec(Operator): """Execute the current console line as a python expression""" bl_idname = "console.execute" bl_label = "Console Execute" + bl_options = {'UNDO_GROUPED'} interactive: BoolProperty( options={'SKIP_SAVE'}, -- cgit v1.2.3 From b12be5a872e308ee356b1da96a7f71346618b616 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 10:41:45 +0100 Subject: Cleanup: Remove static struct without data. --- source/blender/compositor/intern/COM_Converter.cpp | 14 ++-- source/blender/compositor/intern/COM_Converter.h | 78 ++++++++-------------- .../compositor/intern/COM_ExecutionSystem.h | 2 +- source/blender/compositor/intern/COM_NodeGraph.cpp | 4 +- .../compositor/intern/COM_NodeOperationBuilder.cpp | 4 +- 5 files changed, 41 insertions(+), 61 deletions(-) diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index 08035940667..c8ac86ccd5b 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -115,9 +115,9 @@ #include "COM_ViewerNode.h" #include "COM_ZCombineNode.h" -bool Converter::is_fast_node(bNode *b_node) +bool COM_bnode_is_fast_node(const bNode &b_node) { - return !ELEM(b_node->type, + return !ELEM(b_node.type, CMP_NODE_BLUR, CMP_NODE_VECBLUR, CMP_NODE_BILATERALBLUR, @@ -132,7 +132,7 @@ bool Converter::is_fast_node(bNode *b_node) CMP_NODE_DENOISE); } -Node *Converter::convert(bNode *b_node) +Node *COM_convert_bnode(bNode *b_node) { Node *node = nullptr; @@ -419,7 +419,7 @@ Node *Converter::convert(bNode *b_node) return node; } -NodeOperation *Converter::convertDataType(NodeOperationOutput *from, NodeOperationInput *to) +NodeOperation *COM_convert_data_type(NodeOperationOutput *from, NodeOperationInput *to) { DataType fromDatatype = from->getDataType(); DataType toDatatype = to->getDataType(); @@ -446,9 +446,9 @@ NodeOperation *Converter::convertDataType(NodeOperationOutput *from, NodeOperati return nullptr; } -void Converter::convertResolution(NodeOperationBuilder &builder, - NodeOperationOutput *fromSocket, - NodeOperationInput *toSocket) +void COM_convert_resolution(NodeOperationBuilder &builder, + NodeOperationOutput *fromSocket, + NodeOperationInput *toSocket) { InputResizeMode mode = toSocket->getResizeMode(); diff --git a/source/blender/compositor/intern/COM_Converter.h b/source/blender/compositor/intern/COM_Converter.h index fe3b8b75ccc..f110cc99c62 100644 --- a/source/blender/compositor/intern/COM_Converter.h +++ b/source/blender/compositor/intern/COM_Converter.h @@ -31,56 +31,36 @@ class NodeOperationOutput; class NodeOperationBuilder; /** - * \brief Conversion methods for the compositor + * \brief Wraps a bNode in its Node instance. + * + * For all nodetypes a wrapper class is created. + * + * \note When adding a new node to blender, this method needs to be changed to return the correct + * Node instance. + * + * \see Node */ -class Converter { - public: - /** - * \brief Convert/wraps a bNode in its Node instance. - * - * For all nodetypes a wrapper class is created. - * - * \note When adding a new node to blender, this method needs to be changed to return the correct - * Node instance. - * - * \see Node - */ - static Node *convert(bNode *b_node); - - /** - * \brief True if the node is considered 'fast'. - * - * Slow nodes will be skipped if fast execution is required. - */ - static bool is_fast_node(bNode *b_node); +Node *COM_convert_bnode(bNode *b_node); - /** - * \brief This method will add a datetype conversion rule when the to-socket does not support the - * from-socket actual data type. - * - * \note this method is called when conversion is needed. - * - * \param link: the NodeLink what needs conversion - * \param system: the ExecutionSystem to add the conversion to. - * \see NodeLink - a link between two sockets - */ - static NodeOperation *convertDataType(NodeOperationOutput *from, NodeOperationInput *to); +/** + * \brief True if the node is considered 'fast'. + * + * Slow nodes will be skipped if fast execution is required. + */ +bool COM_bnode_is_fast_node(const bNode &b_node); - /** - * \brief This method will add a resolution rule based on the settings of the NodeInput. - * - * \note Conversion logic is implemented in this method - * \see InputSocketResizeMode for the possible conversions. - * - * \param link: the NodeLink what needs conversion - * \param system: the ExecutionSystem to add the conversion to. - * \see NodeLink - a link between two sockets - */ - static void convertResolution(NodeOperationBuilder &builder, - NodeOperationOutput *fromSocket, - NodeOperationInput *toSocket); +/** + * \brief This function will add a datetype conversion rule when the to-socket does not support the + * from-socket actual data type. + */ +NodeOperation *COM_convert_data_type(NodeOperationOutput *from, NodeOperationInput *to); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("COM:Converter") -#endif -}; +/** + * \brief This function will add a resolution rule based on the settings of the NodeInput. + * + * \note Conversion logic is implemented in this function. + * \see InputSocketResizeMode for the possible conversions. + */ +void COM_convert_resolution(NodeOperationBuilder &builder, + NodeOperationOutput *fromSocket, + NodeOperationInput *toSocket); diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index 44b47787b06..d03f9b86bb6 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -79,7 +79,7 @@ class ExecutionGroup; * - [@ref InputSocketResizeMode.COM_SC_NO_RESIZE]: * Bottom left of the images are aligned. * - * \see Converter.convertDataType Datatype conversions + * \see COM_convert_data_type Datatype conversions * \see Converter.convertResolution Image size conversions * * \section EM_Step4 Step4: group operations in executions groups diff --git a/source/blender/compositor/intern/COM_NodeGraph.cpp b/source/blender/compositor/intern/COM_NodeGraph.cpp index b604b8ced88..dc5ae52ba8e 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.cpp +++ b/source/blender/compositor/intern/COM_NodeGraph.cpp @@ -132,7 +132,7 @@ void NodeGraph::add_bNode(const CompositorContext &context, } /* replace slow nodes with proxies for fast execution */ - if (context.isFastCalculation() && !Converter::is_fast_node(b_node)) { + if (context.isFastCalculation() && !COM_bnode_is_fast_node(*b_node)) { add_proxies_skip(b_ntree, b_node, key, is_active_group); return; } @@ -146,7 +146,7 @@ void NodeGraph::add_bNode(const CompositorContext &context, } else { /* regular nodes, handled in Converter */ - Node *node = Converter::convert(b_node); + Node *node = COM_convert_bnode(b_node); if (node) { add_node(node, b_ntree, key, is_active_group); } diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp index 35a3314db3b..769d1342819 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp @@ -288,7 +288,7 @@ void NodeOperationBuilder::add_datatype_conversions() } for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) { const Link &link = *it; - NodeOperation *converter = Converter::convertDataType(link.from(), link.to()); + NodeOperation *converter = COM_convert_data_type(link.from(), link.to()); if (converter) { addOperation(converter); @@ -446,7 +446,7 @@ void NodeOperationBuilder::determineResolutions() } for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) { const Link &link = *it; - Converter::convertResolution(*this, link.from(), link.to()); + COM_convert_resolution(*this, link.from(), link.to()); } } } -- cgit v1.2.3 From a592f7e6cbd30c65360cdeb912bc29afb40a7daf Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 10:54:29 +0100 Subject: Cleanup: COM_convert_data_types parameters. --- source/blender/compositor/intern/COM_Converter.cpp | 19 ++++++++++--------- source/blender/compositor/intern/COM_Converter.h | 3 ++- .../compositor/intern/COM_NodeOperationBuilder.cpp | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index c8ac86ccd5b..7d897d29576 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -419,27 +419,28 @@ Node *COM_convert_bnode(bNode *b_node) return node; } -NodeOperation *COM_convert_data_type(NodeOperationOutput *from, NodeOperationInput *to) +/* TODO(jbakker): make this an std::optional. */ +NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, const NodeOperationInput &to) { - DataType fromDatatype = from->getDataType(); - DataType toDatatype = to->getDataType(); + const DataType src_data_type = from.getDataType(); + const DataType dst_data_type = to.getDataType(); - if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_COLOR) { + if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_COLOR) { return new ConvertValueToColorOperation(); } - if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_VECTOR) { + if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_VECTOR) { return new ConvertValueToVectorOperation(); } - if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VALUE) { + if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VALUE) { return new ConvertColorToValueOperation(); } - if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VECTOR) { + if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VECTOR) { return new ConvertColorToVectorOperation(); } - if (fromDatatype == COM_DT_VECTOR && toDatatype == COM_DT_VALUE) { + if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_VALUE) { return new ConvertVectorToValueOperation(); } - if (fromDatatype == COM_DT_VECTOR && toDatatype == COM_DT_COLOR) { + if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_COLOR) { return new ConvertVectorToColorOperation(); } diff --git a/source/blender/compositor/intern/COM_Converter.h b/source/blender/compositor/intern/COM_Converter.h index f110cc99c62..59be34bf0e3 100644 --- a/source/blender/compositor/intern/COM_Converter.h +++ b/source/blender/compositor/intern/COM_Converter.h @@ -53,7 +53,8 @@ bool COM_bnode_is_fast_node(const bNode &b_node); * \brief This function will add a datetype conversion rule when the to-socket does not support the * from-socket actual data type. */ -NodeOperation *COM_convert_data_type(NodeOperationOutput *from, NodeOperationInput *to); +NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, + const NodeOperationInput &to); /** * \brief This function will add a resolution rule based on the settings of the NodeInput. diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp index 769d1342819..37d8d44ec72 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp @@ -288,7 +288,7 @@ void NodeOperationBuilder::add_datatype_conversions() } for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) { const Link &link = *it; - NodeOperation *converter = COM_convert_data_type(link.from(), link.to()); + NodeOperation *converter = COM_convert_data_type(*link.from(), *link.to()); if (converter) { addOperation(converter); -- cgit v1.2.3 From e0442a955badbbf7ee6f280bb988054175802bc1 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 5 Mar 2021 12:28:15 +0100 Subject: UI Code Quality: Port Outliner Grease Pencil layers to new design Continuation of work in 2e221de4ceee and 249e4df110e0. Now the tree-element types have to be ported one by one. This is probably the most straight forward type to port. --- .../blender/editors/space_outliner/CMakeLists.txt | 2 ++ .../blender/editors/space_outliner/outliner_tree.c | 14 ++++---- .../editors/space_outliner/tree/tree_element.cc | 3 ++ .../tree/tree_element_gpencil_layer.cc | 40 ++++++++++++++++++++++ .../tree/tree_element_gpencil_layer.hh | 34 ++++++++++++++++++ 5 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index d54265aa292..040410c0bdd 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -57,6 +57,7 @@ set(SRC tree/tree_element.cc tree/tree_element_anim_data.cc tree/tree_element_driver_base.cc + tree/tree_element_gpencil_layer.cc tree/tree_element_nla.cc outliner_intern.h @@ -66,6 +67,7 @@ set(SRC tree/tree_element.hh tree/tree_element_anim_data.hh tree/tree_element_driver_base.hh + tree/tree_element_gpencil_layer.hh tree/tree_element_nla.hh ) diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index f94f19246fa..0d82ba992c2 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1016,16 +1016,16 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, outliner_add_id_contents(space_outliner, te, tselem, id); } } - else if (ELEM(type, TSE_ANIM_DATA, TSE_DRIVER_BASE, TSE_NLA, TSE_NLA_ACTION, TSE_NLA_TRACK)) { + else if (ELEM(type, + TSE_ANIM_DATA, + TSE_DRIVER_BASE, + TSE_NLA, + TSE_NLA_ACTION, + TSE_NLA_TRACK, + TSE_GP_LAYER)) { /* Should already use new AbstractTreeElement design. */ BLI_assert(0); } - else if (type == TSE_GP_LAYER) { - bGPDlayer *gpl = (bGPDlayer *)idv; - - te->name = gpl->info; - te->directdata = gpl; - } else if (type == TSE_SEQUENCE) { Sequence *seq = (Sequence *)idv; diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index 27846614994..a692aae37c3 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -22,6 +22,7 @@ #include "tree_element_anim_data.hh" #include "tree_element_driver_base.hh" +#include "tree_element_gpencil_layer.hh" #include "tree_element_nla.hh" #include "tree_element.h" @@ -46,6 +47,8 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te return new TreeElementNLATrack(legacy_te, *static_cast(idv)); case TSE_NLA_ACTION: return new TreeElementNLAAction(legacy_te); + case TSE_GP_LAYER: + return new TreeElementGPencilLayer(legacy_te, *static_cast(idv)); default: break; } diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc new file mode 100644 index 00000000000..91e6fdcde4b --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc @@ -0,0 +1,40 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_utildefines.h" + +#include "DNA_gpencil_types.h" + +#include "../outliner_intern.h" + +#include "tree_element_gpencil_layer.hh" + +namespace blender::ed::outliner { + +TreeElementGPencilLayer::TreeElementGPencilLayer(TreeElement &legacy_te, bGPDlayer &gplayer) + : AbstractTreeElement(legacy_te) +{ + BLI_assert(legacy_te.store_elem->type == TSE_GP_LAYER); + /* this element's info */ + legacy_te.name = gplayer.info; + legacy_te.directdata = &gplayer; +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh new file mode 100644 index 00000000000..dd18dd42344 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +struct bGPDlayer; + +namespace blender::ed::outliner { + +class TreeElementGPencilLayer : public AbstractTreeElement { + public: + TreeElementGPencilLayer(TreeElement &legacy_te, bGPDlayer &gplayer); +}; + +} // namespace blender::ed::outliner -- cgit v1.2.3 From 0dd9a4a576452007da9d3f02a03499e50a8ddfae Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 5 Mar 2021 14:42:30 +0100 Subject: Cleanup: Libmv, clang-format Is based on Google style which was used in the Libmv project before, but is now consistently applied for the sources of the library itself and to C-API. With some time C-API will likely be removed, and it makes it easier to make it follow Libmv style, hence the diversion from Blender's style. There are quite some exceptions (clang-format off) in the code around Eigen matrix initialization. It is rather annoying, and there could be some neat way to make initialization readable without such exception. Could be some places where loss of readability in matrix initialization got lost as the change is quite big. If this has happened it is easier to address readability once actually working on the code. This change allowed to spot some missing header guards, so that's nice. Doing it in bundled version, as the upstream library needs to have some of the recent development ported over from bundle to upstream. There should be no functional changes. --- intern/libmv/.clang-format | 36 +- intern/libmv/intern/autotrack.cc | 35 +- intern/libmv/intern/autotrack.h | 10 +- intern/libmv/intern/camera_intrinsics.cc | 436 +++++++-------- intern/libmv/intern/camera_intrinsics.h | 12 +- intern/libmv/intern/detector.cc | 16 +- intern/libmv/intern/detector.h | 2 +- intern/libmv/intern/frame_accessor.cc | 101 ++-- intern/libmv/intern/frame_accessor.h | 19 +- intern/libmv/intern/homography.cc | 6 +- intern/libmv/intern/image.cc | 64 +-- intern/libmv/intern/image.h | 30 +- intern/libmv/intern/reconstruction.cc | 229 ++++---- intern/libmv/intern/reconstruction.h | 46 +- intern/libmv/intern/stub.cc | 214 ++++--- intern/libmv/intern/track_region.cc | 43 +- intern/libmv/intern/track_region.h | 8 +- intern/libmv/intern/tracks.cc | 6 +- intern/libmv/intern/tracksN.cc | 39 +- intern/libmv/intern/tracksN.h | 10 +- intern/libmv/intern/utildefines.h | 36 +- intern/libmv/libmv/autotrack/autotrack.cc | 68 ++- intern/libmv/libmv/autotrack/autotrack.h | 58 +- intern/libmv/libmv/autotrack/frame_accessor.h | 9 +- intern/libmv/libmv/autotrack/marker.h | 39 +- intern/libmv/libmv/autotrack/model.h | 9 +- intern/libmv/libmv/autotrack/predict_tracks.cc | 60 +- .../libmv/libmv/autotrack/predict_tracks_test.cc | 44 +- intern/libmv/libmv/autotrack/quad.h | 6 +- intern/libmv/libmv/autotrack/reconstruction.h | 12 +- intern/libmv/libmv/autotrack/region.h | 2 +- intern/libmv/libmv/autotrack/tracks.cc | 43 +- intern/libmv/libmv/autotrack/tracks.h | 12 +- intern/libmv/libmv/autotrack/tracks_test.cc | 2 +- intern/libmv/libmv/base/aligned_malloc.cc | 6 +- intern/libmv/libmv/base/aligned_malloc.h | 4 +- intern/libmv/libmv/base/id_generator.h | 1 + intern/libmv/libmv/base/map.h | 2 +- intern/libmv/libmv/base/scoped_ptr.h | 38 +- intern/libmv/libmv/base/scoped_ptr_test.cc | 8 +- intern/libmv/libmv/base/vector_test.cc | 8 +- intern/libmv/libmv/base/vector_utils.h | 5 +- intern/libmv/libmv/image/array_nd.cc | 27 +- intern/libmv/libmv/image/array_nd.h | 188 +++---- intern/libmv/libmv/image/array_nd_test.cc | 10 +- intern/libmv/libmv/image/convolve.cc | 170 +++--- intern/libmv/libmv/image/convolve.h | 62 +-- intern/libmv/libmv/image/convolve_test.cc | 12 +- intern/libmv/libmv/image/correlation.h | 11 +- intern/libmv/libmv/image/image.h | 93 ++-- intern/libmv/libmv/image/image_converter.h | 21 +- intern/libmv/libmv/image/image_drawing.h | 112 ++-- intern/libmv/libmv/image/image_test.cc | 6 +- intern/libmv/libmv/image/sample.h | 40 +- intern/libmv/libmv/image/sample_test.cc | 14 +- intern/libmv/libmv/image/tuple.h | 32 +- intern/libmv/libmv/multiview/conditioning.cc | 28 +- intern/libmv/libmv/multiview/conditioning.h | 24 +- .../libmv/libmv/multiview/euclidean_resection.cc | 198 +++---- intern/libmv/libmv/multiview/euclidean_resection.h | 47 +- .../libmv/multiview/euclidean_resection_test.cc | 74 ++- intern/libmv/libmv/multiview/fundamental.cc | 227 ++++---- intern/libmv/libmv/multiview/fundamental.h | 115 ++-- intern/libmv/libmv/multiview/fundamental_test.cc | 8 +- intern/libmv/libmv/multiview/homography.cc | 249 ++++----- intern/libmv/libmv/multiview/homography.h | 34 +- intern/libmv/libmv/multiview/homography_error.h | 120 ++-- .../libmv/multiview/homography_parameterization.h | 36 +- intern/libmv/libmv/multiview/homography_test.cc | 40 +- intern/libmv/libmv/multiview/nviewtriangulation.h | 32 +- .../libmv/multiview/nviewtriangulation_test.cc | 4 +- intern/libmv/libmv/multiview/panography.cc | 47 +- intern/libmv/libmv/multiview/panography.h | 12 +- intern/libmv/libmv/multiview/panography_kernel.cc | 4 +- intern/libmv/libmv/multiview/panography_kernel.h | 18 +- intern/libmv/libmv/multiview/panography_test.cc | 26 +- intern/libmv/libmv/multiview/projection.cc | 58 +- intern/libmv/libmv/multiview/projection.h | 124 ++--- intern/libmv/libmv/multiview/projection_test.cc | 18 +- intern/libmv/libmv/multiview/resection.h | 18 +- intern/libmv/libmv/multiview/resection_test.cc | 8 +- intern/libmv/libmv/multiview/test_data_sets.cc | 33 +- intern/libmv/libmv/multiview/test_data_sets.h | 42 +- intern/libmv/libmv/multiview/triangulation.cc | 18 +- intern/libmv/libmv/multiview/triangulation.h | 16 +- intern/libmv/libmv/multiview/triangulation_test.cc | 2 +- intern/libmv/libmv/multiview/two_view_kernel.h | 31 +- intern/libmv/libmv/numeric/dogleg.h | 119 ++-- intern/libmv/libmv/numeric/dogleg_test.cc | 31 +- intern/libmv/libmv/numeric/function_derivative.h | 17 +- .../libmv/numeric/function_derivative_test.cc | 18 +- intern/libmv/libmv/numeric/levenberg_marquardt.h | 70 +-- .../libmv/numeric/levenberg_marquardt_test.cc | 10 +- intern/libmv/libmv/numeric/numeric.cc | 36 +- intern/libmv/libmv/numeric/numeric.h | 393 +++++++------ intern/libmv/libmv/numeric/numeric_test.cc | 92 ++- intern/libmv/libmv/numeric/poly.h | 29 +- intern/libmv/libmv/numeric/poly_test.cc | 26 +- intern/libmv/libmv/simple_pipeline/bundle.cc | 458 +++++++-------- intern/libmv/libmv/simple_pipeline/bundle.h | 35 +- intern/libmv/libmv/simple_pipeline/callbacks.h | 2 +- .../libmv/simple_pipeline/camera_intrinsics.cc | 279 +++++----- .../libmv/simple_pipeline/camera_intrinsics.h | 104 ++-- .../libmv/simple_pipeline/camera_intrinsics_impl.h | 143 +++-- .../simple_pipeline/camera_intrinsics_test.cc | 129 +++-- intern/libmv/libmv/simple_pipeline/detect.cc | 172 +++--- intern/libmv/libmv/simple_pipeline/detect.h | 17 +- intern/libmv/libmv/simple_pipeline/detect_test.cc | 19 +- .../libmv/simple_pipeline/distortion_models.cc | 193 ++++--- .../libmv/simple_pipeline/distortion_models.h | 129 +++-- .../simple_pipeline/initialize_reconstruction.cc | 42 +- .../simple_pipeline/initialize_reconstruction.h | 29 +- intern/libmv/libmv/simple_pipeline/intersect.cc | 82 +-- intern/libmv/libmv/simple_pipeline/intersect.h | 16 +- .../libmv/libmv/simple_pipeline/intersect_test.cc | 18 +- .../libmv/simple_pipeline/keyframe_selection.cc | 107 ++-- .../libmv/simple_pipeline/keyframe_selection.h | 9 +- .../simple_pipeline/keyframe_selection_test.cc | 478 +++++++++++----- intern/libmv/libmv/simple_pipeline/modal_solver.cc | 59 +- intern/libmv/libmv/simple_pipeline/modal_solver.h | 10 +- .../libmv/simple_pipeline/modal_solver_test.cc | 31 +- .../libmv/simple_pipeline/packed_intrinsics.h | 18 +- intern/libmv/libmv/simple_pipeline/pipeline.cc | 192 +++---- intern/libmv/libmv/simple_pipeline/pipeline.h | 31 +- .../libmv/libmv/simple_pipeline/reconstruction.cc | 67 +-- .../libmv/libmv/simple_pipeline/reconstruction.h | 41 +- .../libmv/simple_pipeline/reconstruction_scale.cc | 6 +- .../libmv/simple_pipeline/reconstruction_scale.h | 2 +- intern/libmv/libmv/simple_pipeline/resect.cc | 80 +-- intern/libmv/libmv/simple_pipeline/resect.h | 11 +- intern/libmv/libmv/simple_pipeline/resect_test.cc | 4 +- intern/libmv/libmv/simple_pipeline/tracks.cc | 30 +- intern/libmv/libmv/simple_pipeline/tracks.h | 16 +- intern/libmv/libmv/threading/threading.h | 2 +- .../libmv/libmv/tracking/brute_region_tracker.cc | 195 ++++--- intern/libmv/libmv/tracking/brute_region_tracker.h | 14 +- .../libmv/libmv/tracking/hybrid_region_tracker.cc | 12 +- .../libmv/libmv/tracking/hybrid_region_tracker.h | 19 +- intern/libmv/libmv/tracking/kalman_filter.h | 68 ++- intern/libmv/libmv/tracking/klt_region_tracker.cc | 63 ++- intern/libmv/libmv/tracking/klt_region_tracker.h | 10 +- .../libmv/libmv/tracking/pyramid_region_tracker.cc | 19 +- .../libmv/libmv/tracking/pyramid_region_tracker.h | 15 +- .../libmv/tracking/pyramid_region_tracker_test.cc | 10 +- intern/libmv/libmv/tracking/region_tracker.h | 10 +- .../libmv/libmv/tracking/retrack_region_tracker.cc | 10 +- .../libmv/libmv/tracking/retrack_region_tracker.h | 15 +- intern/libmv/libmv/tracking/track_region.cc | 620 +++++++++++---------- intern/libmv/libmv/tracking/track_region.h | 34 +- .../libmv/libmv/tracking/trklt_region_tracker.cc | 63 ++- intern/libmv/libmv/tracking/trklt_region_tracker.h | 10 +- 151 files changed, 4928 insertions(+), 4504 deletions(-) diff --git a/intern/libmv/.clang-format b/intern/libmv/.clang-format index 9d159247d51..fae0530c572 100644 --- a/intern/libmv/.clang-format +++ b/intern/libmv/.clang-format @@ -1,2 +1,34 @@ -DisableFormat: true -SortIncludes: false +BasedOnStyle: Google + +ColumnLimit: 80 + +Standard: Cpp11 + +# Indent nested preprocessor. +# #ifdef Foo +# # include +# #endif +IndentPPDirectives: AfterHash + +# For the cases when namespace is closing with a wrong comment +FixNamespaceComments: true + +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortBlocksOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true + +# No bin packing, every argument is on its own line. +BinPackArguments: false +BinPackParameters: false + +# Ensure pointer alignment. +# ObjectType* object; +PointerAlignment: Left +DerivePointerAlignment: false + +AlignEscapedNewlines: Right + +IncludeBlocks: Preserve +SortIncludes: true diff --git a/intern/libmv/intern/autotrack.cc b/intern/libmv/intern/autotrack.cc index 7000a422de8..b7110957b15 100644 --- a/intern/libmv/intern/autotrack.cc +++ b/intern/libmv/intern/autotrack.cc @@ -22,15 +22,15 @@ #include "intern/utildefines.h" #include "libmv/autotrack/autotrack.h" +using libmv::TrackRegionOptions; +using libmv::TrackRegionResult; using mv::AutoTrack; using mv::FrameAccessor; using mv::Marker; -using libmv::TrackRegionOptions; -using libmv::TrackRegionResult; -libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor *frame_accessor) { - return (libmv_AutoTrack*) LIBMV_OBJECT_NEW(AutoTrack, - (FrameAccessor*) frame_accessor); +libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* frame_accessor) { + return (libmv_AutoTrack*)LIBMV_OBJECT_NEW(AutoTrack, + (FrameAccessor*)frame_accessor); } void libmv_autoTrackDestroy(libmv_AutoTrack* libmv_autotrack) { @@ -39,7 +39,7 @@ void libmv_autoTrackDestroy(libmv_AutoTrack* libmv_autotrack) { void libmv_autoTrackSetOptions(libmv_AutoTrack* libmv_autotrack, const libmv_AutoTrackOptions* options) { - AutoTrack *autotrack = ((AutoTrack*) libmv_autotrack); + AutoTrack* autotrack = ((AutoTrack*)libmv_autotrack); libmv_configureTrackRegionOptions(options->track_region, &autotrack->options.track_region); @@ -51,18 +51,15 @@ void libmv_autoTrackSetOptions(libmv_AutoTrack* libmv_autotrack, int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack, const libmv_TrackRegionOptions* libmv_options, - libmv_Marker *libmv_tracked_marker, + libmv_Marker* libmv_tracked_marker, libmv_TrackRegionResult* libmv_result) { - Marker tracked_marker; TrackRegionOptions options; TrackRegionResult result; libmv_apiMarkerToMarker(*libmv_tracked_marker, &tracked_marker); - libmv_configureTrackRegionOptions(*libmv_options, - &options); - bool ok = (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker, - &result, - &options)); + libmv_configureTrackRegionOptions(*libmv_options, &options); + bool ok = (((AutoTrack*)libmv_autotrack) + ->TrackMarker(&tracked_marker, &result, &options)); libmv_markerToApiMarker(tracked_marker, libmv_tracked_marker); libmv_regionTrackergetResult(result, libmv_result); return ok && result.is_usable(); @@ -72,7 +69,7 @@ void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack, const libmv_Marker* libmv_marker) { Marker marker; libmv_apiMarkerToMarker(*libmv_marker, &marker); - ((AutoTrack*) libmv_autotrack)->AddMarker(marker); + ((AutoTrack*)libmv_autotrack)->AddMarker(marker); } void libmv_autoTrackSetMarkers(libmv_AutoTrack* libmv_autotrack, @@ -87,19 +84,17 @@ void libmv_autoTrackSetMarkers(libmv_AutoTrack* libmv_autotrack, for (size_t i = 0; i < num_markers; ++i) { libmv_apiMarkerToMarker(libmv_marker[i], &markers[i]); } - ((AutoTrack*) libmv_autotrack)->SetMarkers(&markers); + ((AutoTrack*)libmv_autotrack)->SetMarkers(&markers); } int libmv_autoTrackGetMarker(libmv_AutoTrack* libmv_autotrack, int clip, int frame, int track, - libmv_Marker *libmv_marker) { + libmv_Marker* libmv_marker) { Marker marker; - int ok = ((AutoTrack*) libmv_autotrack)->GetMarker(clip, - frame, - track, - &marker); + int ok = + ((AutoTrack*)libmv_autotrack)->GetMarker(clip, frame, track, &marker); if (ok) { libmv_markerToApiMarker(marker, libmv_marker); } diff --git a/intern/libmv/intern/autotrack.h b/intern/libmv/intern/autotrack.h index 6b49a6908e1..3887983814b 100644 --- a/intern/libmv/intern/autotrack.h +++ b/intern/libmv/intern/autotrack.h @@ -21,9 +21,9 @@ #define LIBMV_C_API_AUTOTRACK_H_ #include "intern/frame_accessor.h" -#include "intern/tracksN.h" -#include "intern/track_region.h" #include "intern/region.h" +#include "intern/track_region.h" +#include "intern/tracksN.h" #ifdef __cplusplus extern "C" { @@ -36,7 +36,7 @@ typedef struct libmv_AutoTrackOptions { libmv_Region search_region; } libmv_AutoTrackOptions; -libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor *frame_accessor); +libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* frame_accessor); void libmv_autoTrackDestroy(libmv_AutoTrack* libmv_autotrack); @@ -45,7 +45,7 @@ void libmv_autoTrackSetOptions(libmv_AutoTrack* libmv_autotrack, int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack, const libmv_TrackRegionOptions* libmv_options, - libmv_Marker *libmv_tracker_marker, + libmv_Marker* libmv_tracker_marker, libmv_TrackRegionResult* libmv_result); void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack, @@ -59,7 +59,7 @@ int libmv_autoTrackGetMarker(libmv_AutoTrack* libmv_autotrack, int clip, int frame, int track, - libmv_Marker *libmv_marker); + libmv_Marker* libmv_marker); #ifdef __cplusplus } diff --git a/intern/libmv/intern/camera_intrinsics.cc b/intern/libmv/intern/camera_intrinsics.cc index 628637e12cc..243b26d9fb3 100644 --- a/intern/libmv/intern/camera_intrinsics.cc +++ b/intern/libmv/intern/camera_intrinsics.cc @@ -21,62 +21,56 @@ #include "intern/utildefines.h" #include "libmv/simple_pipeline/camera_intrinsics.h" +using libmv::BrownCameraIntrinsics; using libmv::CameraIntrinsics; using libmv::DivisionCameraIntrinsics; -using libmv::PolynomialCameraIntrinsics; using libmv::NukeCameraIntrinsics; -using libmv::BrownCameraIntrinsics; +using libmv::PolynomialCameraIntrinsics; -libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( +libmv_CameraIntrinsics* libmv_cameraIntrinsicsNew( const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options) { - CameraIntrinsics *camera_intrinsics = - libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); - return (libmv_CameraIntrinsics *) camera_intrinsics; + CameraIntrinsics* camera_intrinsics = + libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); + return (libmv_CameraIntrinsics*)camera_intrinsics; } -libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( +libmv_CameraIntrinsics* libmv_cameraIntrinsicsCopy( const libmv_CameraIntrinsics* libmv_intrinsics) { - const CameraIntrinsics *orig_intrinsics = - (const CameraIntrinsics *) libmv_intrinsics; + const CameraIntrinsics* orig_intrinsics = + (const CameraIntrinsics*)libmv_intrinsics; - CameraIntrinsics *new_intrinsics = NULL; + CameraIntrinsics* new_intrinsics = NULL; switch (orig_intrinsics->GetDistortionModelType()) { - case libmv::DISTORTION_MODEL_POLYNOMIAL: - { - const PolynomialCameraIntrinsics *polynomial_intrinsics = + case libmv::DISTORTION_MODEL_POLYNOMIAL: { + const PolynomialCameraIntrinsics* polynomial_intrinsics = static_cast(orig_intrinsics); - new_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics, - *polynomial_intrinsics); - break; - } - case libmv::DISTORTION_MODEL_DIVISION: - { - const DivisionCameraIntrinsics *division_intrinsics = + new_intrinsics = + LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics, *polynomial_intrinsics); + break; + } + case libmv::DISTORTION_MODEL_DIVISION: { + const DivisionCameraIntrinsics* division_intrinsics = static_cast(orig_intrinsics); - new_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics, - *division_intrinsics); - break; - } - case libmv::DISTORTION_MODEL_NUKE: - { - const NukeCameraIntrinsics *nuke_intrinsics = + new_intrinsics = + LIBMV_OBJECT_NEW(DivisionCameraIntrinsics, *division_intrinsics); + break; + } + case libmv::DISTORTION_MODEL_NUKE: { + const NukeCameraIntrinsics* nuke_intrinsics = static_cast(orig_intrinsics); - new_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics, - *nuke_intrinsics); - break; - } - case libmv::DISTORTION_MODEL_BROWN: - { - const BrownCameraIntrinsics *brown_intrinsics = + new_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics, *nuke_intrinsics); + break; + } + case libmv::DISTORTION_MODEL_BROWN: { + const BrownCameraIntrinsics* brown_intrinsics = static_cast(orig_intrinsics); - new_intrinsics = LIBMV_OBJECT_NEW(BrownCameraIntrinsics, - *brown_intrinsics); - break; - } - default: - assert(!"Unknown distortion model"); + new_intrinsics = + LIBMV_OBJECT_NEW(BrownCameraIntrinsics, *brown_intrinsics); + break; + } + default: assert(!"Unknown distortion model"); } - return (libmv_CameraIntrinsics *) new_intrinsics; + return (libmv_CameraIntrinsics*)new_intrinsics; } void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics) { @@ -86,7 +80,7 @@ void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics) { void libmv_cameraIntrinsicsUpdate( const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, libmv_CameraIntrinsics* libmv_intrinsics) { - CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; + CameraIntrinsics* camera_intrinsics = (CameraIntrinsics*)libmv_intrinsics; double focal_length = libmv_camera_intrinsics_options->focal_length; double principal_x = libmv_camera_intrinsics_options->principal_point_x; @@ -115,191 +109,173 @@ void libmv_cameraIntrinsicsUpdate( } switch (libmv_camera_intrinsics_options->distortion_model) { - case LIBMV_DISTORTION_MODEL_POLYNOMIAL: - { - assert(camera_intrinsics->GetDistortionModelType() == - libmv::DISTORTION_MODEL_POLYNOMIAL); - - PolynomialCameraIntrinsics *polynomial_intrinsics = - (PolynomialCameraIntrinsics *) camera_intrinsics; - - double k1 = libmv_camera_intrinsics_options->polynomial_k1; - double k2 = libmv_camera_intrinsics_options->polynomial_k2; - double k3 = libmv_camera_intrinsics_options->polynomial_k3; - - if (polynomial_intrinsics->k1() != k1 || - polynomial_intrinsics->k2() != k2 || - polynomial_intrinsics->k3() != k3) { - polynomial_intrinsics->SetRadialDistortion(k1, k2, k3); - } - break; + case LIBMV_DISTORTION_MODEL_POLYNOMIAL: { + assert(camera_intrinsics->GetDistortionModelType() == + libmv::DISTORTION_MODEL_POLYNOMIAL); + + PolynomialCameraIntrinsics* polynomial_intrinsics = + (PolynomialCameraIntrinsics*)camera_intrinsics; + + double k1 = libmv_camera_intrinsics_options->polynomial_k1; + double k2 = libmv_camera_intrinsics_options->polynomial_k2; + double k3 = libmv_camera_intrinsics_options->polynomial_k3; + + if (polynomial_intrinsics->k1() != k1 || + polynomial_intrinsics->k2() != k2 || + polynomial_intrinsics->k3() != k3) { + polynomial_intrinsics->SetRadialDistortion(k1, k2, k3); } + break; + } - case LIBMV_DISTORTION_MODEL_DIVISION: - { - assert(camera_intrinsics->GetDistortionModelType() == - libmv::DISTORTION_MODEL_DIVISION); + case LIBMV_DISTORTION_MODEL_DIVISION: { + assert(camera_intrinsics->GetDistortionModelType() == + libmv::DISTORTION_MODEL_DIVISION); - DivisionCameraIntrinsics *division_intrinsics = - (DivisionCameraIntrinsics *) camera_intrinsics; + DivisionCameraIntrinsics* division_intrinsics = + (DivisionCameraIntrinsics*)camera_intrinsics; - double k1 = libmv_camera_intrinsics_options->division_k1; - double k2 = libmv_camera_intrinsics_options->division_k2; + double k1 = libmv_camera_intrinsics_options->division_k1; + double k2 = libmv_camera_intrinsics_options->division_k2; - if (division_intrinsics->k1() != k1 || - division_intrinsics->k2() != k2) { - division_intrinsics->SetDistortion(k1, k2); - } + if (division_intrinsics->k1() != k1 || division_intrinsics->k2() != k2) { + division_intrinsics->SetDistortion(k1, k2); + } - break; + break; + } + + case LIBMV_DISTORTION_MODEL_NUKE: { + assert(camera_intrinsics->GetDistortionModelType() == + libmv::DISTORTION_MODEL_NUKE); + + NukeCameraIntrinsics* nuke_intrinsics = + (NukeCameraIntrinsics*)camera_intrinsics; + + double k1 = libmv_camera_intrinsics_options->nuke_k1; + double k2 = libmv_camera_intrinsics_options->nuke_k2; + + if (nuke_intrinsics->k1() != k1 || nuke_intrinsics->k2() != k2) { + nuke_intrinsics->SetDistortion(k1, k2); } - case LIBMV_DISTORTION_MODEL_NUKE: - { - assert(camera_intrinsics->GetDistortionModelType() == - libmv::DISTORTION_MODEL_NUKE); + break; + } - NukeCameraIntrinsics *nuke_intrinsics = - (NukeCameraIntrinsics *) camera_intrinsics; + case LIBMV_DISTORTION_MODEL_BROWN: { + assert(camera_intrinsics->GetDistortionModelType() == + libmv::DISTORTION_MODEL_BROWN); - double k1 = libmv_camera_intrinsics_options->nuke_k1; - double k2 = libmv_camera_intrinsics_options->nuke_k2; + BrownCameraIntrinsics* brown_intrinsics = + (BrownCameraIntrinsics*)camera_intrinsics; - if (nuke_intrinsics->k1() != k1 || - nuke_intrinsics->k2() != k2) { - nuke_intrinsics->SetDistortion(k1, k2); - } + double k1 = libmv_camera_intrinsics_options->brown_k1; + double k2 = libmv_camera_intrinsics_options->brown_k2; + double k3 = libmv_camera_intrinsics_options->brown_k3; + double k4 = libmv_camera_intrinsics_options->brown_k4; - break; + if (brown_intrinsics->k1() != k1 || brown_intrinsics->k2() != k2 || + brown_intrinsics->k3() != k3 || brown_intrinsics->k4() != k4) { + brown_intrinsics->SetRadialDistortion(k1, k2, k3, k4); } - case LIBMV_DISTORTION_MODEL_BROWN: - { - assert(camera_intrinsics->GetDistortionModelType() == - libmv::DISTORTION_MODEL_BROWN); - - BrownCameraIntrinsics *brown_intrinsics = - (BrownCameraIntrinsics *) camera_intrinsics; - - double k1 = libmv_camera_intrinsics_options->brown_k1; - double k2 = libmv_camera_intrinsics_options->brown_k2; - double k3 = libmv_camera_intrinsics_options->brown_k3; - double k4 = libmv_camera_intrinsics_options->brown_k4; - - if (brown_intrinsics->k1() != k1 || - brown_intrinsics->k2() != k2 || - brown_intrinsics->k3() != k3 || - brown_intrinsics->k4() != k4) { - brown_intrinsics->SetRadialDistortion(k1, k2, k3, k4); - } - - double p1 = libmv_camera_intrinsics_options->brown_p1; - double p2 = libmv_camera_intrinsics_options->brown_p2; - - if (brown_intrinsics->p1() != p1 || brown_intrinsics->p2() != p2) { - brown_intrinsics->SetTangentialDistortion(p1, p2); - } - break; + double p1 = libmv_camera_intrinsics_options->brown_p1; + double p2 = libmv_camera_intrinsics_options->brown_p2; + + if (brown_intrinsics->p1() != p1 || brown_intrinsics->p2() != p2) { + brown_intrinsics->SetTangentialDistortion(p1, p2); } + break; + } - default: - assert(!"Unknown distortion model"); + default: assert(!"Unknown distortion model"); } } void libmv_cameraIntrinsicsSetThreads(libmv_CameraIntrinsics* libmv_intrinsics, int threads) { - CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; + CameraIntrinsics* camera_intrinsics = (CameraIntrinsics*)libmv_intrinsics; camera_intrinsics->SetThreads(threads); } void libmv_cameraIntrinsicsExtractOptions( const libmv_CameraIntrinsics* libmv_intrinsics, libmv_CameraIntrinsicsOptions* camera_intrinsics_options) { - const CameraIntrinsics *camera_intrinsics = - (const CameraIntrinsics *) libmv_intrinsics; + const CameraIntrinsics* camera_intrinsics = + (const CameraIntrinsics*)libmv_intrinsics; // Fill in options which are common for all distortion models. camera_intrinsics_options->focal_length = camera_intrinsics->focal_length(); camera_intrinsics_options->principal_point_x = - camera_intrinsics->principal_point_x(); + camera_intrinsics->principal_point_x(); camera_intrinsics_options->principal_point_y = - camera_intrinsics->principal_point_y(); + camera_intrinsics->principal_point_y(); camera_intrinsics_options->image_width = camera_intrinsics->image_width(); camera_intrinsics_options->image_height = camera_intrinsics->image_height(); switch (camera_intrinsics->GetDistortionModelType()) { - case libmv::DISTORTION_MODEL_POLYNOMIAL: - { - const PolynomialCameraIntrinsics *polynomial_intrinsics = - static_cast(camera_intrinsics); - camera_intrinsics_options->distortion_model = + case libmv::DISTORTION_MODEL_POLYNOMIAL: { + const PolynomialCameraIntrinsics* polynomial_intrinsics = + static_cast(camera_intrinsics); + camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL; - camera_intrinsics_options->polynomial_k1 = polynomial_intrinsics->k1(); - camera_intrinsics_options->polynomial_k2 = polynomial_intrinsics->k2(); - camera_intrinsics_options->polynomial_k3 = polynomial_intrinsics->k3(); - camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p1(); - camera_intrinsics_options->polynomial_p2 = polynomial_intrinsics->p2(); - break; - } + camera_intrinsics_options->polynomial_k1 = polynomial_intrinsics->k1(); + camera_intrinsics_options->polynomial_k2 = polynomial_intrinsics->k2(); + camera_intrinsics_options->polynomial_k3 = polynomial_intrinsics->k3(); + camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p1(); + camera_intrinsics_options->polynomial_p2 = polynomial_intrinsics->p2(); + break; + } - case libmv::DISTORTION_MODEL_DIVISION: - { - const DivisionCameraIntrinsics *division_intrinsics = - static_cast(camera_intrinsics); - camera_intrinsics_options->distortion_model = + case libmv::DISTORTION_MODEL_DIVISION: { + const DivisionCameraIntrinsics* division_intrinsics = + static_cast(camera_intrinsics); + camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION; - camera_intrinsics_options->division_k1 = division_intrinsics->k1(); - camera_intrinsics_options->division_k2 = division_intrinsics->k2(); - break; - } - - case libmv::DISTORTION_MODEL_NUKE: - { - const NukeCameraIntrinsics *nuke_intrinsics = - static_cast(camera_intrinsics); - camera_intrinsics_options->distortion_model = - LIBMV_DISTORTION_MODEL_NUKE; - camera_intrinsics_options->nuke_k1 = nuke_intrinsics->k1(); - camera_intrinsics_options->nuke_k2 = nuke_intrinsics->k2(); - break; - } + camera_intrinsics_options->division_k1 = division_intrinsics->k1(); + camera_intrinsics_options->division_k2 = division_intrinsics->k2(); + break; + } + + case libmv::DISTORTION_MODEL_NUKE: { + const NukeCameraIntrinsics* nuke_intrinsics = + static_cast(camera_intrinsics); + camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_NUKE; + camera_intrinsics_options->nuke_k1 = nuke_intrinsics->k1(); + camera_intrinsics_options->nuke_k2 = nuke_intrinsics->k2(); + break; + } - case libmv::DISTORTION_MODEL_BROWN: - { - const BrownCameraIntrinsics *brown_intrinsics = - static_cast(camera_intrinsics); - camera_intrinsics_options->distortion_model = + case libmv::DISTORTION_MODEL_BROWN: { + const BrownCameraIntrinsics* brown_intrinsics = + static_cast(camera_intrinsics); + camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_BROWN; - camera_intrinsics_options->brown_k1 = brown_intrinsics->k1(); - camera_intrinsics_options->brown_k2 = brown_intrinsics->k2(); - camera_intrinsics_options->brown_k3 = brown_intrinsics->k3(); - camera_intrinsics_options->brown_k4 = brown_intrinsics->k4(); - camera_intrinsics_options->brown_p1 = brown_intrinsics->p1(); - camera_intrinsics_options->brown_p2 = brown_intrinsics->p2(); - break; - } + camera_intrinsics_options->brown_k1 = brown_intrinsics->k1(); + camera_intrinsics_options->brown_k2 = brown_intrinsics->k2(); + camera_intrinsics_options->brown_k3 = brown_intrinsics->k3(); + camera_intrinsics_options->brown_k4 = brown_intrinsics->k4(); + camera_intrinsics_options->brown_p1 = brown_intrinsics->p1(); + camera_intrinsics_options->brown_p2 = brown_intrinsics->p2(); + break; + } - default: - assert(!"Unknown distortion model"); + default: assert(!"Unknown distortion model"); } } void libmv_cameraIntrinsicsUndistortByte( const libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, + const unsigned char* source_image, int width, int height, float overscan, int channels, unsigned char* destination_image) { - CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; - camera_intrinsics->UndistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); + CameraIntrinsics* camera_intrinsics = (CameraIntrinsics*)libmv_intrinsics; + camera_intrinsics->UndistortBuffer( + source_image, width, height, overscan, channels, destination_image); } void libmv_cameraIntrinsicsUndistortFloat( @@ -310,28 +286,22 @@ void libmv_cameraIntrinsicsUndistortFloat( float overscan, int channels, float* destination_image) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; - intrinsics->UndistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); + CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics; + intrinsics->UndistortBuffer( + source_image, width, height, overscan, channels, destination_image); } void libmv_cameraIntrinsicsDistortByte( const struct libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, + const unsigned char* source_image, int width, int height, float overscan, int channels, - unsigned char *destination_image) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; - intrinsics->DistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); + unsigned char* destination_image) { + CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics; + intrinsics->DistortBuffer( + source_image, width, height, overscan, channels, destination_image); } void libmv_cameraIntrinsicsDistortFloat( @@ -342,12 +312,9 @@ void libmv_cameraIntrinsicsDistortFloat( float overscan, int channels, float* destination_image) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; - intrinsics->DistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); + CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics; + intrinsics->DistortBuffer( + source_image, width, height, overscan, channels, destination_image); } void libmv_cameraIntrinsicsApply( @@ -356,7 +323,7 @@ void libmv_cameraIntrinsicsApply( double y, double* x1, double* y1) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; + CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics; intrinsics->ApplyIntrinsics(x, y, x1, y1); } @@ -366,7 +333,7 @@ void libmv_cameraIntrinsicsInvert( double y, double* x1, double* y1) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; + CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics; intrinsics->InvertIntrinsics(x, y, x1, y1); } @@ -381,69 +348,63 @@ static void libmv_cameraIntrinsicsFillFromOptions( camera_intrinsics_options->principal_point_y); camera_intrinsics->SetImageSize(camera_intrinsics_options->image_width, - camera_intrinsics_options->image_height); + camera_intrinsics_options->image_height); switch (camera_intrinsics_options->distortion_model) { - case LIBMV_DISTORTION_MODEL_POLYNOMIAL: - { - PolynomialCameraIntrinsics *polynomial_intrinsics = + case LIBMV_DISTORTION_MODEL_POLYNOMIAL: { + PolynomialCameraIntrinsics* polynomial_intrinsics = static_cast(camera_intrinsics); - polynomial_intrinsics->SetRadialDistortion( - camera_intrinsics_options->polynomial_k1, - camera_intrinsics_options->polynomial_k2, - camera_intrinsics_options->polynomial_k3); + polynomial_intrinsics->SetRadialDistortion( + camera_intrinsics_options->polynomial_k1, + camera_intrinsics_options->polynomial_k2, + camera_intrinsics_options->polynomial_k3); - break; - } + break; + } - case LIBMV_DISTORTION_MODEL_DIVISION: - { - DivisionCameraIntrinsics *division_intrinsics = + case LIBMV_DISTORTION_MODEL_DIVISION: { + DivisionCameraIntrinsics* division_intrinsics = static_cast(camera_intrinsics); - division_intrinsics->SetDistortion( - camera_intrinsics_options->division_k1, - camera_intrinsics_options->division_k2); - break; - } + division_intrinsics->SetDistortion( + camera_intrinsics_options->division_k1, + camera_intrinsics_options->division_k2); + break; + } - case LIBMV_DISTORTION_MODEL_NUKE: - { - NukeCameraIntrinsics *nuke_intrinsics = + case LIBMV_DISTORTION_MODEL_NUKE: { + NukeCameraIntrinsics* nuke_intrinsics = static_cast(camera_intrinsics); - nuke_intrinsics->SetDistortion( - camera_intrinsics_options->nuke_k1, - camera_intrinsics_options->nuke_k2); - break; - } + nuke_intrinsics->SetDistortion(camera_intrinsics_options->nuke_k1, + camera_intrinsics_options->nuke_k2); + break; + } - case LIBMV_DISTORTION_MODEL_BROWN: - { - BrownCameraIntrinsics *brown_intrinsics = + case LIBMV_DISTORTION_MODEL_BROWN: { + BrownCameraIntrinsics* brown_intrinsics = static_cast(camera_intrinsics); - brown_intrinsics->SetRadialDistortion( - camera_intrinsics_options->brown_k1, - camera_intrinsics_options->brown_k2, - camera_intrinsics_options->brown_k3, - camera_intrinsics_options->brown_k4); - brown_intrinsics->SetTangentialDistortion( + brown_intrinsics->SetRadialDistortion( + camera_intrinsics_options->brown_k1, + camera_intrinsics_options->brown_k2, + camera_intrinsics_options->brown_k3, + camera_intrinsics_options->brown_k4); + brown_intrinsics->SetTangentialDistortion( camera_intrinsics_options->brown_p1, camera_intrinsics_options->brown_p2); - break; - } + break; + } - default: - assert(!"Unknown distortion model"); + default: assert(!"Unknown distortion model"); } } CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions( const libmv_CameraIntrinsicsOptions* camera_intrinsics_options) { - CameraIntrinsics *camera_intrinsics = NULL; + CameraIntrinsics* camera_intrinsics = NULL; switch (camera_intrinsics_options->distortion_model) { case LIBMV_DISTORTION_MODEL_POLYNOMIAL: camera_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics); @@ -457,8 +418,7 @@ CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions( case LIBMV_DISTORTION_MODEL_BROWN: camera_intrinsics = LIBMV_OBJECT_NEW(BrownCameraIntrinsics); break; - default: - assert(!"Unknown distortion model"); + default: assert(!"Unknown distortion model"); } libmv_cameraIntrinsicsFillFromOptions(camera_intrinsics_options, camera_intrinsics); diff --git a/intern/libmv/intern/camera_intrinsics.h b/intern/libmv/intern/camera_intrinsics.h index eb6176770ec..8a65c93e6a4 100644 --- a/intern/libmv/intern/camera_intrinsics.h +++ b/intern/libmv/intern/camera_intrinsics.h @@ -56,10 +56,10 @@ typedef struct libmv_CameraIntrinsicsOptions { double brown_p1, brown_p2; } libmv_CameraIntrinsicsOptions; -libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( +libmv_CameraIntrinsics* libmv_cameraIntrinsicsNew( const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options); -libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( +libmv_CameraIntrinsics* libmv_cameraIntrinsicsCopy( const libmv_CameraIntrinsics* libmv_intrinsics); void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics); @@ -76,7 +76,7 @@ void libmv_cameraIntrinsicsExtractOptions( void libmv_cameraIntrinsicsUndistortByte( const libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, + const unsigned char* source_image, int width, int height, float overscan, @@ -94,12 +94,12 @@ void libmv_cameraIntrinsicsUndistortFloat( void libmv_cameraIntrinsicsDistortByte( const struct libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, + const unsigned char* source_image, int width, int height, float overscan, int channels, - unsigned char *destination_image); + unsigned char* destination_image); void libmv_cameraIntrinsicsDistortFloat( const libmv_CameraIntrinsics* libmv_intrinsics, @@ -131,7 +131,7 @@ void libmv_cameraIntrinsicsInvert( #ifdef __cplusplus namespace libmv { - class CameraIntrinsics; +class CameraIntrinsics; } libmv::CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions( diff --git a/intern/libmv/intern/detector.cc b/intern/libmv/intern/detector.cc index 455e431f6f4..21f5b46595c 100644 --- a/intern/libmv/intern/detector.cc +++ b/intern/libmv/intern/detector.cc @@ -34,7 +34,7 @@ struct libmv_Features { namespace { -libmv_Features *libmv_featuresFromVector( +libmv_Features* libmv_featuresFromVector( const libmv::vector& features) { libmv_Features* libmv_features = LIBMV_STRUCT_NEW(libmv_Features, 1); int count = features.size(); @@ -50,12 +50,12 @@ libmv_Features *libmv_featuresFromVector( return libmv_features; } -void libmv_convertDetectorOptions(libmv_DetectOptions *options, - DetectOptions *detector_options) { +void libmv_convertDetectorOptions(libmv_DetectOptions* options, + DetectOptions* detector_options) { switch (options->detector) { -#define LIBMV_CONVERT(the_detector) \ - case LIBMV_DETECTOR_ ## the_detector: \ - detector_options->type = DetectOptions::the_detector; \ +#define LIBMV_CONVERT(the_detector) \ + case LIBMV_DETECTOR_##the_detector: \ + detector_options->type = DetectOptions::the_detector; \ break; LIBMV_CONVERT(FAST) LIBMV_CONVERT(MORAVEC) @@ -72,7 +72,7 @@ void libmv_convertDetectorOptions(libmv_DetectOptions *options, } // namespace -libmv_Features *libmv_detectFeaturesByte(const unsigned char* image_buffer, +libmv_Features* libmv_detectFeaturesByte(const unsigned char* image_buffer, int width, int height, int channels, @@ -133,7 +133,7 @@ void libmv_getFeature(const libmv_Features* libmv_features, double* y, double* score, double* size) { - Feature &feature = libmv_features->features[number]; + Feature& feature = libmv_features->features[number]; *x = feature.x; *y = feature.y; *score = feature.score; diff --git a/intern/libmv/intern/detector.h b/intern/libmv/intern/detector.h index b36935fc67f..f21e78d7f2b 100644 --- a/intern/libmv/intern/detector.h +++ b/intern/libmv/intern/detector.h @@ -38,7 +38,7 @@ typedef struct libmv_DetectOptions { int min_distance; int fast_min_trackness; int moravec_max_count; - unsigned char *moravec_pattern; + unsigned char* moravec_pattern; double harris_threshold; } libmv_DetectOptions; diff --git a/intern/libmv/intern/frame_accessor.cc b/intern/libmv/intern/frame_accessor.cc index 9fde73f0d71..3a6c753cc8d 100644 --- a/intern/libmv/intern/frame_accessor.cc +++ b/intern/libmv/intern/frame_accessor.cc @@ -36,20 +36,18 @@ struct LibmvFrameAccessor : public FrameAccessor { libmv_ReleaseImageCallback release_image_callback, libmv_GetMaskForTrackCallback get_mask_for_track_callback, libmv_ReleaseMaskCallback release_mask_callback) - : user_data_(user_data), - get_image_callback_(get_image_callback), - release_image_callback_(release_image_callback), - get_mask_for_track_callback_(get_mask_for_track_callback), - release_mask_callback_(release_mask_callback) { } + : user_data_(user_data), + get_image_callback_(get_image_callback), + release_image_callback_(release_image_callback), + get_mask_for_track_callback_(get_mask_for_track_callback), + release_mask_callback_(release_mask_callback) {} - virtual ~LibmvFrameAccessor() { - } + virtual ~LibmvFrameAccessor() {} libmv_InputMode get_libmv_input_mode(InputMode input_mode) { switch (input_mode) { -#define CHECK_INPUT_MODE(mode) \ - case mode: \ - return LIBMV_IMAGE_MODE_ ## mode; +#define CHECK_INPUT_MODE(mode) \ + case mode: return LIBMV_IMAGE_MODE_##mode; CHECK_INPUT_MODE(MONO) CHECK_INPUT_MODE(RGBA) #undef CHECK_INPUT_MODE @@ -59,8 +57,7 @@ struct LibmvFrameAccessor : public FrameAccessor { return LIBMV_IMAGE_MODE_MONO; } - void get_libmv_region(const Region& region, - libmv_Region* libmv_region) { + void get_libmv_region(const Region& region, libmv_Region* libmv_region) { libmv_region->min[0] = region.min(0); libmv_region->min[1] = region.min(1); libmv_region->max[0] = region.max(0); @@ -74,7 +71,7 @@ struct LibmvFrameAccessor : public FrameAccessor { const Region* region, const Transform* transform, FloatImage* destination) { - float *float_buffer; + float* float_buffer; int width, height, channels; libmv_Region libmv_region; if (region) { @@ -86,46 +83,41 @@ struct LibmvFrameAccessor : public FrameAccessor { get_libmv_input_mode(input_mode), downscale, region != NULL ? &libmv_region : NULL, - (libmv_FrameTransform*) transform, + (libmv_FrameTransform*)transform, &float_buffer, &width, &height, &channels); // TODO(sergey): Dumb code for until we can set data directly. - FloatImage temp_image(float_buffer, - height, - width, - channels); + FloatImage temp_image(float_buffer, height, width, channels); destination->CopyFrom(temp_image); return cache_key; } - void ReleaseImage(Key cache_key) { - release_image_callback_(cache_key); - } + void ReleaseImage(Key cache_key) { release_image_callback_(cache_key); } Key GetMaskForTrack(int clip, int frame, int track, const Region* region, FloatImage* destination) { - float *float_buffer; + float* float_buffer; int width, height; libmv_Region libmv_region; if (region) { get_libmv_region(*region, &libmv_region); } - Key cache_key = get_mask_for_track_callback_( - user_data_, - clip, - frame, - track, - region != NULL ? &libmv_region : NULL, - &float_buffer, - &width, - &height); + Key cache_key = + get_mask_for_track_callback_(user_data_, + clip, + frame, + track, + region != NULL ? &libmv_region : NULL, + &float_buffer, + &width, + &height); if (cache_key == NULL) { // No mask for the given track. @@ -133,30 +125,21 @@ struct LibmvFrameAccessor : public FrameAccessor { } // TODO(sergey): Dumb code for until we can set data directly. - FloatImage temp_image(float_buffer, - height, - width, - 1); + FloatImage temp_image(float_buffer, height, width, 1); destination->CopyFrom(temp_image); return cache_key; } - void ReleaseMask(Key key) { - release_mask_callback_(key); - } + void ReleaseMask(Key key) { release_mask_callback_(key); } - bool GetClipDimensions(int /*clip*/, int * /*width*/, int * /*height*/) { + bool GetClipDimensions(int /*clip*/, int* /*width*/, int* /*height*/) { return false; } - int NumClips() { - return 1; - } + int NumClips() { return 1; } - int NumFrames(int /*clip*/) { - return 0; - } + int NumFrames(int /*clip*/) { return 0; } libmv_FrameAccessorUserData* user_data_; libmv_GetImageCallback get_image_callback_; @@ -173,35 +156,35 @@ libmv_FrameAccessor* libmv_FrameAccessorNew( libmv_ReleaseImageCallback release_image_callback, libmv_GetMaskForTrackCallback get_mask_for_track_callback, libmv_ReleaseMaskCallback release_mask_callback) { - return (libmv_FrameAccessor*) LIBMV_OBJECT_NEW(LibmvFrameAccessor, - user_data, - get_image_callback, - release_image_callback, - get_mask_for_track_callback, - release_mask_callback); + return (libmv_FrameAccessor*)LIBMV_OBJECT_NEW(LibmvFrameAccessor, + user_data, + get_image_callback, + release_image_callback, + get_mask_for_track_callback, + release_mask_callback); } void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor) { LIBMV_OBJECT_DELETE(frame_accessor, LibmvFrameAccessor); } -int64_t libmv_frameAccessorgetTransformKey(const libmv_FrameTransform *transform) { - return ((FrameAccessor::Transform*) transform)->key(); +int64_t libmv_frameAccessorgetTransformKey( + const libmv_FrameTransform* transform) { + return ((FrameAccessor::Transform*)transform)->key(); } -void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform *transform, - const libmv_FloatImage *input_image, - libmv_FloatImage *output_image) { +void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* transform, + const libmv_FloatImage* input_image, + libmv_FloatImage* output_image) { const FloatImage input(input_image->buffer, input_image->height, input_image->width, input_image->channels); FloatImage output; - ((FrameAccessor::Transform*) transform)->run(input, - &output); + ((FrameAccessor::Transform*)transform)->run(input, &output); - int num_pixels = output.Width() *output.Height() * output.Depth(); + int num_pixels = output.Width() * output.Height() * output.Depth(); output_image->buffer = new float[num_pixels]; memcpy(output_image->buffer, output.Data(), num_pixels * sizeof(float)); output_image->width = output.Width(); diff --git a/intern/libmv/intern/frame_accessor.h b/intern/libmv/intern/frame_accessor.h index 6bccb305282..39a3bc5eb1d 100644 --- a/intern/libmv/intern/frame_accessor.h +++ b/intern/libmv/intern/frame_accessor.h @@ -32,14 +32,14 @@ extern "C" { typedef struct libmv_FrameAccessor libmv_FrameAccessor; typedef struct libmv_FrameTransform libmv_FrameTransform; typedef struct libmv_FrameAccessorUserData libmv_FrameAccessorUserData; -typedef void *libmv_CacheKey; +typedef void* libmv_CacheKey; typedef enum { LIBMV_IMAGE_MODE_MONO, LIBMV_IMAGE_MODE_RGBA, } libmv_InputMode; -typedef libmv_CacheKey (*libmv_GetImageCallback) ( +typedef libmv_CacheKey (*libmv_GetImageCallback)( libmv_FrameAccessorUserData* user_data, int clip, int frame, @@ -52,9 +52,9 @@ typedef libmv_CacheKey (*libmv_GetImageCallback) ( int* height, int* channels); -typedef void (*libmv_ReleaseImageCallback) (libmv_CacheKey cache_key); +typedef void (*libmv_ReleaseImageCallback)(libmv_CacheKey cache_key); -typedef libmv_CacheKey (*libmv_GetMaskForTrackCallback) ( +typedef libmv_CacheKey (*libmv_GetMaskForTrackCallback)( libmv_FrameAccessorUserData* user_data, int clip, int frame, @@ -63,7 +63,7 @@ typedef libmv_CacheKey (*libmv_GetMaskForTrackCallback) ( float** destination, int* width, int* height); -typedef void (*libmv_ReleaseMaskCallback) (libmv_CacheKey cache_key); +typedef void (*libmv_ReleaseMaskCallback)(libmv_CacheKey cache_key); libmv_FrameAccessor* libmv_FrameAccessorNew( libmv_FrameAccessorUserData* user_data, @@ -73,11 +73,12 @@ libmv_FrameAccessor* libmv_FrameAccessorNew( libmv_ReleaseMaskCallback release_mask_callback); void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor); -int64_t libmv_frameAccessorgetTransformKey(const libmv_FrameTransform *transform); +int64_t libmv_frameAccessorgetTransformKey( + const libmv_FrameTransform* transform); -void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform *transform, - const libmv_FloatImage *input_image, - libmv_FloatImage *output_image); +void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* transform, + const libmv_FloatImage* input_image, + libmv_FloatImage* output_image); #ifdef __cplusplus } #endif diff --git a/intern/libmv/intern/homography.cc b/intern/libmv/intern/homography.cc index 179aeaa08aa..dc1009b5636 100644 --- a/intern/libmv/intern/homography.cc +++ b/intern/libmv/intern/homography.cc @@ -41,10 +41,8 @@ void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*x1)[2], LG << "x2: " << x2_mat; libmv::EstimateHomographyOptions options; - libmv::EstimateHomography2DFromCorrespondences(x1_mat, - x2_mat, - options, - &H_mat); + libmv::EstimateHomography2DFromCorrespondences( + x1_mat, x2_mat, options, &H_mat); LG << "H: " << H_mat; diff --git a/intern/libmv/intern/image.cc b/intern/libmv/intern/image.cc index a6e09277680..564e4762448 100644 --- a/intern/libmv/intern/image.cc +++ b/intern/libmv/intern/image.cc @@ -21,14 +21,14 @@ #include "intern/utildefines.h" #include "libmv/tracking/track_region.h" -#include #include +#include using libmv::FloatImage; using libmv::SamplePlanarPatch; -void libmv_floatImageDestroy(libmv_FloatImage *image) { - delete [] image->buffer; +void libmv_floatImageDestroy(libmv_FloatImage* image) { + delete[] image->buffer; } /* Image <-> buffers conversion */ @@ -63,8 +63,7 @@ void libmv_floatBufferToFloatImage(const float* buffer, } } -void libmv_floatImageToFloatBuffer(const FloatImage &image, - float* buffer) { +void libmv_floatImageToFloatBuffer(const FloatImage& image, float* buffer) { for (int y = 0, a = 0; y < image.Height(); y++) { for (int x = 0; x < image.Width(); x++) { for (int k = 0; k < image.Depth(); k++) { @@ -74,9 +73,9 @@ void libmv_floatImageToFloatBuffer(const FloatImage &image, } } -void libmv_floatImageToByteBuffer(const libmv::FloatImage &image, +void libmv_floatImageToByteBuffer(const libmv::FloatImage& image, unsigned char* buffer) { - for (int y = 0, a= 0; y < image.Height(); y++) { + for (int y = 0, a = 0; y < image.Height(); y++) { for (int x = 0; x < image.Width(); x++) { for (int k = 0; k < image.Depth(); k++) { buffer[a++] = image(y, x, k) * 255.0f; @@ -93,7 +92,7 @@ static bool savePNGImage(png_bytep* row_pointers, const char* file_name) { png_infop info_ptr; png_structp png_ptr; - FILE *fp = fopen(file_name, "wb"); + FILE* fp = fopen(file_name, "wb"); if (fp == NULL) { return false; @@ -153,7 +152,7 @@ bool libmv_saveImage(const FloatImage& image, int x0, int y0) { int x, y; - png_bytep *row_pointers; + png_bytep* row_pointers; assert(image.Depth() == 1); @@ -180,9 +179,8 @@ bool libmv_saveImage(const FloatImage& image, static int image_counter = 0; char file_name[128]; - snprintf(file_name, sizeof(file_name), - "%s_%02d.png", - prefix, ++image_counter); + snprintf( + file_name, sizeof(file_name), "%s_%02d.png", prefix, ++image_counter); bool result = savePNGImage(row_pointers, image.Width(), image.Height(), @@ -191,9 +189,9 @@ bool libmv_saveImage(const FloatImage& image, file_name); for (y = 0; y < image.Height(); y++) { - delete [] row_pointers[y]; + delete[] row_pointers[y]; } - delete [] row_pointers; + delete[] row_pointers; return result; } @@ -211,7 +209,7 @@ void libmv_samplePlanarPatchFloat(const float* image, double* warped_position_x, double* warped_position_y) { FloatImage libmv_image, libmv_patch, libmv_mask; - FloatImage *libmv_mask_for_sample = NULL; + FloatImage* libmv_mask_for_sample = NULL; libmv_floatBufferToFloatImage(image, width, height, channels, &libmv_image); @@ -221,8 +219,10 @@ void libmv_samplePlanarPatchFloat(const float* image, } SamplePlanarPatch(libmv_image, - xs, ys, - num_samples_x, num_samples_y, + xs, + ys, + num_samples_x, + num_samples_y, libmv_mask_for_sample, &libmv_patch, warped_position_x, @@ -232,19 +232,19 @@ void libmv_samplePlanarPatchFloat(const float* image, } void libmv_samplePlanarPatchByte(const unsigned char* image, - int width, - int height, - int channels, - const double* xs, - const double* ys, - int num_samples_x, - int num_samples_y, - const float* mask, - unsigned char* patch, - double* warped_position_x, - double* warped_position_y) { + int width, + int height, + int channels, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + const float* mask, + unsigned char* patch, + double* warped_position_x, + double* warped_position_y) { libmv::FloatImage libmv_image, libmv_patch, libmv_mask; - libmv::FloatImage *libmv_mask_for_sample = NULL; + libmv::FloatImage* libmv_mask_for_sample = NULL; libmv_byteBufferToFloatImage(image, width, height, channels, &libmv_image); @@ -254,8 +254,10 @@ void libmv_samplePlanarPatchByte(const unsigned char* image, } libmv::SamplePlanarPatch(libmv_image, - xs, ys, - num_samples_x, num_samples_y, + xs, + ys, + num_samples_x, + num_samples_y, libmv_mask_for_sample, &libmv_patch, warped_position_x, diff --git a/intern/libmv/intern/image.h b/intern/libmv/intern/image.h index a1381a4c216..02cef86a127 100644 --- a/intern/libmv/intern/image.h +++ b/intern/libmv/intern/image.h @@ -35,7 +35,7 @@ void libmv_floatBufferToFloatImage(const float* buffer, libmv::FloatImage* image); void libmv_floatImageToFloatBuffer(const libmv::FloatImage& image, - float *buffer); + float* buffer); void libmv_floatImageToByteBuffer(const libmv::FloatImage& image, unsigned char* buffer); @@ -51,13 +51,13 @@ extern "C" { #endif typedef struct libmv_FloatImage { - float *buffer; + float* buffer; int width; int height; int channels; } libmv_FloatImage; -void libmv_floatImageDestroy(libmv_FloatImage *image); +void libmv_floatImageDestroy(libmv_FloatImage* image); void libmv_samplePlanarPatchFloat(const float* image, int width, @@ -72,18 +72,18 @@ void libmv_samplePlanarPatchFloat(const float* image, double* warped_position_x, double* warped_position_y); - void libmv_samplePlanarPatchByte(const unsigned char* image, - int width, - int height, - int channels, - const double* xs, - const double* ys, - int num_samples_x, - int num_samples_y, - const float* mask, - unsigned char* patch, - double* warped_position_x, - double* warped_position_y); +void libmv_samplePlanarPatchByte(const unsigned char* image, + int width, + int height, + int channels, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + const float* mask, + unsigned char* patch, + double* warped_position_x, + double* warped_position_y); #ifdef __cplusplus } diff --git a/intern/libmv/intern/reconstruction.cc b/intern/libmv/intern/reconstruction.cc index 0f4e890d4ca..430607461da 100644 --- a/intern/libmv/intern/reconstruction.cc +++ b/intern/libmv/intern/reconstruction.cc @@ -24,8 +24,8 @@ #include "libmv/logging/logging.h" #include "libmv/simple_pipeline/bundle.h" -#include "libmv/simple_pipeline/keyframe_selection.h" #include "libmv/simple_pipeline/initialize_reconstruction.h" +#include "libmv/simple_pipeline/keyframe_selection.h" #include "libmv/simple_pipeline/modal_solver.h" #include "libmv/simple_pipeline/pipeline.h" #include "libmv/simple_pipeline/reconstruction_scale.h" @@ -39,19 +39,19 @@ using libmv::EuclideanScaleToUnity; using libmv::Marker; using libmv::ProgressUpdateCallback; -using libmv::PolynomialCameraIntrinsics; -using libmv::Tracks; using libmv::EuclideanBundle; using libmv::EuclideanCompleteReconstruction; using libmv::EuclideanReconstructTwoFrames; using libmv::EuclideanReprojectionError; +using libmv::PolynomialCameraIntrinsics; +using libmv::Tracks; struct libmv_Reconstruction { EuclideanReconstruction reconstruction; /* Used for per-track average error calculation after reconstruction */ Tracks tracks; - CameraIntrinsics *intrinsics; + CameraIntrinsics* intrinsics; double error; bool is_valid; @@ -63,7 +63,7 @@ class ReconstructUpdateCallback : public ProgressUpdateCallback { public: ReconstructUpdateCallback( reconstruct_progress_update_cb progress_update_callback, - void *callback_customdata) { + void* callback_customdata) { progress_update_callback_ = progress_update_callback; callback_customdata_ = callback_customdata; } @@ -73,13 +73,14 @@ class ReconstructUpdateCallback : public ProgressUpdateCallback { progress_update_callback_(callback_customdata_, progress, message); } } + protected: reconstruct_progress_update_cb progress_update_callback_; void* callback_customdata_; }; void libmv_solveRefineIntrinsics( - const Tracks &tracks, + const Tracks& tracks, const int refine_intrinsics, const int bundle_constraints, reconstruct_progress_update_cb progress_update_callback, @@ -96,11 +97,11 @@ void libmv_solveRefineIntrinsics( bundle_intrinsics |= libmv::BUNDLE_PRINCIPAL_POINT; } -#define SET_DISTORTION_FLAG_CHECKED(type, coefficient) \ - do { \ - if (refine_intrinsics & LIBMV_REFINE_ ## type ##_DISTORTION_ ## coefficient) { \ - bundle_intrinsics |= libmv::BUNDLE_ ## type ## _ ## coefficient; \ - } \ +#define SET_DISTORTION_FLAG_CHECKED(type, coefficient) \ + do { \ + if (refine_intrinsics & LIBMV_REFINE_##type##_DISTORTION_##coefficient) { \ + bundle_intrinsics |= libmv::BUNDLE_##type##_##coefficient; \ + } \ } while (0) SET_DISTORTION_FLAG_CHECKED(RADIAL, K1); @@ -123,20 +124,19 @@ void libmv_solveRefineIntrinsics( } void finishReconstruction( - const Tracks &tracks, - const CameraIntrinsics &camera_intrinsics, - libmv_Reconstruction *libmv_reconstruction, + const Tracks& tracks, + const CameraIntrinsics& camera_intrinsics, + libmv_Reconstruction* libmv_reconstruction, reconstruct_progress_update_cb progress_update_callback, - void *callback_customdata) { - EuclideanReconstruction &reconstruction = - libmv_reconstruction->reconstruction; + void* callback_customdata) { + EuclideanReconstruction& reconstruction = + libmv_reconstruction->reconstruction; /* Reprojection error calculation. */ progress_update_callback(callback_customdata, 1.0, "Finishing solution"); libmv_reconstruction->tracks = tracks; - libmv_reconstruction->error = EuclideanReprojectionError(tracks, - reconstruction, - camera_intrinsics); + libmv_reconstruction->error = + EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics); } bool selectTwoKeyframesBasedOnGRICAndVariance( @@ -148,9 +148,8 @@ bool selectTwoKeyframesBasedOnGRICAndVariance( libmv::vector keyframes; /* Get list of all keyframe candidates first. */ - SelectKeyframesBasedOnGRICAndVariance(normalized_tracks, - camera_intrinsics, - keyframes); + SelectKeyframesBasedOnGRICAndVariance( + normalized_tracks, camera_intrinsics, keyframes); if (keyframes.size() < 2) { LG << "Not enough keyframes detected by GRIC"; @@ -175,24 +174,20 @@ bool selectTwoKeyframesBasedOnGRICAndVariance( EuclideanReconstruction reconstruction; int current_keyframe = keyframes[i]; libmv::vector keyframe_markers = - normalized_tracks.MarkersForTracksInBothImages(previous_keyframe, - current_keyframe); + normalized_tracks.MarkersForTracksInBothImages(previous_keyframe, + current_keyframe); Tracks keyframe_tracks(keyframe_markers); /* get a solution from two keyframes only */ EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction); EuclideanBundle(keyframe_tracks, &reconstruction); - EuclideanCompleteReconstruction(keyframe_tracks, - &reconstruction, - NULL); + EuclideanCompleteReconstruction(keyframe_tracks, &reconstruction, NULL); - double current_error = EuclideanReprojectionError(tracks, - reconstruction, - camera_intrinsics); + double current_error = + EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics); - LG << "Error between " << previous_keyframe - << " and " << current_keyframe + LG << "Error between " << previous_keyframe << " and " << current_keyframe << ": " << current_error; if (current_error < best_error) { @@ -214,53 +209,49 @@ Marker libmv_projectMarker(const EuclideanPoint& point, projected /= projected(2); libmv::Marker reprojected_marker; - intrinsics.ApplyIntrinsics(projected(0), projected(1), - &reprojected_marker.x, - &reprojected_marker.y); + intrinsics.ApplyIntrinsics( + projected(0), projected(1), &reprojected_marker.x, &reprojected_marker.y); reprojected_marker.image = camera.image; reprojected_marker.track = point.track; return reprojected_marker; } -void libmv_getNormalizedTracks(const Tracks &tracks, - const CameraIntrinsics &camera_intrinsics, - Tracks *normalized_tracks) { +void libmv_getNormalizedTracks(const Tracks& tracks, + const CameraIntrinsics& camera_intrinsics, + Tracks* normalized_tracks) { libmv::vector markers = tracks.AllMarkers(); for (int i = 0; i < markers.size(); ++i) { - Marker &marker = markers[i]; - camera_intrinsics.InvertIntrinsics(marker.x, marker.y, - &marker.x, &marker.y); - normalized_tracks->Insert(marker.image, - marker.track, - marker.x, marker.y, - marker.weight); + Marker& marker = markers[i]; + camera_intrinsics.InvertIntrinsics( + marker.x, marker.y, &marker.x, &marker.y); + normalized_tracks->Insert( + marker.image, marker.track, marker.x, marker.y, marker.weight); } } } // namespace -libmv_Reconstruction *libmv_solveReconstruction( +libmv_Reconstruction* libmv_solveReconstruction( const libmv_Tracks* libmv_tracks, const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, libmv_ReconstructionOptions* libmv_reconstruction_options, reconstruct_progress_update_cb progress_update_callback, void* callback_customdata) { - libmv_Reconstruction *libmv_reconstruction = - LIBMV_OBJECT_NEW(libmv_Reconstruction); + libmv_Reconstruction* libmv_reconstruction = + LIBMV_OBJECT_NEW(libmv_Reconstruction); - Tracks &tracks = *((Tracks *) libmv_tracks); - EuclideanReconstruction &reconstruction = - libmv_reconstruction->reconstruction; + Tracks& tracks = *((Tracks*)libmv_tracks); + EuclideanReconstruction& reconstruction = + libmv_reconstruction->reconstruction; ReconstructUpdateCallback update_callback = - ReconstructUpdateCallback(progress_update_callback, - callback_customdata); + ReconstructUpdateCallback(progress_update_callback, callback_customdata); /* Retrieve reconstruction options from C-API to libmv API. */ - CameraIntrinsics *camera_intrinsics; + CameraIntrinsics* camera_intrinsics; camera_intrinsics = libmv_reconstruction->intrinsics = - libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); + libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); /* Invert the camera intrinsics/ */ Tracks normalized_tracks; @@ -276,10 +267,10 @@ libmv_Reconstruction *libmv_solveReconstruction( update_callback.invoke(0, "Selecting keyframes"); if (selectTwoKeyframesBasedOnGRICAndVariance(tracks, - normalized_tracks, - *camera_intrinsics, - keyframe1, - keyframe2)) { + normalized_tracks, + *camera_intrinsics, + keyframe1, + keyframe2)) { /* so keyframes in the interface would be updated */ libmv_reconstruction_options->keyframe1 = keyframe1; libmv_reconstruction_options->keyframe2 = keyframe2; @@ -290,7 +281,7 @@ libmv_Reconstruction *libmv_solveReconstruction( LG << "frames to init from: " << keyframe1 << " " << keyframe2; libmv::vector keyframe_markers = - normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2); + normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2); LG << "number of markers for init: " << keyframe_markers.size(); @@ -309,14 +300,12 @@ libmv_Reconstruction *libmv_solveReconstruction( } EuclideanBundle(normalized_tracks, &reconstruction); - EuclideanCompleteReconstruction(normalized_tracks, - &reconstruction, - &update_callback); + EuclideanCompleteReconstruction( + normalized_tracks, &reconstruction, &update_callback); /* Refinement. */ if (libmv_reconstruction_options->refine_intrinsics) { - libmv_solveRefineIntrinsics( - tracks, + libmv_solveRefineIntrinsics(tracks, libmv_reconstruction_options->refine_intrinsics, libmv::BUNDLE_NO_CONSTRAINTS, progress_update_callback, @@ -336,31 +325,29 @@ libmv_Reconstruction *libmv_solveReconstruction( callback_customdata); libmv_reconstruction->is_valid = true; - return (libmv_Reconstruction *) libmv_reconstruction; + return (libmv_Reconstruction*)libmv_reconstruction; } -libmv_Reconstruction *libmv_solveModal( - const libmv_Tracks *libmv_tracks, - const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, - const libmv_ReconstructionOptions *libmv_reconstruction_options, +libmv_Reconstruction* libmv_solveModal( + const libmv_Tracks* libmv_tracks, + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + const libmv_ReconstructionOptions* libmv_reconstruction_options, reconstruct_progress_update_cb progress_update_callback, - void *callback_customdata) { - libmv_Reconstruction *libmv_reconstruction = - LIBMV_OBJECT_NEW(libmv_Reconstruction); + void* callback_customdata) { + libmv_Reconstruction* libmv_reconstruction = + LIBMV_OBJECT_NEW(libmv_Reconstruction); - Tracks &tracks = *((Tracks *) libmv_tracks); - EuclideanReconstruction &reconstruction = - libmv_reconstruction->reconstruction; + Tracks& tracks = *((Tracks*)libmv_tracks); + EuclideanReconstruction& reconstruction = + libmv_reconstruction->reconstruction; ReconstructUpdateCallback update_callback = - ReconstructUpdateCallback(progress_update_callback, - callback_customdata); + ReconstructUpdateCallback(progress_update_callback, callback_customdata); /* Retrieve reconstruction options from C-API to libmv API. */ - CameraIntrinsics *camera_intrinsics; + CameraIntrinsics* camera_intrinsics; camera_intrinsics = libmv_reconstruction->intrinsics = - libmv_cameraIntrinsicsCreateFromOptions( - libmv_camera_intrinsics_options); + libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); /* Invert the camera intrinsics. */ Tracks normalized_tracks; @@ -378,11 +365,11 @@ libmv_Reconstruction *libmv_solveModal( /* Refinement. */ if (libmv_reconstruction_options->refine_intrinsics) { - libmv_solveRefineIntrinsics( - tracks, + libmv_solveRefineIntrinsics(tracks, libmv_reconstruction_options->refine_intrinsics, libmv::BUNDLE_NO_TRANSLATION, - progress_update_callback, callback_customdata, + progress_update_callback, + callback_customdata, &reconstruction, camera_intrinsics); } @@ -395,26 +382,25 @@ libmv_Reconstruction *libmv_solveModal( callback_customdata); libmv_reconstruction->is_valid = true; - return (libmv_Reconstruction *) libmv_reconstruction; + return (libmv_Reconstruction*)libmv_reconstruction; } -int libmv_reconstructionIsValid(libmv_Reconstruction *libmv_reconstruction) { +int libmv_reconstructionIsValid(libmv_Reconstruction* libmv_reconstruction) { return libmv_reconstruction->is_valid; } -void libmv_reconstructionDestroy(libmv_Reconstruction *libmv_reconstruction) { +void libmv_reconstructionDestroy(libmv_Reconstruction* libmv_reconstruction) { LIBMV_OBJECT_DELETE(libmv_reconstruction->intrinsics, CameraIntrinsics); LIBMV_OBJECT_DELETE(libmv_reconstruction, libmv_Reconstruction); } int libmv_reprojectionPointForTrack( - const libmv_Reconstruction *libmv_reconstruction, + const libmv_Reconstruction* libmv_reconstruction, int track, double pos[3]) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const EuclideanPoint *point = - reconstruction->PointForTrack(track); + const EuclideanReconstruction* reconstruction = + &libmv_reconstruction->reconstruction; + const EuclideanPoint* point = reconstruction->PointForTrack(track); if (point) { pos[0] = point->X[0]; pos[1] = point->X[2]; @@ -425,23 +411,22 @@ int libmv_reprojectionPointForTrack( } double libmv_reprojectionErrorForTrack( - const libmv_Reconstruction *libmv_reconstruction, - int track) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const CameraIntrinsics *intrinsics = libmv_reconstruction->intrinsics; + const libmv_Reconstruction* libmv_reconstruction, int track) { + const EuclideanReconstruction* reconstruction = + &libmv_reconstruction->reconstruction; + const CameraIntrinsics* intrinsics = libmv_reconstruction->intrinsics; libmv::vector markers = - libmv_reconstruction->tracks.MarkersForTrack(track); + libmv_reconstruction->tracks.MarkersForTrack(track); int num_reprojected = 0; double total_error = 0.0; for (int i = 0; i < markers.size(); ++i) { double weight = markers[i].weight; - const EuclideanCamera *camera = - reconstruction->CameraForImage(markers[i].image); - const EuclideanPoint *point = - reconstruction->PointForTrack(markers[i].track); + const EuclideanCamera* camera = + reconstruction->CameraForImage(markers[i].image); + const EuclideanPoint* point = + reconstruction->PointForTrack(markers[i].track); if (!camera || !point || weight == 0.0) { continue; @@ -450,7 +435,7 @@ double libmv_reprojectionErrorForTrack( num_reprojected++; Marker reprojected_marker = - libmv_projectMarker(*point, *camera, *intrinsics); + libmv_projectMarker(*point, *camera, *intrinsics); double ex = (reprojected_marker.x - markers[i].x) * weight; double ey = (reprojected_marker.y - markers[i].y) * weight; @@ -461,14 +446,13 @@ double libmv_reprojectionErrorForTrack( } double libmv_reprojectionErrorForImage( - const libmv_Reconstruction *libmv_reconstruction, - int image) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const CameraIntrinsics *intrinsics = libmv_reconstruction->intrinsics; + const libmv_Reconstruction* libmv_reconstruction, int image) { + const EuclideanReconstruction* reconstruction = + &libmv_reconstruction->reconstruction; + const CameraIntrinsics* intrinsics = libmv_reconstruction->intrinsics; libmv::vector markers = - libmv_reconstruction->tracks.MarkersInImage(image); - const EuclideanCamera *camera = reconstruction->CameraForImage(image); + libmv_reconstruction->tracks.MarkersInImage(image); + const EuclideanCamera* camera = reconstruction->CameraForImage(image); int num_reprojected = 0; double total_error = 0.0; @@ -477,8 +461,8 @@ double libmv_reprojectionErrorForImage( } for (int i = 0; i < markers.size(); ++i) { - const EuclideanPoint *point = - reconstruction->PointForTrack(markers[i].track); + const EuclideanPoint* point = + reconstruction->PointForTrack(markers[i].track); if (!point) { continue; @@ -487,7 +471,7 @@ double libmv_reprojectionErrorForImage( num_reprojected++; Marker reprojected_marker = - libmv_projectMarker(*point, *camera, *intrinsics); + libmv_projectMarker(*point, *camera, *intrinsics); double ex = (reprojected_marker.x - markers[i].x) * markers[i].weight; double ey = (reprojected_marker.y - markers[i].y) * markers[i].weight; @@ -498,13 +482,12 @@ double libmv_reprojectionErrorForImage( } int libmv_reprojectionCameraForImage( - const libmv_Reconstruction *libmv_reconstruction, + const libmv_Reconstruction* libmv_reconstruction, int image, double mat[4][4]) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const EuclideanCamera *camera = - reconstruction->CameraForImage(image); + const EuclideanReconstruction* reconstruction = + &libmv_reconstruction->reconstruction; + const EuclideanCamera* camera = reconstruction->CameraForImage(image); if (camera) { for (int j = 0; j < 3; ++j) { @@ -541,11 +524,11 @@ int libmv_reprojectionCameraForImage( } double libmv_reprojectionError( - const libmv_Reconstruction *libmv_reconstruction) { + const libmv_Reconstruction* libmv_reconstruction) { return libmv_reconstruction->error; } -libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics( - libmv_Reconstruction *libmv_reconstruction) { - return (libmv_CameraIntrinsics *) libmv_reconstruction->intrinsics; +libmv_CameraIntrinsics* libmv_reconstructionExtractIntrinsics( + libmv_Reconstruction* libmv_reconstruction) { + return (libmv_CameraIntrinsics*)libmv_reconstruction->intrinsics; } diff --git a/intern/libmv/intern/reconstruction.h b/intern/libmv/intern/reconstruction.h index 408ac884684..600bc92ccfc 100644 --- a/intern/libmv/intern/reconstruction.h +++ b/intern/libmv/intern/reconstruction.h @@ -31,17 +31,16 @@ struct libmv_CameraIntrinsicsOptions; typedef struct libmv_Reconstruction libmv_Reconstruction; enum { - LIBMV_REFINE_FOCAL_LENGTH = (1 << 0), - LIBMV_REFINE_PRINCIPAL_POINT = (1 << 1), - - LIBMV_REFINE_RADIAL_DISTORTION_K1 = (1 << 2), - LIBMV_REFINE_RADIAL_DISTORTION_K2 = (1 << 3), - LIBMV_REFINE_RADIAL_DISTORTION_K3 = (1 << 4), - LIBMV_REFINE_RADIAL_DISTORTION_K4 = (1 << 5), - LIBMV_REFINE_RADIAL_DISTORTION = (LIBMV_REFINE_RADIAL_DISTORTION_K1 | - LIBMV_REFINE_RADIAL_DISTORTION_K2 | - LIBMV_REFINE_RADIAL_DISTORTION_K3 | - LIBMV_REFINE_RADIAL_DISTORTION_K4), + LIBMV_REFINE_FOCAL_LENGTH = (1 << 0), + LIBMV_REFINE_PRINCIPAL_POINT = (1 << 1), + + LIBMV_REFINE_RADIAL_DISTORTION_K1 = (1 << 2), + LIBMV_REFINE_RADIAL_DISTORTION_K2 = (1 << 3), + LIBMV_REFINE_RADIAL_DISTORTION_K3 = (1 << 4), + LIBMV_REFINE_RADIAL_DISTORTION_K4 = (1 << 5), + LIBMV_REFINE_RADIAL_DISTORTION = + (LIBMV_REFINE_RADIAL_DISTORTION_K1 | LIBMV_REFINE_RADIAL_DISTORTION_K2 | + LIBMV_REFINE_RADIAL_DISTORTION_K3 | LIBMV_REFINE_RADIAL_DISTORTION_K4), LIBMV_REFINE_TANGENTIAL_DISTORTION_P1 = (1 << 6), LIBMV_REFINE_TANGENTIAL_DISTORTION_P2 = (1 << 7), @@ -55,9 +54,9 @@ typedef struct libmv_ReconstructionOptions { int refine_intrinsics; } libmv_ReconstructionOptions; -typedef void (*reconstruct_progress_update_cb) (void* customdata, - double progress, - const char* message); +typedef void (*reconstruct_progress_update_cb)(void* customdata, + double progress, + const char* message); libmv_Reconstruction* libmv_solveReconstruction( const struct libmv_Tracks* libmv_tracks, @@ -73,35 +72,32 @@ libmv_Reconstruction* libmv_solveModal( reconstruct_progress_update_cb progress_update_callback, void* callback_customdata); -int libmv_reconstructionIsValid(libmv_Reconstruction *libmv_reconstruction); +int libmv_reconstructionIsValid(libmv_Reconstruction* libmv_reconstruction); void libmv_reconstructionDestroy(libmv_Reconstruction* libmv_reconstruction); int libmv_reprojectionPointForTrack( - const libmv_Reconstruction* libmv_reconstruction, - int track, - double pos[3]); + const libmv_Reconstruction* libmv_reconstruction, int track, double pos[3]); double libmv_reprojectionErrorForTrack( - const libmv_Reconstruction* libmv_reconstruction, - int track); + const libmv_Reconstruction* libmv_reconstruction, int track); double libmv_reprojectionErrorForImage( - const libmv_Reconstruction* libmv_reconstruction, - int image); + const libmv_Reconstruction* libmv_reconstruction, int image); int libmv_reprojectionCameraForImage( const libmv_Reconstruction* libmv_reconstruction, int image, double mat[4][4]); -double libmv_reprojectionError(const libmv_Reconstruction* libmv_reconstruction); +double libmv_reprojectionError( + const libmv_Reconstruction* libmv_reconstruction); struct libmv_CameraIntrinsics* libmv_reconstructionExtractIntrinsics( - libmv_Reconstruction *libmv_Reconstruction); + libmv_Reconstruction* libmv_Reconstruction); #ifdef __cplusplus } #endif -#endif // LIBMV_C_API_RECONSTRUCTION_H_ +#endif // LIBMV_C_API_RECONSTRUCTION_H_ diff --git a/intern/libmv/intern/stub.cc b/intern/libmv/intern/stub.cc index 47e1896b4cf..1920042b4ec 100644 --- a/intern/libmv/intern/stub.cc +++ b/intern/libmv/intern/stub.cc @@ -24,7 +24,7 @@ /* ************ Logging ************ */ -void libmv_initLogging(const char * /*argv0*/) { +void libmv_initLogging(const char* /*argv0*/) { } void libmv_startDebugLogging(void) { @@ -36,18 +36,18 @@ void libmv_setLoggingVerbosity(int /*verbosity*/) { /* ************ Planar tracker ************ */ /* TrackRegion (new planar tracker) */ -int libmv_trackRegion(const libmv_TrackRegionOptions * /*options*/, - const float * /*image1*/, +int libmv_trackRegion(const libmv_TrackRegionOptions* /*options*/, + const float* /*image1*/, int /*image1_width*/, int /*image1_height*/, - const float * /*image2*/, + const float* /*image2*/, int /*image2_width*/, int /*image2_height*/, - const double *x1, - const double *y1, - libmv_TrackRegionResult *result, - double *x2, - double *y2) { + const double* x1, + const double* y1, + libmv_TrackRegionResult* result, + double* x2, + double* y2) { /* Convert to doubles for the libmv api. The four corners and the center. */ for (int i = 0; i < 5; ++i) { x2[i] = x1[i]; @@ -61,46 +61,46 @@ int libmv_trackRegion(const libmv_TrackRegionOptions * /*options*/, return false; } -void libmv_samplePlanarPatchFloat(const float * /*image*/, +void libmv_samplePlanarPatchFloat(const float* /*image*/, int /*width*/, int /*height*/, int /*channels*/, - const double * /*xs*/, - const double * /*ys*/, + const double* /*xs*/, + const double* /*ys*/, int /*num_samples_x*/, int /*num_samples_y*/, - const float * /*mask*/, - float * /*patch*/, - double * /*warped_position_x*/, - double * /*warped_position_y*/) { + const float* /*mask*/, + float* /*patch*/, + double* /*warped_position_x*/, + double* /*warped_position_y*/) { /* TODO(sergey): implement */ } -void libmv_samplePlanarPatchByte(const unsigned char * /*image*/, +void libmv_samplePlanarPatchByte(const unsigned char* /*image*/, int /*width*/, int /*height*/, int /*channels*/, - const double * /*xs*/, - const double * /*ys*/, - int /*num_samples_x*/, int /*num_samples_y*/, - const float * /*mask*/, - unsigned char * /*patch*/, - double * /*warped_position_x*/, - double * /*warped_position_y*/) { + const double* /*xs*/, + const double* /*ys*/, + int /*num_samples_x*/, + int /*num_samples_y*/, + const float* /*mask*/, + unsigned char* /*patch*/, + double* /*warped_position_x*/, + double* /*warped_position_y*/) { /* TODO(sergey): implement */ } -void libmv_floatImageDestroy(libmv_FloatImage* /*image*/) -{ +void libmv_floatImageDestroy(libmv_FloatImage* /*image*/) { } /* ************ Tracks ************ */ -libmv_Tracks *libmv_tracksNew(void) { +libmv_Tracks* libmv_tracksNew(void) { return NULL; } -void libmv_tracksInsert(libmv_Tracks * /*libmv_tracks*/, +void libmv_tracksInsert(libmv_Tracks* /*libmv_tracks*/, int /*image*/, int /*track*/, double /*x*/, @@ -108,152 +108,152 @@ void libmv_tracksInsert(libmv_Tracks * /*libmv_tracks*/, double /*weight*/) { } -void libmv_tracksDestroy(libmv_Tracks * /*libmv_tracks*/) { +void libmv_tracksDestroy(libmv_Tracks* /*libmv_tracks*/) { } /* ************ Reconstruction solver ************ */ -libmv_Reconstruction *libmv_solveReconstruction( - const libmv_Tracks * /*libmv_tracks*/, - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, - libmv_ReconstructionOptions * /*libmv_reconstruction_options*/, +libmv_Reconstruction* libmv_solveReconstruction( + const libmv_Tracks* /*libmv_tracks*/, + const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/, + libmv_ReconstructionOptions* /*libmv_reconstruction_options*/, reconstruct_progress_update_cb /*progress_update_callback*/, - void * /*callback_customdata*/) { + void* /*callback_customdata*/) { return NULL; } -libmv_Reconstruction *libmv_solveModal( - const libmv_Tracks * /*libmv_tracks*/, - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, - const libmv_ReconstructionOptions * /*libmv_reconstruction_options*/, +libmv_Reconstruction* libmv_solveModal( + const libmv_Tracks* /*libmv_tracks*/, + const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/, + const libmv_ReconstructionOptions* /*libmv_reconstruction_options*/, reconstruct_progress_update_cb /*progress_update_callback*/, - void * /*callback_customdata*/) { + void* /*callback_customdata*/) { return NULL; } -int libmv_reconstructionIsValid(libmv_Reconstruction * /*libmv_reconstruction*/) { +int libmv_reconstructionIsValid( + libmv_Reconstruction* /*libmv_reconstruction*/) { return 0; } int libmv_reprojectionPointForTrack( - const libmv_Reconstruction * /*libmv_reconstruction*/, + const libmv_Reconstruction* /*libmv_reconstruction*/, int /*track*/, double /*pos*/[3]) { return 0; } double libmv_reprojectionErrorForTrack( - const libmv_Reconstruction * /*libmv_reconstruction*/, - int /*track*/) { + const libmv_Reconstruction* /*libmv_reconstruction*/, int /*track*/) { return 0.0; } double libmv_reprojectionErrorForImage( - const libmv_Reconstruction * /*libmv_reconstruction*/, - int /*image*/) { + const libmv_Reconstruction* /*libmv_reconstruction*/, int /*image*/) { return 0.0; } int libmv_reprojectionCameraForImage( - const libmv_Reconstruction * /*libmv_reconstruction*/, + const libmv_Reconstruction* /*libmv_reconstruction*/, int /*image*/, double /*mat*/[4][4]) { return 0; } double libmv_reprojectionError( - const libmv_Reconstruction * /*libmv_reconstruction*/) { + const libmv_Reconstruction* /*libmv_reconstruction*/) { return 0.0; } void libmv_reconstructionDestroy( - struct libmv_Reconstruction * /*libmv_reconstruction*/) { + struct libmv_Reconstruction* /*libmv_reconstruction*/) { } /* ************ Feature detector ************ */ -libmv_Features *libmv_detectFeaturesByte(const unsigned char * /*image_buffer*/, +libmv_Features* libmv_detectFeaturesByte(const unsigned char* /*image_buffer*/, int /*width*/, int /*height*/, int /*channels*/, - libmv_DetectOptions * /*options*/) { + libmv_DetectOptions* /*options*/) { return NULL; } -struct libmv_Features *libmv_detectFeaturesFloat( - const float * /*image_buffer*/, +struct libmv_Features* libmv_detectFeaturesFloat( + const float* /*image_buffer*/, int /*width*/, int /*height*/, int /*channels*/, - libmv_DetectOptions * /*options*/) { + libmv_DetectOptions* /*options*/) { return NULL; } -int libmv_countFeatures(const libmv_Features * /*libmv_features*/) { +int libmv_countFeatures(const libmv_Features* /*libmv_features*/) { return 0; } -void libmv_getFeature(const libmv_Features * /*libmv_features*/, +void libmv_getFeature(const libmv_Features* /*libmv_features*/, int /*number*/, - double *x, - double *y, - double *score, - double *size) { + double* x, + double* y, + double* score, + double* size) { *x = 0.0; *y = 0.0; *score = 0.0; *size = 0.0; } -void libmv_featuresDestroy(struct libmv_Features * /*libmv_features*/) { +void libmv_featuresDestroy(struct libmv_Features* /*libmv_features*/) { } /* ************ Camera intrinsics ************ */ -libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics( - libmv_Reconstruction * /*libmv_reconstruction*/) { +libmv_CameraIntrinsics* libmv_reconstructionExtractIntrinsics( + libmv_Reconstruction* /*libmv_reconstruction*/) { return NULL; } -libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/) { +libmv_CameraIntrinsics* libmv_cameraIntrinsicsNew( + const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/) { return NULL; } -libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( - const libmv_CameraIntrinsics * /*libmvIntrinsics*/) { +libmv_CameraIntrinsics* libmv_cameraIntrinsicsCopy( + const libmv_CameraIntrinsics* /*libmvIntrinsics*/) { return NULL; } void libmv_cameraIntrinsicsDestroy( - libmv_CameraIntrinsics * /*libmvIntrinsics*/) { + libmv_CameraIntrinsics* /*libmvIntrinsics*/) { } void libmv_cameraIntrinsicsUpdate( - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, - libmv_CameraIntrinsics * /*libmv_intrinsics*/) { + const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/, + libmv_CameraIntrinsics* /*libmv_intrinsics*/) { } void libmv_cameraIntrinsicsSetThreads( - libmv_CameraIntrinsics * /*libmv_intrinsics*/, - int /*threads*/) { + libmv_CameraIntrinsics* /*libmv_intrinsics*/, int /*threads*/) { } void libmv_cameraIntrinsicsExtractOptions( - const libmv_CameraIntrinsics * /*libmv_intrinsics*/, - libmv_CameraIntrinsicsOptions *camera_intrinsics_options) { + const libmv_CameraIntrinsics* /*libmv_intrinsics*/, + libmv_CameraIntrinsicsOptions* camera_intrinsics_options) { memset(camera_intrinsics_options, 0, sizeof(libmv_CameraIntrinsicsOptions)); camera_intrinsics_options->focal_length = 1.0; } void libmv_cameraIntrinsicsUndistortByte( - const libmv_CameraIntrinsics * /*libmv_intrinsics*/, - const unsigned char *source_image, - int width, int height, + const libmv_CameraIntrinsics* /*libmv_intrinsics*/, + const unsigned char* source_image, + int width, + int height, float /*overscan*/, int channels, - unsigned char *destination_image) { - memcpy(destination_image, source_image, + unsigned char* destination_image) { + memcpy(destination_image, + source_image, channels * width * height * sizeof(unsigned char)); } @@ -265,19 +265,21 @@ void libmv_cameraIntrinsicsUndistortFloat( float /*overscan*/, int channels, float* destination_image) { - memcpy(destination_image, source_image, + memcpy(destination_image, + source_image, channels * width * height * sizeof(float)); } void libmv_cameraIntrinsicsDistortByte( const struct libmv_CameraIntrinsics* /*libmv_intrinsics*/, - const unsigned char *source_image, + const unsigned char* source_image, int width, int height, float /*overscan*/, int channels, - unsigned char *destination_image) { - memcpy(destination_image, source_image, + unsigned char* destination_image) { + memcpy(destination_image, + source_image, channels * width * height * sizeof(unsigned char)); } @@ -289,7 +291,8 @@ void libmv_cameraIntrinsicsDistortFloat( float /*overscan*/, int channels, float* destination_image) { - memcpy(destination_image, source_image, + memcpy(destination_image, + source_image, channels * width * height * sizeof(float)); } @@ -315,8 +318,8 @@ void libmv_cameraIntrinsicsInvert( *y1 = 0.0; } -void libmv_homography2DFromCorrespondencesEuc(/* const */ double (* /*x1*/)[2], - /* const */ double (* /*x2*/)[2], +void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*/*x1*/)[2], + /* const */ double (*/*x2*/)[2], int /*num_points*/, double H[3][3]) { memset(H, 0, sizeof(double[3][3])); @@ -327,45 +330,38 @@ void libmv_homography2DFromCorrespondencesEuc(/* const */ double (* /*x1*/)[2], /* ************ autotrack ************ */ -libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* /*frame_accessor*/) -{ +libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* /*frame_accessor*/) { return NULL; } -void libmv_autoTrackDestroy(libmv_AutoTrack* /*libmv_autotrack*/) -{ +void libmv_autoTrackDestroy(libmv_AutoTrack* /*libmv_autotrack*/) { } void libmv_autoTrackSetOptions(libmv_AutoTrack* /*libmv_autotrack*/, - const libmv_AutoTrackOptions* /*options*/) -{ + const libmv_AutoTrackOptions* /*options*/) { } int libmv_autoTrackMarker(libmv_AutoTrack* /*libmv_autotrack*/, const libmv_TrackRegionOptions* /*libmv_options*/, - libmv_Marker * /*libmv_tracker_marker*/, - libmv_TrackRegionResult* /*libmv_result*/) -{ + libmv_Marker* /*libmv_tracker_marker*/, + libmv_TrackRegionResult* /*libmv_result*/) { return 0; } void libmv_autoTrackAddMarker(libmv_AutoTrack* /*libmv_autotrack*/, - const libmv_Marker* /*libmv_marker*/) -{ + const libmv_Marker* /*libmv_marker*/) { } void libmv_autoTrackSetMarkers(libmv_AutoTrack* /*libmv_autotrack*/, const libmv_Marker* /*libmv_marker-*/, - size_t /*num_markers*/) -{ + size_t /*num_markers*/) { } int libmv_autoTrackGetMarker(libmv_AutoTrack* /*libmv_autotrack*/, int /*clip*/, int /*frame*/, int /*track*/, - libmv_Marker* /*libmv_marker*/) -{ + libmv_Marker* /*libmv_marker*/) { return 0; } @@ -376,24 +372,20 @@ libmv_FrameAccessor* libmv_FrameAccessorNew( libmv_GetImageCallback /*get_image_callback*/, libmv_ReleaseImageCallback /*release_image_callback*/, libmv_GetMaskForTrackCallback /*get_mask_for_track_callback*/, - libmv_ReleaseMaskCallback /*release_mask_callback*/) -{ + libmv_ReleaseMaskCallback /*release_mask_callback*/) { return NULL; } -void libmv_FrameAccessorDestroy(libmv_FrameAccessor* /*frame_accessor*/) -{ +void libmv_FrameAccessorDestroy(libmv_FrameAccessor* /*frame_accessor*/) { } int64_t libmv_frameAccessorgetTransformKey( - const libmv_FrameTransform * /*transform*/) -{ + const libmv_FrameTransform* /*transform*/) { return 0; } -void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* /*transform*/, - const libmv_FloatImage* /*input_image*/, - libmv_FloatImage* /*output_image*/) -{ +void libmv_frameAccessorgetTransformRun( + const libmv_FrameTransform* /*transform*/, + const libmv_FloatImage* /*input_image*/, + libmv_FloatImage* /*output_image*/) { } - diff --git a/intern/libmv/intern/track_region.cc b/intern/libmv/intern/track_region.cc index 2a3909c0ced..af88afd7ac2 100644 --- a/intern/libmv/intern/track_region.cc +++ b/intern/libmv/intern/track_region.cc @@ -32,17 +32,17 @@ #undef DUMP_ALWAYS using libmv::FloatImage; +using libmv::TrackRegion; using libmv::TrackRegionOptions; using libmv::TrackRegionResult; -using libmv::TrackRegion; void libmv_configureTrackRegionOptions( const libmv_TrackRegionOptions& options, TrackRegionOptions* track_region_options) { switch (options.motion_model) { -#define LIBMV_CONVERT(the_model) \ - case TrackRegionOptions::the_model: \ - track_region_options->mode = TrackRegionOptions::the_model; \ +#define LIBMV_CONVERT(the_model) \ + case TrackRegionOptions::the_model: \ + track_region_options->mode = TrackRegionOptions::the_model; \ break; LIBMV_CONVERT(TRANSLATION) LIBMV_CONVERT(TRANSLATION_ROTATION) @@ -66,7 +66,8 @@ void libmv_configureTrackRegionOptions( * so disabling for now for until proper prediction model is landed. * * The thing is, currently blender sends input coordinates as the guess to - * region tracker and in case of fast motion such an early out ruins the track. + * region tracker and in case of fast motion such an early out ruins the + * track. */ track_region_options->attempt_refine_before_brute = false; track_region_options->use_normalized_intensities = options.use_normalization; @@ -74,7 +75,7 @@ void libmv_configureTrackRegionOptions( void libmv_regionTrackergetResult(const TrackRegionResult& track_region_result, libmv_TrackRegionResult* result) { - result->termination = (int) track_region_result.termination; + result->termination = (int)track_region_result.termination; result->termination_reason = ""; result->correlation = track_region_result.correlation; } @@ -108,33 +109,27 @@ int libmv_trackRegion(const libmv_TrackRegionOptions* options, libmv_configureTrackRegionOptions(*options, &track_region_options); if (options->image1_mask) { - libmv_floatBufferToFloatImage(options->image1_mask, - image1_width, - image1_height, - 1, - &image1_mask); + libmv_floatBufferToFloatImage( + options->image1_mask, image1_width, image1_height, 1, &image1_mask); track_region_options.image1_mask = &image1_mask; } // Convert from raw float buffers to libmv's FloatImage. FloatImage old_patch, new_patch; - libmv_floatBufferToFloatImage(image1, - image1_width, - image1_height, - 1, - &old_patch); - libmv_floatBufferToFloatImage(image2, - image2_width, - image2_height, - 1, - &new_patch); + libmv_floatBufferToFloatImage( + image1, image1_width, image1_height, 1, &old_patch); + libmv_floatBufferToFloatImage( + image2, image2_width, image2_height, 1, &new_patch); TrackRegionResult track_region_result; - TrackRegion(old_patch, new_patch, - xx1, yy1, + TrackRegion(old_patch, + new_patch, + xx1, + yy1, track_region_options, - xx2, yy2, + xx2, + yy2, &track_region_result); // Convert to floats for the blender api. diff --git a/intern/libmv/intern/track_region.h b/intern/libmv/intern/track_region.h index 48ae97a1c1a..4566fe9bf0f 100644 --- a/intern/libmv/intern/track_region.h +++ b/intern/libmv/intern/track_region.h @@ -31,7 +31,7 @@ typedef struct libmv_TrackRegionOptions { int use_normalization; double minimum_correlation; double sigma; - float *image1_mask; + float* image1_mask; } libmv_TrackRegionOptions; typedef struct libmv_TrackRegionResult { @@ -42,9 +42,9 @@ typedef struct libmv_TrackRegionResult { #ifdef __cplusplus namespace libmv { - struct TrackRegionOptions; - struct TrackRegionResult; -} +struct TrackRegionOptions; +struct TrackRegionResult; +} // namespace libmv void libmv_configureTrackRegionOptions( const libmv_TrackRegionOptions& options, libmv::TrackRegionOptions* track_region_options); diff --git a/intern/libmv/intern/tracks.cc b/intern/libmv/intern/tracks.cc index 0ca5a31796b..146908d6db5 100644 --- a/intern/libmv/intern/tracks.cc +++ b/intern/libmv/intern/tracks.cc @@ -28,18 +28,18 @@ using libmv::Tracks; libmv_Tracks* libmv_tracksNew(void) { Tracks* tracks = LIBMV_OBJECT_NEW(Tracks); - return (libmv_Tracks*) tracks; + return (libmv_Tracks*)tracks; } void libmv_tracksDestroy(libmv_Tracks* libmv_tracks) { LIBMV_OBJECT_DELETE(libmv_tracks, Tracks); } -void libmv_tracksInsert(libmv_Tracks *libmv_tracks, +void libmv_tracksInsert(libmv_Tracks* libmv_tracks, int image, int track, double x, double y, double weight) { - ((Tracks *) libmv_tracks)->Insert(image, track, x, y, weight); + ((Tracks*)libmv_tracks)->Insert(image, track, x, y, weight); } diff --git a/intern/libmv/intern/tracksN.cc b/intern/libmv/intern/tracksN.cc index 1441d8a2066..c7ffb13a386 100644 --- a/intern/libmv/intern/tracksN.cc +++ b/intern/libmv/intern/tracksN.cc @@ -25,8 +25,7 @@ using mv::Marker; using mv::Tracks; -void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker, - Marker *marker) { +void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker, Marker* marker) { marker->clip = libmv_marker.clip; marker->frame = libmv_marker.frame; marker->track = libmv_marker.track; @@ -41,17 +40,16 @@ void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker, marker->search_region.max(0) = libmv_marker.search_region_max[0]; marker->search_region.max(1) = libmv_marker.search_region_max[1]; marker->weight = libmv_marker.weight; - marker->source = (Marker::Source) libmv_marker.source; - marker->status = (Marker::Status) libmv_marker.status; + marker->source = (Marker::Source)libmv_marker.source; + marker->status = (Marker::Status)libmv_marker.status; marker->reference_clip = libmv_marker.reference_clip; marker->reference_frame = libmv_marker.reference_frame; - marker->model_type = (Marker::ModelType) libmv_marker.model_type; + marker->model_type = (Marker::ModelType)libmv_marker.model_type; marker->model_id = libmv_marker.model_id; marker->disabled_channels = libmv_marker.disabled_channels; } -void libmv_markerToApiMarker(const Marker& marker, - libmv_Marker *libmv_marker) { +void libmv_markerToApiMarker(const Marker& marker, libmv_Marker* libmv_marker) { libmv_marker->clip = marker.clip; libmv_marker->frame = marker.frame; libmv_marker->track = marker.track; @@ -66,11 +64,11 @@ void libmv_markerToApiMarker(const Marker& marker, libmv_marker->search_region_max[0] = marker.search_region.max(0); libmv_marker->search_region_max[1] = marker.search_region.max(1); libmv_marker->weight = marker.weight; - libmv_marker->source = (libmv_MarkerSource) marker.source; - libmv_marker->status = (libmv_MarkerStatus) marker.status; + libmv_marker->source = (libmv_MarkerSource)marker.source; + libmv_marker->status = (libmv_MarkerStatus)marker.status; libmv_marker->reference_clip = marker.reference_clip; libmv_marker->reference_frame = marker.reference_frame; - libmv_marker->model_type = (libmv_MarkerModelType) marker.model_type; + libmv_marker->model_type = (libmv_MarkerModelType)marker.model_type; libmv_marker->model_id = marker.model_id; libmv_marker->disabled_channels = marker.disabled_channels; } @@ -78,7 +76,7 @@ void libmv_markerToApiMarker(const Marker& marker, libmv_TracksN* libmv_tracksNewN(void) { Tracks* tracks = LIBMV_OBJECT_NEW(Tracks); - return (libmv_TracksN*) tracks; + return (libmv_TracksN*)tracks; } void libmv_tracksDestroyN(libmv_TracksN* libmv_tracks) { @@ -89,7 +87,7 @@ void libmv_tracksAddMarkerN(libmv_TracksN* libmv_tracks, const libmv_Marker* libmv_marker) { Marker marker; libmv_apiMarkerToMarker(*libmv_marker, &marker); - ((Tracks*) libmv_tracks)->AddMarker(marker); + ((Tracks*)libmv_tracks)->AddMarker(marker); } void libmv_tracksGetMarkerN(libmv_TracksN* libmv_tracks, @@ -98,7 +96,7 @@ void libmv_tracksGetMarkerN(libmv_TracksN* libmv_tracks, int track, libmv_Marker* libmv_marker) { Marker marker; - ((Tracks*) libmv_tracks)->GetMarker(clip, frame, track, &marker); + ((Tracks*)libmv_tracks)->GetMarker(clip, frame, track, &marker); libmv_markerToApiMarker(marker, libmv_marker); } @@ -106,26 +104,25 @@ void libmv_tracksRemoveMarkerN(libmv_TracksN* libmv_tracks, int clip, int frame, int track) { - ((Tracks *) libmv_tracks)->RemoveMarker(clip, frame, track); + ((Tracks*)libmv_tracks)->RemoveMarker(clip, frame, track); } -void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, - int track) { - ((Tracks *) libmv_tracks)->RemoveMarkersForTrack(track); +void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, int track) { + ((Tracks*)libmv_tracks)->RemoveMarkersForTrack(track); } int libmv_tracksMaxClipN(libmv_TracksN* libmv_tracks) { - return ((Tracks*) libmv_tracks)->MaxClip(); + return ((Tracks*)libmv_tracks)->MaxClip(); } int libmv_tracksMaxFrameN(libmv_TracksN* libmv_tracks, int clip) { - return ((Tracks*) libmv_tracks)->MaxFrame(clip); + return ((Tracks*)libmv_tracks)->MaxFrame(clip); } int libmv_tracksMaxTrackN(libmv_TracksN* libmv_tracks) { - return ((Tracks*) libmv_tracks)->MaxTrack(); + return ((Tracks*)libmv_tracks)->MaxTrack(); } int libmv_tracksNumMarkersN(libmv_TracksN* libmv_tracks) { - return ((Tracks*) libmv_tracks)->NumMarkers(); + return ((Tracks*)libmv_tracks)->NumMarkers(); } diff --git a/intern/libmv/intern/tracksN.h b/intern/libmv/intern/tracksN.h index 9363d34bed7..b5d1f9753e0 100644 --- a/intern/libmv/intern/tracksN.h +++ b/intern/libmv/intern/tracksN.h @@ -79,20 +79,19 @@ typedef struct libmv_Marker { #ifdef __cplusplus namespace mv { - struct Marker; +struct Marker; } void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker, - mv::Marker *marker); + mv::Marker* marker); void libmv_markerToApiMarker(const mv::Marker& marker, - libmv_Marker *libmv_marker); + libmv_Marker* libmv_marker); #endif libmv_TracksN* libmv_tracksNewN(void); void libmv_tracksDestroyN(libmv_TracksN* libmv_tracks); - void libmv_tracksAddMarkerN(libmv_TracksN* libmv_tracks, const libmv_Marker* libmv_marker); @@ -107,8 +106,7 @@ void libmv_tracksRemoveMarkerN(libmv_TracksN* libmv_tracks, int frame, int track); -void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, - int track); +void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, int track); int libmv_tracksMaxClipN(libmv_TracksN* libmv_tracks); int libmv_tracksMaxFrameN(libmv_TracksN* libmv_tracks, int clip); diff --git a/intern/libmv/intern/utildefines.h b/intern/libmv/intern/utildefines.h index d76d32f9c4d..052052a1d76 100644 --- a/intern/libmv/intern/utildefines.h +++ b/intern/libmv/intern/utildefines.h @@ -30,27 +30,33 @@ # define LIBMV_OBJECT_NEW OBJECT_GUARDED_NEW # define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE # define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE -# define LIBMV_STRUCT_NEW(type, count) \ - (type*)MEM_mallocN(sizeof(type) * count, __func__) +# define LIBMV_STRUCT_NEW(type, count) \ + (type*)MEM_mallocN(sizeof(type) * count, __func__) # define LIBMV_STRUCT_DELETE(what) MEM_freeN(what) #else // Need this to keep libmv-capi potentially standalone. # if defined __GNUC__ || defined __sun -# define LIBMV_OBJECT_NEW(type, args ...) \ - new(malloc(sizeof(type))) type(args) +# define LIBMV_OBJECT_NEW(type, args...) \ + new (malloc(sizeof(type))) type(args) # else -# define LIBMV_OBJECT_NEW(type, ...) \ - new(malloc(sizeof(type))) type(__VA_ARGS__) -#endif -# define LIBMV_OBJECT_DELETE(what, type) \ - { \ - if (what) { \ - ((type*)(what))->~type(); \ - free(what); \ - } \ - } (void)0 +# define LIBMV_OBJECT_NEW(type, ...) \ + new (malloc(sizeof(type))) type(__VA_ARGS__) +# endif +# define LIBMV_OBJECT_DELETE(what, type) \ + { \ + if (what) { \ + ((type*)(what))->~type(); \ + free(what); \ + } \ + } \ + (void)0 # define LIBMV_STRUCT_NEW(type, count) (type*)malloc(sizeof(type) * count) -# define LIBMV_STRUCT_DELETE(what) { if (what) free(what); } (void)0 +# define LIBMV_STRUCT_DELETE(what) \ + { \ + if (what) \ + free(what); \ + } \ + (void)0 #endif #endif // LIBMV_C_API_UTILDEFINES_H_ diff --git a/intern/libmv/libmv/autotrack/autotrack.cc b/intern/libmv/libmv/autotrack/autotrack.cc index 3b0a762178a..c18567a5f28 100644 --- a/intern/libmv/libmv/autotrack/autotrack.cc +++ b/intern/libmv/libmv/autotrack/autotrack.cc @@ -21,9 +21,9 @@ // Author: mierle@gmail.com (Keir Mierle) #include "libmv/autotrack/autotrack.h" -#include "libmv/autotrack/quad.h" #include "libmv/autotrack/frame_accessor.h" #include "libmv/autotrack/predict_tracks.h" +#include "libmv/autotrack/quad.h" #include "libmv/base/scoped_ptr.h" #include "libmv/logging/logging.h" #include "libmv/numeric/numeric.h" @@ -35,34 +35,30 @@ namespace { class DisableChannelsTransform : public FrameAccessor::Transform { public: DisableChannelsTransform(int disabled_channels) - : disabled_channels_(disabled_channels) { } + : disabled_channels_(disabled_channels) {} - int64_t key() const { - return disabled_channels_; - } + int64_t key() const { return disabled_channels_; } void run(const FloatImage& input, FloatImage* output) const { - bool disable_red = (disabled_channels_ & Marker::CHANNEL_R) != 0, + bool disable_red = (disabled_channels_ & Marker::CHANNEL_R) != 0, disable_green = (disabled_channels_ & Marker::CHANNEL_G) != 0, - disable_blue = (disabled_channels_ & Marker::CHANNEL_B) != 0; + disable_blue = (disabled_channels_ & Marker::CHANNEL_B) != 0; - LG << "Disabling channels: " - << (disable_red ? "R " : "") - << (disable_green ? "G " : "") - << (disable_blue ? "B" : ""); + LG << "Disabling channels: " << (disable_red ? "R " : "") + << (disable_green ? "G " : "") << (disable_blue ? "B" : ""); // It's important to rescale the resultappropriately so that e.g. if only // blue is selected, it's not zeroed out. - float scale = (disable_red ? 0.0f : 0.2126f) + + float scale = (disable_red ? 0.0f : 0.2126f) + (disable_green ? 0.0f : 0.7152f) + - (disable_blue ? 0.0f : 0.0722f); + (disable_blue ? 0.0f : 0.0722f); output->Resize(input.Height(), input.Width(), 1); for (int y = 0; y < input.Height(); y++) { for (int x = 0; x < input.Width(); x++) { - float r = disable_red ? 0.0f : input(y, x, 0); + float r = disable_red ? 0.0f : input(y, x, 0); float g = disable_green ? 0.0f : input(y, x, 1); - float b = disable_blue ? 0.0f : input(y, x, 2); + float b = disable_blue ? 0.0f : input(y, x, 2); (*output)(y, x, 0) = (0.2126f * r + 0.7152f * g + 0.0722f * b) / scale; } } @@ -73,7 +69,7 @@ class DisableChannelsTransform : public FrameAccessor::Transform { int disabled_channels_; }; -template +template void QuadToArrays(const QuadT& quad, ArrayT* x, ArrayT* y) { for (int i = 0; i < 4; ++i) { x[i] = quad.coordinates(i, 0); @@ -115,11 +111,8 @@ FrameAccessor::Key GetMaskForMarker(const Marker& marker, FrameAccessor* frame_accessor, FloatImage* mask) { Region region = marker.search_region.Rounded(); - return frame_accessor->GetMaskForTrack(marker.clip, - marker.frame, - marker.track, - ®ion, - mask); + return frame_accessor->GetMaskForTrack( + marker.clip, marker.frame, marker.track, ®ion, mask); } } // namespace @@ -152,23 +145,20 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker, // TODO(keir): Technically this could take a smaller slice from the source // image instead of taking one the size of the search window. FloatImage reference_image; - FrameAccessor::Key reference_key = GetImageForMarker(reference_marker, - frame_accessor_, - &reference_image); + FrameAccessor::Key reference_key = + GetImageForMarker(reference_marker, frame_accessor_, &reference_image); if (!reference_key) { LG << "Couldn't get frame for reference marker: " << reference_marker; return false; } FloatImage reference_mask; - FrameAccessor::Key reference_mask_key = GetMaskForMarker(reference_marker, - frame_accessor_, - &reference_mask); + FrameAccessor::Key reference_mask_key = + GetMaskForMarker(reference_marker, frame_accessor_, &reference_mask); FloatImage tracked_image; - FrameAccessor::Key tracked_key = GetImageForMarker(*tracked_marker, - frame_accessor_, - &tracked_image); + FrameAccessor::Key tracked_key = + GetImageForMarker(*tracked_marker, frame_accessor_, &tracked_image); if (!tracked_key) { frame_accessor_->ReleaseImage(reference_key); LG << "Couldn't get frame for tracked marker: " << tracked_marker; @@ -191,9 +181,11 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker, local_track_region_options.attempt_refine_before_brute = predicted_position; TrackRegion(reference_image, tracked_image, - x1, y1, + x1, + y1, local_track_region_options, - x2, y2, + x2, + y2, result); // Copy results over the tracked marker. @@ -208,7 +200,7 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker, tracked_marker->search_region.Offset(delta); tracked_marker->source = Marker::TRACKED; tracked_marker->status = Marker::UNKNOWN; - tracked_marker->reference_clip = reference_marker.clip; + tracked_marker->reference_clip = reference_marker.clip; tracked_marker->reference_frame = reference_marker.frame; // Release the images and masks from the accessor cache. @@ -230,7 +222,9 @@ void AutoTrack::SetMarkers(vector* markers) { tracks_.SetMarkers(markers); } -bool AutoTrack::GetMarker(int clip, int frame, int track, +bool AutoTrack::GetMarker(int clip, + int frame, + int track, Marker* markers) const { return tracks_.GetMarker(clip, frame, track, markers); } @@ -242,7 +236,8 @@ void AutoTrack::DetectAndTrack(const DetectAndTrackOptions& options) { vector previous_frame_markers; // Q: How to decide track #s when detecting? // Q: How to match markers from previous frame? set of prev frame tracks? - // Q: How to decide what markers should get tracked and which ones should not? + // Q: How to decide what markers should get tracked and which ones should + // not? for (int frame = 0; frame < num_frames; ++frame) { if (Cancelled()) { LG << "Got cancel message while detecting and tracking..."; @@ -271,8 +266,7 @@ void AutoTrack::DetectAndTrack(const DetectAndTrackOptions& options) { for (int i = 0; i < this_frame_markers.size(); ++i) { tracks_in_this_frame.push_back(this_frame_markers[i].track); } - std::sort(tracks_in_this_frame.begin(), - tracks_in_this_frame.end()); + std::sort(tracks_in_this_frame.begin(), tracks_in_this_frame.end()); // Find tracks in the previous frame that are not in this one. vector previous_frame_markers_to_track; diff --git a/intern/libmv/libmv/autotrack/autotrack.h b/intern/libmv/libmv/autotrack/autotrack.h index 1d7422f54e7..281766f600f 100644 --- a/intern/libmv/libmv/autotrack/autotrack.h +++ b/intern/libmv/libmv/autotrack/autotrack.h @@ -23,8 +23,8 @@ #ifndef LIBMV_AUTOTRACK_AUTOTRACK_H_ #define LIBMV_AUTOTRACK_AUTOTRACK_H_ -#include "libmv/autotrack/tracks.h" #include "libmv/autotrack/region.h" +#include "libmv/autotrack/tracks.h" #include "libmv/tracking/track_region.h" namespace libmv { @@ -74,15 +74,14 @@ class AutoTrack { Region search_region; }; - AutoTrack(FrameAccessor* frame_accessor) - : frame_accessor_(frame_accessor) {} + AutoTrack(FrameAccessor* frame_accessor) : frame_accessor_(frame_accessor) {} // Marker manipulation. // Clip manipulation. // Set the number of clips. These clips will get accessed from the frame // accessor, matches between frames found, and a reconstruction created. - //void SetNumFrames(int clip, int num_frames); + // void SetNumFrames(int clip, int num_frames); // Tracking & Matching @@ -90,7 +89,7 @@ class AutoTrack { // Caller maintains ownership of *result and *tracked_marker. bool TrackMarker(Marker* tracked_marker, TrackRegionResult* result, - const TrackRegionOptions* track_options=NULL); + const TrackRegionOptions* track_options = NULL); // Wrapper around Tracks API; however these may add additional processing. void AddMarker(const Marker& tracked_marker); @@ -99,36 +98,36 @@ class AutoTrack { // TODO(keir): Implement frame matching! This could be very cool for loop // closing and connecting across clips. - //void MatchFrames(int clip1, int frame1, int clip2, int frame2) {} + // void MatchFrames(int clip1, int frame1, int clip2, int frame2) {} // Wrapper around the Reconstruction API. // Returns the new ID. int AddCameraIntrinsics(CameraIntrinsics* intrinsics) { - (void) intrinsics; + (void)intrinsics; return 0; } // XXX int SetClipIntrinsics(int clip, int intrinsics) { - (void) clip; - (void) intrinsics; + (void)clip; + (void)intrinsics; return 0; - } // XXX + } // XXX enum Motion { GENERAL_CAMERA_MOTION, TRIPOD_CAMERA_MOTION, }; int SetClipMotion(int clip, Motion motion) { - (void) clip; - (void) motion; + (void)clip; + (void)motion; return 0; - } // XXX + } // XXX // Decide what to refine for the given intrinsics. bundle_options is from // bundle.h (e.g. BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL_K1). void SetIntrinsicsRefine(int intrinsics, int bundle_options) { - (void) intrinsics; - (void) bundle_options; - } // XXX + (void)intrinsics; + (void)bundle_options; + } // XXX // Keyframe read/write. struct ClipFrame { @@ -150,20 +149,19 @@ class AutoTrack { }; void DetectAndTrack(const DetectAndTrackOptions& options); - struct DetectFeaturesInFrameOptions { - }; - void DetectFeaturesInFrame(int clip, int frame, - const DetectFeaturesInFrameOptions* options=NULL) { - (void) clip; - (void) frame; - (void) options; - } // XXX + struct DetectFeaturesInFrameOptions {}; + void DetectFeaturesInFrame( + int clip, int frame, const DetectFeaturesInFrameOptions* options = NULL) { + (void)clip; + (void)frame; + (void)options; + } // XXX // Does not take ownership of the given listener, but keeps a reference to it. - void AddListener(OperationListener* listener) {(void) listener;} // XXX + void AddListener(OperationListener* listener) { (void)listener; } // XXX // Create the initial reconstruction, - //void FindInitialReconstruction(); + // void FindInitialReconstruction(); // State machine // @@ -202,17 +200,17 @@ class AutoTrack { bool Cancelled() { return false; } Tracks tracks_; // May be normalized camera coordinates or raw pixels. - //Reconstruction reconstruction_; + // Reconstruction reconstruction_; // TODO(keir): Add the motion models here. - //vector motion_models_; + // vector motion_models_; // TODO(keir): Should num_clips and num_frames get moved to FrameAccessor? // TODO(keir): What about masking for clips and frames to prevent various // things like reconstruction or tracking from happening on certain frames? FrameAccessor* frame_accessor_; - //int num_clips_; - //vector num_frames_; // Indexed by clip. + // int num_clips_; + // vector num_frames_; // Indexed by clip. // The intrinsics for each clip, assuming each clip has fixed intrinsics. // TODO(keir): Decide what the semantics should be for varying focal length. diff --git a/intern/libmv/libmv/autotrack/frame_accessor.h b/intern/libmv/libmv/autotrack/frame_accessor.h index cfad9ca71ff..e9308dc400a 100644 --- a/intern/libmv/libmv/autotrack/frame_accessor.h +++ b/intern/libmv/libmv/autotrack/frame_accessor.h @@ -41,7 +41,7 @@ using libmv::FloatImage; // implementations to cache filtered image pieces). struct FrameAccessor { struct Transform { - virtual ~Transform() { } + virtual ~Transform() {} // The key should depend on the transform arguments. Must be non-zero. virtual int64_t key() const = 0; @@ -50,10 +50,7 @@ struct FrameAccessor { virtual void run(const FloatImage& input, FloatImage* output) const = 0; }; - enum InputMode { - MONO, - RGBA - }; + enum InputMode { MONO, RGBA }; typedef void* Key; @@ -100,6 +97,6 @@ struct FrameAccessor { virtual int NumFrames(int clip) = 0; }; -} // namespace libmv +} // namespace mv #endif // LIBMV_AUTOTRACK_FRAME_ACCESSOR_H_ diff --git a/intern/libmv/libmv/autotrack/marker.h b/intern/libmv/libmv/autotrack/marker.h index bb803313af8..29e163c0446 100644 --- a/intern/libmv/libmv/autotrack/marker.h +++ b/intern/libmv/libmv/autotrack/marker.h @@ -57,23 +57,19 @@ struct Marker { float weight; enum Source { - MANUAL, // The user placed this marker manually. - DETECTED, // A keypoint detector found this point. - TRACKED, // The tracking algorithm placed this marker. - MATCHED, // A matching algorithm (e.g. SIFT or SURF or ORB) found this. - PREDICTED, // A motion model predicted this marker. This is needed for - // handling occlusions in some cases where an imaginary marker - // is placed to keep camera motion smooth. + MANUAL, // The user placed this marker manually. + DETECTED, // A keypoint detector found this point. + TRACKED, // The tracking algorithm placed this marker. + MATCHED, // A matching algorithm (e.g. SIFT or SURF or ORB) found this. + PREDICTED, // A motion model predicted this marker. This is needed for + // handling occlusions in some cases where an imaginary marker + // is placed to keep camera motion smooth. }; Source source; // Markers may be inliers or outliers if the tracking fails; this allows // visualizing the markers in the image. - enum Status { - UNKNOWN, - INLIER, - OUTLIER - }; + enum Status { UNKNOWN, INLIER, OUTLIER }; Status status; // When doing correlation tracking, where to search in the current frame for @@ -90,12 +86,7 @@ struct Marker { // another primitive (a rectangular prisim). This captures the information // needed to say that for example a collection of markers belongs to model #2 // (and model #2 is a plane). - enum ModelType { - POINT, - PLANE, - LINE, - CUBE - }; + enum ModelType { POINT, PLANE, LINE, CUBE }; ModelType model_type; // The model ID this track (e.g. the second model, which is a plane). @@ -114,7 +105,7 @@ struct Marker { int disabled_channels; // Offset everything (center, patch, search) by the given delta. - template + template void Offset(const T& offset) { center += offset.template cast(); patch.coordinates.rowwise() += offset.template cast(); @@ -122,19 +113,15 @@ struct Marker { } // Shift the center to the given new position (and patch, search). - template + template void SetPosition(const T& new_center) { Offset(new_center - center); } }; inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { - out << "{" - << marker.clip << ", " - << marker.frame << ", " - << marker.track << ", (" - << marker.center.x() << ", " - << marker.center.y() << ")" + out << "{" << marker.clip << ", " << marker.frame << ", " << marker.track + << ", (" << marker.center.x() << ", " << marker.center.y() << ")" << "}"; return out; } diff --git a/intern/libmv/libmv/autotrack/model.h b/intern/libmv/libmv/autotrack/model.h index 1165281cdac..e79d38b742b 100644 --- a/intern/libmv/libmv/autotrack/model.h +++ b/intern/libmv/libmv/autotrack/model.h @@ -23,18 +23,13 @@ #ifndef LIBMV_AUTOTRACK_MODEL_H_ #define LIBMV_AUTOTRACK_MODEL_H_ -#include "libmv/numeric/numeric.h" #include "libmv/autotrack/quad.h" +#include "libmv/numeric/numeric.h" namespace mv { struct Model { - enum ModelType { - POINT, - PLANE, - LINE, - CUBE - }; + enum ModelType { POINT, PLANE, LINE, CUBE }; // ??? }; diff --git a/intern/libmv/libmv/autotrack/predict_tracks.cc b/intern/libmv/libmv/autotrack/predict_tracks.cc index 3786c1b9a3b..d78b5b340f9 100644 --- a/intern/libmv/libmv/autotrack/predict_tracks.cc +++ b/intern/libmv/libmv/autotrack/predict_tracks.cc @@ -20,8 +20,8 @@ // // Author: mierle@gmail.com (Keir Mierle) -#include "libmv/autotrack/marker.h" #include "libmv/autotrack/predict_tracks.h" +#include "libmv/autotrack/marker.h" #include "libmv/autotrack/tracks.h" #include "libmv/base/vector.h" #include "libmv/logging/logging.h" @@ -31,8 +31,8 @@ namespace mv { namespace { -using libmv::vector; using libmv::Vec2; +using libmv::vector; // Implied time delta between steps. Set empirically by tweaking and seeing // what numbers did best at prediction. @@ -57,6 +57,8 @@ const double dt = 3.8; // For a typical system having constant velocity. This gives smooth-appearing // predictions, but they are not always as accurate. +// +// clang-format off const double velocity_state_transition_data[] = { 1, dt, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, @@ -65,10 +67,13 @@ const double velocity_state_transition_data[] = { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 }; +// clang-format on #if 0 // This 3rd-order system also models acceleration. This makes for "jerky" // predictions, but that tend to be more accurate. +// +// clang-format off const double acceleration_state_transition_data[] = { 1, dt, dt*dt/2, 0, 0, 0, 0, 1, dt, 0, 0, 0, @@ -77,9 +82,12 @@ const double acceleration_state_transition_data[] = { 0, 0, 0, 0, 1, dt, 0, 0, 0, 0, 0, 1 }; +// clang-format on // This system (attempts) to add an angular velocity component. However, it's // total junk. +// +// clang-format off const double angular_state_transition_data[] = { 1, dt, -dt, 0, 0, 0, // Position x 0, 1, 0, 0, 0, 0, // Velocity x @@ -88,17 +96,22 @@ const double angular_state_transition_data[] = { 0, 0, 0, 0, 1, 0, // Velocity y 0, 0, 0, 0, 0, 1 // Ignored }; +// clang-format on #endif const double* state_transition_data = velocity_state_transition_data; // Observation matrix. +// clang-format off const double observation_data[] = { 1., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0. }; +// clang-format on // Process covariance. +// +// clang-format off const double process_covariance_data[] = { 35, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, @@ -107,14 +120,19 @@ const double process_covariance_data[] = { 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 5 }; +// clang-format on // Process covariance. const double measurement_covariance_data[] = { - 0.01, 0.00, - 0.00, 0.01, + 0.01, + 0.00, + 0.00, + 0.01, }; // Initial covariance. +// +// clang-format off const double initial_covariance_data[] = { 10, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, @@ -123,6 +141,7 @@ const double initial_covariance_data[] = { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 }; +// clang-format on typedef mv::KalmanFilter TrackerKalman; @@ -138,7 +157,7 @@ bool OrderByFrameLessThan(const Marker* a, const Marker* b) { } return a->clip < b->clip; } - return a->frame < b-> frame; + return a->frame < b->frame; } // Predicted must be after the previous markers (in the frame numbering sense). @@ -146,9 +165,9 @@ void RunPrediction(const vector previous_markers, Marker* predicted_marker) { TrackerKalman::State state; state.mean << previous_markers[0]->center.x(), 0, 0, - previous_markers[0]->center.y(), 0, 0; - state.covariance = Eigen::Matrix( - initial_covariance_data); + previous_markers[0]->center.y(), 0, 0; + state.covariance = + Eigen::Matrix(initial_covariance_data); int current_frame = previous_markers[0]->frame; int target_frame = predicted_marker->frame; @@ -159,19 +178,18 @@ void RunPrediction(const vector previous_markers, for (int i = 1; i < previous_markers.size(); ++i) { // Step forward predicting the state until it is on the current marker. int predictions = 0; - for (; - current_frame != previous_markers[i]->frame; + for (; current_frame != previous_markers[i]->frame; current_frame += frame_delta) { filter.Step(&state); predictions++; - LG << "Predicted point (frame " << current_frame << "): " - << state.mean(0) << ", " << state.mean(3); + LG << "Predicted point (frame " << current_frame << "): " << state.mean(0) + << ", " << state.mean(3); } // Log the error -- not actually used, but interesting. Vec2 error = previous_markers[i]->center.cast() - Vec2(state.mean(0), state.mean(3)); - LG << "Prediction error for " << predictions << " steps: (" - << error.x() << ", " << error.y() << "); norm: " << error.norm(); + LG << "Prediction error for " << predictions << " steps: (" << error.x() + << ", " << error.y() << "); norm: " << error.norm(); // Now that the state is predicted in the current frame, update the state // based on the measurement from the current frame. filter.Update(previous_markers[i]->center.cast(), @@ -184,8 +202,8 @@ void RunPrediction(const vector previous_markers, // predict until the target frame. for (; current_frame != target_frame; current_frame += frame_delta) { filter.Step(&state); - LG << "Final predicted point (frame " << current_frame << "): " - << state.mean(0) << ", " << state.mean(3); + LG << "Final predicted point (frame " << current_frame + << "): " << state.mean(0) << ", " << state.mean(3); } // The x and y positions are at 0 and 3; ignore acceleration and velocity. @@ -253,13 +271,13 @@ bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) { } else if (insert_at != -1) { // Found existing marker; scan before and after it. forward_scan_begin = insert_at + 1; - forward_scan_end = markers.size() - 1;; + forward_scan_end = markers.size() - 1; backward_scan_begin = insert_at - 1; backward_scan_end = 0; } else { // Didn't find existing marker but found an insertion point. forward_scan_begin = insert_before; - forward_scan_end = markers.size() - 1;; + forward_scan_end = markers.size() - 1; backward_scan_begin = insert_before - 1; backward_scan_end = 0; } @@ -301,9 +319,8 @@ bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) { return false; } LG << "Predicting backward"; - int predict_begin = - std::min(forward_scan_begin + max_frames_to_predict_from, - forward_scan_end); + int predict_begin = std::min( + forward_scan_begin + max_frames_to_predict_from, forward_scan_end); int predict_end = forward_scan_begin; vector previous_markers; for (int i = predict_begin; i >= predict_end; --i) { @@ -312,7 +329,6 @@ bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) { RunPrediction(previous_markers, marker); return false; } - } } // namespace mv diff --git a/intern/libmv/libmv/autotrack/predict_tracks_test.cc b/intern/libmv/libmv/autotrack/predict_tracks_test.cc index f7c2c68d750..fea93b91bce 100644 --- a/intern/libmv/libmv/autotrack/predict_tracks_test.cc +++ b/intern/libmv/libmv/autotrack/predict_tracks_test.cc @@ -35,17 +35,15 @@ static void AddMarker(int frame, float x, float y, Tracks* tracks) { marker.frame = frame; marker.center.x() = x; marker.center.y() = y; - marker.patch.coordinates << x - 1, y - 1, - x + 1, y - 1, - x + 1, y + 1, - x - 1, y + 1; + marker.patch.coordinates << x - 1, y - 1, x + 1, y - 1, x + 1, y + 1, x - 1, + y + 1; tracks->AddMarker(marker); } TEST(PredictMarkerPosition, EasyLinearMotion) { Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); + AddMarker(0, 1.0, 0.0, &tracks); + AddMarker(1, 2.0, 5.0, &tracks); AddMarker(2, 3.0, 10.0, &tracks); AddMarker(3, 4.0, 15.0, &tracks); AddMarker(4, 5.0, 20.0, &tracks); @@ -66,10 +64,8 @@ TEST(PredictMarkerPosition, EasyLinearMotion) { // Check the patch coordinates as well. double x = 9, y = 40.0; Quad2Df expected_patch; - expected_patch.coordinates << x - 1, y - 1, - x + 1, y - 1, - x + 1, y + 1, - x - 1, y + 1; + expected_patch.coordinates << x - 1, y - 1, x + 1, y - 1, x + 1, y + 1, x - 1, + y + 1; error = (expected_patch.coordinates - predicted.patch.coordinates).norm(); LG << "Patch error: " << error; @@ -78,8 +74,8 @@ TEST(PredictMarkerPosition, EasyLinearMotion) { TEST(PredictMarkerPosition, EasyBackwardLinearMotion) { Tracks tracks; - AddMarker(8, 1.0, 0.0, &tracks); - AddMarker(7, 2.0, 5.0, &tracks); + AddMarker(8, 1.0, 0.0, &tracks); + AddMarker(7, 2.0, 5.0, &tracks); AddMarker(6, 3.0, 10.0, &tracks); AddMarker(5, 4.0, 15.0, &tracks); AddMarker(4, 5.0, 20.0, &tracks); @@ -101,10 +97,8 @@ TEST(PredictMarkerPosition, EasyBackwardLinearMotion) { // Check the patch coordinates as well. double x = 9.0, y = 40.0; Quad2Df expected_patch; - expected_patch.coordinates << x - 1, y - 1, - x + 1, y - 1, - x + 1, y + 1, - x - 1, y + 1; + expected_patch.coordinates << x - 1, y - 1, x + 1, y - 1, x + 1, y + 1, x - 1, + y + 1; error = (expected_patch.coordinates - predicted.patch.coordinates).norm(); LG << "Patch error: " << error; @@ -113,8 +107,8 @@ TEST(PredictMarkerPosition, EasyBackwardLinearMotion) { TEST(PredictMarkerPosition, TwoFrameGap) { Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); + AddMarker(0, 1.0, 0.0, &tracks); + AddMarker(1, 2.0, 5.0, &tracks); AddMarker(2, 3.0, 10.0, &tracks); AddMarker(3, 4.0, 15.0, &tracks); AddMarker(4, 5.0, 20.0, &tracks); @@ -135,8 +129,8 @@ TEST(PredictMarkerPosition, TwoFrameGap) { TEST(PredictMarkerPosition, FourFrameGap) { Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); + AddMarker(0, 1.0, 0.0, &tracks); + AddMarker(1, 2.0, 5.0, &tracks); AddMarker(2, 3.0, 10.0, &tracks); AddMarker(3, 4.0, 15.0, &tracks); // Missing frames 4, 5, 6, 7. @@ -154,13 +148,13 @@ TEST(PredictMarkerPosition, FourFrameGap) { TEST(PredictMarkerPosition, MultipleGaps) { Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); + AddMarker(0, 1.0, 0.0, &tracks); + AddMarker(1, 2.0, 5.0, &tracks); AddMarker(2, 3.0, 10.0, &tracks); // AddMarker(3, 4.0, 15.0, &tracks); // Note the 3-frame gap. // AddMarker(4, 5.0, 20.0, &tracks); // AddMarker(5, 6.0, 25.0, &tracks); - AddMarker(6, 7.0, 30.0, &tracks); // Intermediate measurement. + AddMarker(6, 7.0, 30.0, &tracks); // Intermediate measurement. // AddMarker(7, 8.0, 35.0, &tracks); Marker predicted; @@ -178,14 +172,14 @@ TEST(PredictMarkerPosition, MarkersInRandomOrder) { Tracks tracks; // This is the same as the easy, except that the tracks are randomly ordered. - AddMarker(0, 1.0, 0.0, &tracks); + AddMarker(0, 1.0, 0.0, &tracks); AddMarker(2, 3.0, 10.0, &tracks); AddMarker(7, 8.0, 35.0, &tracks); AddMarker(5, 6.0, 25.0, &tracks); AddMarker(4, 5.0, 20.0, &tracks); AddMarker(3, 4.0, 15.0, &tracks); AddMarker(6, 7.0, 30.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); + AddMarker(1, 2.0, 5.0, &tracks); Marker predicted; predicted.clip = 0; diff --git a/intern/libmv/libmv/autotrack/quad.h b/intern/libmv/libmv/autotrack/quad.h index 0c70f9882da..4aeb66f20f7 100644 --- a/intern/libmv/libmv/autotrack/quad.h +++ b/intern/libmv/libmv/autotrack/quad.h @@ -27,7 +27,7 @@ namespace mv { -template +template struct Quad { // A quad is 4 points; generally in 2D or 3D. // @@ -35,7 +35,7 @@ struct Quad { // |\. // | \. // | z (z goes into screen) - // | + // | // | r0----->r1 // | ^ | // | | . | @@ -44,7 +44,7 @@ struct Quad { // | \. // | \. // v normal goes away (right handed). - // y + // y // // Each row is one of the corners coordinates; either (x, y) or (x, y, z). Eigen::Matrix coordinates; diff --git a/intern/libmv/libmv/autotrack/reconstruction.h b/intern/libmv/libmv/autotrack/reconstruction.h index 732e74063f1..f993b39f79e 100644 --- a/intern/libmv/libmv/autotrack/reconstruction.h +++ b/intern/libmv/libmv/autotrack/reconstruction.h @@ -57,17 +57,17 @@ class Reconstruction { public: // All methods copy their input reference or take ownership of the pointer. void AddCameraPose(const CameraPose& pose); - int AddCameraIntrinsics(CameraIntrinsics* intrinsics); - int AddPoint(const Point& point); - int AddModel(Model* model); + int AddCameraIntrinsics(CameraIntrinsics* intrinsics); + int AddPoint(const Point& point); + int AddModel(Model* model); // Returns the corresponding pose or point or NULL if missing. - CameraPose* CameraPoseForFrame(int clip, int frame); + CameraPose* CameraPoseForFrame(int clip, int frame); const CameraPose* CameraPoseForFrame(int clip, int frame) const; - Point* PointForTrack(int track); + Point* PointForTrack(int track); const Point* PointForTrack(int track) const; - const vector >& camera_poses() const { + const vector>& camera_poses() const { return camera_poses_; } diff --git a/intern/libmv/libmv/autotrack/region.h b/intern/libmv/libmv/autotrack/region.h index b35d99eb60d..687a217ab2a 100644 --- a/intern/libmv/libmv/autotrack/region.h +++ b/intern/libmv/libmv/autotrack/region.h @@ -46,7 +46,7 @@ struct Region { Vec2f min; Vec2f max; - template + template void Offset(const T& offset) { min += offset.template cast(); max += offset.template cast(); diff --git a/intern/libmv/libmv/autotrack/tracks.cc b/intern/libmv/libmv/autotrack/tracks.cc index 174f264f3f2..8044bb28bb4 100644 --- a/intern/libmv/libmv/autotrack/tracks.cc +++ b/intern/libmv/libmv/autotrack/tracks.cc @@ -23,8 +23,8 @@ #include "libmv/autotrack/tracks.h" #include -#include #include +#include #include "libmv/numeric/numeric.h" @@ -34,12 +34,12 @@ Tracks::Tracks(const Tracks& other) { markers_ = other.markers_; } -Tracks::Tracks(const vector& markers) : markers_(markers) {} +Tracks::Tracks(const vector& markers) : markers_(markers) { +} bool Tracks::GetMarker(int clip, int frame, int track, Marker* marker) const { for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == clip && - markers_[i].frame == frame && + if (markers_[i].clip == clip && markers_[i].frame == frame && markers_[i].track == track) { *marker = markers_[i]; return true; @@ -60,8 +60,7 @@ void Tracks::GetMarkersForTrackInClip(int clip, int track, vector* markers) const { for (int i = 0; i < markers_.size(); ++i) { - if (clip == markers_[i].clip && - track == markers_[i].track) { + if (clip == markers_[i].clip && track == markers_[i].track) { markers->push_back(markers_[i]); } } @@ -71,15 +70,16 @@ void Tracks::GetMarkersInFrame(int clip, int frame, vector* markers) const { for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == clip && - markers_[i].frame == frame) { + if (markers_[i].clip == clip && markers_[i].frame == frame) { markers->push_back(markers_[i]); } } } -void Tracks::GetMarkersForTracksInBothImages(int clip1, int frame1, - int clip2, int frame2, +void Tracks::GetMarkersForTracksInBothImages(int clip1, + int frame1, + int clip2, + int frame2, vector* markers) const { std::vector image1_tracks; std::vector image2_tracks; @@ -99,20 +99,19 @@ void Tracks::GetMarkersForTracksInBothImages(int clip1, int frame1, std::sort(image1_tracks.begin(), image1_tracks.end()); std::sort(image2_tracks.begin(), image2_tracks.end()); std::vector intersection; - std::set_intersection(image1_tracks.begin(), image1_tracks.end(), - image2_tracks.begin(), image2_tracks.end(), + std::set_intersection(image1_tracks.begin(), + image1_tracks.end(), + image2_tracks.begin(), + image2_tracks.end(), std::back_inserter(intersection)); // Scan through and get the relevant tracks from the two images. for (int i = 0; i < markers_.size(); ++i) { // Save markers that are in either frame and are in our candidate set. - if (((markers_[i].clip == clip1 && - markers_[i].frame == frame1) || - (markers_[i].clip == clip2 && - markers_[i].frame == frame2)) && - std::binary_search(intersection.begin(), - intersection.end(), - markers_[i].track)) { + if (((markers_[i].clip == clip1 && markers_[i].frame == frame1) || + (markers_[i].clip == clip2 && markers_[i].frame == frame2)) && + std::binary_search( + intersection.begin(), intersection.end(), markers_[i].track)) { markers->push_back(markers_[i]); } } @@ -122,8 +121,7 @@ void Tracks::AddMarker(const Marker& marker) { // TODO(keir): This is quadratic for repeated insertions. Fix this by adding // a smarter data structure like a set<>. for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == marker.clip && - markers_[i].frame == marker.frame && + if (markers_[i].clip == marker.clip && markers_[i].frame == marker.frame && markers_[i].track == marker.track) { markers_[i] = marker; return; @@ -139,8 +137,7 @@ void Tracks::SetMarkers(vector* markers) { bool Tracks::RemoveMarker(int clip, int frame, int track) { int size = markers_.size(); for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == clip && - markers_[i].frame == frame && + if (markers_[i].clip == clip && markers_[i].frame == frame && markers_[i].track == track) { markers_[i] = markers_[size - 1]; markers_.resize(size - 1); diff --git a/intern/libmv/libmv/autotrack/tracks.h b/intern/libmv/libmv/autotrack/tracks.h index 0b7de91d211..dd11a2d6fbd 100644 --- a/intern/libmv/libmv/autotrack/tracks.h +++ b/intern/libmv/libmv/autotrack/tracks.h @@ -23,8 +23,8 @@ #ifndef LIBMV_AUTOTRACK_TRACKS_H_ #define LIBMV_AUTOTRACK_TRACKS_H_ -#include "libmv/base/vector.h" #include "libmv/autotrack/marker.h" +#include "libmv/base/vector.h" namespace mv { @@ -33,8 +33,8 @@ using libmv::vector; // The Tracks container stores correspondences between frames. class Tracks { public: - Tracks() { } - Tracks(const Tracks &other); + Tracks() {} + Tracks(const Tracks& other); // Create a tracks object with markers already initialized. Copies markers. explicit Tracks(const vector& markers); @@ -51,8 +51,10 @@ class Tracks { // // This is not the same as the union of the markers in frame1 and // frame2; each marker is for a track that appears in both images. - void GetMarkersForTracksInBothImages(int clip1, int frame1, - int clip2, int frame2, + void GetMarkersForTracksInBothImages(int clip1, + int frame1, + int clip2, + int frame2, vector* markers) const; void AddMarker(const Marker& marker); diff --git a/intern/libmv/libmv/autotrack/tracks_test.cc b/intern/libmv/libmv/autotrack/tracks_test.cc index 028b4a10913..eeefd3714b0 100644 --- a/intern/libmv/libmv/autotrack/tracks_test.cc +++ b/intern/libmv/libmv/autotrack/tracks_test.cc @@ -22,8 +22,8 @@ #include "libmv/autotrack/tracks.h" -#include "testing/testing.h" #include "libmv/logging/logging.h" +#include "testing/testing.h" namespace mv { diff --git a/intern/libmv/libmv/base/aligned_malloc.cc b/intern/libmv/libmv/base/aligned_malloc.cc index 5d3e05e9df9..6e327acf928 100644 --- a/intern/libmv/libmv/base/aligned_malloc.cc +++ b/intern/libmv/libmv/base/aligned_malloc.cc @@ -41,11 +41,11 @@ namespace libmv { -void *aligned_malloc(int size, int alignment) { +void* aligned_malloc(int size, int alignment) { #ifdef _WIN32 return _aligned_malloc(size, alignment); #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) - void *result; + void* result; if (posix_memalign(&result, alignment, size)) { // non-zero means allocation error @@ -58,7 +58,7 @@ void *aligned_malloc(int size, int alignment) { #endif } -void aligned_free(void *ptr) { +void aligned_free(void* ptr) { #ifdef _WIN32 _aligned_free(ptr); #else diff --git a/intern/libmv/libmv/base/aligned_malloc.h b/intern/libmv/libmv/base/aligned_malloc.h index 096ff6e2d7c..25583bb6be4 100644 --- a/intern/libmv/libmv/base/aligned_malloc.h +++ b/intern/libmv/libmv/base/aligned_malloc.h @@ -24,10 +24,10 @@ namespace libmv { // Allocate block of size bytes at least aligned to a given value. -void *aligned_malloc(int size, int alignment); +void* aligned_malloc(int size, int alignment); // Free memory allocated by aligned_malloc. -void aligned_free(void *ptr); +void aligned_free(void* ptr); } // namespace libmv diff --git a/intern/libmv/libmv/base/id_generator.h b/intern/libmv/libmv/base/id_generator.h index bf1eafd218e..535c9bd7b38 100644 --- a/intern/libmv/libmv/base/id_generator.h +++ b/intern/libmv/libmv/base/id_generator.h @@ -28,6 +28,7 @@ class IdGenerator { public: IdGenerator() : next_(0) {} ID Generate() { return next_++; } + private: ID next_; }; diff --git a/intern/libmv/libmv/base/map.h b/intern/libmv/libmv/base/map.h index 88b720f17fe..a91e3561791 100644 --- a/intern/libmv/libmv/base/map.h +++ b/intern/libmv/libmv/base/map.h @@ -26,8 +26,8 @@ namespace libmv { -using std::map; using std::make_pair; +using std::map; } // namespace libmv diff --git a/intern/libmv/libmv/base/scoped_ptr.h b/intern/libmv/libmv/base/scoped_ptr.h index b9cd4854213..9bfcfe1d615 100644 --- a/intern/libmv/libmv/base/scoped_ptr.h +++ b/intern/libmv/libmv/base/scoped_ptr.h @@ -30,44 +30,44 @@ namespace libmv { * A handle for a heap-allocated resource that should be freed when it goes out * of scope. This looks similar to the one found in TR1. */ -template +template class scoped_ptr { public: - scoped_ptr(T *resource) : resource_(resource) {} + scoped_ptr(T* resource) : resource_(resource) {} ~scoped_ptr() { reset(0); } - T *get() const { return resource_; } - T *operator->() const { return resource_; } - T &operator*() const { return *resource_; } + T* get() const { return resource_; } + T* operator->() const { return resource_; } + T& operator*() const { return *resource_; } - void reset(T *new_resource) { + void reset(T* new_resource) { if (sizeof(T)) { delete resource_; } resource_ = new_resource; } - T *release() { - T *released_resource = resource_; + T* release() { + T* released_resource = resource_; resource_ = 0; return released_resource; } private: // No copying allowed. - T *resource_; + T* resource_; }; // Same as scoped_ptr but caller must allocate the data // with new[] and the destructor will free the memory // using delete[]. -template +template class scoped_array { public: - scoped_array(T *array) : array_(array) {} + scoped_array(T* array) : array_(array) {} ~scoped_array() { reset(NULL); } - T *get() const { return array_; } + T* get() const { return array_; } T& operator[](std::ptrdiff_t i) const { assert(i >= 0); @@ -75,25 +75,27 @@ class scoped_array { return array_[i]; } - void reset(T *new_array) { + void reset(T* new_array) { if (sizeof(T)) { delete array_; } array_ = new_array; } - T *release() { - T *released_array = array_; + T* release() { + T* released_array = array_; array_ = NULL; return released_array; } private: - T *array_; + T* array_; // Forbid comparison of different scoped_array types. - template bool operator==(scoped_array const& p2) const; - template bool operator!=(scoped_array const& p2) const; + template + bool operator==(scoped_array const& p2) const; + template + bool operator!=(scoped_array const& p2) const; // Disallow evil constructors scoped_array(const scoped_array&); diff --git a/intern/libmv/libmv/base/scoped_ptr_test.cc b/intern/libmv/libmv/base/scoped_ptr_test.cc index ce1d56b500a..e86af6d4516 100644 --- a/intern/libmv/libmv/base/scoped_ptr_test.cc +++ b/intern/libmv/libmv/base/scoped_ptr_test.cc @@ -25,9 +25,9 @@ namespace libmv { namespace { struct FreeMe { - FreeMe(int *freed) : freed(freed) {} + FreeMe(int* freed) : freed(freed) {} ~FreeMe() { (*freed)++; } - int *freed; + int* freed; }; TEST(ScopedPtr, NullDoesNothing) { @@ -61,8 +61,8 @@ TEST(ScopedPtr, Reset) { TEST(ScopedPtr, ReleaseAndGet) { int frees = 0; - FreeMe *allocated = new FreeMe(&frees); - FreeMe *released = NULL; + FreeMe* allocated = new FreeMe(&frees); + FreeMe* released = NULL; { scoped_ptr scoped(allocated); EXPECT_EQ(0, frees); diff --git a/intern/libmv/libmv/base/vector_test.cc b/intern/libmv/libmv/base/vector_test.cc index f171e3a18b5..d31bee751cd 100644 --- a/intern/libmv/libmv/base/vector_test.cc +++ b/intern/libmv/libmv/base/vector_test.cc @@ -19,9 +19,9 @@ // IN THE SOFTWARE. #include "libmv/base/vector.h" +#include #include "libmv/numeric/numeric.h" #include "testing/testing.h" -#include namespace { using namespace libmv; @@ -62,7 +62,7 @@ int foo_destruct_calls = 0; struct Foo { public: Foo() : value(5) { foo_construct_calls++; } - ~Foo() { foo_destruct_calls++; } + ~Foo() { foo_destruct_calls++; } int value; }; @@ -150,7 +150,7 @@ TEST_F(VectorTest, CopyConstructor) { a.push_back(3); vector b(a); - EXPECT_EQ(a.size(), b.size()); + EXPECT_EQ(a.size(), b.size()); for (int i = 0; i < a.size(); ++i) { EXPECT_EQ(a[i], b[i]); } @@ -164,7 +164,7 @@ TEST_F(VectorTest, OperatorEquals) { b = a; - EXPECT_EQ(a.size(), b.size()); + EXPECT_EQ(a.size(), b.size()); for (int i = 0; i < a.size(); ++i) { EXPECT_EQ(a[i], b[i]); } diff --git a/intern/libmv/libmv/base/vector_utils.h b/intern/libmv/libmv/base/vector_utils.h index c71e1bea951..5f69c03d937 100644 --- a/intern/libmv/libmv/base/vector_utils.h +++ b/intern/libmv/libmv/base/vector_utils.h @@ -18,14 +18,13 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. - #ifndef LIBMV_BASE_VECTOR_UTILS_H_ #define LIBMV_BASE_VECTOR_UTILS_H_ /// Delete the contents of a container. template -void DeleteElements(Array *array) { - for (int i = 0; i < array->size(); ++i) { +void DeleteElements(Array* array) { + for (int i = 0; i < array->size(); ++i) { delete (*array)[i]; } array->clear(); diff --git a/intern/libmv/libmv/image/array_nd.cc b/intern/libmv/libmv/image/array_nd.cc index 469a19aabf1..07feda33e66 100644 --- a/intern/libmv/libmv/image/array_nd.cc +++ b/intern/libmv/libmv/image/array_nd.cc @@ -18,18 +18,17 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "libmv/image/image.h" -#include #include +#include +#include "libmv/image/image.h" namespace libmv { -void FloatArrayToScaledByteArray(const Array3Df &float_array, - Array3Du *byte_array, - bool automatic_range_detection - ) { +void FloatArrayToScaledByteArray(const Array3Df& float_array, + Array3Du* byte_array, + bool automatic_range_detection) { byte_array->ResizeLike(float_array); - float minval = HUGE_VAL; + float minval = HUGE_VAL; float maxval = -HUGE_VAL; if (automatic_range_detection) { for (int i = 0; i < float_array.Height(); ++i) { @@ -54,8 +53,8 @@ void FloatArrayToScaledByteArray(const Array3Df &float_array, } } -void ByteArrayToScaledFloatArray(const Array3Du &byte_array, - Array3Df *float_array) { +void ByteArrayToScaledFloatArray(const Array3Du& byte_array, + Array3Df* float_array) { float_array->ResizeLike(byte_array); for (int i = 0; i < byte_array.Height(); ++i) { for (int j = 0; j < byte_array.Width(); ++j) { @@ -66,10 +65,10 @@ void ByteArrayToScaledFloatArray(const Array3Du &byte_array, } } -void SplitChannels(const Array3Df &input, - Array3Df *channel0, - Array3Df *channel1, - Array3Df *channel2) { +void SplitChannels(const Array3Df& input, + Array3Df* channel0, + Array3Df* channel1, + Array3Df* channel2) { assert(input.Depth() >= 3); channel0->Resize(input.Height(), input.Width()); channel1->Resize(input.Height(), input.Width()); @@ -83,7 +82,7 @@ void SplitChannels(const Array3Df &input, } } -void PrintArray(const Array3Df &array) { +void PrintArray(const Array3Df& array) { using namespace std; printf("[\n"); diff --git a/intern/libmv/libmv/image/array_nd.h b/intern/libmv/libmv/image/array_nd.h index e95e66aa2b3..1a3c39d0461 100644 --- a/intern/libmv/libmv/image/array_nd.h +++ b/intern/libmv/libmv/image/array_nd.h @@ -44,13 +44,13 @@ class ArrayND : public BaseArray { ArrayND() : data_(NULL), own_data_(true) { Resize(Index(0)); } /// Create an array with the specified shape. - ArrayND(const Index &shape) : data_(NULL), own_data_(true) { Resize(shape); } + ArrayND(const Index& shape) : data_(NULL), own_data_(true) { Resize(shape); } /// Create an array with the specified shape. - ArrayND(int *shape) : data_(NULL), own_data_(true) { Resize(shape); } + ArrayND(int* shape) : data_(NULL), own_data_(true) { Resize(shape); } /// Copy constructor. - ArrayND(const ArrayND &b) : data_(NULL), own_data_(true) { + ArrayND(const ArrayND& b) : data_(NULL), own_data_(true) { ResizeLike(b); std::memcpy(Data(), b.Data(), sizeof(T) * Size()); } @@ -58,7 +58,7 @@ class ArrayND : public BaseArray { ArrayND(int s0) : data_(NULL), own_data_(true) { Resize(s0); } ArrayND(int s0, int s1) : data_(NULL), own_data_(true) { Resize(s0, s1); } ArrayND(int s0, int s1, int s2) : data_(NULL), own_data_(true) { - Resize(s0, s1, s2); + Resize(s0, s1, s2); } ArrayND(T* data, int s0, int s1, int s2) @@ -69,28 +69,24 @@ class ArrayND : public BaseArray { /// Destructor deletes pixel data. ~ArrayND() { if (own_data_) { - delete [] data_; + delete[] data_; } } /// Assignation copies pixel data. - ArrayND &operator=(const ArrayND &b) { + ArrayND& operator=(const ArrayND& b) { assert(this != &b); ResizeLike(b); std::memcpy(Data(), b.Data(), sizeof(T) * Size()); return *this; } - const Index &Shapes() const { - return shape_; - } + const Index& Shapes() const { return shape_; } - const Index &Strides() const { - return strides_; - } + const Index& Strides() const { return strides_; } /// Create an array of shape s. - void Resize(const Index &new_shape) { + void Resize(const Index& new_shape) { if (data_ != NULL && shape_ == new_shape) { // Don't bother realloacting if the shapes match. return; @@ -101,7 +97,7 @@ class ArrayND : public BaseArray { strides_(i - 1) = strides_(i) * shape_(i); } if (own_data_) { - delete [] data_; + delete[] data_; data_ = NULL; if (Size() > 0) { data_ = new T[Size()]; @@ -109,15 +105,13 @@ class ArrayND : public BaseArray { } } - template - void ResizeLike(const ArrayND &other) { + template + void ResizeLike(const ArrayND& other) { Resize(other.Shape()); } /// Resizes the array to shape s. All data is lost. - void Resize(const int *new_shape_array) { - Resize(Index(new_shape_array)); - } + void Resize(const int* new_shape_array) { Resize(Index(new_shape_array)); } /// Resize a 1D array to length s0. void Resize(int s0) { @@ -136,9 +130,7 @@ class ArrayND : public BaseArray { } // Match Eigen2's API. - void resize(int rows, int cols) { - Resize(rows, cols); - } + void resize(int rows, int cols) { Resize(rows, cols); } /// Resize a 3D array to shape (s0,s1,s2). void Resize(int s0, int s1, int s2) { @@ -147,11 +139,11 @@ class ArrayND : public BaseArray { Resize(shape); } - template - void CopyFrom(const ArrayND &other) { + template + void CopyFrom(const ArrayND& other) { ResizeLike(other); - T *data = Data(); - const D *other_data = other.Data(); + T* data = Data(); + const D* other_data = other.Data(); for (int i = 0; i < Size(); ++i) { data[i] = T(other_data[i]); } @@ -171,19 +163,13 @@ class ArrayND : public BaseArray { } /// Return a tuple containing the length of each axis. - const Index &Shape() const { - return shape_; - } + const Index& Shape() const { return shape_; } /// Return the length of an axis. - int Shape(int axis) const { - return shape_(axis); - } + int Shape(int axis) const { return shape_(axis); } /// Return the distance between neighboring elements along axis. - int Stride(int axis) const { - return strides_(axis); - } + int Stride(int axis) const { return strides_(axis); } /// Return the number of elements of the array. int Size() const { @@ -194,18 +180,16 @@ class ArrayND : public BaseArray { } /// Return the total amount of memory used by the array. - int MemorySizeInBytes() const { - return sizeof(*this) + Size() * sizeof(T); - } + int MemorySizeInBytes() const { return sizeof(*this) + Size() * sizeof(T); } /// Pointer to the first element of the array. - T *Data() { return data_; } + T* Data() { return data_; } /// Constant pointer to the first element of the array. - const T *Data() const { return data_; } + const T* Data() const { return data_; } /// Distance between the first element and the element at position index. - int Offset(const Index &index) const { + int Offset(const Index& index) const { int offset = 0; for (int i = 0; i < N; ++i) offset += index(i) * Stride(i); @@ -231,25 +215,23 @@ class ArrayND : public BaseArray { } /// Return a reference to the element at position index. - T &operator()(const Index &index) { + T& operator()(const Index& index) { // TODO(pau) Boundary checking in debug mode. - return *( Data() + Offset(index) ); + return *(Data() + Offset(index)); } /// 1D specialization. - T &operator()(int i0) { - return *( Data() + Offset(i0) ); - } + T& operator()(int i0) { return *(Data() + Offset(i0)); } /// 2D specialization. - T &operator()(int i0, int i1) { + T& operator()(int i0, int i1) { assert(0 <= i0 && i0 < Shape(0)); assert(0 <= i1 && i1 < Shape(1)); return *(Data() + Offset(i0, i1)); } /// 3D specialization. - T &operator()(int i0, int i1, int i2) { + T& operator()(int i0, int i1, int i2) { assert(0 <= i0 && i0 < Shape(0)); assert(0 <= i1 && i1 < Shape(1)); assert(0 <= i2 && i2 < Shape(2)); @@ -257,29 +239,27 @@ class ArrayND : public BaseArray { } /// Return a constant reference to the element at position index. - const T &operator()(const Index &index) const { + const T& operator()(const Index& index) const { return *(Data() + Offset(index)); } /// 1D specialization. - const T &operator()(int i0) const { - return *(Data() + Offset(i0)); - } + const T& operator()(int i0) const { return *(Data() + Offset(i0)); } /// 2D specialization. - const T &operator()(int i0, int i1) const { + const T& operator()(int i0, int i1) const { assert(0 <= i0 && i0 < Shape(0)); assert(0 <= i1 && i1 < Shape(1)); return *(Data() + Offset(i0, i1)); } /// 3D specialization. - const T &operator()(int i0, int i1, int i2) const { + const T& operator()(int i0, int i1, int i2) const { return *(Data() + Offset(i0, i1, i2)); } /// True if index is inside array. - bool Contains(const Index &index) const { + bool Contains(const Index& index) const { for (int i = 0; i < N; ++i) if (index(i) < 0 || index(i) >= Shape(i)) return false; @@ -287,26 +267,24 @@ class ArrayND : public BaseArray { } /// 1D specialization. - bool Contains(int i0) const { - return 0 <= i0 && i0 < Shape(0); - } + bool Contains(int i0) const { return 0 <= i0 && i0 < Shape(0); } /// 2D specialization. bool Contains(int i0, int i1) const { - return 0 <= i0 && i0 < Shape(0) - && 0 <= i1 && i1 < Shape(1); + return 0 <= i0 && i0 < Shape(0) && 0 <= i1 && i1 < Shape(1); } /// 3D specialization. bool Contains(int i0, int i1, int i2) const { - return 0 <= i0 && i0 < Shape(0) - && 0 <= i1 && i1 < Shape(1) - && 0 <= i2 && i2 < Shape(2); + return 0 <= i0 && i0 < Shape(0) && 0 <= i1 && i1 < Shape(1) && 0 <= i2 && + i2 < Shape(2); } - bool operator==(const ArrayND &other) const { - if (shape_ != other.shape_) return false; - if (strides_ != other.strides_) return false; + bool operator==(const ArrayND& other) const { + if (shape_ != other.shape_) + return false; + if (strides_ != other.strides_) + return false; for (int i = 0; i < Size(); ++i) { if (this->Data()[i] != other.Data()[i]) return false; @@ -314,11 +292,11 @@ class ArrayND : public BaseArray { return true; } - bool operator!=(const ArrayND &other) const { + bool operator!=(const ArrayND& other) const { return !(*this == other); } - ArrayND operator*(const ArrayND &other) const { + ArrayND operator*(const ArrayND& other) const { assert(Shape() = other.Shape()); ArrayND res; res.ResizeLike(*this); @@ -336,7 +314,7 @@ class ArrayND : public BaseArray { Index strides_; /// Pointer to the first element of the array. - T *data_; + T* data_; /// Flag if this Array either own or reference the data bool own_data_; @@ -346,30 +324,20 @@ class ArrayND : public BaseArray { template class Array3D : public ArrayND { typedef ArrayND Base; + public: - Array3D() - : Base() { - } - Array3D(int height, int width, int depth = 1) - : Base(height, width, depth) { - } + Array3D() : Base() {} + Array3D(int height, int width, int depth = 1) : Base(height, width, depth) {} Array3D(T* data, int height, int width, int depth = 1) - : Base(data, height, width, depth) { - } + : Base(data, height, width, depth) {} void Resize(int height, int width, int depth = 1) { Base::Resize(height, width, depth); } - int Height() const { - return Base::Shape(0); - } - int Width() const { - return Base::Shape(1); - } - int Depth() const { - return Base::Shape(2); - } + int Height() const { return Base::Shape(0); } + int Width() const { return Base::Shape(1); } + int Depth() const { return Base::Shape(2); } // Match Eigen2's API so that Array3D's and Mat*'s can work together via // template magic. @@ -377,15 +345,15 @@ class Array3D : public ArrayND { int cols() const { return Width(); } int depth() const { return Depth(); } - int Get_Step() const { return Width()*Depth(); } + int Get_Step() const { return Width() * Depth(); } /// Enable accessing with 2 indices for grayscale images. - T &operator()(int i0, int i1, int i2 = 0) { + T& operator()(int i0, int i1, int i2 = 0) { assert(0 <= i0 && i0 < Height()); assert(0 <= i1 && i1 < Width()); return Base::operator()(i0, i1, i2); } - const T &operator()(int i0, int i1, int i2 = 0) const { + const T& operator()(int i0, int i1, int i2 = 0) const { assert(0 <= i0 && i0 < Height()); assert(0 <= i1 && i1 < Width()); return Base::operator()(i0, i1, i2); @@ -398,31 +366,29 @@ typedef Array3D Array3Di; typedef Array3D Array3Df; typedef Array3D Array3Ds; -void SplitChannels(const Array3Df &input, - Array3Df *channel0, - Array3Df *channel1, - Array3Df *channel2); +void SplitChannels(const Array3Df& input, + Array3Df* channel0, + Array3Df* channel1, + Array3Df* channel2); -void PrintArray(const Array3Df &array); +void PrintArray(const Array3Df& array); /** Convert a float array into a byte array by scaling values by 255* (max-min). - * where max and min are automatically detected + * where max and min are automatically detected * (if automatic_range_detection = true) * \note and TODO this automatic detection only works when the image contains * at least one pixel of both bounds. **/ -void FloatArrayToScaledByteArray(const Array3Df &float_array, - Array3Du *byte_array, +void FloatArrayToScaledByteArray(const Array3Df& float_array, + Array3Du* byte_array, bool automatic_range_detection = false); //! Convert a byte array into a float array by dividing values by 255. -void ByteArrayToScaledFloatArray(const Array3Du &byte_array, - Array3Df *float_array); +void ByteArrayToScaledFloatArray(const Array3Du& byte_array, + Array3Df* float_array); template -void MultiplyElements(const AArrayType &a, - const BArrayType &b, - CArrayType *c) { +void MultiplyElements(const AArrayType& a, const BArrayType& b, CArrayType* c) { // This function does an element-wise multiply between // the two Arrays A and B, and stores the result in C. // A and B must have the same dimensions. @@ -435,7 +401,7 @@ void MultiplyElements(const AArrayType &a, // The index starts at the maximum value for each dimension const typename CArrayType::Index& cShape = c->Shape(); - for ( int i = 0; i < CArrayType::Index::SIZE; ++i ) + for (int i = 0; i < CArrayType::Index::SIZE; ++i) index(i) = cShape(i) - 1; // After each multiplication, the highest-dimensional index is reduced. @@ -443,12 +409,12 @@ void MultiplyElements(const AArrayType &a, // and decrements the index of the next lower dimension. // This ripple-action continues until the entire new array has been // calculated, indicated by dimension zero having a negative index. - while ( index(0) >= 0 ) { + while (index(0) >= 0) { (*c)(index) = a(index) * b(index); int dimension = CArrayType::Index::SIZE - 1; index(dimension) = index(dimension) - 1; - while ( dimension > 0 && index(dimension) < 0 ) { + while (dimension > 0 && index(dimension) < 0) { index(dimension) = cShape(dimension) - 1; index(dimension - 1) = index(dimension - 1) - 1; --dimension; @@ -457,9 +423,9 @@ void MultiplyElements(const AArrayType &a, } template -void MultiplyElements(const ArrayND &a, - const ArrayND &b, - ArrayND *c) { +void MultiplyElements(const ArrayND& a, + const ArrayND& b, + ArrayND* c) { // Specialization for N==3 c->ResizeLike(a); assert(a.Shape(0) == b.Shape(0)); @@ -475,9 +441,9 @@ void MultiplyElements(const ArrayND &a, } template -void MultiplyElements(const Array3D &a, - const Array3D &b, - Array3D *c) { +void MultiplyElements(const Array3D& a, + const Array3D& b, + Array3D* c) { // Specialization for N==3 c->ResizeLike(a); assert(a.Shape(0) == b.Shape(0)); diff --git a/intern/libmv/libmv/image/array_nd_test.cc b/intern/libmv/libmv/image/array_nd_test.cc index dc7cfacf90d..67838d34051 100644 --- a/intern/libmv/libmv/image/array_nd_test.cc +++ b/intern/libmv/libmv/image/array_nd_test.cc @@ -21,9 +21,9 @@ #include "libmv/image/array_nd.h" #include "testing/testing.h" -using libmv::ArrayND; using libmv::Array3D; using libmv::Array3Df; +using libmv::ArrayND; namespace { @@ -100,7 +100,7 @@ TEST(ArrayND, Size) { int l[] = {0, 1, 2}; ArrayND::Index last(l); - EXPECT_EQ(a.Size(), a.Offset(last)+1); + EXPECT_EQ(a.Size(), a.Offset(last) + 1); EXPECT_TRUE(a.Contains(last)); EXPECT_FALSE(a.Contains(shape)); } @@ -120,8 +120,8 @@ TEST(ArrayND, Parenthesis) { int s[] = {3, 3}; ArrayND a(s); - *(a.Data()+0) = 0; - *(a.Data()+5) = 5; + *(a.Data() + 0) = 0; + *(a.Data() + 5) = 5; int i1[] = {0, 0}; EXPECT_EQ(0, a(Index(i1))); @@ -210,7 +210,7 @@ TEST(ArrayND, MultiplyElements) { b(1, 1, 0) = 3; ArrayND c; MultiplyElements(a, b, &c); - EXPECT_FLOAT_EQ(6, c(0, 0, 0)); + EXPECT_FLOAT_EQ(6, c(0, 0, 0)); EXPECT_FLOAT_EQ(10, c(0, 1, 0)); EXPECT_FLOAT_EQ(12, c(1, 0, 0)); EXPECT_FLOAT_EQ(12, c(1, 1, 0)); diff --git a/intern/libmv/libmv/image/convolve.cc b/intern/libmv/libmv/image/convolve.cc index 464043581d2..478e320377d 100644 --- a/intern/libmv/libmv/image/convolve.cc +++ b/intern/libmv/libmv/image/convolve.cc @@ -29,7 +29,7 @@ namespace libmv { // Compute a Gaussian kernel and derivative, such that you can take the // derivative of an image by convolving with the kernel horizontally then the // derivative vertically to get (eg) the y derivative. -void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) { +void ComputeGaussianKernel(double sigma, Vec* kernel, Vec* derivative) { assert(sigma >= 0.0); // 0.004 implies a 3 pixel kernel with 1 pixel sigma. @@ -37,7 +37,7 @@ void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) { // Calculate the kernel size based on sigma such that it is odd. float precisehalfwidth = GaussianInversePositive(truncation_factor, sigma); - int width = lround(2*precisehalfwidth); + int width = lround(2 * precisehalfwidth); if (width % 2 == 0) { width++; } @@ -47,7 +47,7 @@ void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) { kernel->setZero(); derivative->setZero(); int halfwidth = width / 2; - for (int i = -halfwidth; i <= halfwidth; ++i) { + for (int i = -halfwidth; i <= halfwidth; ++i) { (*kernel)(i + halfwidth) = Gaussian(i, sigma); (*derivative)(i + halfwidth) = GaussianDerivative(i, sigma); } @@ -57,16 +57,21 @@ void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) { // Normalize the derivative differently. See // www.cs.duke.edu/courses/spring03/cps296.1/handouts/Image%20Processing.pdf double factor = 0.; - for (int i = -halfwidth; i <= halfwidth; ++i) { - factor -= i*(*derivative)(i+halfwidth); + for (int i = -halfwidth; i <= halfwidth; ++i) { + factor -= i * (*derivative)(i + halfwidth); } *derivative /= factor; } template -void FastConvolve(const Vec &kernel, int width, int height, - const float* src, int src_stride, int src_line_stride, - float* dst, int dst_stride) { +void FastConvolve(const Vec& kernel, + int width, + int height, + const float* src, + int src_stride, + int src_line_stride, + float* dst, + int dst_stride) { double coefficients[2 * size + 1]; for (int k = 0; k < 2 * size + 1; ++k) { coefficients[k] = kernel(2 * size - k); @@ -93,14 +98,14 @@ void FastConvolve(const Vec &kernel, int width, int height, } } -template -void Convolve(const Array3Df &in, - const Vec &kernel, - Array3Df *out_pointer, +template +void Convolve(const Array3Df& in, + const Vec& kernel, + Array3Df* out_pointer, int plane) { int width = in.Width(); int height = in.Height(); - Array3Df &out = *out_pointer; + Array3Df& out = *out_pointer; if (plane == -1) { out.ResizeLike(in); plane = 0; @@ -119,61 +124,62 @@ void Convolve(const Array3Df &in, // fast path. int half_width = kernel.size() / 2; switch (half_width) { -#define static_convolution(size) case size: \ - FastConvolve(kernel, width, height, src, src_stride, \ - src_line_stride, dst, dst_stride); break; - static_convolution(1) - static_convolution(2) - static_convolution(3) - static_convolution(4) - static_convolution(5) - static_convolution(6) - static_convolution(7) +#define static_convolution(size) \ + case size: \ + FastConvolve(kernel, \ + width, \ + height, \ + src, \ + src_stride, \ + src_line_stride, \ + dst, \ + dst_stride); \ + break; + static_convolution(1) static_convolution(2) static_convolution(3) + static_convolution(4) static_convolution(5) static_convolution(6) + static_convolution(7) #undef static_convolution - default: - int dynamic_size = kernel.size() / 2; - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - double sum = 0; - // Slow path: this loop cannot be unrolled. - for (int k = -dynamic_size; k <= dynamic_size; ++k) { - if (vertical) { - if (y + k >= 0 && y + k < height) { - sum += src[k * src_line_stride] * - kernel(2 * dynamic_size - (k + dynamic_size)); - } - } else { - if (x + k >= 0 && x + k < width) { - sum += src[k * src_stride] * - kernel(2 * dynamic_size - (k + dynamic_size)); - } + default : int dynamic_size = kernel.size() / 2; + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + double sum = 0; + // Slow path: this loop cannot be unrolled. + for (int k = -dynamic_size; k <= dynamic_size; ++k) { + if (vertical) { + if (y + k >= 0 && y + k < height) { + sum += src[k * src_line_stride] * + kernel(2 * dynamic_size - (k + dynamic_size)); + } + } else { + if (x + k >= 0 && x + k < width) { + sum += src[k * src_stride] * + kernel(2 * dynamic_size - (k + dynamic_size)); } } - dst[0] = static_cast(sum); - src += src_stride; - dst += dst_stride; } + dst[0] = static_cast(sum); + src += src_stride; + dst += dst_stride; } + } } } -void ConvolveHorizontal(const Array3Df &in, - const Vec &kernel, - Array3Df *out_pointer, +void ConvolveHorizontal(const Array3Df& in, + const Vec& kernel, + Array3Df* out_pointer, int plane) { Convolve(in, kernel, out_pointer, plane); } -void ConvolveVertical(const Array3Df &in, - const Vec &kernel, - Array3Df *out_pointer, +void ConvolveVertical(const Array3Df& in, + const Vec& kernel, + Array3Df* out_pointer, int plane) { Convolve(in, kernel, out_pointer, plane); } -void ConvolveGaussian(const Array3Df &in, - double sigma, - Array3Df *out_pointer) { +void ConvolveGaussian(const Array3Df& in, double sigma, Array3Df* out_pointer) { Vec kernel, derivative; ComputeGaussianKernel(sigma, &kernel, &derivative); @@ -182,10 +188,10 @@ void ConvolveGaussian(const Array3Df &in, ConvolveHorizontal(tmp, kernel, out_pointer); } -void ImageDerivatives(const Array3Df &in, +void ImageDerivatives(const Array3Df& in, double sigma, - Array3Df *gradient_x, - Array3Df *gradient_y) { + Array3Df* gradient_x, + Array3Df* gradient_y) { Vec kernel, derivative; ComputeGaussianKernel(sigma, &kernel, &derivative); Array3Df tmp; @@ -199,11 +205,11 @@ void ImageDerivatives(const Array3Df &in, ConvolveVertical(tmp, derivative, gradient_y); } -void BlurredImageAndDerivatives(const Array3Df &in, +void BlurredImageAndDerivatives(const Array3Df& in, double sigma, - Array3Df *blurred_image, - Array3Df *gradient_x, - Array3Df *gradient_y) { + Array3Df* blurred_image, + Array3Df* gradient_x, + Array3Df* gradient_y) { Vec kernel, derivative; ComputeGaussianKernel(sigma, &kernel, &derivative); Array3Df tmp; @@ -224,9 +230,9 @@ void BlurredImageAndDerivatives(const Array3Df &in, // image, and store the results in three channels. Since the blurred value and // gradients are closer in memory, this leads to better performance if all // three values are needed at the same time. -void BlurredImageAndDerivativesChannels(const Array3Df &in, +void BlurredImageAndDerivativesChannels(const Array3Df& in, double sigma, - Array3Df *blurred_and_gradxy) { + Array3Df* blurred_and_gradxy) { assert(in.Depth() == 1); Vec kernel, derivative; @@ -246,10 +252,10 @@ void BlurredImageAndDerivativesChannels(const Array3Df &in, ConvolveVertical(tmp, derivative, blurred_and_gradxy, 2); } -void BoxFilterHorizontal(const Array3Df &in, +void BoxFilterHorizontal(const Array3Df& in, int window_size, - Array3Df *out_pointer) { - Array3Df &out = *out_pointer; + Array3Df* out_pointer) { + Array3Df& out = *out_pointer; out.ResizeLike(in); int half_width = (window_size - 1) / 2; @@ -266,7 +272,7 @@ void BoxFilterHorizontal(const Array3Df &in, out(i, j, k) = sum; } // Fill interior. - for (int j = half_width + 1; j < in.Width()-half_width; ++j) { + for (int j = half_width + 1; j < in.Width() - half_width; ++j) { sum -= in(i, j - half_width - 1, k); sum += in(i, j + half_width, k); out(i, j, k) = sum; @@ -280,10 +286,10 @@ void BoxFilterHorizontal(const Array3Df &in, } } -void BoxFilterVertical(const Array3Df &in, +void BoxFilterVertical(const Array3Df& in, int window_size, - Array3Df *out_pointer) { - Array3Df &out = *out_pointer; + Array3Df* out_pointer) { + Array3Df& out = *out_pointer; out.ResizeLike(in); int half_width = (window_size - 1) / 2; @@ -300,7 +306,7 @@ void BoxFilterVertical(const Array3Df &in, out(i, j, k) = sum; } // Fill interior. - for (int i = half_width + 1; i < in.Height()-half_width; ++i) { + for (int i = half_width + 1; i < in.Height() - half_width; ++i) { sum -= in(i - half_width - 1, j, k); sum += in(i + half_width, j, k); out(i, j, k) = sum; @@ -314,9 +320,7 @@ void BoxFilterVertical(const Array3Df &in, } } -void BoxFilter(const Array3Df &in, - int box_width, - Array3Df *out) { +void BoxFilter(const Array3Df& in, int box_width, Array3Df* out) { Array3Df tmp; BoxFilterHorizontal(in, box_width, &tmp); BoxFilterVertical(tmp, box_width, out); @@ -327,17 +331,17 @@ void LaplaceFilter(unsigned char* src, int width, int height, int strength) { - for (int y = 1; y < height-1; y++) - for (int x = 1; x < width-1; x++) { - const unsigned char* s = &src[y*width+x]; - int l = 128 + - s[-width-1] + s[-width] + s[-width+1] + - s[1] - 8*s[0] + s[1] + - s[ width-1] + s[ width] + s[ width+1]; - int d = ((256-strength)*s[0] + strength*l) / 256; - if (d < 0) d=0; - if (d > 255) d=255; - dst[y*width+x] = d; + for (int y = 1; y < height - 1; y++) + for (int x = 1; x < width - 1; x++) { + const unsigned char* s = &src[y * width + x]; + int l = 128 + s[-width - 1] + s[-width] + s[-width + 1] + s[1] - + 8 * s[0] + s[1] + s[width - 1] + s[width] + s[width + 1]; + int d = ((256 - strength) * s[0] + strength * l) / 256; + if (d < 0) + d = 0; + if (d > 255) + d = 255; + dst[y * width + x] = d; } } diff --git a/intern/libmv/libmv/image/convolve.h b/intern/libmv/libmv/image/convolve.h index d3b6da9794b..3794550eb73 100644 --- a/intern/libmv/libmv/image/convolve.h +++ b/intern/libmv/libmv/image/convolve.h @@ -30,70 +30,71 @@ namespace libmv { // Zero mean Gaussian. inline double Gaussian(double x, double sigma) { - return 1/sqrt(2*M_PI*sigma*sigma) * exp(-(x*x/2/sigma/sigma)); + return 1 / sqrt(2 * M_PI * sigma * sigma) * exp(-(x * x / 2 / sigma / sigma)); } // 2D gaussian (zero mean) // (9) in http://mathworld.wolfram.com/GaussianFunction.html inline double Gaussian2D(double x, double y, double sigma) { - return 1.0/(2.0*M_PI*sigma*sigma) * exp( -(x*x+y*y)/(2.0*sigma*sigma)); + return 1.0 / (2.0 * M_PI * sigma * sigma) * + exp(-(x * x + y * y) / (2.0 * sigma * sigma)); } inline double GaussianDerivative(double x, double sigma) { return -x / sigma / sigma * Gaussian(x, sigma); } // Solve the inverse of the Gaussian for positive x. inline double GaussianInversePositive(double y, double sigma) { - return sqrt(-2 * sigma * sigma * log(y * sigma * sqrt(2*M_PI))); + return sqrt(-2 * sigma * sigma * log(y * sigma * sqrt(2 * M_PI))); } -void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative); -void ConvolveHorizontal(const FloatImage &in, - const Vec &kernel, - FloatImage *out_pointer, +void ComputeGaussianKernel(double sigma, Vec* kernel, Vec* derivative); +void ConvolveHorizontal(const FloatImage& in, + const Vec& kernel, + FloatImage* out_pointer, int plane = -1); -void ConvolveVertical(const FloatImage &in, - const Vec &kernel, - FloatImage *out_pointer, +void ConvolveVertical(const FloatImage& in, + const Vec& kernel, + FloatImage* out_pointer, int plane = -1); -void ConvolveGaussian(const FloatImage &in, +void ConvolveGaussian(const FloatImage& in, double sigma, - FloatImage *out_pointer); + FloatImage* out_pointer); -void ImageDerivatives(const FloatImage &in, +void ImageDerivatives(const FloatImage& in, double sigma, - FloatImage *gradient_x, - FloatImage *gradient_y); + FloatImage* gradient_x, + FloatImage* gradient_y); -void BlurredImageAndDerivatives(const FloatImage &in, +void BlurredImageAndDerivatives(const FloatImage& in, double sigma, - FloatImage *blurred_image, - FloatImage *gradient_x, - FloatImage *gradient_y); + FloatImage* blurred_image, + FloatImage* gradient_x, + FloatImage* gradient_y); // Blur and take the gradients of an image, storing the results inside the // three channels of blurred_and_gradxy. -void BlurredImageAndDerivativesChannels(const FloatImage &in, +void BlurredImageAndDerivativesChannels(const FloatImage& in, double sigma, - FloatImage *blurred_and_gradxy); + FloatImage* blurred_and_gradxy); -void BoxFilterHorizontal(const FloatImage &in, +void BoxFilterHorizontal(const FloatImage& in, int window_size, - FloatImage *out_pointer); + FloatImage* out_pointer); -void BoxFilterVertical(const FloatImage &in, +void BoxFilterVertical(const FloatImage& in, int window_size, - FloatImage *out_pointer); + FloatImage* out_pointer); -void BoxFilter(const FloatImage &in, - int box_width, - FloatImage *out); +void BoxFilter(const FloatImage& in, int box_width, FloatImage* out); /*! Convolve \a src into \a dst with the discrete laplacian operator. \a src and \a dst should be \a width x \a height images. - \a strength is an interpolation coefficient (0-256) between original image and the laplacian. + \a strength is an interpolation coefficient (0-256) between original image + and the laplacian. - \note Make sure the search region is filtered with the same strength as the pattern. + \note Make sure the search region is filtered with the same strength as the + pattern. */ void LaplaceFilter(unsigned char* src, unsigned char* dst, @@ -104,4 +105,3 @@ void LaplaceFilter(unsigned char* src, } // namespace libmv #endif // LIBMV_IMAGE_CONVOLVE_H_ - diff --git a/intern/libmv/libmv/image/convolve_test.cc b/intern/libmv/libmv/image/convolve_test.cc index 0cdef8e1e72..1ad4cb9a40e 100644 --- a/intern/libmv/libmv/image/convolve_test.cc +++ b/intern/libmv/libmv/image/convolve_test.cc @@ -85,26 +85,26 @@ TEST(Convolve, BlurredImageAndDerivativesChannelsHorizontalSlope) { FloatImage image(10, 10), blurred_and_derivatives; for (int j = 0; j < 10; ++j) { for (int i = 0; i < 10; ++i) { - image(j, i) = 2*i; + image(j, i) = 2 * i; } } BlurredImageAndDerivativesChannels(image, 0.9, &blurred_and_derivatives); EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 10.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 2.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 0.0, 1e-7); + EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 2.0, 1e-7); + EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 0.0, 1e-7); } TEST(Convolve, BlurredImageAndDerivativesChannelsVerticalSlope) { FloatImage image(10, 10), blurred_and_derivatives; for (int j = 0; j < 10; ++j) { for (int i = 0; i < 10; ++i) { - image(j, i) = 2*j; + image(j, i) = 2 * j; } } BlurredImageAndDerivativesChannels(image, 0.9, &blurred_and_derivatives); EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 10.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 0.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 2.0, 1e-7); + EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 0.0, 1e-7); + EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 2.0, 1e-7); } } // namespace diff --git a/intern/libmv/libmv/image/correlation.h b/intern/libmv/libmv/image/correlation.h index c354f7e891e..25123efe8d0 100644 --- a/intern/libmv/libmv/image/correlation.h +++ b/intern/libmv/libmv/image/correlation.h @@ -21,14 +21,14 @@ #ifndef LIBMV_IMAGE_CORRELATION_H #define LIBMV_IMAGE_CORRELATION_H -#include "libmv/logging/logging.h" #include "libmv/image/image.h" +#include "libmv/logging/logging.h" namespace libmv { inline double PearsonProductMomentCorrelation( - const FloatImage &image_and_gradient1_sampled, - const FloatImage &image_and_gradient2_sampled) { + const FloatImage& image_and_gradient1_sampled, + const FloatImage& image_and_gradient2_sampled) { assert(image_and_gradient1_sampled.Width() == image_and_gradient2_sampled.Width()); assert(image_and_gradient1_sampled.Height() == @@ -63,9 +63,8 @@ inline double PearsonProductMomentCorrelation( double covariance_xy = sXY - sX * sY; double correlation = covariance_xy / sqrt(var_x * var_y); - LG << "Covariance xy: " << covariance_xy - << ", var 1: " << var_x << ", var 2: " << var_y - << ", correlation: " << correlation; + LG << "Covariance xy: " << covariance_xy << ", var 1: " << var_x + << ", var 2: " << var_y << ", correlation: " << correlation; return correlation; } diff --git a/intern/libmv/libmv/image/image.h b/intern/libmv/libmv/image/image.h index e0f200a4c93..40d6aa6f70a 100644 --- a/intern/libmv/libmv/image/image.h +++ b/intern/libmv/libmv/image/image.h @@ -39,14 +39,11 @@ typedef Array3Ds ShortImage; // is the best solution after all. class Image { public: - // Create an image from an array. The image takes ownership of the array. - Image(Array3Du *array) : array_type_(BYTE), array_(array) {} - Image(Array3Df *array) : array_type_(FLOAT), array_(array) {} + Image(Array3Du* array) : array_type_(BYTE), array_(array) {} + Image(Array3Df* array) : array_type_(FLOAT), array_(array) {} - Image(const Image &img): array_type_(NONE), array_(NULL) { - *this = img; - } + Image(const Image& img) : array_type_(NONE), array_(NULL) { *this = img; } // Underlying data type. enum DataType { @@ -62,20 +59,18 @@ class Image { int size; switch (array_type_) { case BYTE: - size = reinterpret_cast(array_)->MemorySizeInBytes(); - break; + size = reinterpret_cast(array_)->MemorySizeInBytes(); + break; case FLOAT: - size = reinterpret_cast(array_)->MemorySizeInBytes(); - break; + size = reinterpret_cast(array_)->MemorySizeInBytes(); + break; case INT: - size = reinterpret_cast(array_)->MemorySizeInBytes(); - break; + size = reinterpret_cast(array_)->MemorySizeInBytes(); + break; case SHORT: - size = reinterpret_cast(array_)->MemorySizeInBytes(); - break; - default : - size = 0; - assert(0); + size = reinterpret_cast(array_)->MemorySizeInBytes(); + break; + default: size = 0; assert(0); } size += sizeof(*this); return size; @@ -83,71 +78,57 @@ class Image { ~Image() { switch (array_type_) { - case BYTE: - delete reinterpret_cast(array_); - - break; - case FLOAT: - delete reinterpret_cast(array_); - - break; - case INT: - delete reinterpret_cast(array_); - - break; - case SHORT: - delete reinterpret_cast(array_); - - break; - default: - assert(0); - } + case BYTE: delete reinterpret_cast(array_); break; + case FLOAT: delete reinterpret_cast(array_); break; + case INT: delete reinterpret_cast(array_); break; + case SHORT: delete reinterpret_cast(array_); break; + default: assert(0); + } } - Image& operator= (const Image& f) { + Image& operator=(const Image& f) { if (this != &f) { array_type_ = f.array_type_; switch (array_type_) { case BYTE: - delete reinterpret_cast(array_); - array_ = new Array3Du(*(Array3Du *)f.array_); - break; + delete reinterpret_cast(array_); + array_ = new Array3Du(*(Array3Du*)f.array_); + break; case FLOAT: - delete reinterpret_cast(array_); - array_ = new Array3Df(*(Array3Df *)f.array_); - break; + delete reinterpret_cast(array_); + array_ = new Array3Df(*(Array3Df*)f.array_); + break; case INT: - delete reinterpret_cast(array_); - array_ = new Array3Di(*(Array3Di *)f.array_); - break; + delete reinterpret_cast(array_); + array_ = new Array3Di(*(Array3Di*)f.array_); + break; case SHORT: - delete reinterpret_cast(array_); - array_ = new Array3Ds(*(Array3Ds *)f.array_); - break; - default: - assert(0); + delete reinterpret_cast(array_); + array_ = new Array3Ds(*(Array3Ds*)f.array_); + break; + default: assert(0); } } return *this; } - Array3Du *AsArray3Du() const { + Array3Du* AsArray3Du() const { if (array_type_ == BYTE) { - return reinterpret_cast(array_); + return reinterpret_cast(array_); } return NULL; } - Array3Df *AsArray3Df() const { + Array3Df* AsArray3Df() const { if (array_type_ == FLOAT) { - return reinterpret_cast(array_); + return reinterpret_cast(array_); } return NULL; } private: DataType array_type_; - BaseArray *array_; + BaseArray* array_; }; } // namespace libmv diff --git a/intern/libmv/libmv/image/image_converter.h b/intern/libmv/libmv/image/image_converter.h index b3a3fa2bf8c..41d53be6722 100644 --- a/intern/libmv/libmv/image/image_converter.h +++ b/intern/libmv/libmv/image/image_converter.h @@ -28,7 +28,7 @@ namespace libmv { // The factor comes from http://www.easyrgb.com/ // RGB to XYZ : Y is the luminance channel // var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722 -template +template inline T RGB2GRAY(const T r, const T g, const T b) { return static_cast(r * 0.2126 + g * 0.7152 + b * 0.0722); } @@ -42,8 +42,8 @@ inline unsigned char RGB2GRAY(const unsigned char r, return (unsigned char)(r * 0.2126 + g * 0.7152 + b * 0.0722 +0.5); }*/ -template -void Rgb2Gray(const ImageIn &imaIn, ImageOut *imaOut) { +template +void Rgb2Gray(const ImageIn& imaIn, ImageOut* imaOut) { // It is all fine to cnvert RGBA image here as well, // all the additional channels will be nicely ignored. assert(imaIn.Depth() >= 3); @@ -52,21 +52,22 @@ void Rgb2Gray(const ImageIn &imaIn, ImageOut *imaOut) { // Convert each RGB pixel into Gray value (luminance) for (int j = 0; j < imaIn.Height(); ++j) { - for (int i = 0; i < imaIn.Width(); ++i) { - (*imaOut)(j, i) = RGB2GRAY(imaIn(j, i, 0) , imaIn(j, i, 1), imaIn(j, i, 2)); + for (int i = 0; i < imaIn.Width(); ++i) { + (*imaOut)(j, i) = + RGB2GRAY(imaIn(j, i, 0), imaIn(j, i, 1), imaIn(j, i, 2)); } } } // Convert given float image to an unsigned char array of pixels. -template -unsigned char *FloatImageToUCharArray(const Image &image) { - unsigned char *buffer = +template +unsigned char* FloatImageToUCharArray(const Image& image) { + unsigned char* buffer = new unsigned char[image.Width() * image.Height() * image.Depth()]; for (int y = 0; y < image.Height(); y++) { - for (int x = 0; x < image.Width(); x++) { - for (int d = 0; d < image.Depth(); d++) { + for (int x = 0; x < image.Width(); x++) { + for (int d = 0; d < image.Depth(); d++) { int index = (y * image.Width() + x) * image.Depth() + d; buffer[index] = 255.0 * image(y, x, d); } diff --git a/intern/libmv/libmv/image/image_drawing.h b/intern/libmv/libmv/image/image_drawing.h index f50e48b75a3..dd6a94dd7d4 100644 --- a/intern/libmv/libmv/image/image_drawing.h +++ b/intern/libmv/libmv/image/image_drawing.h @@ -34,9 +34,9 @@ namespace libmv { /// Put the pixel in the image to the given color only if the point (xc,yc) /// is inside the image. template -inline void safePutPixel(int yc, int xc, const Color & col, Image *pim) { +inline void safePutPixel(int yc, int xc, const Color& col, Image* pim) { if (!pim) - return; + return; if (pim->Contains(yc, xc)) { (*pim)(yc, xc) = col; } @@ -45,9 +45,9 @@ inline void safePutPixel(int yc, int xc, const Color & col, Image *pim) { /// is inside the image. This function support multi-channel color /// \note The color pointer col must have size as the image depth template -inline void safePutPixel(int yc, int xc, const Color *col, Image *pim) { +inline void safePutPixel(int yc, int xc, const Color* col, Image* pim) { if (!pim) - return; + return; if (pim->Contains(yc, xc)) { for (int i = 0; i < pim->Depth(); ++i) (*pim)(yc, xc, i) = *(col + i); @@ -59,19 +59,23 @@ inline void safePutPixel(int yc, int xc, const Color *col, Image *pim) { // Add the rotation of the ellipse. // As the algo. use symmetry we must use 4 rotations. template -void DrawEllipse(int xc, int yc, int radiusA, int radiusB, - const Color &col, Image *pim, double angle = 0.0) { +void DrawEllipse(int xc, + int yc, + int radiusA, + int radiusB, + const Color& col, + Image* pim, + double angle = 0.0) { int a = radiusA; int b = radiusB; // Counter Clockwise rotation matrix. - double matXY[4] = { cos(angle), sin(angle), - -sin(angle), cos(angle)}; + double matXY[4] = {cos(angle), sin(angle), -sin(angle), cos(angle)}; int x, y; double d1, d2; x = 0; y = b; - d1 = b*b - a*a*b + a*a/4; + d1 = b * b - a * a * b + a * a / 4; float rotX = (matXY[0] * x + matXY[1] * y); float rotY = (matXY[2] * x + matXY[3] * y); @@ -86,12 +90,12 @@ void DrawEllipse(int xc, int yc, int radiusA, int radiusB, rotY = (-matXY[2] * x + matXY[3] * y); safePutPixel(yc + rotY, xc + rotX, col, pim); - while (a*a*(y-.5) > b*b*(x+1)) { + while (a * a * (y - .5) > b * b * (x + 1)) { if (d1 < 0) { - d1 += b*b*(2*x+3); + d1 += b * b * (2 * x + 3); ++x; } else { - d1 += b*b*(2*x+3) + a*a*(-2*y+2); + d1 += b * b * (2 * x + 3) + a * a * (-2 * y + 2); ++x; --y; } @@ -108,14 +112,14 @@ void DrawEllipse(int xc, int yc, int radiusA, int radiusB, rotY = (-matXY[2] * x + matXY[3] * y); safePutPixel(yc + rotY, xc + rotX, col, pim); } - d2 = b*b*(x+.5)*(x+.5) + a*a*(y-1)*(y-1) - a*a*b*b; + d2 = b * b * (x + .5) * (x + .5) + a * a * (y - 1) * (y - 1) - a * a * b * b; while (y > 0) { if (d2 < 0) { - d2 += b*b*(2*x+2) + a*a*(-2*y+3); + d2 += b * b * (2 * x + 2) + a * a * (-2 * y + 3); --y; ++x; } else { - d2 += a*a*(-2*y+3); + d2 += a * a * (-2 * y + 3); --y; } rotX = (matXY[0] * x + matXY[1] * y); @@ -137,23 +141,23 @@ void DrawEllipse(int xc, int yc, int radiusA, int radiusB, // So it's better the use the Andres method. // http://fr.wikipedia.org/wiki/Algorithme_de_tracé_de_cercle_d'Andres. template -void DrawCircle(int x, int y, int radius, const Color &col, Image *pim) { - Image &im = *pim; - if ( im.Contains(y + radius, x + radius) - || im.Contains(y + radius, x - radius) - || im.Contains(y - radius, x + radius) - || im.Contains(y - radius, x - radius)) { +void DrawCircle(int x, int y, int radius, const Color& col, Image* pim) { + Image& im = *pim; + if (im.Contains(y + radius, x + radius) || + im.Contains(y + radius, x - radius) || + im.Contains(y - radius, x + radius) || + im.Contains(y - radius, x - radius)) { int x1 = 0; int y1 = radius; int d = radius - 1; while (y1 >= x1) { // Draw the point for each octant. - safePutPixel( y1 + y, x1 + x, col, pim); - safePutPixel( x1 + y, y1 + x, col, pim); - safePutPixel( y1 + y, -x1 + x, col, pim); - safePutPixel( x1 + y, -y1 + x, col, pim); - safePutPixel(-y1 + y, x1 + x, col, pim); - safePutPixel(-x1 + y, y1 + x, col, pim); + safePutPixel(y1 + y, x1 + x, col, pim); + safePutPixel(x1 + y, y1 + x, col, pim); + safePutPixel(y1 + y, -x1 + x, col, pim); + safePutPixel(x1 + y, -y1 + x, col, pim); + safePutPixel(-y1 + y, x1 + x, col, pim); + safePutPixel(-x1 + y, y1 + x, col, pim); safePutPixel(-y1 + y, -x1 + x, col, pim); safePutPixel(-x1 + y, -y1 + x, col, pim); if (d >= 2 * x1) { @@ -163,7 +167,7 @@ void DrawCircle(int x, int y, int radius, const Color &col, Image *pim) { if (d <= 2 * (radius - y1)) { d = d + 2 * y1 - 1; y1 -= 1; - } else { + } else { d = d + 2 * (y1 - x1 - 1); y1 -= 1; x1 += 1; @@ -175,8 +179,8 @@ void DrawCircle(int x, int y, int radius, const Color &col, Image *pim) { // Bresenham algorithm template -void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) { - Image &im = *pim; +void DrawLine(int xa, int ya, int xb, int yb, const Color& col, Image* pim) { + Image& im = *pim; // If one point is outside the image // Replace the outside point by the intersection of the line and @@ -185,35 +189,37 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) { int width = pim->Width(); int height = pim->Height(); const bool xdir = xa < xb, ydir = ya < yb; - float nx0 = xa, nx1 = xb, ny0 = ya, ny1 = yb, - &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, - &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0, - &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, - &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0; + float nx0 = xa, nx1 = xb, ny0 = ya, ny1 = yb, &xleft = xdir ? nx0 : nx1, + &yleft = xdir ? ny0 : ny1, &xright = xdir ? nx1 : nx0, + &yright = xdir ? ny1 : ny0, &xup = ydir ? nx0 : nx1, + &yup = ydir ? ny0 : ny1, &xdown = ydir ? nx1 : nx0, + &ydown = ydir ? ny1 : ny0; - if (xright < 0 || xleft >= width) return; + if (xright < 0 || xleft >= width) + return; if (xleft < 0) { - yleft -= xleft*(yright - yleft)/(xright - xleft); - xleft = 0; + yleft -= xleft * (yright - yleft) / (xright - xleft); + xleft = 0; } if (xright >= width) { - yright -= (xright - width)*(yright - yleft)/(xright - xleft); - xright = width - 1; + yright -= (xright - width) * (yright - yleft) / (xright - xleft); + xright = width - 1; } - if (ydown < 0 || yup >= height) return; + if (ydown < 0 || yup >= height) + return; if (yup < 0) { - xup -= yup*(xdown - xup)/(ydown - yup); - yup = 0; + xup -= yup * (xdown - xup) / (ydown - yup); + yup = 0; } if (ydown >= height) { - xdown -= (ydown - height)*(xdown - xup)/(ydown - yup); - ydown = height - 1; + xdown -= (ydown - height) * (xdown - xup) / (ydown - yup); + ydown = height - 1; } - xa = (int) xleft; - xb = (int) xright; - ya = (int) yleft; - yb = (int) yright; + xa = (int)xleft; + xb = (int)xright; + ya = (int)yleft; + yb = (int)yright; } int xbas, xhaut, ybas, yhaut; @@ -241,7 +247,7 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) { } if (dy > 0) { // Positive slope will increment X. incrmY = 1; - } else { // Negative slope. + } else { // Negative slope. incrmY = -1; } if (dx >= dy) { @@ -255,9 +261,9 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) { x += incrmX; if (dp <= 0) { // Go in direction of the South Pixel. dp += S; - } else { // Go to the North. + } else { // Go to the North. dp += N; - y+=incrmY; + y += incrmY; } } } else { @@ -271,7 +277,7 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) { y += incrmY; if (dp <= 0) { // Go in direction of the South Pixel. dp += S; - } else { // Go to the North. + } else { // Go to the North. dp += N; x += incrmX; } diff --git a/intern/libmv/libmv/image/image_test.cc b/intern/libmv/libmv/image/image_test.cc index 241f49f2244..a1730a9a55e 100644 --- a/intern/libmv/libmv/image/image_test.cc +++ b/intern/libmv/libmv/image/image_test.cc @@ -23,20 +23,20 @@ #include "libmv/image/image.h" #include "testing/testing.h" -using libmv::Image; using libmv::Array3Df; +using libmv::Image; namespace { TEST(Image, SimpleImageAccessors) { - Array3Df *array = new Array3Df(2, 3); + Array3Df* array = new Array3Df(2, 3); Image image(array); EXPECT_EQ(array, image.AsArray3Df()); EXPECT_TRUE(NULL == image.AsArray3Du()); } TEST(Image, MemorySizeInBytes) { - Array3Df *array = new Array3Df(2, 3); + Array3Df* array = new Array3Df(2, 3); Image image(array); int size = sizeof(image) + array->MemorySizeInBytes(); EXPECT_EQ(size, image.MemorySizeInBytes()); diff --git a/intern/libmv/libmv/image/sample.h b/intern/libmv/libmv/image/sample.h index 24eb9ccd57d..2b57baf27b9 100644 --- a/intern/libmv/libmv/image/sample.h +++ b/intern/libmv/libmv/image/sample.h @@ -26,17 +26,14 @@ namespace libmv { /// Nearest neighbor interpolation. -template -inline T SampleNearest(const Array3D &image, - float y, float x, int v = 0) { +template +inline T SampleNearest(const Array3D& image, float y, float x, int v = 0) { const int i = int(round(y)); const int j = int(round(x)); return image(i, j, v); } -inline void LinearInitAxis(float x, int size, - int *x1, int *x2, - float *dx) { +inline void LinearInitAxis(float x, int size, int* x1, int* x2, float* dx) { const int ix = static_cast(x); if (ix < 0) { *x1 = 0; @@ -54,32 +51,32 @@ inline void LinearInitAxis(float x, int size, } /// Linear interpolation. -template -inline T SampleLinear(const Array3D &image, float y, float x, int v = 0) { +template +inline T SampleLinear(const Array3D& image, float y, float x, int v = 0) { int x1, y1, x2, y2; float dx, dy; LinearInitAxis(y, image.Height(), &y1, &y2, &dy); - LinearInitAxis(x, image.Width(), &x1, &x2, &dx); + LinearInitAxis(x, image.Width(), &x1, &x2, &dx); const T im11 = image(y1, x1, v); const T im12 = image(y1, x2, v); const T im21 = image(y2, x1, v); const T im22 = image(y2, x2, v); - return T( dy * (dx * im11 + (1.0 - dx) * im12) + + return T(dy * (dx * im11 + (1.0 - dx) * im12) + (1 - dy) * (dx * im21 + (1.0 - dx) * im22)); } /// Linear interpolation, of all channels. The sample is assumed to have the /// same size as the number of channels in image. -template -inline void SampleLinear(const Array3D &image, float y, float x, T *sample) { +template +inline void SampleLinear(const Array3D& image, float y, float x, T* sample) { int x1, y1, x2, y2; float dx, dy; LinearInitAxis(y, image.Height(), &y1, &y2, &dy); - LinearInitAxis(x, image.Width(), &x1, &x2, &dx); + LinearInitAxis(x, image.Width(), &x1, &x2, &dx); for (int i = 0; i < image.Depth(); ++i) { const T im11 = image(y1, x1, i); @@ -87,7 +84,7 @@ inline void SampleLinear(const Array3D &image, float y, float x, T *sample) { const T im21 = image(y2, x1, i); const T im22 = image(y2, x2, i); - sample[i] = T( dy * (dx * im11 + (1.0 - dx) * im12) + + sample[i] = T(dy * (dx * im11 + (1.0 - dx) * im12) + (1 - dy) * (dx * im21 + (1.0 - dx) * im22)); } } @@ -95,7 +92,7 @@ inline void SampleLinear(const Array3D &image, float y, float x, T *sample) { // Downsample all channels by 2. If the image has odd width or height, the last // row or column is ignored. // FIXME(MatthiasF): this implementation shouldn't be in an interface file -inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) { +inline void DownsampleChannelsBy2(const Array3Df& in, Array3Df* out) { int height = in.Height() / 2; int width = in.Width() / 2; int depth = in.Depth(); @@ -106,10 +103,12 @@ inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) { for (int r = 0; r < height; ++r) { for (int c = 0; c < width; ++c) { for (int k = 0; k < depth; ++k) { + // clang-format off (*out)(r, c, k) = (in(2 * r, 2 * c, k) + in(2 * r + 1, 2 * c, k) + in(2 * r, 2 * c + 1, k) + in(2 * r + 1, 2 * c + 1, k)) / 4.0f; + // clang-format on } } } @@ -117,11 +116,12 @@ inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) { // Sample a region centered at x,y in image with size extending by half_width // from x,y. Channels specifies the number of channels to sample from. -inline void SamplePattern(const FloatImage &image, - double x, double y, - int half_width, - int channels, - FloatImage *sampled) { +inline void SamplePattern(const FloatImage& image, + double x, + double y, + int half_width, + int channels, + FloatImage* sampled) { sampled->Resize(2 * half_width + 1, 2 * half_width + 1, channels); for (int r = -half_width; r <= half_width; ++r) { for (int c = -half_width; c <= half_width; ++c) { diff --git a/intern/libmv/libmv/image/sample_test.cc b/intern/libmv/libmv/image/sample_test.cc index c8a0ce470c2..f1fb4c42c67 100644 --- a/intern/libmv/libmv/image/sample_test.cc +++ b/intern/libmv/libmv/image/sample_test.cc @@ -32,9 +32,9 @@ TEST(Image, Nearest) { image(1, 0) = 2; image(1, 1) = 3; EXPECT_EQ(0, SampleNearest(image, -0.4f, -0.4f)); - EXPECT_EQ(0, SampleNearest(image, 0.4f, 0.4f)); - EXPECT_EQ(3, SampleNearest(image, 0.6f, 0.6f)); - EXPECT_EQ(3, SampleNearest(image, 1.4f, 1.4f)); + EXPECT_EQ(0, SampleNearest(image, 0.4f, 0.4f)); + EXPECT_EQ(3, SampleNearest(image, 0.6f, 0.6f)); + EXPECT_EQ(3, SampleNearest(image, 1.4f, 1.4f)); } TEST(Image, Linear) { @@ -57,7 +57,7 @@ TEST(Image, DownsampleBy2) { ASSERT_EQ(1, resampled_image.Height()); ASSERT_EQ(1, resampled_image.Width()); ASSERT_EQ(1, resampled_image.Depth()); - EXPECT_FLOAT_EQ(6./4., resampled_image(0, 0)); + EXPECT_FLOAT_EQ(6. / 4., resampled_image(0, 0)); } TEST(Image, DownsampleBy2MultiChannel) { @@ -82,8 +82,8 @@ TEST(Image, DownsampleBy2MultiChannel) { ASSERT_EQ(1, resampled_image.Height()); ASSERT_EQ(1, resampled_image.Width()); ASSERT_EQ(3, resampled_image.Depth()); - EXPECT_FLOAT_EQ((0+1+2+3)/4., resampled_image(0, 0, 0)); - EXPECT_FLOAT_EQ((5+6+7+8)/4., resampled_image(0, 0, 1)); - EXPECT_FLOAT_EQ((9+10+11+12)/4., resampled_image(0, 0, 2)); + EXPECT_FLOAT_EQ((0 + 1 + 2 + 3) / 4., resampled_image(0, 0, 0)); + EXPECT_FLOAT_EQ((5 + 6 + 7 + 8) / 4., resampled_image(0, 0, 1)); + EXPECT_FLOAT_EQ((9 + 10 + 11 + 12) / 4., resampled_image(0, 0, 2)); } } // namespace diff --git a/intern/libmv/libmv/image/tuple.h b/intern/libmv/libmv/image/tuple.h index c8dc36f2e18..447bf0cc81c 100644 --- a/intern/libmv/libmv/image/tuple.h +++ b/intern/libmv/libmv/image/tuple.h @@ -34,10 +34,14 @@ class Tuple { Tuple(T initial_value) { Reset(initial_value); } template - Tuple(D *values) { Reset(values); } + Tuple(D* values) { + Reset(values); + } template - Tuple(const Tuple &b) { Reset(b); } + Tuple(const Tuple& b) { + Reset(b); + } template Tuple& operator=(const Tuple& b) { @@ -46,30 +50,32 @@ class Tuple { } template - void Reset(const Tuple& b) { Reset(b.Data()); } + void Reset(const Tuple& b) { + Reset(b.Data()); + } template - void Reset(D *values) { - for (int i = 0;i < N; i++) { + void Reset(D* values) { + for (int i = 0; i < N; i++) { data_[i] = T(values[i]); } } // Set all tuple values to the same thing. void Reset(T value) { - for (int i = 0;i < N; i++) { + for (int i = 0; i < N; i++) { data_[i] = value; } } // Pointer to the first element. - T *Data() { return &data_[0]; } - const T *Data() const { return &data_[0]; } + T* Data() { return &data_[0]; } + const T* Data() const { return &data_[0]; } - T &operator()(int i) { return data_[i]; } - const T &operator()(int i) const { return data_[i]; } + T& operator()(int i) { return data_[i]; } + const T& operator()(int i) const { return data_[i]; } - bool operator==(const Tuple &other) const { + bool operator==(const Tuple& other) const { for (int i = 0; i < N; ++i) { if ((*this)(i) != other(i)) { return false; @@ -77,9 +83,7 @@ class Tuple { } return true; } - bool operator!=(const Tuple &other) const { - return !(*this == other); - } + bool operator!=(const Tuple& other) const { return !(*this == other); } private: T data_[N]; diff --git a/intern/libmv/libmv/multiview/conditioning.cc b/intern/libmv/libmv/multiview/conditioning.cc index 0afbf119ea3..2f4bf653ca0 100644 --- a/intern/libmv/libmv/multiview/conditioning.cc +++ b/intern/libmv/libmv/multiview/conditioning.cc @@ -24,7 +24,7 @@ namespace libmv { // HZ 4.4.4 pag.109: Point conditioning (non isotropic) -void PreconditionerFromPoints(const Mat &points, Mat3 *T) { +void PreconditionerFromPoints(const Mat& points, Mat3* T) { Vec mean, variance; MeanAndVarianceAlongRows(points, &mean, &variance); @@ -38,12 +38,14 @@ void PreconditionerFromPoints(const Mat &points, Mat3 *T) { if (variance(1) < 1e-8) yfactor = mean(1) = 1.0; + // clang-format off *T << xfactor, 0, -xfactor * mean(0), 0, yfactor, -yfactor * mean(1), 0, 0, 1; + // clang-format on } // HZ 4.4.4 pag.107: Point conditioning (isotropic) -void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T) { +void IsotropicPreconditionerFromPoints(const Mat& points, Mat3* T) { Vec mean, variance; MeanAndVarianceAlongRows(points, &mean, &variance); @@ -57,14 +59,16 @@ void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T) { mean.setOnes(); } + // clang-format off *T << factor, 0, -factor * mean(0), 0, factor, -factor * mean(1), 0, 0, 1; + // clang-format on } -void ApplyTransformationToPoints(const Mat &points, - const Mat3 &T, - Mat *transformed_points) { +void ApplyTransformationToPoints(const Mat& points, + const Mat3& T, + Mat* transformed_points) { int n = points.cols(); transformed_points->resize(2, n); Mat3X p(3, n); @@ -73,26 +77,24 @@ void ApplyTransformationToPoints(const Mat &points, HomogeneousToEuclidean(p, transformed_points); } -void NormalizePoints(const Mat &points, - Mat *normalized_points, - Mat3 *T) { +void NormalizePoints(const Mat& points, Mat* normalized_points, Mat3* T) { PreconditionerFromPoints(points, T); ApplyTransformationToPoints(points, *T, normalized_points); } -void NormalizeIsotropicPoints(const Mat &points, - Mat *normalized_points, - Mat3 *T) { +void NormalizeIsotropicPoints(const Mat& points, + Mat* normalized_points, + Mat3* T) { IsotropicPreconditionerFromPoints(points, T); ApplyTransformationToPoints(points, *T, normalized_points); } // Denormalize the results. See HZ page 109. -void UnnormalizerT::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H) { +void UnnormalizerT::Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H) { *H = T2.transpose() * (*H) * T1; } -void UnnormalizerI::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H) { +void UnnormalizerI::Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H) { *H = T2.inverse() * (*H) * T1; } diff --git a/intern/libmv/libmv/multiview/conditioning.h b/intern/libmv/libmv/multiview/conditioning.h index 8f3e3a76070..876c5af48e6 100644 --- a/intern/libmv/libmv/multiview/conditioning.h +++ b/intern/libmv/libmv/multiview/conditioning.h @@ -26,32 +26,30 @@ namespace libmv { // Point conditioning (non isotropic) -void PreconditionerFromPoints(const Mat &points, Mat3 *T); +void PreconditionerFromPoints(const Mat& points, Mat3* T); // Point conditioning (isotropic) -void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T); +void IsotropicPreconditionerFromPoints(const Mat& points, Mat3* T); -void ApplyTransformationToPoints(const Mat &points, - const Mat3 &T, - Mat *transformed_points); +void ApplyTransformationToPoints(const Mat& points, + const Mat3& T, + Mat* transformed_points); -void NormalizePoints(const Mat &points, - Mat *normalized_points, - Mat3 *T); +void NormalizePoints(const Mat& points, Mat* normalized_points, Mat3* T); -void NormalizeIsotropicPoints(const Mat &points, - Mat *normalized_points, - Mat3 *T); +void NormalizeIsotropicPoints(const Mat& points, + Mat* normalized_points, + Mat3* T); /// Use inverse for unnormalize struct UnnormalizerI { // Denormalize the results. See HZ page 109. - static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H); + static void Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H); }; /// Use transpose for unnormalize struct UnnormalizerT { // Denormalize the results. See HZ page 109. - static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H); + static void Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H); }; } // namespace libmv diff --git a/intern/libmv/libmv/multiview/euclidean_resection.cc b/intern/libmv/libmv/multiview/euclidean_resection.cc index 16a1a0caafa..249d7ebef3d 100644 --- a/intern/libmv/libmv/multiview/euclidean_resection.cc +++ b/intern/libmv/libmv/multiview/euclidean_resection.cc @@ -23,8 +23,8 @@ #include #include -#include #include +#include #include "libmv/base/vector.h" #include "libmv/logging/logging.h" @@ -35,9 +35,10 @@ namespace euclidean_resection { typedef unsigned int uint; -bool EuclideanResection(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t, +bool EuclideanResection(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t, ResectionMethod method) { switch (method) { case RESECTION_ANSAR_DANIILIDIS: @@ -49,20 +50,20 @@ bool EuclideanResection(const Mat2X &x_camera, case RESECTION_PPNP: return EuclideanResectionPPnP(x_camera, X_world, R, t); break; - default: - LOG(FATAL) << "Unknown resection method."; + default: LOG(FATAL) << "Unknown resection method."; } return false; } -bool EuclideanResection(const Mat &x_image, - const Mat3X &X_world, - const Mat3 &K, - Mat3 *R, Vec3 *t, +bool EuclideanResection(const Mat& x_image, + const Mat3X& X_world, + const Mat3& K, + Mat3* R, + Vec3* t, ResectionMethod method) { CHECK(x_image.rows() == 2 || x_image.rows() == 3) - << "Invalid size for x_image: " - << x_image.rows() << "x" << x_image.cols(); + << "Invalid size for x_image: " << x_image.rows() << "x" + << x_image.cols(); Mat2X x_camera; if (x_image.rows() == 2) { @@ -73,18 +74,15 @@ bool EuclideanResection(const Mat &x_image, return EuclideanResection(x_camera, X_world, R, t, method); } -void AbsoluteOrientation(const Mat3X &X, - const Mat3X &Xp, - Mat3 *R, - Vec3 *t) { +void AbsoluteOrientation(const Mat3X& X, const Mat3X& Xp, Mat3* R, Vec3* t) { int num_points = X.cols(); - Vec3 C = X.rowwise().sum() / num_points; // Centroid of X. + Vec3 C = X.rowwise().sum() / num_points; // Centroid of X. Vec3 Cp = Xp.rowwise().sum() / num_points; // Centroid of Xp. // Normalize the two point sets. Mat3X Xn(3, num_points), Xpn(3, num_points); for (int i = 0; i < num_points; ++i) { - Xn.col(i) = X.col(i) - C; + Xn.col(i) = X.col(i) - C; Xpn.col(i) = Xp.col(i) - Cp; } @@ -100,10 +98,12 @@ void AbsoluteOrientation(const Mat3X &X, double Szy = Xn.row(2).dot(Xpn.row(1)); Mat4 N; + // clang-format off N << Sxx + Syy + Szz, Syz - Szy, Szx - Sxz, Sxy - Syx, Syz - Szy, Sxx - Syy - Szz, Sxy + Syx, Szx + Sxz, Szx - Sxz, Sxy + Syx, -Sxx + Syy - Szz, Syz + Szy, Sxy - Syx, Szx + Sxz, Syz + Szy, -Sxx - Syy + Szz; + // clang-format on // Find the unit quaternion q that maximizes qNq. It is the eigenvector // corresponding to the lagest eigenvalue. @@ -118,6 +118,7 @@ void AbsoluteOrientation(const Mat3X &X, double q1q3 = q(1) * q(3); double q2q3 = q(2) * q(3); + // clang-format off (*R) << qq(0) + qq(1) - qq(2) - qq(3), 2 * (q1q2 - q0q3), 2 * (q1q3 + q0q2), @@ -127,6 +128,7 @@ void AbsoluteOrientation(const Mat3X &X, 2 * (q1q3 - q0q2), 2 * (q2q3 + q0q1), qq(0) - qq(1) - qq(2) + qq(3); + // clang-format on // Fix the handedness of the R matrix. if (R->determinant() < 0) { @@ -176,9 +178,7 @@ static int Sign(double value) { // Lambda to create the constraints in equation (5) in "Linear Pose Estimation // from Points or Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no. // 5. -static Vec MatrixToConstraint(const Mat &A, - int num_k_columns, - int num_lambda) { +static Vec MatrixToConstraint(const Mat& A, int num_k_columns, int num_lambda) { Vec C(num_k_columns); C.setZero(); int idx = 0; @@ -195,17 +195,17 @@ static Vec MatrixToConstraint(const Mat &A, } // Normalizes the columns of vectors. -static void NormalizeColumnVectors(Mat3X *vectors) { +static void NormalizeColumnVectors(Mat3X* vectors) { int num_columns = vectors->cols(); for (int i = 0; i < num_columns; ++i) { vectors->col(i).normalize(); } } -void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, - Vec3 *t) { +void EuclideanResectionAnsarDaniilidis(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t) { CHECK(x_camera.cols() == X_world.cols()); CHECK(x_camera.cols() > 3); @@ -229,14 +229,14 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, // them into the M matrix (8). Also store the initial (i, j) indices. int row = 0; for (int i = 0; i < num_points; ++i) { - for (int j = i+1; j < num_points; ++j) { + for (int j = i + 1; j < num_points; ++j) { M(row, row) = -2 * x_camera_unit.col(i).dot(x_camera_unit.col(j)); M(row, num_m_rows + i) = x_camera_unit.col(i).dot(x_camera_unit.col(i)); M(row, num_m_rows + j) = x_camera_unit.col(j).dot(x_camera_unit.col(j)); Vec3 Xdiff = X_world.col(i) - X_world.col(j); double center_to_point_distance = Xdiff.norm(); M(row, num_m_columns - 1) = - - center_to_point_distance * center_to_point_distance; + -center_to_point_distance * center_to_point_distance; ij_index(row, 0) = i; ij_index(row, 1) = j; ++row; @@ -246,17 +246,17 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, } int num_lambda = num_points + 1; // Dimension of the null space of M. - Mat V = M.jacobiSvd(Eigen::ComputeFullV).matrixV().block(0, - num_m_rows, - num_m_columns, - num_lambda); + Mat V = M.jacobiSvd(Eigen::ComputeFullV) + .matrixV() + .block(0, num_m_rows, num_m_columns, num_lambda); // TODO(vess): The number of constraint equations in K (num_k_rows) must be // (num_points + 1) * (num_points + 2)/2. This creates a performance issue // for more than 4 points. It is fine for 4 points at the moment with 18 // instead of 15 equations. - int num_k_rows = num_m_rows + num_points * - (num_points*(num_points-1)/2 - num_points+1); + int num_k_rows = + num_m_rows + + num_points * (num_points * (num_points - 1) / 2 - num_points + 1); int num_k_columns = num_lambda * (num_lambda + 1) / 2; Mat K(num_k_rows, num_k_columns); K.setZero(); @@ -275,8 +275,8 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, int idx4 = IJToPointIndex(i, k, num_points); K.row(counter_k_row) = - MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)- - V.row(idx3).transpose() * V.row(idx4), + MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2) - + V.row(idx3).transpose() * V.row(idx4), num_k_columns, num_lambda); ++counter_k_row; @@ -296,8 +296,8 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, int idx4 = IJToPointIndex(i, k, num_points); K.row(counter_k_row) = - MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)- - V.row(idx3).transpose() * V.row(idx4), + MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2) - + V.row(idx3).transpose() * V.row(idx4), num_k_columns, num_lambda); ++counter_k_row; @@ -317,14 +317,12 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, } } // Ensure positiveness of the largest value corresponding to lambda_ii. - L_sq = L_sq * Sign(L_sq(IJToIndex(max_L_sq_index, - max_L_sq_index, - num_lambda))); + L_sq = + L_sq * Sign(L_sq(IJToIndex(max_L_sq_index, max_L_sq_index, num_lambda))); Vec L(num_lambda); - L(max_L_sq_index) = sqrt(L_sq(IJToIndex(max_L_sq_index, - max_L_sq_index, - num_lambda))); + L(max_L_sq_index) = + sqrt(L_sq(IJToIndex(max_L_sq_index, max_L_sq_index, num_lambda))); for (int i = 0; i < num_lambda; ++i) { if (i != max_L_sq_index) { @@ -353,9 +351,9 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, } // Selects 4 virtual control points using mean and PCA. -static void SelectControlPoints(const Mat3X &X_world, - Mat *X_centered, - Mat34 *X_control_points) { +static void SelectControlPoints(const Mat3X& X_world, + Mat* X_centered, + Mat34* X_control_points) { size_t num_points = X_world.cols(); // The first virtual control point, C0, is the centroid. @@ -379,13 +377,13 @@ static void SelectControlPoints(const Mat3X &X_world, } // Computes the barycentric coordinates for all real points -static void ComputeBarycentricCoordinates(const Mat3X &X_world_centered, - const Mat34 &X_control_points, - Mat4X *alphas) { +static void ComputeBarycentricCoordinates(const Mat3X& X_world_centered, + const Mat34& X_control_points, + Mat4X* alphas) { size_t num_points = X_world_centered.cols(); Mat3 C2; for (size_t c = 1; c < 4; c++) { - C2.col(c-1) = X_control_points.col(c) - X_control_points.col(0); + C2.col(c - 1) = X_control_points.col(c) - X_control_points.col(0); } Mat3 C2inv = C2.inverse(); @@ -401,14 +399,15 @@ static void ComputeBarycentricCoordinates(const Mat3X &X_world_centered, // Estimates the coordinates of all real points in the camera coordinate frame static void ComputePointsCoordinatesInCameraFrame( - const Mat4X &alphas, - const Vec4 &betas, - const Eigen::Matrix &U, - Mat3X *X_camera) { + const Mat4X& alphas, + const Vec4& betas, + const Eigen::Matrix& U, + Mat3X* X_camera) { size_t num_points = alphas.cols(); // Estimates the control points in the camera reference frame. - Mat34 C2b; C2b.setZero(); + Mat34 C2b; + C2b.setZero(); for (size_t cu = 0; cu < 4; cu++) { for (size_t c = 0; c < 4; c++) { C2b.col(c) += betas(cu) * U.block(11 - cu, c * 3, 1, 3).transpose(); @@ -436,9 +435,10 @@ static void ComputePointsCoordinatesInCameraFrame( } } -bool EuclideanResectionEPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t) { +bool EuclideanResectionEPnP(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t) { CHECK(x_camera.cols() == X_world.cols()); CHECK(x_camera.cols() > 3); size_t num_points = X_world.cols(); @@ -462,6 +462,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, double a3 = alphas(3, c); double ui = x_camera(0, c); double vi = x_camera(1, c); + // clang-format off M.block(2*c, 0, 2, 12) << a0, 0, a0*(-ui), a1, 0, a1*(-ui), a2, 0, @@ -471,10 +472,11 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, a1, a1*(-vi), 0, a2, a2*(-vi), 0, a3, a3*(-vi); + // clang-format on } // TODO(julien): Avoid the transpose by rewriting the u2.block() calls. - Eigen::JacobiSVD MtMsvd(M.transpose()*M, Eigen::ComputeFullU); + Eigen::JacobiSVD MtMsvd(M.transpose() * M, Eigen::ComputeFullU); Eigen::Matrix u2 = MtMsvd.matrixU().transpose(); // Estimate the L matrix. @@ -495,21 +497,22 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, dv2.row(3) = u2.block(10, 3, 1, 3) - u2.block(10, 6, 1, 3); dv2.row(4) = u2.block(10, 3, 1, 3) - u2.block(10, 9, 1, 3); dv2.row(5) = u2.block(10, 6, 1, 3) - u2.block(10, 9, 1, 3); - dv3.row(0) = u2.block(9, 0, 1, 3) - u2.block(9, 3, 1, 3); - dv3.row(1) = u2.block(9, 0, 1, 3) - u2.block(9, 6, 1, 3); - dv3.row(2) = u2.block(9, 0, 1, 3) - u2.block(9, 9, 1, 3); - dv3.row(3) = u2.block(9, 3, 1, 3) - u2.block(9, 6, 1, 3); - dv3.row(4) = u2.block(9, 3, 1, 3) - u2.block(9, 9, 1, 3); - dv3.row(5) = u2.block(9, 6, 1, 3) - u2.block(9, 9, 1, 3); - dv4.row(0) = u2.block(8, 0, 1, 3) - u2.block(8, 3, 1, 3); - dv4.row(1) = u2.block(8, 0, 1, 3) - u2.block(8, 6, 1, 3); - dv4.row(2) = u2.block(8, 0, 1, 3) - u2.block(8, 9, 1, 3); - dv4.row(3) = u2.block(8, 3, 1, 3) - u2.block(8, 6, 1, 3); - dv4.row(4) = u2.block(8, 3, 1, 3) - u2.block(8, 9, 1, 3); - dv4.row(5) = u2.block(8, 6, 1, 3) - u2.block(8, 9, 1, 3); + dv3.row(0) = u2.block(9, 0, 1, 3) - u2.block(9, 3, 1, 3); + dv3.row(1) = u2.block(9, 0, 1, 3) - u2.block(9, 6, 1, 3); + dv3.row(2) = u2.block(9, 0, 1, 3) - u2.block(9, 9, 1, 3); + dv3.row(3) = u2.block(9, 3, 1, 3) - u2.block(9, 6, 1, 3); + dv3.row(4) = u2.block(9, 3, 1, 3) - u2.block(9, 9, 1, 3); + dv3.row(5) = u2.block(9, 6, 1, 3) - u2.block(9, 9, 1, 3); + dv4.row(0) = u2.block(8, 0, 1, 3) - u2.block(8, 3, 1, 3); + dv4.row(1) = u2.block(8, 0, 1, 3) - u2.block(8, 6, 1, 3); + dv4.row(2) = u2.block(8, 0, 1, 3) - u2.block(8, 9, 1, 3); + dv4.row(3) = u2.block(8, 3, 1, 3) - u2.block(8, 6, 1, 3); + dv4.row(4) = u2.block(8, 3, 1, 3) - u2.block(8, 9, 1, 3); + dv4.row(5) = u2.block(8, 6, 1, 3) - u2.block(8, 9, 1, 3); Eigen::Matrix L; for (size_t r = 0; r < 6; r++) { + // clang-format off L.row(r) << dv1.row(r).dot(dv1.row(r)), 2.0 * dv1.row(r).dot(dv2.row(r)), dv2.row(r).dot(dv2.row(r)), @@ -520,19 +523,23 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, 2.0 * dv2.row(r).dot(dv4.row(r)), 2.0 * dv3.row(r).dot(dv4.row(r)), dv4.row(r).dot(dv4.row(r)); + // clang-format on } Vec6 rho; + // clang-format off rho << (X_control_points.col(0) - X_control_points.col(1)).squaredNorm(), (X_control_points.col(0) - X_control_points.col(2)).squaredNorm(), (X_control_points.col(0) - X_control_points.col(3)).squaredNorm(), (X_control_points.col(1) - X_control_points.col(2)).squaredNorm(), (X_control_points.col(1) - X_control_points.col(3)).squaredNorm(), (X_control_points.col(2) - X_control_points.col(3)).squaredNorm(); + // clang-format on // There are three possible solutions based on the three approximations of L // (betas). Below, each one is solved for then the best one is chosen. Mat3X X_camera; - Mat3 K; K.setIdentity(); + Mat3 K; + K.setIdentity(); vector Rs(3); vector ts(3); Vec rmse(3); @@ -546,7 +553,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, // // TODO(keir): Decide if setting this to infinity, effectively disabling the // check, is the right approach. So far this seems the case. - double kSuccessThreshold = std::numeric_limits::max(); + double kSuccessThreshold = std::numeric_limits::max(); // Find the first possible solution for R, t corresponding to: // Betas = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33] @@ -563,7 +570,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, if (b4(0) < 0) { b4 = -b4; } - b4(0) = std::sqrt(b4(0)); + b4(0) = std::sqrt(b4(0)); betas << b4(0), b4(1) / b4(0), b4(2) / b4(0), b4(3) / b4(0); ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera); AbsoluteOrientation(X_world, X_camera, &Rs[0], &ts[0]); @@ -669,12 +676,12 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, // TODO(julien): Improve the solutions with non-linear refinement. return true; } - + /* - + Straight from the paper: http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf - + function [R T] = ppnp(P,S,tol) % input % P : matrix (nx3) image coordinates in camera reference [u v 1] @@ -708,33 +715,34 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, end T = -R*c; end - + */ // TODO(keir): Re-do all the variable names and add comments matching the paper. // This implementation has too much of the terseness of the original. On the // other hand, it did work on the first try. -bool EuclideanResectionPPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t) { +bool EuclideanResectionPPnP(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t) { int n = x_camera.cols(); Mat Z = Mat::Zero(n, n); Vec e = Vec::Ones(n); Mat A = Mat::Identity(n, n) - (e * e.transpose() / n); Vec II = e / n; - + Mat P(n, 3); P.col(0) = x_camera.row(0); P.col(1) = x_camera.row(1); P.col(2).setConstant(1.0); - + Mat S = X_world.transpose(); - + double error = std::numeric_limits::infinity(); Mat E_old = 1000 * Mat::Ones(n, 3); - + Vec3 c; Mat E(n, 3); - + int iteration = 0; double tolerance = 1e-5; // TODO(keir): The limit of 100 can probably be reduced, but this will require @@ -748,20 +756,21 @@ bool EuclideanResectionPPnP(const Mat2X &x_camera, s << 1, 1, (U * VT).determinant(); *R = U * s.asDiagonal() * VT; Mat PR = P * *R; // n x 3 - c = (S - Z*PR).transpose() * II; - Mat Y = S - e*c.transpose(); // n x 3 - Vec Zmindiag = (PR * Y.transpose()).diagonal() - .cwiseQuotient(P.rowwise().squaredNorm()); + c = (S - Z * PR).transpose() * II; + Mat Y = S - e * c.transpose(); // n x 3 + Vec Zmindiag = (PR * Y.transpose()) + .diagonal() + .cwiseQuotient(P.rowwise().squaredNorm()); for (int i = 0; i < n; ++i) { Zmindiag[i] = std::max(Zmindiag[i], 0.0); } Z = Zmindiag.asDiagonal(); - E = Y - Z*PR; + E = Y - Z * PR; error = (E - E_old).norm(); LG << "PPnP error(" << (iteration++) << "): " << error; E_old = E; } - *t = -*R*c; + *t = -*R * c; // TODO(keir): Figure out what the failure cases are. Is it too many // iterations? Spend some time going through the math figuring out if there @@ -769,6 +778,5 @@ bool EuclideanResectionPPnP(const Mat2X &x_camera, return true; } - -} // namespace resection +} // namespace euclidean_resection } // namespace libmv diff --git a/intern/libmv/libmv/multiview/euclidean_resection.h b/intern/libmv/libmv/multiview/euclidean_resection.h index 28eae92611c..3c4c3979ff6 100644 --- a/intern/libmv/libmv/multiview/euclidean_resection.h +++ b/intern/libmv/libmv/multiview/euclidean_resection.h @@ -21,8 +21,8 @@ #ifndef LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ #define LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ -#include "libmv/numeric/numeric.h" #include "libmv/multiview/projection.h" +#include "libmv/numeric/numeric.h" namespace libmv { namespace euclidean_resection { @@ -33,7 +33,7 @@ enum ResectionMethod { // The "EPnP" algorithm by Lepetit et al. // http://cvlab.epfl.ch/~lepetit/papers/lepetit_ijcv08.pdf RESECTION_EPNP, - + // The Procrustes PNP algorithm ("PPnP") // http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf RESECTION_PPNP @@ -50,9 +50,10 @@ enum ResectionMethod { * \param t Solution for the camera translation vector * \param method The resection method to use. */ -bool EuclideanResection(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t, +bool EuclideanResection(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t, ResectionMethod method = RESECTION_EPNP); /** @@ -68,10 +69,11 @@ bool EuclideanResection(const Mat2X &x_camera, * \param t Solution for the camera translation vector * \param method Resection method */ -bool EuclideanResection(const Mat &x_image, - const Mat3X &X_world, - const Mat3 &K, - Mat3 *R, Vec3 *t, +bool EuclideanResection(const Mat& x_image, + const Mat3X& X_world, + const Mat3& K, + Mat3* R, + Vec3* t, ResectionMethod method = RESECTION_EPNP); /** @@ -84,10 +86,7 @@ bool EuclideanResection(const Mat &x_image, * Horn, Hilden, "Closed-form solution of absolute orientation using * orthonormal matrices" */ -void AbsoluteOrientation(const Mat3X &X, - const Mat3X &Xp, - Mat3 *R, - Vec3 *t); +void AbsoluteOrientation(const Mat3X& X, const Mat3X& Xp, Mat3* R, Vec3* t); /** * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or @@ -102,9 +101,10 @@ void AbsoluteOrientation(const Mat3X &X, * This is the algorithm described in: "Linear Pose Estimation from Points or * Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no. 5. */ -void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t); +void EuclideanResectionAnsarDaniilidis(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t); /** * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or * more 3D points and their images. @@ -120,9 +120,10 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, * and F. Moreno-Noguer and P. Fua, IJCV 2009. vol. 81, no. 2 * \note: the non-linear optimization is not implemented here. */ -bool EuclideanResectionEPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t); +bool EuclideanResectionEPnP(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t); /** * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or @@ -137,12 +138,12 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, * Straight from the paper: * http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf */ -bool EuclideanResectionPPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t); +bool EuclideanResectionPPnP(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t); } // namespace euclidean_resection } // namespace libmv - #endif /* LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ */ diff --git a/intern/libmv/libmv/multiview/euclidean_resection_test.cc b/intern/libmv/libmv/multiview/euclidean_resection_test.cc index 378837d3d2d..3bb8e6e1710 100644 --- a/intern/libmv/libmv/multiview/euclidean_resection_test.cc +++ b/intern/libmv/libmv/multiview/euclidean_resection_test.cc @@ -19,9 +19,9 @@ // IN THE SOFTWARE. #include "libmv/multiview/euclidean_resection.h" -#include "libmv/numeric/numeric.h" #include "libmv/logging/logging.h" #include "libmv/multiview/projection.h" +#include "libmv/numeric/numeric.h" #include "testing/testing.h" using namespace libmv::euclidean_resection; @@ -33,10 +33,10 @@ static void CreateCameraSystem(const Mat3& KK, const Vec& X_distances, const Mat3& R_input, const Vec3& T_input, - Mat2X *x_camera, - Mat3X *X_world, - Mat3 *R_expected, - Vec3 *T_expected) { + Mat2X* x_camera, + Mat3X* X_world, + Mat3* R_expected, + Vec3* T_expected) { int num_points = x_image.cols(); Mat3X x_unit_cam(3, num_points); @@ -76,9 +76,9 @@ TEST(AbsoluteOrientation, QuaternionSolution) { // Create a random translation and rotation. Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); + R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); Vec3 t_input; t_input.setRandom(); @@ -109,26 +109,29 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { image_dimensions << 1600, 1200; Mat3 KK; + // clang-format off KK << 2796, 0, 804, 0 , 2796, 641, 0, 0, 1; + // clang-format on // The real image points. int num_points = 4; Mat3X x_image(3, num_points); + // clang-format off x_image << 1164.06, 734.948, 749.599, 430.727, 681.386, 844.59, 496.315, 580.775, 1, 1, 1, 1; - + // clang-format on // A vector of the 4 distances to the 3D points. Vec X_distances = 100 * Vec::Random(num_points).array().abs(); // Create the random camera motion R and t that resection should recover. Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); + R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); Vec3 T_input; T_input.setRandom(); @@ -140,15 +143,21 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { Vec3 T_expected; Mat3X X_world; Mat2X x_camera; - CreateCameraSystem(KK, x_image, X_distances, R_input, T_input, - &x_camera, &X_world, &R_expected, &T_expected); + CreateCameraSystem(KK, + x_image, + X_distances, + R_input, + T_input, + &x_camera, + &X_world, + &R_expected, + &T_expected); // Finally, run the code under test. Mat3 R_output; Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_ANSAR_DANIILIDIS); + EuclideanResection( + x_camera, X_world, &R_output, &T_output, RESECTION_ANSAR_DANIILIDIS); EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); @@ -173,9 +182,11 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { // TODO(jmichot): Reduce the code duplication here with the code above. TEST(EuclideanResection, Points6AllRandomInput) { Mat3 KK; + // clang-format off KK << 2796, 0, 804, 0 , 2796, 641, 0, 0, 1; + // clang-format on // Create random image points for a 1600x1200 image. int w = 1600; @@ -192,9 +203,9 @@ TEST(EuclideanResection, Points6AllRandomInput) { // Create the random camera motion R and t that resection should recover. Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); + R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); Vec3 T_input; T_input.setRandom(); @@ -204,33 +215,36 @@ TEST(EuclideanResection, Points6AllRandomInput) { Mat3 R_expected; Vec3 T_expected; Mat3X X_world; - CreateCameraSystem(KK, x_image, X_distances, R_input, T_input, - &x_camera, &X_world, &R_expected, &T_expected); + CreateCameraSystem(KK, + x_image, + X_distances, + R_input, + T_input, + &x_camera, + &X_world, + &R_expected, + &T_expected); // Test each of the resection methods. { Mat3 R_output; Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_ANSAR_DANIILIDIS); + EuclideanResection( + x_camera, X_world, &R_output, &T_output, RESECTION_ANSAR_DANIILIDIS); EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); } { Mat3 R_output; Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_EPNP); + EuclideanResection(x_camera, X_world, &R_output, &T_output, RESECTION_EPNP); EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); } { Mat3 R_output; Vec3 T_output; - EuclideanResection(x_image, X_world, KK, - &R_output, &T_output); + EuclideanResection(x_image, X_world, KK, &R_output, &T_output); EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); } diff --git a/intern/libmv/libmv/multiview/fundamental.cc b/intern/libmv/libmv/multiview/fundamental.cc index ea8594c8cc0..c8c94ecd7bb 100644 --- a/intern/libmv/libmv/multiview/fundamental.cc +++ b/intern/libmv/libmv/multiview/fundamental.cc @@ -22,15 +22,15 @@ #include "ceres/ceres.h" #include "libmv/logging/logging.h" -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/poly.h" #include "libmv/multiview/conditioning.h" #include "libmv/multiview/projection.h" #include "libmv/multiview/triangulation.h" +#include "libmv/numeric/numeric.h" +#include "libmv/numeric/poly.h" namespace libmv { -static void EliminateRow(const Mat34 &P, int row, Mat *X) { +static void EliminateRow(const Mat34& P, int row, Mat* X) { X->resize(2, 4); int first_row = (row + 1) % 3; @@ -42,7 +42,7 @@ static void EliminateRow(const Mat34 &P, int row, Mat *X) { } } -void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2) { +void ProjectionsFromFundamental(const Mat3& F, Mat34* P1, Mat34* P2) { *P1 << Mat3::Identity(), Vec3::Zero(); Vec3 e2; Mat3 Ft = F.transpose(); @@ -51,7 +51,7 @@ void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2) { } // Addapted from vgg_F_from_P. -void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F) { +void FundamentalFromProjections(const Mat34& P1, const Mat34& P2, Mat3* F) { Mat X[3]; Mat Y[3]; Mat XY; @@ -71,7 +71,7 @@ void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F) { // HZ 11.1 pag.279 (x1 = x, x2 = x') // http://www.cs.unc.edu/~marc/tutorial/node54.html -static double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F) { +static double EightPointSolver(const Mat& x1, const Mat& x2, Mat3* F) { DCHECK_EQ(x1.rows(), 2); DCHECK_GE(x1.cols(), 8); DCHECK_EQ(x1.rows(), x2.rows()); @@ -98,7 +98,7 @@ static double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F) { } // HZ 11.1.1 pag.280 -void EnforceFundamentalRank2Constraint(Mat3 *F) { +void EnforceFundamentalRank2Constraint(Mat3* F) { Eigen::JacobiSVD USV(*F, Eigen::ComputeFullU | Eigen::ComputeFullV); Vec3 d = USV.singularValues(); d(2) = 0.0; @@ -106,9 +106,7 @@ void EnforceFundamentalRank2Constraint(Mat3 *F) { } // HZ 11.2 pag.281 (x1 = x, x2 = x') -double NormalizedEightPointSolver(const Mat &x1, - const Mat &x2, - Mat3 *F) { +double NormalizedEightPointSolver(const Mat& x1, const Mat& x2, Mat3* F) { DCHECK_EQ(x1.rows(), 2); DCHECK_GE(x1.cols(), 8); DCHECK_EQ(x1.rows(), x2.rows()); @@ -135,9 +133,9 @@ double NormalizedEightPointSolver(const Mat &x1, // Seven-point algorithm. // http://www.cs.unc.edu/~marc/tutorial/node55.html -double FundamentalFrom7CorrespondencesLinear(const Mat &x1, - const Mat &x2, - std::vector *F) { +double FundamentalFrom7CorrespondencesLinear(const Mat& x1, + const Mat& x2, + std::vector* F) { DCHECK_EQ(x1.rows(), 2); DCHECK_EQ(x1.cols(), 7); DCHECK_EQ(x1.rows(), x2.rows()); @@ -169,25 +167,29 @@ double FundamentalFrom7CorrespondencesLinear(const Mat &x1, // Then, use the condition det(F) = 0 to determine F. In other words, solve // det(F1 + a*F2) = 0 for a. - double a = F1(0, 0), j = F2(0, 0), - b = F1(0, 1), k = F2(0, 1), - c = F1(0, 2), l = F2(0, 2), - d = F1(1, 0), m = F2(1, 0), - e = F1(1, 1), n = F2(1, 1), - f = F1(1, 2), o = F2(1, 2), - g = F1(2, 0), p = F2(2, 0), - h = F1(2, 1), q = F2(2, 1), - i = F1(2, 2), r = F2(2, 2); + double a = F1(0, 0), j = F2(0, 0); + double b = F1(0, 1), k = F2(0, 1); + double c = F1(0, 2), l = F2(0, 2); + double d = F1(1, 0), m = F2(1, 0); + double e = F1(1, 1), n = F2(1, 1); + double f = F1(1, 2), o = F2(1, 2); + double g = F1(2, 0), p = F2(2, 0); + double h = F1(2, 1), q = F2(2, 1); + double i = F1(2, 2), r = F2(2, 2); // Run fundamental_7point_coeffs.py to get the below coefficients. // The coefficients are in ascending powers of alpha, i.e. P[N]*x^N. double P[4] = { - a*e*i + b*f*g + c*d*h - a*f*h - b*d*i - c*e*g, - a*e*r + a*i*n + b*f*p + b*g*o + c*d*q + c*h*m + d*h*l + e*i*j + f*g*k - - a*f*q - a*h*o - b*d*r - b*i*m - c*e*p - c*g*n - d*i*k - e*g*l - f*h*j, - a*n*r + b*o*p + c*m*q + d*l*q + e*j*r + f*k*p + g*k*o + h*l*m + i*j*n - - a*o*q - b*m*r - c*n*p - d*k*r - e*l*p - f*j*q - g*l*n - h*j*o - i*k*m, - j*n*r + k*o*p + l*m*q - j*o*q - k*m*r - l*n*p, + a * e * i + b * f * g + c * d * h - a * f * h - b * d * i - c * e * g, + a * e * r + a * i * n + b * f * p + b * g * o + c * d * q + c * h * m + + d * h * l + e * i * j + f * g * k - a * f * q - a * h * o - + b * d * r - b * i * m - c * e * p - c * g * n - d * i * k - + e * g * l - f * h * j, + a * n * r + b * o * p + c * m * q + d * l * q + e * j * r + f * k * p + + g * k * o + h * l * m + i * j * n - a * o * q - b * m * r - + c * n * p - d * k * r - e * l * p - f * j * q - g * l * n - + h * j * o - i * k * m, + j * n * r + k * o * p + l * m * q - j * o * q - k * m * r - l * n * p, }; // Solve for the roots of P[3]*x^3 + P[2]*x^2 + P[1]*x + P[0] = 0. @@ -195,15 +197,15 @@ double FundamentalFrom7CorrespondencesLinear(const Mat &x1, int num_roots = SolveCubicPolynomial(P, roots); // Build the fundamental matrix for each solution. - for (int kk = 0; kk < num_roots; ++kk) { + for (int kk = 0; kk < num_roots; ++kk) { F->push_back(F1 + roots[kk] * F2); } return s; } -double FundamentalFromCorrespondences7Point(const Mat &x1, - const Mat &x2, - std::vector *F) { +double FundamentalFromCorrespondences7Point(const Mat& x1, + const Mat& x2, + std::vector* F) { DCHECK_EQ(x1.rows(), 2); DCHECK_GE(x1.cols(), 7); DCHECK_EQ(x1.rows(), x2.rows()); @@ -218,25 +220,25 @@ double FundamentalFromCorrespondences7Point(const Mat &x1, ApplyTransformationToPoints(x2, T2, &x2_normalized); // Estimate the fundamental matrix. - double smaller_singular_value = - FundamentalFrom7CorrespondencesLinear(x1_normalized, x2_normalized, &(*F)); + double smaller_singular_value = FundamentalFrom7CorrespondencesLinear( + x1_normalized, x2_normalized, &(*F)); for (int k = 0; k < F->size(); ++k) { - Mat3 & Fmat = (*F)[k]; + Mat3& Fmat = (*F)[k]; // Denormalize the fundamental matrix. Fmat = T2.transpose() * Fmat * T1; } return smaller_singular_value; } -void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized) { +void NormalizeFundamental(const Mat3& F, Mat3* F_normalized) { *F_normalized = F / FrobeniusNorm(F); if ((*F_normalized)(2, 2) < 0) { *F_normalized *= -1; } } -double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) { +double SampsonDistance(const Mat& F, const Vec2& x1, const Vec2& x2) { Vec3 x(x1(0), x1(1), 1.0); Vec3 y(x2(0), x2(1), 1.0); @@ -244,11 +246,11 @@ double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) { Vec3 Ft_y = F.transpose() * y; double y_F_x = y.dot(F_x); - return Square(y_F_x) / ( F_x.head<2>().squaredNorm() - + Ft_y.head<2>().squaredNorm()); + return Square(y_F_x) / + (F_x.head<2>().squaredNorm() + Ft_y.head<2>().squaredNorm()); } -double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) { +double SymmetricEpipolarDistance(const Mat& F, const Vec2& x1, const Vec2& x2) { Vec3 x(x1(0), x1(1), 1.0); Vec3 y(x2(0), x2(1), 1.0); @@ -256,43 +258,40 @@ double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) { Vec3 Ft_y = F.transpose() * y; double y_F_x = y.dot(F_x); - return Square(y_F_x) * ( 1 / F_x.head<2>().squaredNorm() - + 1 / Ft_y.head<2>().squaredNorm()); + return Square(y_F_x) * + (1 / F_x.head<2>().squaredNorm() + 1 / Ft_y.head<2>().squaredNorm()); } // HZ 9.6 pag 257 (formula 9.12) -void EssentialFromFundamental(const Mat3 &F, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *E) { +void EssentialFromFundamental(const Mat3& F, + const Mat3& K1, + const Mat3& K2, + Mat3* E) { *E = K2.transpose() * F * K1; } // HZ 9.6 pag 257 (formula 9.12) // Or http://ai.stanford.edu/~birch/projective/node20.html -void FundamentalFromEssential(const Mat3 &E, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *F) { +void FundamentalFromEssential(const Mat3& E, + const Mat3& K1, + const Mat3& K2, + Mat3* F) { *F = K2.inverse().transpose() * E * K1.inverse(); } -void RelativeCameraMotion(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *R, - Vec3 *t) { +void RelativeCameraMotion(const Mat3& R1, + const Vec3& t1, + const Mat3& R2, + const Vec3& t2, + Mat3* R, + Vec3* t) { *R = R2 * R1.transpose(); *t = t2 - (*R) * t1; } // HZ 9.6 pag 257 -void EssentialFromRt(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *E) { +void EssentialFromRt( + const Mat3& R1, const Vec3& t1, const Mat3& R2, const Vec3& t2, Mat3* E) { Mat3 R; Vec3 t; RelativeCameraMotion(R1, t1, R2, t2, &R, &t); @@ -301,11 +300,11 @@ void EssentialFromRt(const Mat3 &R1, } // HZ 9.6 pag 259 (Result 9.19) -void MotionFromEssential(const Mat3 &E, - std::vector *Rs, - std::vector *ts) { +void MotionFromEssential(const Mat3& E, + std::vector* Rs, + std::vector* ts) { Eigen::JacobiSVD USV(E, Eigen::ComputeFullU | Eigen::ComputeFullV); - Mat3 U = USV.matrixU(); + Mat3 U = USV.matrixU(); Mat3 Vt = USV.matrixV().transpose(); // Last column of U is undetermined since d = (a a 0). @@ -318,9 +317,11 @@ void MotionFromEssential(const Mat3 &E, } Mat3 W; + // clang-format off W << 0, -1, 0, 1, 0, 0, 0, 0, 1; + // clang-format on Mat3 U_W_Vt = U * W * Vt; Mat3 U_Wt_Vt = U * W.transpose() * Vt; @@ -332,18 +333,18 @@ void MotionFromEssential(const Mat3 &E, (*Rs)[3] = U_Wt_Vt; ts->resize(4); - (*ts)[0] = U.col(2); + (*ts)[0] = U.col(2); (*ts)[1] = -U.col(2); - (*ts)[2] = U.col(2); + (*ts)[2] = U.col(2); (*ts)[3] = -U.col(2); } -int MotionFromEssentialChooseSolution(const std::vector &Rs, - const std::vector &ts, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2) { +int MotionFromEssentialChooseSolution(const std::vector& Rs, + const std::vector& ts, + const Mat3& K1, + const Vec2& x1, + const Mat3& K2, + const Vec2& x2) { DCHECK_EQ(4, Rs.size()); DCHECK_EQ(4, ts.size()); @@ -354,8 +355,8 @@ int MotionFromEssentialChooseSolution(const std::vector &Rs, t1.setZero(); P_From_KRt(K1, R1, t1, &P1); for (int i = 0; i < 4; ++i) { - const Mat3 &R2 = Rs[i]; - const Vec3 &t2 = ts[i]; + const Mat3& R2 = Rs[i]; + const Vec3& t2 = ts[i]; P_From_KRt(K2, R2, t2, &P2); Vec3 X; TriangulateDLT(P1, x1, P2, x2, &X); @@ -369,13 +370,13 @@ int MotionFromEssentialChooseSolution(const std::vector &Rs, return -1; } -bool MotionFromEssentialAndCorrespondence(const Mat3 &E, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2, - Mat3 *R, - Vec3 *t) { +bool MotionFromEssentialAndCorrespondence(const Mat3& E, + const Mat3& K1, + const Vec2& x1, + const Mat3& K2, + const Vec2& x2, + Mat3* R, + Vec3* t) { std::vector Rs; std::vector ts; MotionFromEssential(E, &Rs, &ts); @@ -389,7 +390,7 @@ bool MotionFromEssentialAndCorrespondence(const Mat3 &E, } } -void FundamentalToEssential(const Mat3 &F, Mat3 *E) { +void FundamentalToEssential(const Mat3& F, Mat3* E) { Eigen::JacobiSVD svd(F, Eigen::ComputeFullU | Eigen::ComputeFullV); // See Hartley & Zisserman page 294, result 11.1, which shows how to get the @@ -399,8 +400,8 @@ void FundamentalToEssential(const Mat3 &F, Mat3 *E) { double s = (a + b) / 2.0; LG << "Initial reconstruction's rotation is non-euclidean by " - << (((a - b) / std::max(a, b)) * 100) << "%; singular values:" - << svd.singularValues().transpose(); + << (((a - b) / std::max(a, b)) * 100) + << "%; singular values:" << svd.singularValues().transpose(); Vec3 diag; diag << s, s, 0; @@ -410,9 +411,8 @@ void FundamentalToEssential(const Mat3 &F, Mat3 *E) { // Default settings for fundamental estimation which should be suitable // for a wide range of use cases. -EstimateFundamentalOptions::EstimateFundamentalOptions(void) : - max_num_iterations(50), - expected_average_symmetric_distance(1e-16) { +EstimateFundamentalOptions::EstimateFundamentalOptions(void) + : max_num_iterations(50), expected_average_symmetric_distance(1e-16) { } namespace { @@ -420,12 +420,11 @@ namespace { // used for fundamental matrix refinement. class FundamentalSymmetricEpipolarCostFunctor { public: - FundamentalSymmetricEpipolarCostFunctor(const Vec2 &x, - const Vec2 &y) - : x_(x), y_(y) {} + FundamentalSymmetricEpipolarCostFunctor(const Vec2& x, const Vec2& y) + : x_(x), y_(y) {} - template - bool operator()(const T *fundamental_parameters, T *residuals) const { + template + bool operator()(const T* fundamental_parameters, T* residuals) const { typedef Eigen::Matrix Mat3; typedef Eigen::Matrix Vec3; @@ -454,9 +453,10 @@ class FundamentalSymmetricEpipolarCostFunctor { // average value. class TerminationCheckingCallback : public ceres::IterationCallback { public: - TerminationCheckingCallback(const Mat &x1, const Mat &x2, - const EstimateFundamentalOptions &options, - Mat3 *F) + TerminationCheckingCallback(const Mat& x1, + const Mat& x2, + const EstimateFundamentalOptions& options, + Mat3* F) : options_(options), x1_(x1), x2_(x2), F_(F) {} virtual ceres::CallbackReturnType operator()( @@ -469,9 +469,7 @@ class TerminationCheckingCallback : public ceres::IterationCallback { // Calculate average of symmetric epipolar distance. double average_distance = 0.0; for (int i = 0; i < x1_.cols(); i++) { - average_distance = SymmetricEpipolarDistance(*F_, - x1_.col(i), - x2_.col(i)); + average_distance = SymmetricEpipolarDistance(*F_, x1_.col(i), x2_.col(i)); } average_distance /= x1_.cols(); @@ -483,19 +481,19 @@ class TerminationCheckingCallback : public ceres::IterationCallback { } private: - const EstimateFundamentalOptions &options_; - const Mat &x1_; - const Mat &x2_; - Mat3 *F_; + const EstimateFundamentalOptions& options_; + const Mat& x1_; + const Mat& x2_; + Mat3* F_; }; } // namespace /* Fundamental transformation estimation. */ bool EstimateFundamentalFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateFundamentalOptions &options, - Mat3 *F) { + const Mat& x1, + const Mat& x2, + const EstimateFundamentalOptions& options, + Mat3* F) { // Step 1: Algebraic fundamental estimation. // Assume algebraic estiation always succeeds, @@ -506,16 +504,15 @@ bool EstimateFundamentalFromCorrespondences( // Step 2: Refine matrix using Ceres minimizer. ceres::Problem problem; for (int i = 0; i < x1.cols(); i++) { - FundamentalSymmetricEpipolarCostFunctor - *fundamental_symmetric_epipolar_cost_function = - new FundamentalSymmetricEpipolarCostFunctor(x1.col(i), - x2.col(i)); + FundamentalSymmetricEpipolarCostFunctor* + fundamental_symmetric_epipolar_cost_function = + new FundamentalSymmetricEpipolarCostFunctor(x1.col(i), x2.col(i)); problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - FundamentalSymmetricEpipolarCostFunctor, - 2, // num_residuals - 9>(fundamental_symmetric_epipolar_cost_function), + new ceres::AutoDiffCostFunction( + fundamental_symmetric_epipolar_cost_function), NULL, F->data()); } diff --git a/intern/libmv/libmv/multiview/fundamental.h b/intern/libmv/libmv/multiview/fundamental.h index a6c7a6802fe..6d25691c4a3 100644 --- a/intern/libmv/libmv/multiview/fundamental.h +++ b/intern/libmv/libmv/multiview/fundamental.h @@ -27,36 +27,34 @@ namespace libmv { -void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2); -void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F); +void ProjectionsFromFundamental(const Mat3& F, Mat34* P1, Mat34* P2); +void FundamentalFromProjections(const Mat34& P1, const Mat34& P2, Mat3* F); /** * 7 points (minimal case, points coordinates must be normalized before): */ -double FundamentalFrom7CorrespondencesLinear(const Mat &x1, - const Mat &x2, - std::vector *F); +double FundamentalFrom7CorrespondencesLinear(const Mat& x1, + const Mat& x2, + std::vector* F); /** * 7 points (points coordinates must be in image space): */ -double FundamentalFromCorrespondences7Point(const Mat &x1, - const Mat &x2, - std::vector *F); +double FundamentalFromCorrespondences7Point(const Mat& x1, + const Mat& x2, + std::vector* F); /** * 8 points (points coordinates must be in image space): */ -double NormalizedEightPointSolver(const Mat &x1, - const Mat &x2, - Mat3 *F); +double NormalizedEightPointSolver(const Mat& x1, const Mat& x2, Mat3* F); /** * Fundamental matrix utility function: */ -void EnforceFundamentalRank2Constraint(Mat3 *F); +void EnforceFundamentalRank2Constraint(Mat3* F); -void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized); +void NormalizeFundamental(const Mat3& F, Mat3* F_normalized); /** * Approximate squared reprojection errror. @@ -64,14 +62,14 @@ void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized); * See page 287 of HZ equation 11.9. This avoids triangulating the point, * relying only on the entries in F. */ -double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2); +double SampsonDistance(const Mat& F, const Vec2& x1, const Vec2& x2); /** * Calculates the sum of the distances from the points to the epipolar lines. * * See page 288 of HZ equation 11.10. */ -double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2); +double SymmetricEpipolarDistance(const Mat& F, const Vec2& x1, const Vec2& x2); /** * Compute the relative camera motion between two cameras. @@ -81,32 +79,29 @@ double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2); * If T1 and T2 are the camera motions, the computed relative motion is * T = T2 T1^{-1} */ -void RelativeCameraMotion(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *R, - Vec3 *t); - -void EssentialFromFundamental(const Mat3 &F, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *E); - -void FundamentalFromEssential(const Mat3 &E, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *F); - -void EssentialFromRt(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *E); - -void MotionFromEssential(const Mat3 &E, - std::vector *Rs, - std::vector *ts); +void RelativeCameraMotion(const Mat3& R1, + const Vec3& t1, + const Mat3& R2, + const Vec3& t2, + Mat3* R, + Vec3* t); + +void EssentialFromFundamental(const Mat3& F, + const Mat3& K1, + const Mat3& K2, + Mat3* E); + +void FundamentalFromEssential(const Mat3& E, + const Mat3& K1, + const Mat3& K2, + Mat3* F); + +void EssentialFromRt( + const Mat3& R1, const Vec3& t1, const Mat3& R2, const Vec3& t2, Mat3* E); + +void MotionFromEssential(const Mat3& E, + std::vector* Rs, + std::vector* ts); /** * Choose one of the four possible motion solutions from an essential matrix. @@ -117,25 +112,25 @@ void MotionFromEssential(const Mat3 &E, * * \return index of the right solution or -1 if no solution. */ -int MotionFromEssentialChooseSolution(const std::vector &Rs, - const std::vector &ts, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2); - -bool MotionFromEssentialAndCorrespondence(const Mat3 &E, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2, - Mat3 *R, - Vec3 *t); +int MotionFromEssentialChooseSolution(const std::vector& Rs, + const std::vector& ts, + const Mat3& K1, + const Vec2& x1, + const Mat3& K2, + const Vec2& x2); + +bool MotionFromEssentialAndCorrespondence(const Mat3& E, + const Mat3& K1, + const Vec2& x1, + const Mat3& K2, + const Vec2& x2, + Mat3* R, + Vec3* t); /** * Find closest essential matrix E to fundamental F */ -void FundamentalToEssential(const Mat3 &F, Mat3 *E); +void FundamentalToEssential(const Mat3& F, Mat3* E); /** * This structure contains options that controls how the fundamental @@ -170,10 +165,10 @@ struct EstimateFundamentalOptions { * refinement. */ bool EstimateFundamentalFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateFundamentalOptions &options, - Mat3 *F); + const Mat& x1, + const Mat& x2, + const EstimateFundamentalOptions& options, + Mat3* F); } // namespace libmv diff --git a/intern/libmv/libmv/multiview/fundamental_test.cc b/intern/libmv/libmv/multiview/fundamental_test.cc index da0eb449b8f..0ec91ca8d19 100644 --- a/intern/libmv/libmv/multiview/fundamental_test.cc +++ b/intern/libmv/libmv/multiview/fundamental_test.cc @@ -34,12 +34,14 @@ using namespace libmv; TEST(Fundamental, FundamentalFromProjections) { Mat34 P1_gt, P2_gt; + // clang-format off P1_gt << 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0; P2_gt << 1, 1, 1, 3, 0, 2, 0, 3, 0, 1, 1, 0; + // clang-format on Mat3 F_gt; FundamentalFromProjections(P1_gt, P2_gt, &F_gt); @@ -55,8 +57,10 @@ TEST(Fundamental, FundamentalFromProjections) { TEST(Fundamental, PreconditionerFromPoints) { int n = 4; Mat points(2, n); + // clang-format off points << 0, 0, 1, 1, 0, 2, 1, 3; + // clang-format on Mat3 T; PreconditionerFromPoints(points, &T); @@ -152,8 +156,8 @@ TEST(Fundamental, MotionFromEssentialAndCorrespondence) { Mat3 R_estimated; Vec3 t_estimated; - MotionFromEssentialAndCorrespondence(E, d.K1, x1, d.K2, x2, - &R_estimated, &t_estimated); + MotionFromEssentialAndCorrespondence( + E, d.K1, x1, d.K2, x2, &R_estimated, &t_estimated); EXPECT_LE(FrobeniusDistance(R_estimated, R), 1e-8); EXPECT_LE(DistanceL2(t_estimated, t), 1e-8); diff --git a/intern/libmv/libmv/multiview/homography.cc b/intern/libmv/libmv/multiview/homography.cc index 69177743f94..2db2c0cd3d5 100644 --- a/intern/libmv/libmv/multiview/homography.cc +++ b/intern/libmv/libmv/multiview/homography.cc @@ -26,7 +26,7 @@ #include "libmv/multiview/homography_parameterization.h" namespace libmv { -/** 2D Homography transformation estimation in the case that points are in +/** 2D Homography transformation estimation in the case that points are in * euclidean coordinates. * * x = H y @@ -44,10 +44,7 @@ namespace libmv { * (-x2*a+x1*d)*y1 + (-x2*b+x1*e)*y2 + -x2*c+x1*f |0| */ static bool Homography2DFromCorrespondencesLinearEuc( - const Mat &x1, - const Mat &x2, - Mat3 *H, - double expected_precision) { + const Mat& x1, const Mat& x2, Mat3* H, double expected_precision) { assert(2 == x1.rows()); assert(4 <= x1.cols()); assert(x1.rows() == x2.rows()); @@ -58,27 +55,27 @@ static bool Homography2DFromCorrespondencesLinearEuc( Mat b = Mat::Zero(n * 3, 1); for (int i = 0; i < n; ++i) { int j = 3 * i; - L(j, 0) = x1(0, i); // a - L(j, 1) = x1(1, i); // b - L(j, 2) = 1.0; // c + L(j, 0) = x1(0, i); // a + L(j, 1) = x1(1, i); // b + L(j, 2) = 1.0; // c L(j, 6) = -x2(0, i) * x1(0, i); // g L(j, 7) = -x2(0, i) * x1(1, i); // h - b(j, 0) = x2(0, i); // i + b(j, 0) = x2(0, i); // i ++j; - L(j, 3) = x1(0, i); // d - L(j, 4) = x1(1, i); // e - L(j, 5) = 1.0; // f + L(j, 3) = x1(0, i); // d + L(j, 4) = x1(1, i); // e + L(j, 5) = 1.0; // f L(j, 6) = -x2(1, i) * x1(0, i); // g L(j, 7) = -x2(1, i) * x1(1, i); // h - b(j, 0) = x2(1, i); // i + b(j, 0) = x2(1, i); // i // This ensures better stability // TODO(julien) make a lite version without this 3rd set ++j; - L(j, 0) = x2(1, i) * x1(0, i); // a - L(j, 1) = x2(1, i) * x1(1, i); // b - L(j, 2) = x2(1, i); // c + L(j, 0) = x2(1, i) * x1(0, i); // a + L(j, 1) = x2(1, i) * x1(1, i); // b + L(j, 2) = x2(1, i); // c L(j, 3) = -x2(0, i) * x1(0, i); // d L(j, 4) = -x2(0, i) * x1(1, i); // e L(j, 5) = -x2(0, i); // f @@ -86,14 +83,15 @@ static bool Homography2DFromCorrespondencesLinearEuc( // Solve Lx=B Vec h = L.fullPivLu().solve(b); Homography2DNormalizedParameterization::To(h, H); - if ((L * h).isApprox(b, expected_precision)) { + if ((L * h).isApprox(b, expected_precision)) { return true; } else { return false; } } -/** 2D Homography transformation estimation in the case that points are in +// clang-format off +/** 2D Homography transformation estimation in the case that points are in * homogeneous coordinates. * * | 0 -x3 x2| |a b c| |y1| -x3*d+x2*g -x3*e+x2*h -x3*f+x2*1 |y1| (-x3*d+x2*g)*y1 (-x3*e+x2*h)*y2 (-x3*f+x2*1)*y3 |0| @@ -101,13 +99,14 @@ static bool Homography2DFromCorrespondencesLinearEuc( * |-x2 x1 0| |g h 1| |y3| -x2*a+x1*d -x2*b+x1*e -x2*c+x1*f |y3| (-x2*a+x1*d)*y1 (-x2*b+x1*e)*y2 (-x2*c+x1*f)*y3 |0| * X = |a b c d e f g h|^t */ -bool Homography2DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat3 *H, +// clang-format on +bool Homography2DFromCorrespondencesLinear(const Mat& x1, + const Mat& x2, + Mat3* H, double expected_precision) { if (x1.rows() == 2) { - return Homography2DFromCorrespondencesLinearEuc(x1, x2, H, - expected_precision); + return Homography2DFromCorrespondencesLinearEuc( + x1, x2, H, expected_precision); } assert(3 == x1.rows()); assert(4 <= x1.cols()); @@ -122,33 +121,33 @@ bool Homography2DFromCorrespondencesLinear(const Mat &x1, Mat b = Mat::Zero(n * 3, 1); for (int i = 0; i < n; ++i) { int j = 3 * i; - L(j, 0) = x2(w, i) * x1(x, i); // a - L(j, 1) = x2(w, i) * x1(y, i); // b - L(j, 2) = x2(w, i) * x1(w, i); // c + L(j, 0) = x2(w, i) * x1(x, i); // a + L(j, 1) = x2(w, i) * x1(y, i); // b + L(j, 2) = x2(w, i) * x1(w, i); // c L(j, 6) = -x2(x, i) * x1(x, i); // g L(j, 7) = -x2(x, i) * x1(y, i); // h - b(j, 0) = x2(x, i) * x1(w, i); + b(j, 0) = x2(x, i) * x1(w, i); ++j; - L(j, 3) = x2(w, i) * x1(x, i); // d - L(j, 4) = x2(w, i) * x1(y, i); // e - L(j, 5) = x2(w, i) * x1(w, i); // f + L(j, 3) = x2(w, i) * x1(x, i); // d + L(j, 4) = x2(w, i) * x1(y, i); // e + L(j, 5) = x2(w, i) * x1(w, i); // f L(j, 6) = -x2(y, i) * x1(x, i); // g L(j, 7) = -x2(y, i) * x1(y, i); // h - b(j, 0) = x2(y, i) * x1(w, i); + b(j, 0) = x2(y, i) * x1(w, i); // This ensures better stability ++j; - L(j, 0) = x2(y, i) * x1(x, i); // a - L(j, 1) = x2(y, i) * x1(y, i); // b - L(j, 2) = x2(y, i) * x1(w, i); // c + L(j, 0) = x2(y, i) * x1(x, i); // a + L(j, 1) = x2(y, i) * x1(y, i); // b + L(j, 2) = x2(y, i) * x1(w, i); // c L(j, 3) = -x2(x, i) * x1(x, i); // d L(j, 4) = -x2(x, i) * x1(y, i); // e L(j, 5) = -x2(x, i) * x1(w, i); // f } // Solve Lx=B Vec h = L.fullPivLu().solve(b); - if ((L * h).isApprox(b, expected_precision)) { + if ((L * h).isApprox(b, expected_precision)) { Homography2DNormalizedParameterization::To(h, H); return true; } else { @@ -158,32 +157,30 @@ bool Homography2DFromCorrespondencesLinear(const Mat &x1, // Default settings for homography estimation which should be suitable // for a wide range of use cases. -EstimateHomographyOptions::EstimateHomographyOptions(void) : - use_normalization(true), - max_num_iterations(50), - expected_average_symmetric_distance(1e-16) { +EstimateHomographyOptions::EstimateHomographyOptions(void) + : use_normalization(true), + max_num_iterations(50), + expected_average_symmetric_distance(1e-16) { } namespace { -void GetNormalizedPoints(const Mat &original_points, - Mat *normalized_points, - Mat3 *normalization_matrix) { +void GetNormalizedPoints(const Mat& original_points, + Mat* normalized_points, + Mat3* normalization_matrix) { IsotropicPreconditionerFromPoints(original_points, normalization_matrix); - ApplyTransformationToPoints(original_points, - *normalization_matrix, - normalized_points); + ApplyTransformationToPoints( + original_points, *normalization_matrix, normalized_points); } // Cost functor which computes symmetric geometric distance // used for homography matrix refinement. class HomographySymmetricGeometricCostFunctor { public: - HomographySymmetricGeometricCostFunctor(const Vec2 &x, - const Vec2 &y) - : x_(x), y_(y) { } + HomographySymmetricGeometricCostFunctor(const Vec2& x, const Vec2& y) + : x_(x), y_(y) {} - template - bool operator()(const T *homography_parameters, T *residuals) const { + template + bool operator()(const T* homography_parameters, T* residuals) const { typedef Eigen::Matrix Mat3; typedef Eigen::Matrix Vec3; @@ -221,9 +218,10 @@ class HomographySymmetricGeometricCostFunctor { // average value. class TerminationCheckingCallback : public ceres::IterationCallback { public: - TerminationCheckingCallback(const Mat &x1, const Mat &x2, - const EstimateHomographyOptions &options, - Mat3 *H) + TerminationCheckingCallback(const Mat& x1, + const Mat& x2, + const EstimateHomographyOptions& options, + Mat3* H) : options_(options), x1_(x1), x2_(x2), H_(H) {} virtual ceres::CallbackReturnType operator()( @@ -236,9 +234,8 @@ class TerminationCheckingCallback : public ceres::IterationCallback { // Calculate average of symmetric geometric distance. double average_distance = 0.0; for (int i = 0; i < x1_.cols(); i++) { - average_distance = SymmetricGeometricDistance(*H_, - x1_.col(i), - x2_.col(i)); + average_distance = + SymmetricGeometricDistance(*H_, x1_.col(i), x2_.col(i)); } average_distance /= x1_.cols(); @@ -250,10 +247,10 @@ class TerminationCheckingCallback : public ceres::IterationCallback { } private: - const EstimateHomographyOptions &options_; - const Mat &x1_; - const Mat &x2_; - Mat3 *H_; + const EstimateHomographyOptions& options_; + const Mat& x1_; + const Mat& x2_; + Mat3* H_; }; } // namespace @@ -261,10 +258,10 @@ class TerminationCheckingCallback : public ceres::IterationCallback { * euclidean coordinates. */ bool EstimateHomography2DFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateHomographyOptions &options, - Mat3 *H) { + const Mat& x1, + const Mat& x2, + const EstimateHomographyOptions& options, + Mat3* H) { // TODO(sergey): Support homogenous coordinates, not just euclidean. assert(2 == x1.rows()); @@ -272,8 +269,7 @@ bool EstimateHomography2DFromCorrespondences( assert(x1.rows() == x2.rows()); assert(x1.cols() == x2.cols()); - Mat3 T1 = Mat3::Identity(), - T2 = Mat3::Identity(); + Mat3 T1 = Mat3::Identity(), T2 = Mat3::Identity(); // Step 1: Algebraic homography estimation. Mat x1_normalized, x2_normalized; @@ -300,16 +296,15 @@ bool EstimateHomography2DFromCorrespondences( // Step 2: Refine matrix using Ceres minimizer. ceres::Problem problem; for (int i = 0; i < x1.cols(); i++) { - HomographySymmetricGeometricCostFunctor - *homography_symmetric_geometric_cost_function = - new HomographySymmetricGeometricCostFunctor(x1.col(i), - x2.col(i)); + HomographySymmetricGeometricCostFunctor* + homography_symmetric_geometric_cost_function = + new HomographySymmetricGeometricCostFunctor(x1.col(i), x2.col(i)); problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - HomographySymmetricGeometricCostFunctor, - 4, // num_residuals - 9>(homography_symmetric_geometric_cost_function), + new ceres::AutoDiffCostFunction( + homography_symmetric_geometric_cost_function), NULL, H->data()); } @@ -335,15 +330,16 @@ bool EstimateHomography2DFromCorrespondences( return summary.IsSolutionUsable(); } +// clang-format off /** * x2 ~ A * x1 * x2^t * Hi * A *x1 = 0 - * H1 = H2 = H3 = + * H1 = H2 = H3 = * | 0 0 0 1| |-x2w| |0 0 0 0| | 0 | | 0 0 1 0| |-x2z| * | 0 0 0 0| -> | 0 | |0 0 1 0| -> |-x2z| | 0 0 0 0| -> | 0 | * | 0 0 0 0| | 0 | |0-1 0 0| | x2y| |-1 0 0 0| | x2x| * |-1 0 0 0| | x2x| |0 0 0 0| | 0 | | 0 0 0 0| | 0 | - * H4 = H5 = H6 = + * H4 = H5 = H6 = * |0 0 0 0| | 0 | | 0 1 0 0| |-x2y| |0 0 0 0| | 0 | * |0 0 0 1| -> |-x2w| |-1 0 0 0| -> | x2x| |0 0 0 0| -> | 0 | * |0 0 0 0| | 0 | | 0 0 0 0| | 0 | |0 0 0 1| |-x2w| @@ -361,10 +357,11 @@ bool EstimateHomography2DFromCorrespondences( * x2^t * H6 * A *x1 = (-x2w*i +x2z*m )*x1x + (-x2w*j +x2z*n )*x1y + (-x2w*k +x2z*o )*x1z + (-x2w*l +x2z*1 )*x1w = 0 * * X = |a b c d e f g h i j k l m n o|^t -*/ -bool Homography3DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat4 *H, + */ +// clang-format on +bool Homography3DFromCorrespondencesLinear(const Mat& x1, + const Mat& x2, + Mat4* H, double expected_precision) { assert(4 == x1.rows()); assert(5 <= x1.cols()); @@ -379,68 +376,68 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1, Mat b = Mat::Zero(n * 6, 1); for (int i = 0; i < n; ++i) { int j = 6 * i; - L(j, 0) = -x2(w, i) * x1(x, i); // a - L(j, 1) = -x2(w, i) * x1(y, i); // b - L(j, 2) = -x2(w, i) * x1(z, i); // c - L(j, 3) = -x2(w, i) * x1(w, i); // d - L(j, 12) = x2(x, i) * x1(x, i); // m - L(j, 13) = x2(x, i) * x1(y, i); // n - L(j, 14) = x2(x, i) * x1(z, i); // o - b(j, 0) = -x2(x, i) * x1(w, i); + L(j, 0) = -x2(w, i) * x1(x, i); // a + L(j, 1) = -x2(w, i) * x1(y, i); // b + L(j, 2) = -x2(w, i) * x1(z, i); // c + L(j, 3) = -x2(w, i) * x1(w, i); // d + L(j, 12) = x2(x, i) * x1(x, i); // m + L(j, 13) = x2(x, i) * x1(y, i); // n + L(j, 14) = x2(x, i) * x1(z, i); // o + b(j, 0) = -x2(x, i) * x1(w, i); ++j; - L(j, 4) = -x2(z, i) * x1(x, i); // e - L(j, 5) = -x2(z, i) * x1(y, i); // f - L(j, 6) = -x2(z, i) * x1(z, i); // g - L(j, 7) = -x2(z, i) * x1(w, i); // h - L(j, 8) = x2(y, i) * x1(x, i); // i - L(j, 9) = x2(y, i) * x1(y, i); // j - L(j, 10) = x2(y, i) * x1(z, i); // k - L(j, 11) = x2(y, i) * x1(w, i); // l + L(j, 4) = -x2(z, i) * x1(x, i); // e + L(j, 5) = -x2(z, i) * x1(y, i); // f + L(j, 6) = -x2(z, i) * x1(z, i); // g + L(j, 7) = -x2(z, i) * x1(w, i); // h + L(j, 8) = x2(y, i) * x1(x, i); // i + L(j, 9) = x2(y, i) * x1(y, i); // j + L(j, 10) = x2(y, i) * x1(z, i); // k + L(j, 11) = x2(y, i) * x1(w, i); // l ++j; - L(j, 0) = -x2(z, i) * x1(x, i); // a - L(j, 1) = -x2(z, i) * x1(y, i); // b - L(j, 2) = -x2(z, i) * x1(z, i); // c - L(j, 3) = -x2(z, i) * x1(w, i); // d - L(j, 8) = x2(x, i) * x1(x, i); // i - L(j, 9) = x2(x, i) * x1(y, i); // j - L(j, 10) = x2(x, i) * x1(z, i); // k - L(j, 11) = x2(x, i) * x1(w, i); // l + L(j, 0) = -x2(z, i) * x1(x, i); // a + L(j, 1) = -x2(z, i) * x1(y, i); // b + L(j, 2) = -x2(z, i) * x1(z, i); // c + L(j, 3) = -x2(z, i) * x1(w, i); // d + L(j, 8) = x2(x, i) * x1(x, i); // i + L(j, 9) = x2(x, i) * x1(y, i); // j + L(j, 10) = x2(x, i) * x1(z, i); // k + L(j, 11) = x2(x, i) * x1(w, i); // l ++j; - L(j, 4) = -x2(w, i) * x1(x, i); // e - L(j, 5) = -x2(w, i) * x1(y, i); // f - L(j, 6) = -x2(w, i) * x1(z, i); // g - L(j, 7) = -x2(w, i) * x1(w, i); // h - L(j, 12) = x2(y, i) * x1(x, i); // m - L(j, 13) = x2(y, i) * x1(y, i); // n - L(j, 14) = x2(y, i) * x1(z, i); // o - b(j, 0) = -x2(y, i) * x1(w, i); + L(j, 4) = -x2(w, i) * x1(x, i); // e + L(j, 5) = -x2(w, i) * x1(y, i); // f + L(j, 6) = -x2(w, i) * x1(z, i); // g + L(j, 7) = -x2(w, i) * x1(w, i); // h + L(j, 12) = x2(y, i) * x1(x, i); // m + L(j, 13) = x2(y, i) * x1(y, i); // n + L(j, 14) = x2(y, i) * x1(z, i); // o + b(j, 0) = -x2(y, i) * x1(w, i); ++j; L(j, 0) = -x2(y, i) * x1(x, i); // a L(j, 1) = -x2(y, i) * x1(y, i); // b L(j, 2) = -x2(y, i) * x1(z, i); // c L(j, 3) = -x2(y, i) * x1(w, i); // d - L(j, 4) = x2(x, i) * x1(x, i); // e - L(j, 5) = x2(x, i) * x1(y, i); // f - L(j, 6) = x2(x, i) * x1(z, i); // g - L(j, 7) = x2(x, i) * x1(w, i); // h + L(j, 4) = x2(x, i) * x1(x, i); // e + L(j, 5) = x2(x, i) * x1(y, i); // f + L(j, 6) = x2(x, i) * x1(z, i); // g + L(j, 7) = x2(x, i) * x1(w, i); // h ++j; - L(j, 8) = -x2(w, i) * x1(x, i); // i - L(j, 9) = -x2(w, i) * x1(y, i); // j + L(j, 8) = -x2(w, i) * x1(x, i); // i + L(j, 9) = -x2(w, i) * x1(y, i); // j L(j, 10) = -x2(w, i) * x1(z, i); // k L(j, 11) = -x2(w, i) * x1(w, i); // l - L(j, 12) = x2(z, i) * x1(x, i); // m - L(j, 13) = x2(z, i) * x1(y, i); // n - L(j, 14) = x2(z, i) * x1(z, i); // o - b(j, 0) = -x2(z, i) * x1(w, i); + L(j, 12) = x2(z, i) * x1(x, i); // m + L(j, 13) = x2(z, i) * x1(y, i); // n + L(j, 14) = x2(z, i) * x1(z, i); // o + b(j, 0) = -x2(z, i) * x1(w, i); } // Solve Lx=B Vec h = L.fullPivLu().solve(b); - if ((L * h).isApprox(b, expected_precision)) { + if ((L * h).isApprox(b, expected_precision)) { Homography3DNormalizedParameterization::To(h, H); return true; } else { @@ -448,9 +445,9 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1, } } -double SymmetricGeometricDistance(const Mat3 &H, - const Vec2 &x1, - const Vec2 &x2) { +double SymmetricGeometricDistance(const Mat3& H, + const Vec2& x1, + const Vec2& x2) { Vec3 x(x1(0), x1(1), 1.0); Vec3 y(x2(0), x2(1), 1.0); diff --git a/intern/libmv/libmv/multiview/homography.h b/intern/libmv/libmv/multiview/homography.h index a76aa9405a5..0742c6f7c70 100644 --- a/intern/libmv/libmv/multiview/homography.h +++ b/intern/libmv/libmv/multiview/homography.h @@ -49,11 +49,11 @@ namespace libmv { * \return True if the transformation estimation has succeeded. * \note There must be at least 4 non-colinear points. */ -bool Homography2DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat3 *H, - double expected_precision = - EigenDouble::dummy_precision()); +bool Homography2DFromCorrespondencesLinear( + const Mat& x1, + const Mat& x2, + Mat3* H, + double expected_precision = EigenDouble::dummy_precision()); /** * This structure contains options that controls how the homography @@ -101,10 +101,10 @@ struct EstimateHomographyOptions { * refinement. */ bool EstimateHomography2DFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateHomographyOptions &options, - Mat3 *H); + const Mat& x1, + const Mat& x2, + const EstimateHomographyOptions& options, + Mat3* H); /** * 3D Homography transformation estimation. @@ -129,20 +129,20 @@ bool EstimateHomography2DFromCorrespondences( * \note Need at least 5 non coplanar points * \note Points coordinates must be in homogeneous coordinates */ -bool Homography3DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat4 *H, - double expected_precision = - EigenDouble::dummy_precision()); +bool Homography3DFromCorrespondencesLinear( + const Mat& x1, + const Mat& x2, + Mat4* H, + double expected_precision = EigenDouble::dummy_precision()); /** * Calculate symmetric geometric cost: * * D(H * x1, x2)^2 + D(H^-1 * x2, x1) */ -double SymmetricGeometricDistance(const Mat3 &H, - const Vec2 &x1, - const Vec2 &x2); +double SymmetricGeometricDistance(const Mat3& H, + const Vec2& x1, + const Vec2& x2); } // namespace libmv diff --git a/intern/libmv/libmv/multiview/homography_error.h b/intern/libmv/libmv/multiview/homography_error.h index f8b9d45e73c..786ca245ea6 100644 --- a/intern/libmv/libmv/multiview/homography_error.h +++ b/intern/libmv/libmv/multiview/homography_error.h @@ -27,18 +27,18 @@ namespace libmv { namespace homography { namespace homography2D { - /** - * Structure for estimating the asymmetric error between a vector x2 and the - * transformed x1 such that - * Error = ||x2 - Psi(H * x1)||^2 - * where Psi is the function that transforms homogeneous to euclidean coords. - * \note It should be distributed as Chi-squared with k = 2. - */ +/** + * Structure for estimating the asymmetric error between a vector x2 and the + * transformed x1 such that + * Error = ||x2 - Psi(H * x1)||^2 + * where Psi is the function that transforms homogeneous to euclidean coords. + * \note It should be distributed as Chi-squared with k = 2. + */ struct AsymmetricError { /** - * Computes the asymmetric residuals between a set of 2D points x2 and the + * Computes the asymmetric residuals between a set of 2D points x2 and the * transformed 2D point set x1 such that - * Residuals_i = x2_i - Psi(H * x1_i) + * Residuals_i = x2_i - Psi(H * x1_i) * where Psi is the function that transforms homogeneous to euclidean coords. * * \param[in] H The 3x3 homography matrix. @@ -47,8 +47,7 @@ struct AsymmetricError { * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). * \param[out] dx A 2xN matrix of column vectors of residuals errors */ - static void Residuals(const Mat &H, const Mat &x1, - const Mat &x2, Mat2X *dx) { + static void Residuals(const Mat& H, const Mat& x1, const Mat& x2, Mat2X* dx) { dx->resize(2, x1.cols()); Mat3X x2h_est; if (x1.rows() == 2) @@ -63,19 +62,18 @@ struct AsymmetricError { *dx = HomogeneousToEuclidean(static_cast(x2)) - *dx; } /** - * Computes the asymmetric residuals between a 2D point x2 and the transformed + * Computes the asymmetric residuals between a 2D point x2 and the transformed * 2D point x1 such that - * Residuals = x2 - Psi(H * x1) + * Residuals = x2 - Psi(H * x1) * where Psi is the function that transforms homogeneous to euclidean coords. * * \param[in] H The 3x3 homography matrix. * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) * \param[out] dx A vector of size 2 of the residual error */ - static void Residuals(const Mat &H, const Vec &x1, - const Vec &x2, Vec2 *dx) { + static void Residuals(const Mat& H, const Vec& x1, const Vec& x2, Vec2* dx) { Vec3 x2h_est; if (x1.rows() == 2) x2h_est = H * EuclideanToHomogeneous(static_cast(x1)); @@ -85,10 +83,10 @@ struct AsymmetricError { *dx = x2 - x2h_est.head<2>() / x2h_est[2]; else *dx = HomogeneousToEuclidean(static_cast(x2)) - - x2h_est.head<2>() / x2h_est[2]; + x2h_est.head<2>() / x2h_est[2]; } /** - * Computes the squared norm of the residuals between a set of 2D points x2 + * Computes the squared norm of the residuals between a set of 2D points x2 * and the transformed 2D point set x1 such that * Error = || x2 - Psi(H * x1) ||^2 * where Psi is the function that transforms homogeneous to euclidean coords. @@ -99,70 +97,70 @@ struct AsymmetricError { * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). * \return The squared norm of the asymmetric residuals errors */ - static double Error(const Mat &H, const Mat &x1, const Mat &x2) { + static double Error(const Mat& H, const Mat& x1, const Mat& x2) { Mat2X dx; Residuals(H, x1, x2, &dx); return dx.squaredNorm(); } /** - * Computes the squared norm of the residuals between a 2D point x2 and the - * transformed 2D point x1 such that rms = || x2 - Psi(H * x1) ||^2 + * Computes the squared norm of the residuals between a 2D point x2 and the + * transformed 2D point x1 such that rms = || x2 - Psi(H * x1) ||^2 * where Psi is the function that transforms homogeneous to euclidean coords. * * \param[in] H The 3x3 homography matrix. * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) * \return The squared norm of the asymmetric residual error */ - static double Error(const Mat &H, const Vec &x1, const Vec &x2) { + static double Error(const Mat& H, const Vec& x1, const Vec& x2) { Vec2 dx; Residuals(H, x1, x2, &dx); return dx.squaredNorm(); } }; - /** - * Structure for estimating the symmetric error - * between a vector x2 and the transformed x1 such that - * Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2 - * where Psi is the function that transforms homogeneous to euclidean coords. - * \note It should be distributed as Chi-squared with k = 4. - */ +/** + * Structure for estimating the symmetric error + * between a vector x2 and the transformed x1 such that + * Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2 + * where Psi is the function that transforms homogeneous to euclidean coords. + * \note It should be distributed as Chi-squared with k = 4. + */ struct SymmetricError { /** - * Computes the squared norm of the residuals between x2 and the - * transformed x1 such that + * Computes the squared norm of the residuals between x2 and the + * transformed x1 such that * Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2 * where Psi is the function that transforms homogeneous to euclidean coords. * * \param[in] H The 3x3 homography matrix. * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) * \return The squared norm of the symmetric residuals errors */ - static double Error(const Mat &H, const Vec &x1, const Vec &x2) { + static double Error(const Mat& H, const Vec& x1, const Vec& x2) { // TODO(keir): This is awesomely inefficient because it does a 3x3 // inversion for each evaluation. Mat3 Hinv = H.inverse(); - return AsymmetricError::Error(H, x1, x2) + + return AsymmetricError::Error(H, x1, x2) + AsymmetricError::Error(Hinv, x2, x1); } // TODO(julien) Add residuals function \see AsymmetricError }; - /** - * Structure for estimating the algebraic error (cross product) - * between a vector x2 and the transformed x1 such that - * Error = ||[x2] * H * x1||^^2 - * where [x2] is the skew matrix of x2. - */ +/** + * Structure for estimating the algebraic error (cross product) + * between a vector x2 and the transformed x1 such that + * Error = ||[x2] * H * x1||^^2 + * where [x2] is the skew matrix of x2. + */ struct AlgebraicError { // TODO(julien) Make an AlgebraicError2Rows and AlgebraicError3Rows /** - * Computes the algebraic residuals (cross product) between a set of 2D - * points x2 and the transformed 2D point set x1 such that + * Computes the algebraic residuals (cross product) between a set of 2D + * points x2 and the transformed 2D point set x1 such that * [x2] * H * x1 where [x2] is the skew matrix of x2. * * \param[in] H The 3x3 homography matrix. @@ -171,8 +169,7 @@ struct AlgebraicError { * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). * \param[out] dx A 3xN matrix of column vectors of residuals errors */ - static void Residuals(const Mat &H, const Mat &x1, - const Mat &x2, Mat3X *dx) { + static void Residuals(const Mat& H, const Mat& x1, const Mat& x2, Mat3X* dx) { dx->resize(3, x1.cols()); Vec3 col; for (int i = 0; i < x1.cols(); ++i) { @@ -181,18 +178,17 @@ struct AlgebraicError { } } /** - * Computes the algebraic residuals (cross product) between a 2D point x2 - * and the transformed 2D point x1 such that + * Computes the algebraic residuals (cross product) between a 2D point x2 + * and the transformed 2D point x1 such that * [x2] * H * x1 where [x2] is the skew matrix of x2. * * \param[in] H The 3x3 homography matrix. * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) * \param[out] dx A vector of size 3 of the residual error */ - static void Residuals(const Mat &H, const Vec &x1, - const Vec &x2, Vec3 *dx) { + static void Residuals(const Mat& H, const Vec& x1, const Vec& x2, Vec3* dx) { Vec3 x2h_est; if (x1.rows() == 2) x2h_est = H * EuclideanToHomogeneous(static_cast(x1)); @@ -206,8 +202,8 @@ struct AlgebraicError { // identical 3x3 skew matrix for each evaluation. } /** - * Computes the squared norm of the algebraic residuals between a set of 2D - * points x2 and the transformed 2D point set x1 such that + * Computes the squared norm of the algebraic residuals between a set of 2D + * points x2 and the transformed 2D point set x1 such that * [x2] * H * x1 where [x2] is the skew matrix of x2. * * \param[in] H The 3x3 homography matrix. @@ -216,23 +212,23 @@ struct AlgebraicError { * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). * \return The squared norm of the asymmetric residuals errors */ - static double Error(const Mat &H, const Mat &x1, const Mat &x2) { + static double Error(const Mat& H, const Mat& x1, const Mat& x2) { Mat3X dx; Residuals(H, x1, x2, &dx); return dx.squaredNorm(); } /** - * Computes the squared norm of the algebraic residuals between a 2D point x2 - * and the transformed 2D point x1 such that + * Computes the squared norm of the algebraic residuals between a 2D point x2 + * and the transformed 2D point x1 such that * [x2] * H * x1 where [x2] is the skew matrix of x2. * * \param[in] H The 3x3 homography matrix. * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) * \return The squared norm of the asymmetric residual error */ - static double Error(const Mat &H, const Vec &x1, const Vec &x2) { + static double Error(const Mat& H, const Vec& x1, const Vec& x2) { Vec3 dx; Residuals(H, x1, x2, &dx); return dx.squaredNorm(); diff --git a/intern/libmv/libmv/multiview/homography_parameterization.h b/intern/libmv/libmv/multiview/homography_parameterization.h index ca8fbd8066e..ae2d74da9ff 100644 --- a/intern/libmv/libmv/multiview/homography_parameterization.h +++ b/intern/libmv/libmv/multiview/homography_parameterization.h @@ -25,64 +25,72 @@ namespace libmv { -/** A parameterization of the 2D homography matrix that uses 8 parameters so +/** A parameterization of the 2D homography matrix that uses 8 parameters so * that the matrix is normalized (H(2,2) == 1). * The homography matrix H is built from a list of 8 parameters (a, b,...g, h) * as follows - * |a b c| + * |a b c| * H = |d e f| - * |g h 1| + * |g h 1| */ -template +template class Homography2DNormalizedParameterization { public: typedef Eigen::Matrix Parameters; // a, b, ... g, h typedef Eigen::Matrix Parameterized; // H /// Convert from the 8 parameters to a H matrix. - static void To(const Parameters &p, Parameterized *h) { + static void To(const Parameters& p, Parameterized* h) { + // clang-format off *h << p(0), p(1), p(2), p(3), p(4), p(5), p(6), p(7), 1.0; + // clang-format on } /// Convert from a H matrix to the 8 parameters. - static void From(const Parameterized &h, Parameters *p) { + static void From(const Parameterized& h, Parameters* p) { + // clang-format off *p << h(0, 0), h(0, 1), h(0, 2), h(1, 0), h(1, 1), h(1, 2), h(2, 0), h(2, 1); + // clang-format on } }; -/** A parameterization of the 2D homography matrix that uses 15 parameters so +/** A parameterization of the 2D homography matrix that uses 15 parameters so * that the matrix is normalized (H(3,3) == 1). * The homography matrix H is built from a list of 15 parameters (a, b,...n, o) * as follows - * |a b c d| + * |a b c d| * H = |e f g h| * |i j k l| - * |m n o 1| + * |m n o 1| */ -template +template class Homography3DNormalizedParameterization { public: - typedef Eigen::Matrix Parameters; // a, b, ... n, o - typedef Eigen::Matrix Parameterized; // H + typedef Eigen::Matrix Parameters; // a, b, ... n, o + typedef Eigen::Matrix Parameterized; // H /// Convert from the 15 parameters to a H matrix. - static void To(const Parameters &p, Parameterized *h) { + static void To(const Parameters& p, Parameterized* h) { + // clang-format off *h << p(0), p(1), p(2), p(3), p(4), p(5), p(6), p(7), p(8), p(9), p(10), p(11), p(12), p(13), p(14), 1.0; + // clang-format on } /// Convert from a H matrix to the 15 parameters. - static void From(const Parameterized &h, Parameters *p) { + static void From(const Parameterized& h, Parameters* p) { + // clang-format off *p << h(0, 0), h(0, 1), h(0, 2), h(0, 3), h(1, 0), h(1, 1), h(1, 2), h(1, 3), h(2, 0), h(2, 1), h(2, 2), h(2, 3), h(3, 0), h(3, 1), h(3, 2); + // clang-format on } }; diff --git a/intern/libmv/libmv/multiview/homography_test.cc b/intern/libmv/libmv/multiview/homography_test.cc index 8d7266e3d11..87d1c85028d 100644 --- a/intern/libmv/libmv/multiview/homography_test.cc +++ b/intern/libmv/libmv/multiview/homography_test.cc @@ -18,10 +18,10 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "testing/testing.h" +#include "libmv/multiview/homography.h" #include "libmv/logging/logging.h" #include "libmv/multiview/projection.h" -#include "libmv/multiview/homography.h" +#include "testing/testing.h" namespace { using namespace libmv; @@ -34,9 +34,7 @@ namespace { // TODO(sergey): Consider using this in all tests since possible homography // matrix is not fixed to a single value and different-looking matrices // might actually crrespond to the same exact transform. -void CheckHomography2DTransform(const Mat3 &H, - const Mat &x1, - const Mat &x2) { +void CheckHomography2DTransform(const Mat3& H, const Mat& x1, const Mat& x2) { for (int i = 0; i < x2.cols(); ++i) { Vec3 x2_expected = x2.col(i); Vec3 x2_observed = H * x1.col(i); @@ -49,15 +47,19 @@ void CheckHomography2DTransform(const Mat3 &H, TEST(Homography2DTest, Rotation45AndTranslationXY) { Mat x1(3, 4); + // clang-format off x1 << 0, 1, 0, 5, 0, 0, 2, 3, 1, 1, 1, 1; + // clang-format on double angle = 45.0; Mat3 m; + // clang-format off m << cos(angle), -sin(angle), -2, sin(angle), cos(angle), 5, 0, 0, 1; + // clang-format on Mat x2 = x1; // Transform point from ground truth matrix @@ -76,13 +78,17 @@ TEST(Homography2DTest, Rotation45AndTranslationXY) { TEST(Homography2DTest, AffineGeneral4) { // TODO(julien) find why it doesn't work with 4 points!!! Mat x1(3, 4); + // clang-format off x1 << 0, 1, 0, 2, 0, 0, 1, 2, 1, 1, 1, 1; + // clang-format on Mat3 m; + // clang-format off m << 3, -1, 4, 6, -2, -3, 0, 0, 1; + // clang-format on Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) { @@ -109,13 +115,17 @@ TEST(Homography2DTest, AffineGeneral4) { TEST(Homography2DTest, AffineGeneral5) { Mat x1(3, 5); + // clang-format off x1 << 0, 1, 0, 2, 5, 0, 0, 1, 2, 2, 1, 1, 1, 1, 1; + // clang-format on Mat3 m; + // clang-format off m << 3, -1, 4, 6, -2, -3, 0, 0, 1; + // clang-format on Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) @@ -142,13 +152,17 @@ TEST(Homography2DTest, AffineGeneral5) { TEST(Homography2DTest, HomographyGeneral) { Mat x1(3, 4); + // clang-format off x1 << 0, 1, 0, 5, 0, 0, 2, 3, 1, 1, 1, 1; + // clang-format on Mat3 m; + // clang-format off m << 3, -1, 4, 6, -2, -3, 1, -3, 1; + // clang-format on Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) @@ -164,10 +178,12 @@ TEST(Homography2DTest, HomographyGeneral) { TEST(Homography3DTest, RotationAndTranslationXYZ) { Mat x1(4, 5); + // clang-format off x1 << 0, 0, 1, 5, 2, 0, 1, 2, 3, 5, 0, 2, 0, 1, 5, 1, 1, 1, 1, 1; + // clang-format on Mat4 M; M.setIdentity(); /* @@ -178,24 +194,30 @@ TEST(Homography3DTest, RotationAndTranslationXYZ) { // Rotation on x + translation double angle = 45.0; Mat4 rot; + // clang-format off rot << 1, 0, 0, 1, 0, cos(angle), -sin(angle), 3, 0, sin(angle), cos(angle), -2, 0, 0, 0, 1; + // clang-format on M *= rot; // Rotation on y angle = 25.0; + // clang-format off rot << cos(angle), 0, sin(angle), 0, 0, 1, 0, 0, -sin(angle), 0, cos(angle), 0, 0, 0, 0, 1; + // clang-format on M *= rot; // Rotation on z angle = 5.0; + // clang-format off rot << cos(angle), -sin(angle), 0, 0, sin(angle), cos(angle), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1; + // clang-format on M *= rot; Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) { @@ -212,15 +234,19 @@ TEST(Homography3DTest, RotationAndTranslationXYZ) { TEST(Homography3DTest, AffineGeneral) { Mat x1(4, 5); + // clang-format off x1 << 0, 0, 1, 5, 2, 0, 1, 2, 3, 5, 0, 2, 0, 1, 5, 1, 1, 1, 1, 1; + // clang-format on Mat4 m; + // clang-format off m << 3, -1, 4, 1, 6, -2, -3, -6, 1, 0, 1, 2, 0, 0, 0, 1; + // clang-format on Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) { @@ -236,15 +262,19 @@ TEST(Homography3DTest, AffineGeneral) { TEST(Homography3DTest, HomographyGeneral) { Mat x1(4, 5); + // clang-format off x1 << 0, 0, 1, 5, 2, 0, 1, 2, 3, 5, 0, 2, 0, 1, 5, 1, 1, 1, 1, 1; + // clang-format on Mat4 m; + // clang-format off m << 3, -1, 4, 1, 6, -2, -3, -6, 1, 0, 1, 2, -3, 1, 0, 1; + // clang-format on Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) { diff --git a/intern/libmv/libmv/multiview/nviewtriangulation.h b/intern/libmv/libmv/multiview/nviewtriangulation.h index f4614ab1a5c..b2a320953a7 100644 --- a/intern/libmv/libmv/multiview/nviewtriangulation.h +++ b/intern/libmv/libmv/multiview/nviewtriangulation.h @@ -34,22 +34,22 @@ namespace libmv { // x's are 2D coordinates (x,y,1) in each image; Ps are projective cameras. The // output, X, is a homogeneous four vectors. -template -void NViewTriangulate(const Matrix &x, - const vector > &Ps, - Matrix *X) { +template +void NViewTriangulate(const Matrix& x, + const vector>& Ps, + Matrix* X) { int nviews = x.cols(); assert(nviews == Ps.size()); - Matrix design(3*nviews, 4 + nviews); + Matrix design(3 * nviews, 4 + nviews); design.setConstant(0.0); for (int i = 0; i < nviews; i++) { - design.template block<3, 4>(3*i, 0) = -Ps[i]; - design(3*i + 0, 4 + i) = x(0, i); - design(3*i + 1, 4 + i) = x(1, i); - design(3*i + 2, 4 + i) = 1.0; + design.template block<3, 4>(3 * i, 0) = -Ps[i]; + design(3 * i + 0, 4 + i) = x(0, i); + design(3 * i + 1, 4 + i) = x(1, i); + design(3 * i + 2, 4 + i) = 1.0; } - Matrix X_and_alphas; + Matrix X_and_alphas; Nullspace(&design, &X_and_alphas); X->resize(4); *X = X_and_alphas.head(4); @@ -60,16 +60,16 @@ void NViewTriangulate(const Matrix &x, // This method uses the algebraic distance approximation. // Note that this method works better when the 2D points are normalized // with an isotopic normalization. -template -void NViewTriangulateAlgebraic(const Matrix &x, - const vector > &Ps, - Matrix *X) { +template +void NViewTriangulateAlgebraic(const Matrix& x, + const vector>& Ps, + Matrix* X) { int nviews = x.cols(); assert(nviews == Ps.size()); - Matrix design(2*nviews, 4); + Matrix design(2 * nviews, 4); for (int i = 0; i < nviews; i++) { - design.template block<2, 4>(2*i, 0) = SkewMatMinimal(x.col(i)) * Ps[i]; + design.template block<2, 4>(2 * i, 0) = SkewMatMinimal(x.col(i)) * Ps[i]; } X->resize(4); Nullspace(&design, X); diff --git a/intern/libmv/libmv/multiview/nviewtriangulation_test.cc b/intern/libmv/libmv/multiview/nviewtriangulation_test.cc index 5a4d8499753..dba5fd07d5c 100644 --- a/intern/libmv/libmv/multiview/nviewtriangulation_test.cc +++ b/intern/libmv/libmv/multiview/nviewtriangulation_test.cc @@ -54,7 +54,7 @@ TEST(NViewTriangulate, FiveViews) { // Check reprojection error. Should be nearly zero. for (int j = 0; j < nviews; ++j) { - Vec3 x_reprojected = Ps[j]*X; + Vec3 x_reprojected = Ps[j] * X; x_reprojected /= x_reprojected(2); double error = (x_reprojected.head(2) - xs.col(j)).norm(); EXPECT_NEAR(error, 0.0, 1e-9); @@ -84,7 +84,7 @@ TEST(NViewTriangulateAlgebraic, FiveViews) { // Check reprojection error. Should be nearly zero. for (int j = 0; j < nviews; ++j) { - Vec3 x_reprojected = Ps[j]*X; + Vec3 x_reprojected = Ps[j] * X; x_reprojected /= x_reprojected(2); double error = (x_reprojected.head<2>() - xs.col(j)).norm(); EXPECT_NEAR(error, 0.0, 1e-9); diff --git a/intern/libmv/libmv/multiview/panography.cc b/intern/libmv/libmv/multiview/panography.cc index b62802948c4..42b1c19d65e 100644 --- a/intern/libmv/libmv/multiview/panography.cc +++ b/intern/libmv/libmv/multiview/panography.cc @@ -24,8 +24,9 @@ namespace libmv { static bool Build_Minimal2Point_PolynomialFactor( - const Mat & x1, const Mat & x2, - double * P) { // P must be a double[4] + const Mat& x1, + const Mat& x2, + double* P) { // P must be a double[4] assert(2 == x1.rows()); assert(2 == x1.cols()); assert(x1.rows() == x2.rows()); @@ -40,11 +41,11 @@ static bool Build_Minimal2Point_PolynomialFactor( Vec yx2 = (x2.col(1)).transpose(); double b12 = xx2.dot(yx2); - double a1 = xx1.squaredNorm(); - double a2 = yx1.squaredNorm(); + double a1 = xx1.squaredNorm(); + double a2 = yx1.squaredNorm(); - double b1 = xx2.squaredNorm(); - double b2 = yx2.squaredNorm(); + double b1 = xx2.squaredNorm(); + double b2 = yx2.squaredNorm(); // Build the 3rd degre polynomial in F^2. // @@ -52,10 +53,12 @@ static bool Build_Minimal2Point_PolynomialFactor( // // Coefficients in ascending powers of alpha, i.e. P[N]*x^N. // Run panography_coeffs.py to get the below coefficients. - P[0] = b1*b2*a12*a12-a1*a2*b12*b12; - P[1] = -2*a1*a2*b12+2*a12*b1*b2+b1*a12*a12+b2*a12*a12-a1*b12*b12-a2*b12*b12; - P[2] = b1*b2-a1*a2-2*a1*b12-2*a2*b12+2*a12*b1+2*a12*b2+a12*a12-b12*b12; - P[3] = b1+b2-2*b12-a1-a2+2*a12; + P[0] = b1 * b2 * a12 * a12 - a1 * a2 * b12 * b12; + P[1] = -2 * a1 * a2 * b12 + 2 * a12 * b1 * b2 + b1 * a12 * a12 + + b2 * a12 * a12 - a1 * b12 * b12 - a2 * b12 * b12; + P[2] = b1 * b2 - a1 * a2 - 2 * a1 * b12 - 2 * a2 * b12 + 2 * a12 * b1 + + 2 * a12 * b2 + a12 * a12 - b12 * b12; + P[3] = b1 + b2 - 2 * b12 - a1 - a2 + 2 * a12; // If P[3] equal to 0 we get ill conditionned data return (P[3] != 0.0); @@ -67,8 +70,9 @@ static bool Build_Minimal2Point_PolynomialFactor( // // [1] M. Brown and R. Hartley and D. Nister. Minimal Solutions for Panoramic // Stitching. CVPR07. -void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, - vector *fs) { +void F_FromCorrespondance_2points(const Mat& x1, + const Mat& x2, + vector* fs) { // Build Polynomial factor to get squared focal value. double P[4]; Build_Minimal2Point_PolynomialFactor(x1, x2, &P[0]); @@ -79,8 +83,8 @@ void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, // double roots[3]; int num_roots = SolveCubicPolynomial(P, roots); - for (int i = 0; i < num_roots; ++i) { - if (roots[i] > 0.0) { + for (int i = 0; i < num_roots; ++i) { + if (roots[i] > 0.0) { fs->push_back(sqrt(roots[i])); } } @@ -92,17 +96,18 @@ void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, // K. Arun,T. Huand and D. Blostein. Least-squares fitting of 2 3-D point // sets. IEEE Transactions on Pattern Analysis and Machine Intelligence, // 9:698-700, 1987. -void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2, +void GetR_FixedCameraCenter(const Mat& x1, + const Mat& x2, const double focal, - Mat3 *R) { + Mat3* R) { assert(3 == x1.rows()); assert(2 <= x1.cols()); assert(x1.rows() == x2.rows()); assert(x1.cols() == x2.cols()); // Build simplified K matrix - Mat3 K(Mat3::Identity() * 1.0/focal); - K(2, 2)= 1.0; + Mat3 K(Mat3::Identity() * 1.0 / focal); + K(2, 2) = 1.0; // Build the correlation matrix; equation (22) in [1]. Mat3 C = Mat3::Zero(); @@ -115,9 +120,9 @@ void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2, // Solve for rotation. Equations (24) and (25) in [1]. Eigen::JacobiSVD svd(C, Eigen::ComputeThinU | Eigen::ComputeThinV); Mat3 scale = Mat3::Identity(); - scale(2, 2) = ((svd.matrixU() * svd.matrixV().transpose()).determinant() > 0.0) - ? 1.0 - : -1.0; + scale(2, 2) = + ((svd.matrixU() * svd.matrixV().transpose()).determinant() > 0.0) ? 1.0 + : -1.0; (*R) = svd.matrixU() * scale * svd.matrixV().transpose(); } diff --git a/intern/libmv/libmv/multiview/panography.h b/intern/libmv/libmv/multiview/panography.h index 6e87bd71304..5860a34d1fd 100644 --- a/intern/libmv/libmv/multiview/panography.h +++ b/intern/libmv/libmv/multiview/panography.h @@ -22,9 +22,9 @@ #ifndef LIBMV_MULTIVIEW_PANOGRAPHY_H #define LIBMV_MULTIVIEW_PANOGRAPHY_H +#include "libmv/base/vector.h" #include "libmv/numeric/numeric.h" #include "libmv/numeric/poly.h" -#include "libmv/base/vector.h" namespace libmv { @@ -53,8 +53,9 @@ namespace libmv { // K = [0 f 0] // [0 0 1] // -void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, - vector *fs); +void F_FromCorrespondance_2points(const Mat& x1, + const Mat& x2, + vector* fs); // Compute the 3x3 rotation matrix that fits two 3D point clouds in the least // square sense. The method is from: @@ -90,9 +91,10 @@ void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, // // R = arg min || X2 - R * x1 || // -void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2, +void GetR_FixedCameraCenter(const Mat& x1, + const Mat& x2, const double focal, - Mat3 *R); + Mat3* R); } // namespace libmv diff --git a/intern/libmv/libmv/multiview/panography_kernel.cc b/intern/libmv/libmv/multiview/panography_kernel.cc index 8fdc9e79aed..e8ba648e352 100644 --- a/intern/libmv/libmv/multiview/panography_kernel.cc +++ b/intern/libmv/libmv/multiview/panography_kernel.cc @@ -25,7 +25,7 @@ namespace libmv { namespace panography { namespace kernel { -void TwoPointSolver::Solve(const Mat &x1, const Mat &x2, vector *Hs) { +void TwoPointSolver::Solve(const Mat& x1, const Mat& x2, vector* Hs) { // Solve for the focal lengths. vector fs; F_FromCorrespondance_2points(x1, x2, &fs); @@ -34,7 +34,7 @@ void TwoPointSolver::Solve(const Mat &x1, const Mat &x2, vector *Hs) { Mat x1h, x2h; EuclideanToHomogeneous(x1, &x1h); EuclideanToHomogeneous(x2, &x2h); - for (int i = 0; i < fs.size(); ++i) { + for (int i = 0; i < fs.size(); ++i) { Mat3 K1 = Mat3::Identity() * fs[i]; K1(2, 2) = 1.0; diff --git a/intern/libmv/libmv/multiview/panography_kernel.h b/intern/libmv/libmv/multiview/panography_kernel.h index a6adbd54b20..d50d3ea0789 100644 --- a/intern/libmv/libmv/multiview/panography_kernel.h +++ b/intern/libmv/libmv/multiview/panography_kernel.h @@ -23,9 +23,9 @@ #include "libmv/base/vector.h" #include "libmv/multiview/conditioning.h" +#include "libmv/multiview/homography_error.h" #include "libmv/multiview/projection.h" #include "libmv/multiview/two_view_kernel.h" -#include "libmv/multiview/homography_error.h" #include "libmv/numeric/numeric.h" namespace libmv { @@ -34,18 +34,18 @@ namespace kernel { struct TwoPointSolver { enum { MINIMUM_SAMPLES = 2 }; - static void Solve(const Mat &x1, const Mat &x2, vector *Hs); + static void Solve(const Mat& x1, const Mat& x2, vector* Hs); }; -typedef two_view::kernel::Kernel< - TwoPointSolver, homography::homography2D::AsymmetricError, Mat3> - UnnormalizedKernel; +typedef two_view::kernel:: + Kernel + UnnormalizedKernel; typedef two_view::kernel::Kernel< - two_view::kernel::NormalizedSolver, - homography::homography2D::AsymmetricError, - Mat3> - Kernel; + two_view::kernel::NormalizedSolver, + homography::homography2D::AsymmetricError, + Mat3> + Kernel; } // namespace kernel } // namespace panography diff --git a/intern/libmv/libmv/multiview/panography_test.cc b/intern/libmv/libmv/multiview/panography_test.cc index 96d52acfc3c..a7cbd371d40 100644 --- a/intern/libmv/libmv/multiview/panography_test.cc +++ b/intern/libmv/libmv/multiview/panography_test.cc @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "libmv/logging/logging.h" #include "libmv/multiview/panography.h" +#include "libmv/logging/logging.h" #include "libmv/multiview/panography_kernel.h" #include "libmv/multiview/projection.h" #include "libmv/numeric/numeric.h" @@ -30,18 +30,16 @@ namespace { TEST(Panography, PrintSomeSharedFocalEstimationValues) { Mat x1(2, 2), x2(2, 2); - x1<< 158, 78, - 124, 113; - x2<< 300, 214, - 125, 114; + x1 << 158, 78, 124, 113; + x2 << 300, 214, 125, 114; // Normalize data (set principal point 0,0 and image border to 1.0). x1.block<1, 2>(0, 0) /= 320; x1.block<1, 2>(1, 0) /= 240; x2.block<1, 2>(0, 0) /= 320; x2.block<1, 2>(1, 0) /= 240; - x1+=Mat2::Constant(0.5); - x2+=Mat2::Constant(0.5); + x1 += Mat2::Constant(0.5); + x2 += Mat2::Constant(0.5); vector fs; F_FromCorrespondance_2points(x1, x2, &fs); @@ -53,9 +51,11 @@ TEST(Panography, PrintSomeSharedFocalEstimationValues) { TEST(Panography, GetR_FixedCameraCenterWithIdentity) { Mat x1(3, 3); + // clang-format off x1 << 0.5, 0.6, 0.7, 0.5, 0.5, 0.4, 10.0, 10.0, 10.0; + // clang-format on Mat3 R; GetR_FixedCameraCenter(x1, x1, 1.0, &R); @@ -68,16 +68,20 @@ TEST(Panography, Homography_GetR_Test_PitchY30) { int n = 3; Mat x1(3, n); + // clang-format off x1 << 0.5, 0.6, 0.7, 0.5, 0.5, 0.4, 10, 10, 10; + // clang-format on Mat x2 = x1; const double alpha = 30.0 * M_PI / 180.0; Mat3 rotY; + // clang-format off rotY << cos(alpha), 0, -sin(alpha), 0, 1, 0, sin(alpha), 0, cos(alpha); + // clang-format on for (int i = 0; i < n; ++i) { x2.block<3, 1>(0, i) = rotY * x1.col(i); @@ -101,17 +105,23 @@ TEST(Panography, Homography_GetR_Test_PitchY30) { TEST(MinimalPanoramic, Real_Case_Kernel) { const int n = 2; Mat x1(2, n); // From image 0.jpg + // clang-format off x1<< 158, 78, 124, 113; + // clang-format on Mat x2(2, n); // From image 3.jpg + // clang-format off x2<< 300, 214, 125, 114; + // clang-format on Mat3 Ground_TruthHomography; + // clang-format off Ground_TruthHomography<< 1, 0.02, 129.83, -0.02, 1.012, 0.07823, 0, 0, 1; + // clang-format on vector Hs; @@ -130,7 +140,7 @@ TEST(MinimalPanoramic, Real_Case_Kernel) { // Assert that residuals are small enough for (int i = 0; i < n; ++i) { Vec x1p = H * x1h.col(i); - Vec residuals = x1p/x1p(2) - x2h.col(i); + Vec residuals = x1p / x1p(2) - x2h.col(i); EXPECT_MATRIX_NEAR_ZERO(residuals, 1e-5); } } diff --git a/intern/libmv/libmv/multiview/projection.cc b/intern/libmv/libmv/multiview/projection.cc index f8bece3de68..001da89e127 100644 --- a/intern/libmv/libmv/multiview/projection.cc +++ b/intern/libmv/libmv/multiview/projection.cc @@ -23,13 +23,13 @@ namespace libmv { -void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P) { +void P_From_KRt(const Mat3& K, const Mat3& R, const Vec3& t, Mat34* P) { P->block<3, 3>(0, 0) = R; P->col(3) = t; (*P) = K * (*P); } -void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { +void KRt_From_P(const Mat34& P, Mat3* Kp, Mat3* Rp, Vec3* tp) { // Decompose using the RQ decomposition HZ A4.1.1 pag.579. Mat3 K = P.block(0, 0, 3, 3); @@ -44,9 +44,11 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { c /= l; s /= l; Mat3 Qx; + // clang-format off Qx << 1, 0, 0, 0, c, -s, 0, s, c; + // clang-format on K = K * Qx; Q = Qx.transpose() * Q; } @@ -58,9 +60,11 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { c /= l; s /= l; Mat3 Qy; + // clang-format off Qy << c, 0, s, 0, 1, 0, -s, 0, c; + // clang-format on K = K * Qy; Q = Qy.transpose() * Q; } @@ -72,9 +76,11 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { c /= l; s /= l; Mat3 Qz; + // clang-format off Qz << c, -s, 0, s, c, 0, 0, 0, 1; + // clang-format on K = K * Qz; Q = Qz.transpose() * Q; } @@ -92,17 +98,21 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { } if (K(1, 1) < 0) { Mat3 S; + // clang-format off S << 1, 0, 0, 0, -1, 0, 0, 0, 1; + // clang-format on K = K * S; R = S * R; } if (K(0, 0) < 0) { Mat3 S; + // clang-format off S << -1, 0, 0, 0, 1, 0, 0, 0, 1; + // clang-format on K = K * S; R = S * R; } @@ -122,26 +132,30 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { *tp = t; } -void ProjectionShiftPrincipalPoint(const Mat34 &P, - const Vec2 &principal_point, - const Vec2 &principal_point_new, - Mat34 *P_new) { +void ProjectionShiftPrincipalPoint(const Mat34& P, + const Vec2& principal_point, + const Vec2& principal_point_new, + Mat34* P_new) { Mat3 T; + // clang-format off T << 1, 0, principal_point_new(0) - principal_point(0), 0, 1, principal_point_new(1) - principal_point(1), 0, 0, 1; + // clang-format on *P_new = T * P; } -void ProjectionChangeAspectRatio(const Mat34 &P, - const Vec2 &principal_point, +void ProjectionChangeAspectRatio(const Mat34& P, + const Vec2& principal_point, double aspect_ratio, double aspect_ratio_new, - Mat34 *P_new) { + Mat34* P_new) { Mat3 T; + // clang-format off T << 1, 0, 0, 0, aspect_ratio_new / aspect_ratio, 0, 0, 0, 1; + // clang-format on Mat34 P_temp; ProjectionShiftPrincipalPoint(P, principal_point, Vec2(0, 0), &P_temp); @@ -149,7 +163,7 @@ void ProjectionChangeAspectRatio(const Mat34 &P, ProjectionShiftPrincipalPoint(P_temp, Vec2(0, 0), principal_point, P_new); } -void HomogeneousToEuclidean(const Mat &H, Mat *X) { +void HomogeneousToEuclidean(const Mat& H, Mat* X) { int d = H.rows() - 1; int n = H.cols(); X->resize(d, n); @@ -161,29 +175,29 @@ void HomogeneousToEuclidean(const Mat &H, Mat *X) { } } -void HomogeneousToEuclidean(const Mat3X &h, Mat2X *e) { +void HomogeneousToEuclidean(const Mat3X& h, Mat2X* e) { e->resize(2, h.cols()); e->row(0) = h.row(0).array() / h.row(2).array(); e->row(1) = h.row(1).array() / h.row(2).array(); } -void HomogeneousToEuclidean(const Mat4X &h, Mat3X *e) { +void HomogeneousToEuclidean(const Mat4X& h, Mat3X* e) { e->resize(3, h.cols()); e->row(0) = h.row(0).array() / h.row(3).array(); e->row(1) = h.row(1).array() / h.row(3).array(); e->row(2) = h.row(2).array() / h.row(3).array(); } -void HomogeneousToEuclidean(const Vec3 &H, Vec2 *X) { +void HomogeneousToEuclidean(const Vec3& H, Vec2* X) { double w = H(2); *X << H(0) / w, H(1) / w; } -void HomogeneousToEuclidean(const Vec4 &H, Vec3 *X) { +void HomogeneousToEuclidean(const Vec4& H, Vec3* X) { double w = H(3); *X << H(0) / w, H(1) / w, H(2) / w; } -void EuclideanToHomogeneous(const Mat &X, Mat *H) { +void EuclideanToHomogeneous(const Mat& X, Mat* H) { int d = X.rows(); int n = X.cols(); H->resize(d + 1, n); @@ -191,32 +205,32 @@ void EuclideanToHomogeneous(const Mat &X, Mat *H) { H->row(d).setOnes(); } -void EuclideanToHomogeneous(const Vec2 &X, Vec3 *H) { +void EuclideanToHomogeneous(const Vec2& X, Vec3* H) { *H << X(0), X(1), 1; } -void EuclideanToHomogeneous(const Vec3 &X, Vec4 *H) { +void EuclideanToHomogeneous(const Vec3& X, Vec4* H) { *H << X(0), X(1), X(2), 1; } // TODO(julien) Call conditioning.h/ApplyTransformationToPoints ? -void EuclideanToNormalizedCamera(const Mat2X &x, const Mat3 &K, Mat2X *n) { +void EuclideanToNormalizedCamera(const Mat2X& x, const Mat3& K, Mat2X* n) { Mat3X x_image_h; EuclideanToHomogeneous(x, &x_image_h); Mat3X x_camera_h = K.inverse() * x_image_h; HomogeneousToEuclidean(x_camera_h, n); } -void HomogeneousToNormalizedCamera(const Mat3X &x, const Mat3 &K, Mat2X *n) { +void HomogeneousToNormalizedCamera(const Mat3X& x, const Mat3& K, Mat2X* n) { Mat3X x_camera_h = K.inverse() * x; HomogeneousToEuclidean(x_camera_h, n); } -double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X) { - return (R*X)(2) + t(2); +double Depth(const Mat3& R, const Vec3& t, const Vec3& X) { + return (R * X)(2) + t(2); } -double Depth(const Mat3 &R, const Vec3 &t, const Vec4 &X) { +double Depth(const Mat3& R, const Vec3& t, const Vec4& X) { Vec3 Xe = X.head<3>() / X(3); return Depth(R, t, Xe); } diff --git a/intern/libmv/libmv/multiview/projection.h b/intern/libmv/libmv/multiview/projection.h index 8f304f31ec6..ba8fc5d8303 100644 --- a/intern/libmv/libmv/multiview/projection.h +++ b/intern/libmv/libmv/multiview/projection.h @@ -25,108 +25,108 @@ namespace libmv { -void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P); -void KRt_From_P(const Mat34 &P, Mat3 *K, Mat3 *R, Vec3 *t); +void P_From_KRt(const Mat3& K, const Mat3& R, const Vec3& t, Mat34* P); +void KRt_From_P(const Mat34& P, Mat3* K, Mat3* R, Vec3* t); // Applies a change of basis to the image coordinates of the projection matrix // so that the principal point becomes principal_point_new. -void ProjectionShiftPrincipalPoint(const Mat34 &P, - const Vec2 &principal_point, - const Vec2 &principal_point_new, - Mat34 *P_new); +void ProjectionShiftPrincipalPoint(const Mat34& P, + const Vec2& principal_point, + const Vec2& principal_point_new, + Mat34* P_new); // Applies a change of basis to the image coordinates of the projection matrix // so that the aspect ratio becomes aspect_ratio_new. This is done by // stretching the y axis. The aspect ratio is defined as the quotient between // the focal length of the y and the x axis. -void ProjectionChangeAspectRatio(const Mat34 &P, - const Vec2 &principal_point, +void ProjectionChangeAspectRatio(const Mat34& P, + const Vec2& principal_point, double aspect_ratio, double aspect_ratio_new, - Mat34 *P_new); - -void HomogeneousToEuclidean(const Mat &H, Mat *X); -void HomogeneousToEuclidean(const Mat3X &h, Mat2X *e); -void HomogeneousToEuclidean(const Mat4X &h, Mat3X *e); -void HomogeneousToEuclidean(const Vec3 &H, Vec2 *X); -void HomogeneousToEuclidean(const Vec4 &H, Vec3 *X); -inline Vec2 HomogeneousToEuclidean(const Vec3 &h) { + Mat34* P_new); + +void HomogeneousToEuclidean(const Mat& H, Mat* X); +void HomogeneousToEuclidean(const Mat3X& h, Mat2X* e); +void HomogeneousToEuclidean(const Mat4X& h, Mat3X* e); +void HomogeneousToEuclidean(const Vec3& H, Vec2* X); +void HomogeneousToEuclidean(const Vec4& H, Vec3* X); +inline Vec2 HomogeneousToEuclidean(const Vec3& h) { return h.head<2>() / h(2); } -inline Vec3 HomogeneousToEuclidean(const Vec4 &h) { +inline Vec3 HomogeneousToEuclidean(const Vec4& h) { return h.head<3>() / h(3); } -inline Mat2X HomogeneousToEuclidean(const Mat3X &h) { +inline Mat2X HomogeneousToEuclidean(const Mat3X& h) { Mat2X e(2, h.cols()); e.row(0) = h.row(0).array() / h.row(2).array(); e.row(1) = h.row(1).array() / h.row(2).array(); return e; } -void EuclideanToHomogeneous(const Mat &X, Mat *H); -inline Mat3X EuclideanToHomogeneous(const Mat2X &x) { +void EuclideanToHomogeneous(const Mat& X, Mat* H); +inline Mat3X EuclideanToHomogeneous(const Mat2X& x) { Mat3X h(3, x.cols()); h.block(0, 0, 2, x.cols()) = x; h.row(2).setOnes(); return h; } -inline void EuclideanToHomogeneous(const Mat2X &x, Mat3X *h) { +inline void EuclideanToHomogeneous(const Mat2X& x, Mat3X* h) { h->resize(3, x.cols()); h->block(0, 0, 2, x.cols()) = x; h->row(2).setOnes(); } -inline Mat4X EuclideanToHomogeneous(const Mat3X &x) { +inline Mat4X EuclideanToHomogeneous(const Mat3X& x) { Mat4X h(4, x.cols()); h.block(0, 0, 3, x.cols()) = x; h.row(3).setOnes(); return h; } -inline void EuclideanToHomogeneous(const Mat3X &x, Mat4X *h) { +inline void EuclideanToHomogeneous(const Mat3X& x, Mat4X* h) { h->resize(4, x.cols()); h->block(0, 0, 3, x.cols()) = x; h->row(3).setOnes(); } -void EuclideanToHomogeneous(const Vec2 &X, Vec3 *H); -void EuclideanToHomogeneous(const Vec3 &X, Vec4 *H); -inline Vec3 EuclideanToHomogeneous(const Vec2 &x) { +void EuclideanToHomogeneous(const Vec2& X, Vec3* H); +void EuclideanToHomogeneous(const Vec3& X, Vec4* H); +inline Vec3 EuclideanToHomogeneous(const Vec2& x) { return Vec3(x(0), x(1), 1); } -inline Vec4 EuclideanToHomogeneous(const Vec3 &x) { +inline Vec4 EuclideanToHomogeneous(const Vec3& x) { return Vec4(x(0), x(1), x(2), 1); } // Conversion from image coordinates to normalized camera coordinates -void EuclideanToNormalizedCamera(const Mat2X &x, const Mat3 &K, Mat2X *n); -void HomogeneousToNormalizedCamera(const Mat3X &x, const Mat3 &K, Mat2X *n); +void EuclideanToNormalizedCamera(const Mat2X& x, const Mat3& K, Mat2X* n); +void HomogeneousToNormalizedCamera(const Mat3X& x, const Mat3& K, Mat2X* n); -inline Vec2 Project(const Mat34 &P, const Vec3 &X) { +inline Vec2 Project(const Mat34& P, const Vec3& X) { Vec4 HX; HX << X, 1.0; Vec3 hx = P * HX; return hx.head<2>() / hx(2); } -inline void Project(const Mat34 &P, const Vec4 &X, Vec3 *x) { +inline void Project(const Mat34& P, const Vec4& X, Vec3* x) { *x = P * X; } -inline void Project(const Mat34 &P, const Vec4 &X, Vec2 *x) { +inline void Project(const Mat34& P, const Vec4& X, Vec2* x) { Vec3 hx = P * X; *x = hx.head<2>() / hx(2); } -inline void Project(const Mat34 &P, const Vec3 &X, Vec3 *x) { +inline void Project(const Mat34& P, const Vec3& X, Vec3* x) { Vec4 HX; HX << X, 1.0; Project(P, HX, x); } -inline void Project(const Mat34 &P, const Vec3 &X, Vec2 *x) { +inline void Project(const Mat34& P, const Vec3& X, Vec2* x) { Vec3 hx; Project(P, X, &hx); *x = hx.head<2>() / hx(2); } -inline void Project(const Mat34 &P, const Mat4X &X, Mat2X *x) { +inline void Project(const Mat34& P, const Mat4X& X, Mat2X* x) { x->resize(2, X.cols()); for (int c = 0; c < X.cols(); ++c) { Vec3 hx = P * X.col(c); @@ -134,13 +134,13 @@ inline void Project(const Mat34 &P, const Mat4X &X, Mat2X *x) { } } -inline Mat2X Project(const Mat34 &P, const Mat4X &X) { +inline Mat2X Project(const Mat34& P, const Mat4X& X) { Mat2X x; Project(P, X, &x); return x; } -inline void Project(const Mat34 &P, const Mat3X &X, Mat2X *x) { +inline void Project(const Mat34& P, const Mat3X& X, Mat2X* x) { x->resize(2, X.cols()); for (int c = 0; c < X.cols(); ++c) { Vec4 HX; @@ -150,7 +150,7 @@ inline void Project(const Mat34 &P, const Mat3X &X, Mat2X *x) { } } -inline void Project(const Mat34 &P, const Mat3X &X, const Vecu &ids, Mat2X *x) { +inline void Project(const Mat34& P, const Mat3X& X, const Vecu& ids, Mat2X* x) { x->resize(2, ids.size()); Vec4 HX; Vec3 hx; @@ -161,26 +161,26 @@ inline void Project(const Mat34 &P, const Mat3X &X, const Vecu &ids, Mat2X *x) { } } -inline Mat2X Project(const Mat34 &P, const Mat3X &X) { +inline Mat2X Project(const Mat34& P, const Mat3X& X) { Mat2X x(2, X.cols()); Project(P, X, &x); return x; } -inline Mat2X Project(const Mat34 &P, const Mat3X &X, const Vecu &ids) { +inline Mat2X Project(const Mat34& P, const Mat3X& X, const Vecu& ids) { Mat2X x(2, ids.size()); Project(P, X, ids, &x); return x; } -double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X); -double Depth(const Mat3 &R, const Vec3 &t, const Vec4 &X); +double Depth(const Mat3& R, const Vec3& t, const Vec3& X); +double Depth(const Mat3& R, const Vec3& t, const Vec4& X); /** -* Returns true if the homogenious 3D point X is in front of -* the camera P. -*/ -inline bool isInFrontOfCamera(const Mat34 &P, const Vec4 &X) { + * Returns true if the homogenious 3D point X is in front of + * the camera P. + */ +inline bool isInFrontOfCamera(const Mat34& P, const Vec4& X) { double condition_1 = P.row(2).dot(X) * X[3]; double condition_2 = X[2] * X[3]; if (condition_1 > 0 && condition_2 > 0) @@ -189,37 +189,37 @@ inline bool isInFrontOfCamera(const Mat34 &P, const Vec4 &X) { return false; } -inline bool isInFrontOfCamera(const Mat34 &P, const Vec3 &X) { +inline bool isInFrontOfCamera(const Mat34& P, const Vec3& X) { Vec4 X_homo; X_homo.segment<3>(0) = X; X_homo(3) = 1; - return isInFrontOfCamera( P, X_homo); + return isInFrontOfCamera(P, X_homo); } /** -* Transforms a 2D point from pixel image coordinates to a 2D point in -* normalized image coordinates. -*/ -inline Vec2 ImageToNormImageCoordinates(Mat3 &Kinverse, Vec2 &x) { - Vec3 x_h = Kinverse*EuclideanToHomogeneous(x); - return HomogeneousToEuclidean( x_h ); + * Transforms a 2D point from pixel image coordinates to a 2D point in + * normalized image coordinates. + */ +inline Vec2 ImageToNormImageCoordinates(Mat3& Kinverse, Vec2& x) { + Vec3 x_h = Kinverse * EuclideanToHomogeneous(x); + return HomogeneousToEuclidean(x_h); } /// Estimates the root mean square error (2D) -inline double RootMeanSquareError(const Mat2X &x_image, - const Mat4X &X_world, - const Mat34 &P) { +inline double RootMeanSquareError(const Mat2X& x_image, + const Mat4X& X_world, + const Mat34& P) { size_t num_points = x_image.cols(); Mat2X dx = Project(P, X_world) - x_image; return dx.norm() / num_points; } /// Estimates the root mean square error (2D) -inline double RootMeanSquareError(const Mat2X &x_image, - const Mat3X &X_world, - const Mat3 &K, - const Mat3 &R, - const Vec3 &t) { +inline double RootMeanSquareError(const Mat2X& x_image, + const Mat3X& X_world, + const Mat3& K, + const Mat3& R, + const Vec3& t) { Mat34 P; P_From_KRt(K, R, t, &P); size_t num_points = x_image.cols(); diff --git a/intern/libmv/libmv/multiview/projection_test.cc b/intern/libmv/libmv/multiview/projection_test.cc index 40e766bfae7..683edefa99c 100644 --- a/intern/libmv/libmv/multiview/projection_test.cc +++ b/intern/libmv/libmv/multiview/projection_test.cc @@ -29,14 +29,18 @@ using namespace libmv; TEST(Projection, P_From_KRt) { Mat3 K, Kp; + // clang-format off K << 10, 1, 30, 0, 20, 40, 0, 0, 1; + // clang-format on Mat3 R, Rp; + // clang-format off R << 1, 0, 0, 0, 1, 0, 0, 0, 1; + // clang-format on Vec3 t, tp; t << 1, 2, 3; @@ -62,16 +66,18 @@ Vec4 GetRandomPoint() { TEST(Projection, isInFrontOfCamera) { Mat34 P; + // clang-format off P << 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0; + // clang-format on Vec4 X_front = GetRandomPoint(); Vec4 X_back = GetRandomPoint(); - X_front(2) = 10; /* Any point in the positive Z direction - * where Z > 1 is in front of the camera. */ - X_back(2) = -10; /* Any point in the negative Z direction - * is behind the camera. */ + X_front(2) = 10; /* Any point in the positive Z direction + * where Z > 1 is in front of the camera. */ + X_back(2) = -10; /* Any point in the negative Z direction + * is behind the camera. */ bool res_front = isInFrontOfCamera(P, X_front); bool res_back = isInFrontOfCamera(P, X_back); @@ -82,12 +88,14 @@ TEST(Projection, isInFrontOfCamera) { TEST(AutoCalibration, ProjectionShiftPrincipalPoint) { Mat34 P1, P2; + // clang-format off P1 << 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0; P2 << 1, 0, 3, 0, 0, 1, 4, 0, 0, 0, 1, 0; + // clang-format on Mat34 P1_computed, P2_computed; ProjectionShiftPrincipalPoint(P1, Vec2(0, 0), Vec2(3, 4), &P2_computed); ProjectionShiftPrincipalPoint(P2, Vec2(3, 4), Vec2(0, 0), &P1_computed); @@ -98,12 +106,14 @@ TEST(AutoCalibration, ProjectionShiftPrincipalPoint) { TEST(AutoCalibration, ProjectionChangeAspectRatio) { Mat34 P1, P2; + // clang-format off P1 << 1, 0, 3, 0, 0, 1, 4, 0, 0, 0, 1, 0; P2 << 1, 0, 3, 0, 0, 2, 4, 0, 0, 0, 1, 0; + // clang-format on Mat34 P1_computed, P2_computed; ProjectionChangeAspectRatio(P1, Vec2(3, 4), 1, 2, &P2_computed); ProjectionChangeAspectRatio(P2, Vec2(3, 4), 2, 1, &P1_computed); diff --git a/intern/libmv/libmv/multiview/resection.h b/intern/libmv/libmv/multiview/resection.h index c142d6deeb2..e543827c932 100644 --- a/intern/libmv/libmv/multiview/resection.h +++ b/intern/libmv/libmv/multiview/resection.h @@ -33,23 +33,23 @@ namespace libmv { namespace resection { // x's are 2D image coordinates, (x,y,1), and X's are homogeneous four vectors. -template -void Resection(const Matrix &x, - const Matrix &X, - Matrix *P) { +template +void Resection(const Matrix& x, + const Matrix& X, + Matrix* P) { int N = x.cols(); assert(X.cols() == N); - Matrix design(2*N, 12); + Matrix design(2 * N, 12); design.setZero(); for (int i = 0; i < N; i++) { T xi = x(0, i); T yi = x(1, i); // See equation (7.2) on page 179 of H&Z. - design.template block<1, 4>(2*i, 4) = -X.col(i).transpose(); - design.template block<1, 4>(2*i, 8) = yi*X.col(i).transpose(); - design.template block<1, 4>(2*i + 1, 0) = X.col(i).transpose(); - design.template block<1, 4>(2*i + 1, 8) = -xi*X.col(i).transpose(); + design.template block<1, 4>(2 * i, 4) = -X.col(i).transpose(); + design.template block<1, 4>(2 * i, 8) = yi * X.col(i).transpose(); + design.template block<1, 4>(2 * i + 1, 0) = X.col(i).transpose(); + design.template block<1, 4>(2 * i + 1, 8) = -xi * X.col(i).transpose(); } Matrix p; Nullspace(&design, &p); diff --git a/intern/libmv/libmv/multiview/resection_test.cc b/intern/libmv/libmv/multiview/resection_test.cc index 368e2281cfa..fb075d02d69 100644 --- a/intern/libmv/libmv/multiview/resection_test.cc +++ b/intern/libmv/libmv/multiview/resection_test.cc @@ -20,12 +20,12 @@ #include +#include "libmv/logging/logging.h" #include "libmv/multiview/projection.h" #include "libmv/multiview/resection.h" #include "libmv/multiview/test_data_sets.h" #include "libmv/numeric/numeric.h" #include "testing/testing.h" -#include "libmv/logging/logging.h" namespace { @@ -40,15 +40,15 @@ TEST(Resection, ThreeViews) { Mat4X X(4, npoints); X.block(0, 0, 3, npoints) = d.X; X.row(3).setOnes(); - const Mat2X &x = d.x[i]; + const Mat2X& x = d.x[i]; Mat34 P; Resection(x, X, &P); Mat34 P_expected = d.P(i); // Because the P matrices are homogeneous, it is necessary to be tricky // about the scale factor to make them match. - P_expected *= 1/P_expected.array().abs().sum(); - P *= 1/P.array().abs().sum(); + P_expected *= 1 / P_expected.array().abs().sum(); + P *= 1 / P.array().abs().sum(); if (!((P(0, 0) > 0 && P_expected(0, 0) > 0) || (P(0, 0) < 0 && P_expected(0, 0) < 0))) { P *= -1; diff --git a/intern/libmv/libmv/multiview/test_data_sets.cc b/intern/libmv/libmv/multiview/test_data_sets.cc index 110bde6f762..a927c166d19 100644 --- a/intern/libmv/libmv/multiview/test_data_sets.cc +++ b/intern/libmv/libmv/multiview/test_data_sets.cc @@ -22,24 +22,28 @@ #include -#include "libmv/numeric/numeric.h" -#include "libmv/multiview/projection.h" #include "libmv/multiview/fundamental.h" +#include "libmv/multiview/projection.h" +#include "libmv/numeric/numeric.h" namespace libmv { TwoViewDataSet TwoRealisticCameras(bool same_K) { TwoViewDataSet d; + // clang-format off d.K1 << 320, 0, 160, 0, 320, 120, 0, 0, 1; + // clang-format on if (same_K) { d.K2 = d.K1; } else { + // clang-format off d.K2 << 360, 0, 170, 0, 360, 110, 0, 0, 1; + // clang-format on } d.R1 = RotationAroundZ(-0.1); d.R2 = RotationAroundX(-0.1); @@ -59,10 +63,8 @@ TwoViewDataSet TwoRealisticCameras(bool same_K) { return d; } -nViewDatasetConfigator::nViewDatasetConfigator(int fx , int fy, - int cx, int cy, - double distance, - double jitter_amount) { +nViewDatasetConfigator::nViewDatasetConfigator( + int fx, int fy, int cx, int cy, double distance, double jitter_amount) { _fx = fx; _fy = fy; _cx = cx; @@ -71,7 +73,8 @@ nViewDatasetConfigator::nViewDatasetConfigator(int fx , int fy, _jitter_amount = jitter_amount; } -NViewDataSet NRealisticCamerasFull(int nviews, int npoints, +NViewDataSet NRealisticCamerasFull(int nviews, + int npoints, const nViewDatasetConfigator config) { NViewDataSet d; d.n = nviews; @@ -102,9 +105,11 @@ NViewDataSet NRealisticCamerasFull(int nviews, int npoints, jitter *= config._jitter_amount / camera_center.norm(); lookdir = -camera_center + jitter; + // clang-format off d.K[i] << config._fx, 0, config._cx, 0, config._fy, config._cy, 0, 0, 1; + // clang-format on d.R[i] = LookAt(lookdir); d.t[i] = -d.R[i] * camera_center; d.x[i] = Project(d.P(i), d.X); @@ -113,9 +118,10 @@ NViewDataSet NRealisticCamerasFull(int nviews, int npoints, return d; } - -NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, - float view_ratio, unsigned min_projections, +NViewDataSet NRealisticCamerasSparse(int nviews, + int npoints, + float view_ratio, + unsigned min_projections, const nViewDatasetConfigator config) { assert(view_ratio <= 1.0); assert(view_ratio > 0.0); @@ -137,7 +143,7 @@ NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, visibility.setZero(); Mat randoms(nviews, npoints); randoms.setRandom(); - randoms = (randoms.array() + 1)/2.0; + randoms = (randoms.array() + 1) / 2.0; unsigned num_visibles = 0; for (size_t i = 0; i < nviews; ++i) { num_visibles = 0; @@ -174,15 +180,17 @@ NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, jitter *= config._jitter_amount / camera_center.norm(); lookdir = -camera_center + jitter; + // clang-format off d.K[i] << config._fx, 0, config._cx, 0, config._fy, config._cy, 0, 0, 1; + // clang-format on d.R[i] = LookAt(lookdir); d.t[i] = -d.R[i] * camera_center; j_visible = 0; for (size_t j = 0; j < npoints; j++) { if (visibility(i, j)) { - X = d.X.col(j); + X = d.X.col(j); d.x[i].col(j_visible) = Project(d.P(i), X); d.x_ids[i][j_visible] = j; j_visible++; @@ -192,5 +200,4 @@ NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, return d; } - } // namespace libmv diff --git a/intern/libmv/libmv/multiview/test_data_sets.h b/intern/libmv/libmv/multiview/test_data_sets.h index cf01663ca02..0c8785728bd 100644 --- a/intern/libmv/libmv/multiview/test_data_sets.h +++ b/intern/libmv/libmv/multiview/test_data_sets.h @@ -34,8 +34,8 @@ struct TwoViewDataSet { Vec3 t1, t2; // Translation. Mat34 P1, P2; // Projection matrix, P = K(R|t) Mat3 F; // Fundamental matrix. - Mat3X X; // 3D points. - Mat2X x1, x2; // Projected points. + Mat3X X; // 3D points. + Mat2X x1, x2; // Projected points. }; // Two cameras at (-1,-1,-10) and (2,1,-10) looking approximately towards z+. @@ -45,13 +45,13 @@ TwoViewDataSet TwoRealisticCameras(bool same_K = false); // and the other reconstruction data types is that all points are seen by all // cameras. struct NViewDataSet { - vector K; // Internal parameters (fx, fy, etc). - vector R; // Rotation. - vector t; // Translation. - vector C; // Camera centers. - Mat3X X; // 3D points. - vector x; // Projected points; may have noise added. - vector x_ids; // Indexes of points corresponding to the projections + vector K; // Internal parameters (fx, fy, etc). + vector R; // Rotation. + vector t; // Translation. + vector C; // Camera centers. + Mat3X X; // 3D points. + vector x; // Projected points; may have noise added. + vector x_ids; // Indexes of points corresponding to the projections int n; // Actual number of cameras. @@ -83,22 +83,26 @@ struct nViewDatasetConfigator { double _dist; double _jitter_amount; - nViewDatasetConfigator(int fx = 1000, int fy = 1000, - int cx = 500, int cy = 500, + nViewDatasetConfigator(int fx = 1000, + int fy = 1000, + int cx = 500, + int cy = 500, double distance = 1.5, double jitter_amount = 0.01); }; -NViewDataSet NRealisticCamerasFull(int nviews, int npoints, - const nViewDatasetConfigator - config = nViewDatasetConfigator()); +NViewDataSet NRealisticCamerasFull( + int nviews, + int npoints, + const nViewDatasetConfigator config = nViewDatasetConfigator()); // Generates sparse projections (not all points are projected) -NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, - float view_ratio = 0.6, - unsigned min_projections = 3, - const nViewDatasetConfigator - config = nViewDatasetConfigator()); +NViewDataSet NRealisticCamerasSparse( + int nviews, + int npoints, + float view_ratio = 0.6, + unsigned min_projections = 3, + const nViewDatasetConfigator config = nViewDatasetConfigator()); } // namespace libmv diff --git a/intern/libmv/libmv/multiview/triangulation.cc b/intern/libmv/libmv/multiview/triangulation.cc index 4d146c8f21b..568625de19d 100644 --- a/intern/libmv/libmv/multiview/triangulation.cc +++ b/intern/libmv/libmv/multiview/triangulation.cc @@ -20,15 +20,17 @@ #include "libmv/multiview/triangulation.h" -#include "libmv/numeric/numeric.h" #include "libmv/multiview/projection.h" +#include "libmv/numeric/numeric.h" namespace libmv { // HZ 12.2 pag.312 -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec4 *X_homogeneous) { +void TriangulateDLT(const Mat34& P1, + const Vec2& x1, + const Mat34& P2, + const Vec2& x2, + Vec4* X_homogeneous) { Mat4 design; for (int i = 0; i < 4; ++i) { design(0, i) = x1(0) * P1(2, i) - P1(0, i); @@ -39,9 +41,11 @@ void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, Nullspace(&design, X_homogeneous); } -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec3 *X_euclidean) { +void TriangulateDLT(const Mat34& P1, + const Vec2& x1, + const Mat34& P2, + const Vec2& x2, + Vec3* X_euclidean) { Vec4 X_homogeneous; TriangulateDLT(P1, x1, P2, x2, &X_homogeneous); HomogeneousToEuclidean(X_homogeneous, X_euclidean); diff --git a/intern/libmv/libmv/multiview/triangulation.h b/intern/libmv/libmv/multiview/triangulation.h index be878890242..c538433eb8b 100644 --- a/intern/libmv/libmv/multiview/triangulation.h +++ b/intern/libmv/libmv/multiview/triangulation.h @@ -25,13 +25,17 @@ namespace libmv { -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec4 *X_homogeneous); +void TriangulateDLT(const Mat34& P1, + const Vec2& x1, + const Mat34& P2, + const Vec2& x2, + Vec4* X_homogeneous); -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec3 *X_euclidean); +void TriangulateDLT(const Mat34& P1, + const Vec2& x1, + const Mat34& P2, + const Vec2& x2, + Vec3* X_euclidean); } // namespace libmv diff --git a/intern/libmv/libmv/multiview/triangulation_test.cc b/intern/libmv/libmv/multiview/triangulation_test.cc index 66d1ee25a62..54d20f4ee17 100644 --- a/intern/libmv/libmv/multiview/triangulation_test.cc +++ b/intern/libmv/libmv/multiview/triangulation_test.cc @@ -20,10 +20,10 @@ #include -#include "libmv/multiview/triangulation.h" #include "libmv/multiview/fundamental.h" #include "libmv/multiview/projection.h" #include "libmv/multiview/test_data_sets.h" +#include "libmv/multiview/triangulation.h" #include "libmv/numeric/numeric.h" #include "testing/testing.h" diff --git a/intern/libmv/libmv/multiview/two_view_kernel.h b/intern/libmv/libmv/multiview/two_view_kernel.h index 7af0ed5ddab..4df99183ee0 100644 --- a/intern/libmv/libmv/multiview/two_view_kernel.h +++ b/intern/libmv/libmv/multiview/two_view_kernel.h @@ -30,10 +30,10 @@ namespace libmv { namespace two_view { namespace kernel { -template +template struct NormalizedSolver { enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES }; - static void Solve(const Mat &x1, const Mat &x2, vector *models) { + static void Solve(const Mat& x1, const Mat& x2, vector* models) { assert(2 == x1.rows()); assert(MINIMUM_SAMPLES <= x1.cols()); assert(x1.rows() == x2.rows()); @@ -53,10 +53,10 @@ struct NormalizedSolver { } }; -template +template struct IsotropicNormalizedSolver { enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES }; - static void Solve(const Mat &x1, const Mat &x2, vector *models) { + static void Solve(const Mat& x1, const Mat& x2, vector* models) { assert(2 == x1.rows()); assert(MINIMUM_SAMPLES <= x1.cols()); assert(x1.rows() == x2.rows()); @@ -99,35 +99,32 @@ struct IsotropicNormalizedSolver { // // The fit routine must not clear existing entries in the vector of models; it // should append new solutions to the end. -template +template class Kernel { public: - Kernel(const Mat &x1, const Mat &x2) : x1_(x1), x2_(x2) {} + Kernel(const Mat& x1, const Mat& x2) : x1_(x1), x2_(x2) {} typedef SolverArg Solver; - typedef ModelArg Model; + typedef ModelArg Model; enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES }; - void Fit(const vector &samples, vector *models) const { + void Fit(const vector& samples, vector* models) const { Mat x1 = ExtractColumns(x1_, samples); Mat x2 = ExtractColumns(x2_, samples); Solver::Solve(x1, x2, models); } - double Error(int sample, const Model &model) const { + double Error(int sample, const Model& model) const { return ErrorArg::Error(model, static_cast(x1_.col(sample)), static_cast(x2_.col(sample))); } - int NumSamples() const { - return x1_.cols(); - } - static void Solve(const Mat &x1, const Mat &x2, vector *models) { + int NumSamples() const { return x1_.cols(); } + static void Solve(const Mat& x1, const Mat& x2, vector* models) { // By offering this, Kernel types can be passed to templates. Solver::Solve(x1, x2, models); } + protected: - const Mat &x1_; - const Mat &x2_; + const Mat& x1_; + const Mat& x2_; }; } // namespace kernel diff --git a/intern/libmv/libmv/numeric/dogleg.h b/intern/libmv/libmv/numeric/dogleg.h index bf6f996ddaf..62abfbdcd4b 100644 --- a/intern/libmv/libmv/numeric/dogleg.h +++ b/intern/libmv/libmv/numeric/dogleg.h @@ -32,18 +32,18 @@ #include #include -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/function_derivative.h" #include "libmv/logging/logging.h" +#include "libmv/numeric/function_derivative.h" +#include "libmv/numeric/numeric.h" namespace libmv { -template, - typename Solver = Eigen::PartialPivLU< - Matrix > > +template , + typename Solver = Eigen::PartialPivLU< + Matrix>> class Dogleg { public: typedef typename Function::XMatrixType::RealScalar Scalar; @@ -51,10 +51,12 @@ class Dogleg { typedef typename Function::XMatrixType Parameters; typedef Matrix JMatrixType; + Function::XMatrixType::RowsAtCompileTime> + JMatrixType; typedef Matrix AMatrixType; + JMatrixType::ColsAtCompileTime> + AMatrixType; enum Status { RUNNING, @@ -71,34 +73,38 @@ class Dogleg { STEEPEST_DESCENT, }; - Dogleg(const Function &f) - : f_(f), df_(f) {} + Dogleg(const Function& f) : f_(f), df_(f) {} struct SolverParameters { SolverParameters() - : gradient_threshold(1e-16), - relative_step_threshold(1e-16), - error_threshold(1e-16), - initial_trust_radius(1e0), - max_iterations(500) {} + : gradient_threshold(1e-16), + relative_step_threshold(1e-16), + error_threshold(1e-16), + initial_trust_radius(1e0), + max_iterations(500) {} Scalar gradient_threshold; // eps > max(J'*f(x)) Scalar relative_step_threshold; // eps > ||dx|| / ||x|| Scalar error_threshold; // eps > ||f(x)|| Scalar initial_trust_radius; // Initial u for solving normal equations. - int max_iterations; // Maximum number of solver iterations. + int max_iterations; // Maximum number of solver iterations. }; struct Results { Scalar error_magnitude; // ||f(x)|| Scalar gradient_magnitude; // ||J'f(x)|| - int iterations; + int iterations; Status status; }; - Status Update(const Parameters &x, const SolverParameters ¶ms, - JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) { + Status Update(const Parameters& x, + const SolverParameters& params, + JMatrixType* J, + AMatrixType* A, + FVec* error, + Parameters* g) { *J = df_(x); - // TODO(keir): In the case of m = n, avoid computing A and just do J^-1 directly. + // TODO(keir): In the case of m = n, avoid computing A and just do J^-1 + // directly. *A = (*J).transpose() * (*J); *error = f_(x); *g = (*J).transpose() * *error; @@ -110,12 +116,12 @@ class Dogleg { return RUNNING; } - Step SolveDoglegDirection(const Parameters &dx_sd, - const Parameters &dx_gn, + Step SolveDoglegDirection(const Parameters& dx_sd, + const Parameters& dx_gn, Scalar radius, Scalar alpha, - Parameters *dx_dl, - Scalar *beta) { + Parameters* dx_dl, + Scalar* beta) { Parameters a, b_minus_a; // Solve for Dogleg step dx_dl. if (dx_gn.norm() < radius) { @@ -128,30 +134,29 @@ class Dogleg { } else { Parameters a = alpha * dx_sd; - const Parameters &b = dx_gn; + const Parameters& b = dx_gn; b_minus_a = a - b; Scalar Mbma2 = b_minus_a.squaredNorm(); Scalar Ma2 = a.squaredNorm(); Scalar c = a.dot(b_minus_a); - Scalar radius2 = radius*radius; + Scalar radius2 = radius * radius; if (c <= 0) { - *beta = (-c + sqrt(c*c + Mbma2*(radius2 - Ma2)))/(Mbma2); + *beta = (-c + sqrt(c * c + Mbma2 * (radius2 - Ma2))) / (Mbma2); } else { - *beta = (radius2 - Ma2) / - (c + sqrt(c*c + Mbma2*(radius2 - Ma2))); + *beta = (radius2 - Ma2) / (c + sqrt(c * c + Mbma2 * (radius2 - Ma2))); } - *dx_dl = alpha * dx_sd + (*beta) * (dx_gn - alpha*dx_sd); + *dx_dl = alpha * dx_sd + (*beta) * (dx_gn - alpha * dx_sd); return DOGLEG; } } - Results minimize(Parameters *x_and_min) { + Results minimize(Parameters* x_and_min) { SolverParameters params; return minimize(params, x_and_min); } - Results minimize(const SolverParameters ¶ms, Parameters *x_and_min) { - Parameters &x = *x_and_min; + Results minimize(const SolverParameters& params, Parameters* x_and_min) { + Parameters& x = *x_and_min; JMatrixType J; AMatrixType A; FVec error; @@ -167,18 +172,21 @@ class Dogleg { Parameters dx_sd; // Steepest descent step. Parameters dx_dl; // Dogleg step. Parameters dx_gn; // Gauss-Newton step. - printf("iteration ||f(x)|| max(g) radius\n"); + printf("iteration ||f(x)|| max(g) radius\n"); int i = 0; for (; results.status == RUNNING && i < params.max_iterations; ++i) { printf("%9d %12g %12g %12g", - i, f_(x).norm(), g.array().abs().maxCoeff(), radius); + i, + f_(x).norm(), + g.array().abs().maxCoeff(), + radius); - //LG << "iteration: " << i; - //LG << "||f(x)||: " << f_(x).norm(); - //LG << "max(g): " << g.cwise().abs().maxCoeff(); - //LG << "radius: " << radius; + // LG << "iteration: " << i; + // LG << "||f(x)||: " << f_(x).norm(); + // LG << "max(g): " << g.cwise().abs().maxCoeff(); + // LG << "radius: " << radius; // Eqn 3.19 from [1] - Scalar alpha = g.squaredNorm() / (J*g).squaredNorm(); + Scalar alpha = g.squaredNorm() / (J * g).squaredNorm(); // Solve for steepest descent direction dx_sd. dx_sd = -g; @@ -199,11 +207,11 @@ class Dogleg { // Solve for dogleg direction dx_dl. Scalar beta = 0; - Step step = SolveDoglegDirection(dx_sd, dx_gn, radius, alpha, - &dx_dl, &beta); + Step step = + SolveDoglegDirection(dx_sd, dx_gn, radius, alpha, &dx_dl, &beta); Scalar e3 = params.relative_step_threshold; - if (dx_dl.norm() < e3*(x.norm() + e3)) { + if (dx_dl.norm() < e3 * (x.norm() + e3)) { results.status = RELATIVE_STEP_SIZE_TOO_SMALL; break; } @@ -214,16 +222,19 @@ class Dogleg { if (step == GAUSS_NEWTON) { predicted = f_(x).squaredNorm(); } else if (step == STEEPEST_DESCENT) { - predicted = radius * (2*alpha*g.norm() - radius) / 2 / alpha; + predicted = radius * (2 * alpha * g.norm() - radius) / 2 / alpha; } else if (step == DOGLEG) { - predicted = 0.5 * alpha * (1-beta)*(1-beta)*g.squaredNorm() + - beta*(2-beta)*f_(x).squaredNorm(); + predicted = 0.5 * alpha * (1 - beta) * (1 - beta) * g.squaredNorm() + + beta * (2 - beta) * f_(x).squaredNorm(); } Scalar rho = actual / predicted; - if (step == GAUSS_NEWTON) printf(" GAUSS"); - if (step == STEEPEST_DESCENT) printf(" STEE"); - if (step == DOGLEG) printf(" DOGL"); + if (step == GAUSS_NEWTON) + printf(" GAUSS"); + if (step == STEEPEST_DESCENT) + printf(" STEE"); + if (step == DOGLEG) + printf(" DOGL"); printf(" %12g %12g %12g\n", rho, actual, predicted); @@ -234,7 +245,7 @@ class Dogleg { x_updated = true; } if (rho > 0.75) { - radius = std::max(radius, 3*dx_dl.norm()); + radius = std::max(radius, 3 * dx_dl.norm()); } else if (rho < 0.25) { radius /= 2; if (radius < e3 * (x.norm() + e3)) { @@ -252,10 +263,10 @@ class Dogleg { } private: - const Function &f_; + const Function& f_; Jacobian df_; }; -} // namespace mv +} // namespace libmv #endif // LIBMV_NUMERIC_DOGLEG_H diff --git a/intern/libmv/libmv/numeric/dogleg_test.cc b/intern/libmv/libmv/numeric/dogleg_test.cc index 90c46c31672..a5ab1957632 100644 --- a/intern/libmv/libmv/numeric/dogleg_test.cc +++ b/intern/libmv/libmv/numeric/dogleg_test.cc @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "testing/testing.h" #include "libmv/numeric/dogleg.h" +#include "testing/testing.h" using namespace libmv; @@ -29,26 +29,26 @@ class F { public: typedef Vec4 FMatrixType; typedef Vec3 XMatrixType; - Vec4 operator()(const Vec3 &x) const { + Vec4 operator()(const Vec3& x) const { double x1 = x.x() - 2; double y1 = x.y() - 5; double z1 = x.z(); - Vec4 fx; fx << x1*x1 + z1*z1, - y1*y1 + z1*z1, - z1*z1, - x1*x1; + Vec4 fx; + fx << x1 * x1 + z1 * z1, y1 * y1 + z1 * z1, z1 * z1, x1 * x1; return fx; } }; TEST(Dogleg, SimpleCase) { - Vec3 x; x << 0.76026643, -30.01799744, 0.55192142; + Vec3 x; + x << 0.76026643, -30.01799744, 0.55192142; F f; Dogleg::SolverParameters params; Dogleg lm(f); /* TODO(sergey): Better error handling. */ /* Dogleg::Results results = */ lm.minimize(params, &x); - Vec3 expected_min_x; expected_min_x << 2, 5, 0; + Vec3 expected_min_x; + expected_min_x << 2, 5, 0; EXPECT_MATRIX_NEAR(expected_min_x, x, 1e-5); } @@ -59,20 +59,21 @@ class F32 { public: typedef Vec2 FMatrixType; typedef Vec2 XMatrixType; - Vec2 operator()(const Vec2 &x) const { + Vec2 operator()(const Vec2& x) const { double x1 = x(0); - double x2 = 10*x(0)/(x(0) + 0.1) + 2*x(1)*x(1); - Vec2 fx; fx << x1, x2; + double x2 = 10 * x(0) / (x(0) + 0.1) + 2 * x(1) * x(1); + Vec2 fx; + fx << x1, x2; return fx; } }; class JF32 { public: - JF32(const F32 &f) { (void) f; } - Mat2 operator()(const Vec2 &x) { - Mat2 J; J << 1, 0, - 1./pow(x(0) + 0.1, 2), 4*x(1)*x(1); + JF32(const F32& f) { (void)f; } + Mat2 operator()(const Vec2& x) { + Mat2 J; + J << 1, 0, 1. / pow(x(0) + 0.1, 2), 4 * x(1) * x(1); return J; } }; diff --git a/intern/libmv/libmv/numeric/function_derivative.h b/intern/libmv/libmv/numeric/function_derivative.h index 9820885f04e..30d7c4d34e9 100644 --- a/intern/libmv/libmv/numeric/function_derivative.h +++ b/intern/libmv/libmv/numeric/function_derivative.h @@ -23,8 +23,8 @@ #include -#include "libmv/numeric/numeric.h" #include "libmv/logging/logging.h" +#include "libmv/numeric/numeric.h" namespace libmv { @@ -36,7 +36,7 @@ enum NumericJacobianMode { FORWARD, }; -template +template class NumericJacobian { public: typedef typename Function::XMatrixType Parameters; @@ -45,12 +45,12 @@ class NumericJacobian { typedef Matrix - JMatrixType; + JMatrixType; - NumericJacobian(const Function &f) : f_(f) {} + NumericJacobian(const Function& f) : f_(f) {} // TODO(keir): Perhaps passing the jacobian back by value is not a good idea. - JMatrixType operator()(const Parameters &x) { + JMatrixType operator()(const Parameters& x) { // Empirically determined constant. Parameters eps = x.array().abs() * XScalar(1e-5); // To handle cases where a paremeter is exactly zero, instead use the mean @@ -87,12 +87,13 @@ class NumericJacobian { } return jacobian; } + private: - const Function &f_; + const Function& f_; }; -template -bool CheckJacobian(const Function &f, const typename Function::XMatrixType &x) { +template +bool CheckJacobian(const Function& f, const typename Function::XMatrixType& x) { Jacobian j_analytic(f); NumericJacobian j_numeric(f); diff --git a/intern/libmv/libmv/numeric/function_derivative_test.cc b/intern/libmv/libmv/numeric/function_derivative_test.cc index 8d976d3e9a0..defeedaa8a4 100644 --- a/intern/libmv/libmv/numeric/function_derivative_test.cc +++ b/intern/libmv/libmv/numeric/function_derivative_test.cc @@ -18,9 +18,9 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "testing/testing.h" -#include "libmv/numeric/numeric.h" #include "libmv/numeric/function_derivative.h" +#include "libmv/numeric/numeric.h" +#include "testing/testing.h" using namespace libmv; @@ -30,22 +30,22 @@ class F { public: typedef Vec2 FMatrixType; typedef Vec3 XMatrixType; - Vec2 operator()(const Vec3 &x) const { + Vec2 operator()(const Vec3& x) const { Vec2 fx; - fx << 0.19*x(0) + 0.19*x(1)*x(1) + x(2), - 3*sin(x(0)) + 2*cos(x(1)); + fx << 0.19 * x(0) + 0.19 * x(1) * x(1) + x(2), + 3 * sin(x(0)) + 2 * cos(x(1)); return fx; } - Mat23 J(const Vec3 &x) const { + Mat23 J(const Vec3& x) const { Mat23 jacobian; - jacobian << 0.19, 2*0.19*x(1), 1.0, - 3*cos(x(0)), -2*sin(x(1)), 0; + jacobian << 0.19, 2 * 0.19 * x(1), 1.0, 3 * cos(x(0)), -2 * sin(x(1)), 0; return jacobian; } }; TEST(FunctionDerivative, SimpleCase) { - Vec3 x; x << 0.76026643, 0.01799744, 0.55192142; + Vec3 x; + x << 0.76026643, 0.01799744, 0.55192142; F f; NumericJacobian J(f); EXPECT_MATRIX_NEAR(f.J(x), J(x), 1e-8); diff --git a/intern/libmv/libmv/numeric/levenberg_marquardt.h b/intern/libmv/libmv/numeric/levenberg_marquardt.h index 2af9a62cf7b..30c04a5ad5c 100644 --- a/intern/libmv/libmv/numeric/levenberg_marquardt.h +++ b/intern/libmv/libmv/numeric/levenberg_marquardt.h @@ -31,18 +31,18 @@ #include -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/function_derivative.h" #include "libmv/logging/logging.h" +#include "libmv/numeric/function_derivative.h" +#include "libmv/numeric/numeric.h" namespace libmv { -template, - typename Solver = Eigen::PartialPivLU< - Matrix > > +template , + typename Solver = Eigen::PartialPivLU< + Matrix>> class LevenbergMarquardt { public: typedef typename Function::XMatrixType::RealScalar Scalar; @@ -50,10 +50,12 @@ class LevenbergMarquardt { typedef typename Function::XMatrixType Parameters; typedef Matrix JMatrixType; + Function::XMatrixType::RowsAtCompileTime> + JMatrixType; typedef Matrix AMatrixType; + JMatrixType::ColsAtCompileTime> + AMatrixType; // TODO(keir): Some of these knobs can be derived from each other and // removed, instead of requiring the user to set them. @@ -65,32 +67,35 @@ class LevenbergMarquardt { HIT_MAX_ITERATIONS, }; - LevenbergMarquardt(const Function &f) - : f_(f), df_(f) {} + LevenbergMarquardt(const Function& f) : f_(f), df_(f) {} struct SolverParameters { SolverParameters() - : gradient_threshold(1e-16), - relative_step_threshold(1e-16), - error_threshold(1e-16), - initial_scale_factor(1e-3), - max_iterations(100) {} + : gradient_threshold(1e-16), + relative_step_threshold(1e-16), + error_threshold(1e-16), + initial_scale_factor(1e-3), + max_iterations(100) {} Scalar gradient_threshold; // eps > max(J'*f(x)) Scalar relative_step_threshold; // eps > ||dx|| / ||x|| Scalar error_threshold; // eps > ||f(x)|| Scalar initial_scale_factor; // Initial u for solving normal equations. - int max_iterations; // Maximum number of solver iterations. + int max_iterations; // Maximum number of solver iterations. }; struct Results { Scalar error_magnitude; // ||f(x)|| Scalar gradient_magnitude; // ||J'f(x)|| - int iterations; + int iterations; Status status; }; - Status Update(const Parameters &x, const SolverParameters ¶ms, - JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) { + Status Update(const Parameters& x, + const SolverParameters& params, + JMatrixType* J, + AMatrixType* A, + FVec* error, + Parameters* g) { *J = df_(x); *A = (*J).transpose() * (*J); *error = -f_(x); @@ -103,13 +108,13 @@ class LevenbergMarquardt { return RUNNING; } - Results minimize(Parameters *x_and_min) { + Results minimize(Parameters* x_and_min) { SolverParameters params; minimize(params, x_and_min); } - Results minimize(const SolverParameters ¶ms, Parameters *x_and_min) { - Parameters &x = *x_and_min; + Results minimize(const SolverParameters& params, Parameters* x_and_min) { + Parameters& x = *x_and_min; JMatrixType J; AMatrixType A; FVec error; @@ -118,7 +123,7 @@ class LevenbergMarquardt { Results results; results.status = Update(x, params, &J, &A, &error, &g); - Scalar u = Scalar(params.initial_scale_factor*A.diagonal().maxCoeff()); + Scalar u = Scalar(params.initial_scale_factor * A.diagonal().maxCoeff()); Scalar v = 2; Parameters dx, x_new; @@ -130,7 +135,8 @@ class LevenbergMarquardt { VLOG(3) << "u: " << u; VLOG(3) << "v: " << v; - AMatrixType A_augmented = A + u*AMatrixType::Identity(J.cols(), J.cols()); + AMatrixType A_augmented = + A + u * AMatrixType::Identity(J.cols(), J.cols()); Solver solver(A_augmented); dx = solver.solve(g); bool solved = (A_augmented * dx).isApprox(g); @@ -146,14 +152,14 @@ class LevenbergMarquardt { // Rho is the ratio of the actual reduction in error to the reduction // in error that would be obtained if the problem was linear. // See [1] for details. - Scalar rho((error.squaredNorm() - f_(x_new).squaredNorm()) - / dx.dot(u*dx + g)); + Scalar rho((error.squaredNorm() - f_(x_new).squaredNorm()) / + dx.dot(u * dx + g)); if (rho > 0) { // Accept the Gauss-Newton step because the linear model fits well. x = x_new; results.status = Update(x, params, &J, &A, &error, &g); - Scalar tmp = Scalar(2*rho-1); - u = u*std::max(1/3., 1 - (tmp*tmp*tmp)); + Scalar tmp = Scalar(2 * rho - 1); + u = u * std::max(1 / 3., 1 - (tmp * tmp * tmp)); v = 2; continue; } @@ -174,10 +180,10 @@ class LevenbergMarquardt { } private: - const Function &f_; + const Function& f_; Jacobian df_; }; -} // namespace mv +} // namespace libmv #endif // LIBMV_NUMERIC_LEVENBERG_MARQUARDT_H diff --git a/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc b/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc index fc3f9ebbb29..805aac275b4 100644 --- a/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc +++ b/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "testing/testing.h" #include "libmv/numeric/levenberg_marquardt.h" +#include "testing/testing.h" using namespace libmv; @@ -29,14 +29,12 @@ class F { public: typedef Vec4 FMatrixType; typedef Vec3 XMatrixType; - Vec4 operator()(const Vec3 &x) const { + Vec4 operator()(const Vec3& x) const { double x1 = x.x() - 2; double y1 = x.y() - 5; double z1 = x.z(); - Vec4 fx; fx << x1*x1 + z1*z1, - y1*y1 + z1*z1, - z1*z1, - x1*x1; + Vec4 fx; + fx << x1 * x1 + z1 * z1, y1 * y1 + z1 * z1, z1 * z1, x1 * x1; return fx; } }; diff --git a/intern/libmv/libmv/numeric/numeric.cc b/intern/libmv/libmv/numeric/numeric.cc index 3fc1e3b2bfd..b7660950c2a 100644 --- a/intern/libmv/libmv/numeric/numeric.cc +++ b/intern/libmv/libmv/numeric/numeric.cc @@ -18,7 +18,6 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. - #include "libmv/numeric/numeric.h" namespace libmv { @@ -27,9 +26,11 @@ Mat3 RotationAroundX(double angle) { double c, s; sincos(angle, &s, &c); Mat3 R; + // clang-format off R << 1, 0, 0, 0, c, -s, 0, s, c; + // clang-format on return R; } @@ -37,9 +38,11 @@ Mat3 RotationAroundY(double angle) { double c, s; sincos(angle, &s, &c); Mat3 R; + // clang-format off R << c, 0, s, 0, 1, 0, -s, 0, c; + // clang-format on return R; } @@ -47,14 +50,15 @@ Mat3 RotationAroundZ(double angle) { double c, s; sincos(angle, &s, &c); Mat3 R; + // clang-format off R << c, -s, 0, s, c, 0, 0, 0, 1; + // clang-format on return R; } - -Mat3 RotationRodrigues(const Vec3 &axis) { +Mat3 RotationRodrigues(const Vec3& axis) { double theta = axis.norm(); Vec3 w = axis / theta; Mat3 W = CrossProductMatrix(w); @@ -62,7 +66,6 @@ Mat3 RotationRodrigues(const Vec3 &axis) { return Mat3::Identity() + sin(theta) * W + (1 - cos(theta)) * W * W; } - Mat3 LookAt(Vec3 center) { Vec3 zc = center.normalized(); Vec3 xc = Vec3::UnitY().cross(zc).normalized(); @@ -74,19 +77,21 @@ Mat3 LookAt(Vec3 center) { return R; } -Mat3 CrossProductMatrix(const Vec3 &x) { +Mat3 CrossProductMatrix(const Vec3& x) { Mat3 X; + // clang-format off X << 0, -x(2), x(1), x(2), 0, -x(0), -x(1), x(0), 0; + // clang-format on return X; } -void MeanAndVarianceAlongRows(const Mat &A, - Vec *mean_pointer, - Vec *variance_pointer) { - Vec &mean = *mean_pointer; - Vec &variance = *variance_pointer; +void MeanAndVarianceAlongRows(const Mat& A, + Vec* mean_pointer, + Vec* variance_pointer) { + Vec& mean = *mean_pointer; + Vec& variance = *variance_pointer; int n = A.rows(); int m = A.cols(); mean.resize(n); @@ -108,29 +113,28 @@ void MeanAndVarianceAlongRows(const Mat &A, } } -void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked) { +void HorizontalStack(const Mat& left, const Mat& right, Mat* stacked) { assert(left.rows() == right.rows()); int n = left.rows(); int m1 = left.cols(); int m2 = right.cols(); stacked->resize(n, m1 + m2); - stacked->block(0, 0, n, m1) = left; + stacked->block(0, 0, n, m1) = left; stacked->block(0, m1, n, m2) = right; } -void MatrixColumn(const Mat &A, int i, Vec2 *v) { +void MatrixColumn(const Mat& A, int i, Vec2* v) { assert(A.rows() == 2); *v << A(0, i), A(1, i); } -void MatrixColumn(const Mat &A, int i, Vec3 *v) { +void MatrixColumn(const Mat& A, int i, Vec3* v) { assert(A.rows() == 3); *v << A(0, i), A(1, i), A(2, i); } -void MatrixColumn(const Mat &A, int i, Vec4 *v) { +void MatrixColumn(const Mat& A, int i, Vec4* v) { assert(A.rows() == 4); *v << A(0, i), A(1, i), A(2, i), A(3, i); } } // namespace libmv - diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h index f5478bee6ab..e3d44226338 100644 --- a/intern/libmv/libmv/numeric/numeric.h +++ b/intern/libmv/libmv/numeric/numeric.h @@ -34,10 +34,9 @@ #include #if !defined(__MINGW64__) -# if defined(_WIN32) || defined(__APPLE__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__HAIKU__) -inline void sincos(double x, double *sinx, double *cosx) { +# if defined(_WIN32) || defined(__APPLE__) || defined(__FreeBSD__) || \ + defined(__NetBSD__) || defined(__HAIKU__) +inline void sincos(double x, double* sinx, double* cosx) { *sinx = sin(x); *cosx = cos(x); } @@ -46,11 +45,11 @@ inline void sincos(double x, double *sinx, double *cosx) { #if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__) inline long lround(double d) { - return (long)(d>0 ? d+0.5 : ceil(d-0.5)); + return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5)); } # if _MSC_VER < 1800 inline int round(double d) { - return (d>0) ? int(d+0.5) : int(d-0.5); + return (d > 0) ? int(d + 0.5) : int(d - 0.5); } # endif // _MSC_VER < 1800 typedef unsigned int uint; @@ -92,25 +91,25 @@ typedef Eigen::Matrix RMat4; typedef Eigen::Matrix Mat2X; typedef Eigen::Matrix Mat3X; typedef Eigen::Matrix Mat4X; -typedef Eigen::Matrix MatX2; -typedef Eigen::Matrix MatX3; -typedef Eigen::Matrix MatX4; -typedef Eigen::Matrix MatX5; -typedef Eigen::Matrix MatX6; -typedef Eigen::Matrix MatX7; -typedef Eigen::Matrix MatX8; -typedef Eigen::Matrix MatX9; +typedef Eigen::Matrix MatX2; +typedef Eigen::Matrix MatX3; +typedef Eigen::Matrix MatX4; +typedef Eigen::Matrix MatX5; +typedef Eigen::Matrix MatX6; +typedef Eigen::Matrix MatX7; +typedef Eigen::Matrix MatX8; +typedef Eigen::Matrix MatX9; typedef Eigen::Matrix MatX15; typedef Eigen::Matrix MatX16; typedef Eigen::Vector2d Vec2; typedef Eigen::Vector3d Vec3; typedef Eigen::Vector4d Vec4; -typedef Eigen::Matrix Vec5; -typedef Eigen::Matrix Vec6; -typedef Eigen::Matrix Vec7; -typedef Eigen::Matrix Vec8; -typedef Eigen::Matrix Vec9; +typedef Eigen::Matrix Vec5; +typedef Eigen::Matrix Vec6; +typedef Eigen::Matrix Vec7; +typedef Eigen::Matrix Vec8; +typedef Eigen::Matrix Vec9; typedef Eigen::Matrix Vec10; typedef Eigen::Matrix Vec11; typedef Eigen::Matrix Vec12; @@ -133,15 +132,13 @@ typedef Eigen::Vector2i Vec2i; typedef Eigen::Vector3i Vec3i; typedef Eigen::Vector4i Vec4i; -typedef Eigen::Matrix RMatf; +typedef Eigen::Matrix + RMatf; typedef Eigen::NumTraits EigenDouble; -using Eigen::Map; using Eigen::Dynamic; +using Eigen::Map; using Eigen::Matrix; // Find U, s, and VT such that @@ -149,7 +146,7 @@ using Eigen::Matrix; // A = U * diag(s) * VT // template -inline void SVD(TMat * /*A*/, Vec * /*s*/, Mat * /*U*/, Mat * /*VT*/) { +inline void SVD(TMat* /*A*/, Vec* /*s*/, Mat* /*U*/, Mat* /*VT*/) { assert(0); } @@ -158,11 +155,11 @@ inline void SVD(TMat * /*A*/, Vec * /*s*/, Mat * /*U*/, Mat * /*VT*/) { // Destroys A and resizes x if necessary. // TODO(maclean): Take the SVD of the transpose instead of this zero padding. template -double Nullspace(TMat *A, TVec *nullspace) { +double Nullspace(TMat* A, TVec* nullspace) { Eigen::JacobiSVD svd(*A, Eigen::ComputeFullV); - (*nullspace) = svd.matrixV().col(A->cols()-1); + (*nullspace) = svd.matrixV().col(A->cols() - 1); if (A->rows() >= A->cols()) - return svd.singularValues()(A->cols()-1); + return svd.singularValues()(A->cols() - 1); else return 0.0; } @@ -173,55 +170,55 @@ double Nullspace(TMat *A, TVec *nullspace) { // the singluar value corresponding to the solution x1. Destroys A and resizes // x if necessary. template -double Nullspace2(TMat *A, TVec1 *x1, TVec2 *x2) { +double Nullspace2(TMat* A, TVec1* x1, TVec2* x2) { Eigen::JacobiSVD svd(*A, Eigen::ComputeFullV); *x1 = svd.matrixV().col(A->cols() - 1); *x2 = svd.matrixV().col(A->cols() - 2); if (A->rows() >= A->cols()) - return svd.singularValues()(A->cols()-1); + return svd.singularValues()(A->cols() - 1); else return 0.0; } // In place transpose for square matrices. -template -inline void TransposeInPlace(TA *A) { +template +inline void TransposeInPlace(TA* A) { *A = A->transpose().eval(); } -template -inline double NormL1(const TVec &x) { +template +inline double NormL1(const TVec& x) { return x.array().abs().sum(); } -template -inline double NormL2(const TVec &x) { +template +inline double NormL2(const TVec& x) { return x.norm(); } -template -inline double NormLInfinity(const TVec &x) { +template +inline double NormLInfinity(const TVec& x) { return x.array().abs().maxCoeff(); } -template -inline double DistanceL1(const TVec &x, const TVec &y) { +template +inline double DistanceL1(const TVec& x, const TVec& y) { return (x - y).array().abs().sum(); } -template -inline double DistanceL2(const TVec &x, const TVec &y) { +template +inline double DistanceL2(const TVec& x, const TVec& y) { return (x - y).norm(); } -template -inline double DistanceLInfinity(const TVec &x, const TVec &y) { +template +inline double DistanceLInfinity(const TVec& x, const TVec& y) { return (x - y).array().abs().maxCoeff(); } // Normalize a vector with the L1 norm, and return the norm before it was // normalized. -template -inline double NormalizeL1(TVec *x) { +template +inline double NormalizeL1(TVec* x) { double norm = NormL1(*x); *x /= norm; return norm; @@ -229,8 +226,8 @@ inline double NormalizeL1(TVec *x) { // Normalize a vector with the L2 norm, and return the norm before it was // normalized. -template -inline double NormalizeL2(TVec *x) { +template +inline double NormalizeL2(TVec* x) { double norm = NormL2(*x); *x /= norm; return norm; @@ -238,15 +235,15 @@ inline double NormalizeL2(TVec *x) { // Normalize a vector with the L^Infinity norm, and return the norm before it // was normalized. -template -inline double NormalizeLInfinity(TVec *x) { +template +inline double NormalizeLInfinity(TVec* x) { double norm = NormLInfinity(*x); *x /= norm; return norm; } // Return the square of a number. -template +template inline T Square(T x) { return x * x; } @@ -258,7 +255,7 @@ Mat3 RotationAroundZ(double angle); // Returns the rotation matrix of a rotation of angle |axis| around axis. // This is computed using the Rodrigues formula, see: // http://mathworld.wolfram.com/RodriguesRotationFormula.html -Mat3 RotationRodrigues(const Vec3 &axis); +Mat3 RotationRodrigues(const Vec3& axis); // Make a rotation matrix such that center becomes the direction of the // positive z-axis, and y is oriented close to up. @@ -266,177 +263,173 @@ Mat3 LookAt(Vec3 center); // Return a diagonal matrix from a vector containg the diagonal values. template -inline Mat Diag(const TVec &x) { +inline Mat Diag(const TVec& x) { return x.asDiagonal(); } -template -inline double FrobeniusNorm(const TMat &A) { +template +inline double FrobeniusNorm(const TMat& A) { return sqrt(A.array().abs2().sum()); } -template -inline double FrobeniusDistance(const TMat &A, const TMat &B) { +template +inline double FrobeniusDistance(const TMat& A, const TMat& B) { return FrobeniusNorm(A - B); } -inline Vec3 CrossProduct(const Vec3 &x, const Vec3 &y) { +inline Vec3 CrossProduct(const Vec3& x, const Vec3& y) { return x.cross(y); } -Mat3 CrossProductMatrix(const Vec3 &x); +Mat3 CrossProductMatrix(const Vec3& x); -void MeanAndVarianceAlongRows(const Mat &A, - Vec *mean_pointer, - Vec *variance_pointer); +void MeanAndVarianceAlongRows(const Mat& A, + Vec* mean_pointer, + Vec* variance_pointer); #if defined(_WIN32) - // TODO(bomboze): un-#if this for both platforms once tested under Windows - /* This solution was extensively discussed here - http://forum.kde.org/viewtopic.php?f=74&t=61940 */ - #define SUM_OR_DYNAMIC(x, y) (x == Eigen::Dynamic || y == Eigen::Dynamic) ? Eigen::Dynamic : (x+y) - - template - struct hstack_return { - typedef typename Derived1::Scalar Scalar; - enum { - RowsAtCompileTime = Derived1::RowsAtCompileTime, - ColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::ColsAtCompileTime, - Derived2::ColsAtCompileTime), - Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0, - MaxRowsAtCompileTime = Derived1::MaxRowsAtCompileTime, - MaxColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxColsAtCompileTime, - Derived2::MaxColsAtCompileTime) - }; - typedef Eigen::Matrix type; +// TODO(bomboze): un-#if this for both platforms once tested under Windows +/* This solution was extensively discussed here + http://forum.kde.org/viewtopic.php?f=74&t=61940 */ +# define SUM_OR_DYNAMIC(x, y) \ + (x == Eigen::Dynamic || y == Eigen::Dynamic) ? Eigen::Dynamic : (x + y) + +template +struct hstack_return { + typedef typename Derived1::Scalar Scalar; + enum { + RowsAtCompileTime = Derived1::RowsAtCompileTime, + ColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::ColsAtCompileTime, + Derived2::ColsAtCompileTime), + Options = Derived1::Flags & Eigen::RowMajorBit ? Eigen::RowMajor : 0, + MaxRowsAtCompileTime = Derived1::MaxRowsAtCompileTime, + MaxColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxColsAtCompileTime, + Derived2::MaxColsAtCompileTime) }; - - template - typename hstack_return::type - HStack(const Eigen::MatrixBase& lhs, - const Eigen::MatrixBase& rhs) { - typename hstack_return::type res; - res.resize(lhs.rows(), lhs.cols()+rhs.cols()); - res << lhs, rhs; - return res; - }; - - - template - struct vstack_return { - typedef typename Derived1::Scalar Scalar; - enum { - RowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::RowsAtCompileTime, - Derived2::RowsAtCompileTime), - ColsAtCompileTime = Derived1::ColsAtCompileTime, - Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0, - MaxRowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxRowsAtCompileTime, - Derived2::MaxRowsAtCompileTime), - MaxColsAtCompileTime = Derived1::MaxColsAtCompileTime - }; - typedef Eigen::Matrix type; + typedef Eigen::Matrix + type; +}; + +template +typename hstack_return::type HStack( + const Eigen::MatrixBase& lhs, + const Eigen::MatrixBase& rhs) { + typename hstack_return::type res; + res.resize(lhs.rows(), lhs.cols() + rhs.cols()); + res << lhs, rhs; + return res; +}; + +template +struct vstack_return { + typedef typename Derived1::Scalar Scalar; + enum { + RowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::RowsAtCompileTime, + Derived2::RowsAtCompileTime), + ColsAtCompileTime = Derived1::ColsAtCompileTime, + Options = Derived1::Flags & Eigen::RowMajorBit ? Eigen::RowMajor : 0, + MaxRowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxRowsAtCompileTime, + Derived2::MaxRowsAtCompileTime), + MaxColsAtCompileTime = Derived1::MaxColsAtCompileTime }; - - template - typename vstack_return::type - VStack(const Eigen::MatrixBase& lhs, - const Eigen::MatrixBase& rhs) { - typename vstack_return::type res; - res.resize(lhs.rows()+rhs.rows(), lhs.cols()); - res << lhs, rhs; - return res; - }; - + typedef Eigen::Matrix + type; +}; + +template +typename vstack_return::type VStack( + const Eigen::MatrixBase& lhs, + const Eigen::MatrixBase& rhs) { + typename vstack_return::type res; + res.resize(lhs.rows() + rhs.rows(), lhs.cols()); + res << lhs, rhs; + return res; +}; #else // _WIN32 - // Since it is not possible to typedef privately here, use a macro. - // Always take dynamic columns if either side is dynamic. - #define COLS \ - ((ColsLeft == Eigen::Dynamic || ColsRight == Eigen::Dynamic) \ - ? Eigen::Dynamic : (ColsLeft + ColsRight)) - - // Same as above, except that prefer fixed size if either is fixed. - #define ROWS \ - ((RowsLeft == Eigen::Dynamic && RowsRight == Eigen::Dynamic) \ - ? Eigen::Dynamic \ - : ((RowsLeft == Eigen::Dynamic) \ - ? RowsRight \ - : RowsLeft \ - ) \ - ) - - // TODO(keir): Add a static assert if both rows are at compiletime. - template - Eigen::Matrix - HStack(const Eigen::Matrix &left, - const Eigen::Matrix &right) { - assert(left.rows() == right.rows()); - int n = left.rows(); - int m1 = left.cols(); - int m2 = right.cols(); - - Eigen::Matrix stacked(n, m1 + m2); - stacked.block(0, 0, n, m1) = left; - stacked.block(0, m1, n, m2) = right; - return stacked; - } - - // Reuse the above macros by swapping the order of Rows and Cols. Nasty, but - // the duplication is worse. - // TODO(keir): Add a static assert if both rows are at compiletime. - // TODO(keir): Mail eigen list about making this work for general expressions - // rather than only matrix types. - template - Eigen::Matrix - VStack(const Eigen::Matrix &top, - const Eigen::Matrix &bottom) { - assert(top.cols() == bottom.cols()); - int n1 = top.rows(); - int n2 = bottom.rows(); - int m = top.cols(); - - Eigen::Matrix stacked(n1 + n2, m); - stacked.block(0, 0, n1, m) = top; - stacked.block(n1, 0, n2, m) = bottom; - return stacked; - } - #undef COLS - #undef ROWS -#endif // _WIN32 +// Since it is not possible to typedef privately here, use a macro. +// Always take dynamic columns if either side is dynamic. +# define COLS \ + ((ColsLeft == Eigen::Dynamic || ColsRight == Eigen::Dynamic) \ + ? Eigen::Dynamic \ + : (ColsLeft + ColsRight)) + +// Same as above, except that prefer fixed size if either is fixed. +# define ROWS \ + ((RowsLeft == Eigen::Dynamic && RowsRight == Eigen::Dynamic) \ + ? Eigen::Dynamic \ + : ((RowsLeft == Eigen::Dynamic) ? RowsRight : RowsLeft)) + +// TODO(keir): Add a static assert if both rows are at compiletime. +template +Eigen::Matrix HStack( + const Eigen::Matrix& left, + const Eigen::Matrix& right) { + assert(left.rows() == right.rows()); + int n = left.rows(); + int m1 = left.cols(); + int m2 = right.cols(); + + Eigen::Matrix stacked(n, m1 + m2); + stacked.block(0, 0, n, m1) = left; + stacked.block(0, m1, n, m2) = right; + return stacked; +} +// Reuse the above macros by swapping the order of Rows and Cols. Nasty, but +// the duplication is worse. +// TODO(keir): Add a static assert if both rows are at compiletime. +// TODO(keir): Mail eigen list about making this work for general expressions +// rather than only matrix types. +template +Eigen::Matrix VStack( + const Eigen::Matrix& top, + const Eigen::Matrix& bottom) { + assert(top.cols() == bottom.cols()); + int n1 = top.rows(); + int n2 = bottom.rows(); + int m = top.cols(); + Eigen::Matrix stacked(n1 + n2, m); + stacked.block(0, 0, n1, m) = top; + stacked.block(n1, 0, n2, m) = bottom; + return stacked; +} +# undef COLS +# undef ROWS +#endif // _WIN32 -void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked); +void HorizontalStack(const Mat& left, const Mat& right, Mat* stacked); -template -void VerticalStack(const TTop &top, const TBot &bottom, TStacked *stacked) { +template +void VerticalStack(const TTop& top, const TBot& bottom, TStacked* stacked) { assert(top.cols() == bottom.cols()); int n1 = top.rows(); int n2 = bottom.rows(); int m = top.cols(); stacked->resize(n1 + n2, m); - stacked->block(0, 0, n1, m) = top; + stacked->block(0, 0, n1, m) = top; stacked->block(n1, 0, n2, m) = bottom; } -void MatrixColumn(const Mat &A, int i, Vec2 *v); -void MatrixColumn(const Mat &A, int i, Vec3 *v); -void MatrixColumn(const Mat &A, int i, Vec4 *v); +void MatrixColumn(const Mat& A, int i, Vec2* v); +void MatrixColumn(const Mat& A, int i, Vec3* v); +void MatrixColumn(const Mat& A, int i, Vec4* v); template -TMat ExtractColumns(const TMat &A, const TCols &columns) { +TMat ExtractColumns(const TMat& A, const TCols& columns) { TMat compressed(A.rows(), columns.size()); for (int i = 0; i < columns.size(); ++i) { compressed.col(i) = A.col(columns[i]); @@ -445,12 +438,12 @@ TMat ExtractColumns(const TMat &A, const TCols &columns) { } template -void reshape(const TMat &a, int rows, int cols, TDest *b) { - assert(a.rows()*a.cols() == rows*cols); +void reshape(const TMat& a, int rows, int cols, TDest* b) { + assert(a.rows() * a.cols() == rows * cols); b->resize(rows, cols); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { - (*b)(i, j) = a[cols*i + j]; + (*b)(i, j) = a[cols * i + j]; } } } @@ -467,24 +460,21 @@ inline bool isnan(double i) { /// and negative values template FloatType ceil0(const FloatType& value) { - FloatType result = std::ceil(std::fabs(value)); - return (value < 0.0) ? -result : result; + FloatType result = std::ceil(std::fabs(value)); + return (value < 0.0) ? -result : result; } /// Returns the skew anti-symmetric matrix of a vector -inline Mat3 SkewMat(const Vec3 &x) { +inline Mat3 SkewMat(const Vec3& x) { Mat3 skew; - skew << 0 , -x(2), x(1), - x(2), 0 , -x(0), - -x(1), x(0), 0; + skew << 0, -x(2), x(1), x(2), 0, -x(0), -x(1), x(0), 0; return skew; } /// Returns the skew anti-symmetric matrix of a vector with only /// the first two (independent) lines -inline Mat23 SkewMatMinimal(const Vec2 &x) { +inline Mat23 SkewMatMinimal(const Vec2& x) { Mat23 skew; - skew << 0, -1, x(1), - 1, 0, -x(0); + skew << 0, -1, x(1), 1, 0, -x(0); return skew; } @@ -496,7 +486,8 @@ inline Mat3 RotationFromEulerVector(Vec3 euler_vector) { } Vec3 w = euler_vector / theta; Mat3 w_hat = CrossProductMatrix(w); - return Mat3::Identity() + w_hat*sin(theta) + w_hat*w_hat*(1 - cos(theta)); + return Mat3::Identity() + w_hat * sin(theta) + + w_hat * w_hat * (1 - cos(theta)); } } // namespace libmv diff --git a/intern/libmv/libmv/numeric/numeric_test.cc b/intern/libmv/libmv/numeric/numeric_test.cc index 0cdfaf33ab2..b2650a04658 100644 --- a/intern/libmv/libmv/numeric/numeric_test.cc +++ b/intern/libmv/libmv/numeric/numeric_test.cc @@ -27,9 +27,11 @@ namespace { TEST(Numeric, DynamicSizedNullspace) { Mat A(3, 4); + // clang-format off A << 0.76026643, 0.01799744, 0.55192142, 0.8699745, 0.42016166, 0.97863392, 0.33711682, 0.14479271, 0.51016811, 0.66528302, 0.54395496, 0.57794893; + // clang-format on Vec x; double s = Nullspace(&A, &x); EXPECT_NEAR(0.0, s, 1e-15); @@ -39,9 +41,11 @@ TEST(Numeric, DynamicSizedNullspace) { TEST(Numeric, FixedSizeMatrixNullspace) { Mat34 A; + // clang-format off A << 0.76026643, 0.01799744, 0.55192142, 0.8699745, 0.42016166, 0.97863392, 0.33711682, 0.14479271, 0.51016811, 0.66528302, 0.54395496, 0.57794893; + // clang-format on Vec x; double s = Nullspace(&A, &x); EXPECT_NEAR(0.0, s, 1e-15); @@ -51,10 +55,12 @@ TEST(Numeric, FixedSizeMatrixNullspace) { TEST(Numeric, NullspaceMatchesLapackSVD) { Mat43 A; + // clang-format off A << 0.76026643, 0.01799744, 0.55192142, 0.8699745, 0.42016166, 0.97863392, 0.33711682, 0.14479271, 0.51016811, 0.66528302, 0.54395496, 0.57794893; + // clang-format on Vec x; double s = Nullspace(&A, &x); EXPECT_NEAR(1.0, x.norm(), 1e-15); @@ -68,10 +74,12 @@ TEST(Numeric, NullspaceMatchesLapackSVD) { TEST(Numeric, Nullspace2) { Mat43 A; + // clang-format off A << 0.76026643, 0.01799744, 0.55192142, 0.8699745, 0.42016166, 0.97863392, 0.33711682, 0.14479271, 0.51016811, 0.66528302, 0.54395496, 0.57794893; + // clang-format on Vec3 x1, x2; double s = Nullspace2(&A, &x1, &x2); EXPECT_NEAR(1.0, x1.norm(), 1e-15); @@ -80,14 +88,14 @@ TEST(Numeric, Nullspace2) { EXPECT_NEAR(-0.64999717, x1(0), 1e-8); EXPECT_NEAR(-0.18452646, x1(1), 1e-8); - EXPECT_NEAR( 0.7371931, x1(2), 1e-8); + EXPECT_NEAR(0.7371931, x1(2), 1e-8); if (x2(0) < 0) { x2 *= -1; } - EXPECT_NEAR( 0.34679618, x2(0), 1e-8); + EXPECT_NEAR(0.34679618, x2(0), 1e-8); EXPECT_NEAR(-0.93519689, x2(1), 1e-8); - EXPECT_NEAR( 0.07168809, x2(2), 1e-8); + EXPECT_NEAR(0.07168809, x2(2), 1e-8); } TEST(Numeric, TinyMatrixSquareTranspose) { @@ -105,8 +113,8 @@ TEST(Numeric, NormalizeL1) { x << 1, 2; double l1 = NormalizeL1(&x); EXPECT_DOUBLE_EQ(3., l1); - EXPECT_DOUBLE_EQ(1./3., x(0)); - EXPECT_DOUBLE_EQ(2./3., x(1)); + EXPECT_DOUBLE_EQ(1. / 3., x(0)); + EXPECT_DOUBLE_EQ(2. / 3., x(1)); } TEST(Numeric, NormalizeL2) { @@ -114,8 +122,8 @@ TEST(Numeric, NormalizeL2) { x << 1, 2; double l2 = NormalizeL2(&x); EXPECT_DOUBLE_EQ(sqrt(5.0), l2); - EXPECT_DOUBLE_EQ(1./sqrt(5.), x(0)); - EXPECT_DOUBLE_EQ(2./sqrt(5.), x(1)); + EXPECT_DOUBLE_EQ(1. / sqrt(5.), x(0)); + EXPECT_DOUBLE_EQ(2. / sqrt(5.), x(1)); } TEST(Numeric, Diag) { @@ -130,31 +138,32 @@ TEST(Numeric, Diag) { TEST(Numeric, Determinant) { Mat A(2, 2); - A << 1, 2, - -1, 3; + A << 1, 2, -1, 3; double detA = A.determinant(); EXPECT_NEAR(5, detA, 1e-8); Mat B(4, 4); + // clang-format off B << 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15; + // clang-format on double detB = B.determinant(); EXPECT_NEAR(0, detB, 1e-8); Mat3 C; - C << 0, 1, 2, - 3, 4, 5, - 6, 7, 1; + C << 0, 1, 2, 3, 4, 5, 6, 7, 1; double detC = C.determinant(); EXPECT_NEAR(21, detC, 1e-8); } TEST(Numeric, Inverse) { Mat A(2, 2), A1; + // clang-format off A << 1, 2, -1, 3; + // clang-format on Mat I = A * A.inverse(); EXPECT_NEAR(1, I(0, 0), 1e-8); @@ -163,10 +172,12 @@ TEST(Numeric, Inverse) { EXPECT_NEAR(1, I(1, 1), 1e-8); Mat B(4, 4), B1; + // clang-format off B << 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 2, 11, 12, 13, 14, 4; + // clang-format on Mat I2 = B * B.inverse(); EXPECT_NEAR(1, I2(0, 0), 1e-8); EXPECT_NEAR(0, I2(0, 1), 1e-8); @@ -182,8 +193,10 @@ TEST(Numeric, Inverse) { TEST(Numeric, MeanAndVarianceAlongRows) { int n = 4; Mat points(2, n); + // clang-format off points << 0, 0, 1, 1, 0, 2, 1, 3; + // clang-format on Vec mean, variance; MeanAndVarianceAlongRows(points, &mean, &variance); @@ -213,15 +226,17 @@ TEST(Numeric, HStack) { Mat x(2, 1), y(2, 1), z(2, 2); x << 1, 2; y << 3, 4; + // clang-format off z << 1, 3, 2, 4; + // clang-format on Vec2 xC = x, yC = y; - Mat2 xy = HStack(x, y); + Mat2 xy = HStack(x, y); EXPECT_MATRIX_EQ(z, xy); - EXPECT_MATRIX_EQ(z, HStack(x, y)); - EXPECT_MATRIX_EQ(z, HStack(x, yC)); + EXPECT_MATRIX_EQ(z, HStack(x, y)); + EXPECT_MATRIX_EQ(z, HStack(x, yC)); EXPECT_MATRIX_EQ(z, HStack(xC, y)); EXPECT_MATRIX_EQ(z, HStack(xC, yC)); } @@ -230,6 +245,7 @@ TEST(Numeric, HStack) { // resulting stacked matrices properly propagate the fixed dimensions. TEST(Numeric, VStack) { Mat x(2, 2), y(2, 2), z(4, 2); + // clang-format off x << 1, 2, 3, 4; y << 10, 20, @@ -238,13 +254,14 @@ TEST(Numeric, VStack) { 3, 4, 10, 20, 30, 40; + // clang-format on Mat2 xC = x, yC = y; - Mat xy = VStack(x, y); + Mat xy = VStack(x, y); EXPECT_MATRIX_EQ(z, xy); - EXPECT_MATRIX_EQ(z, VStack(x, y)); - EXPECT_MATRIX_EQ(z, VStack(x, yC)); + EXPECT_MATRIX_EQ(z, VStack(x, y)); + EXPECT_MATRIX_EQ(z, VStack(x, yC)); EXPECT_MATRIX_EQ(z, VStack(xC, y)); EXPECT_MATRIX_EQ(z, VStack(xC, yC)); } @@ -293,17 +310,21 @@ TEST(Numeric, CrossProductMatrix) { TEST(Numeric, MatrixColumn) { Mat A2(2, 3); Vec2 v2; + // clang-format off A2 << 1, 2, 3, 4, 5, 6; + // clang-format on MatrixColumn(A2, 1, &v2); EXPECT_EQ(2, v2(0)); EXPECT_EQ(5, v2(1)); Mat A3(3, 3); Vec3 v3; + // clang-format off A3 << 1, 2, 3, 4, 5, 6, 7, 8, 9; + // clang-format on MatrixColumn(A3, 1, &v3); EXPECT_EQ(2, v3(0)); EXPECT_EQ(5, v3(1)); @@ -311,14 +332,16 @@ TEST(Numeric, MatrixColumn) { Mat A4(4, 3); Vec4 v4; + // clang-format off A4 << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12; + // clang-format on MatrixColumn(A4, 1, &v4); - EXPECT_EQ( 2, v4(0)); - EXPECT_EQ( 5, v4(1)); - EXPECT_EQ( 8, v4(2)); + EXPECT_EQ(2, v4(0)); + EXPECT_EQ(5, v4(1)); + EXPECT_EQ(8, v4(2)); EXPECT_EQ(11, v4(3)); } @@ -337,7 +360,8 @@ TEST(Numeric, Mat3MatProduct) { // This gives a compile error. TEST(Numeric, Vec3Negative) { - Vec3 y; y << 1, 2, 3; + Vec3 y; + y << 1, 2, 3; Vec3 x = -y; EXPECT_EQ(-1, x(0)); EXPECT_EQ(-2, x(1)); @@ -357,19 +381,23 @@ TEST(Numeric, Vec3VecInteroperability) { // This segfaults inside lapack. TEST(Numeric, DeterminantLU7) { Mat A(5, 5); + // clang-format off A << 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1; + // clang-format on EXPECT_NEAR(1, A.determinant(), 1e-8); } // This segfaults inside lapack. TEST(Numeric, DeterminantLU) { Mat A(2, 2); + // clang-format off A << 1, 2, -1, 3; + // clang-format on EXPECT_NEAR(5, A.determinant(), 1e-8); } @@ -377,19 +405,24 @@ TEST(Numeric, DeterminantLU) { // Keir: Not with eigen2! TEST(Numeric, InplaceProduct) { Mat2 K, S; + // clang-format off K << 1, 0, 0, 1; S << 1, 0, 0, 1; K = K * S; + // clang-format on EXPECT_MATRIX_NEAR(Mat2::Identity(), K, 1e-8); } TEST(Numeric, ExtractColumns) { Mat2X A(2, 5); + // clang-format off A << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; - Vec2i columns; columns << 0, 2; + // clang-format on + Vec2i columns; + columns << 0, 2; Mat2X extracted = ExtractColumns(A, columns); EXPECT_NEAR(1, extracted(0, 0), 1e-15); EXPECT_NEAR(3, extracted(0, 1), 1e-15); @@ -418,21 +451,22 @@ TEST(Numeric, RotationRodrigues) { TEST(Numeric, LookAt) { // Simple orthogonality check. - Vec3 e; e << 1, 2, 3; + Vec3 e; + e << 1, 2, 3; Mat3 R = LookAt(e), I = Mat3::Identity(); - Mat3 RRT = R*R.transpose(); - Mat3 RTR = R.transpose()*R; + Mat3 RRT = R * R.transpose(); + Mat3 RTR = R.transpose() * R; EXPECT_MATRIX_NEAR(I, RRT, 1e-15); EXPECT_MATRIX_NEAR(I, RTR, 1e-15); } TEST(Numeric, Reshape) { - Vec4 x; x << 1, 2, 3, 4; + Vec4 x; + x << 1, 2, 3, 4; Mat2 M, M_expected; reshape(x, 2, 2, &M); - M_expected << 1, 2, - 3, 4; + M_expected << 1, 2, 3, 4; EXPECT_MATRIX_NEAR(M_expected, M, 1e-15); } diff --git a/intern/libmv/libmv/numeric/poly.h b/intern/libmv/libmv/numeric/poly.h index 76ba062d475..a3d3801a399 100644 --- a/intern/libmv/libmv/numeric/poly.h +++ b/intern/libmv/libmv/numeric/poly.h @@ -21,8 +21,8 @@ #ifndef LIBMV_NUMERIC_POLY_H_ #define LIBMV_NUMERIC_POLY_H_ -#include #include +#include namespace libmv { @@ -35,9 +35,8 @@ namespace libmv { // if there are 2 roots, only x0 and x1 are set. // // The GSL cubic solver was used as a reference for this routine. -template -int SolveCubicPolynomial(Real a, Real b, Real c, - Real *x0, Real *x1, Real *x2) { +template +int SolveCubicPolynomial(Real a, Real b, Real c, Real* x0, Real* x1, Real* x2) { Real q = a * a - 3 * b; Real r = 2 * a * a * a - 9 * a * b + 27 * c; @@ -65,12 +64,12 @@ int SolveCubicPolynomial(Real a, Real b, Real c, Real sqrtQ = sqrt(Q); if (R > 0) { *x0 = -2 * sqrtQ - a / 3; - *x1 = sqrtQ - a / 3; - *x2 = sqrtQ - a / 3; + *x1 = sqrtQ - a / 3; + *x2 = sqrtQ - a / 3; } else { - *x0 = -sqrtQ - a / 3; - *x1 = -sqrtQ - a / 3; - *x2 = 2 * sqrtQ - a / 3; + *x0 = -sqrtQ - a / 3; + *x1 = -sqrtQ - a / 3; + *x2 = 2 * sqrtQ - a / 3; } return 3; @@ -97,15 +96,15 @@ int SolveCubicPolynomial(Real a, Real b, Real c, return 3; } Real sgnR = (R >= 0 ? 1 : -1); - Real A = -sgnR * pow(fabs(R) + sqrt(R2 - Q3), 1.0/3.0); + Real A = -sgnR * pow(fabs(R) + sqrt(R2 - Q3), 1.0 / 3.0); Real B = Q / A; *x0 = A + B - a / 3; return 1; } // The coefficients are in ascending powers, i.e. coeffs[N]*x^N. -template -int SolveCubicPolynomial(const Real *coeffs, Real *solutions) { +template +int SolveCubicPolynomial(const Real* coeffs, Real* solutions) { if (coeffs[0] == 0.0) { // TODO(keir): This is a quadratic not a cubic. Implement a quadratic // solver! @@ -114,10 +113,8 @@ int SolveCubicPolynomial(const Real *coeffs, Real *solutions) { Real a = coeffs[2] / coeffs[3]; Real b = coeffs[1] / coeffs[3]; Real c = coeffs[0] / coeffs[3]; - return SolveCubicPolynomial(a, b, c, - solutions + 0, - solutions + 1, - solutions + 2); + return SolveCubicPolynomial( + a, b, c, solutions + 0, solutions + 1, solutions + 2); } } // namespace libmv #endif // LIBMV_NUMERIC_POLY_H_ diff --git a/intern/libmv/libmv/numeric/poly_test.cc b/intern/libmv/libmv/numeric/poly_test.cc index 69f887b416c..cb85c068468 100644 --- a/intern/libmv/libmv/numeric/poly_test.cc +++ b/intern/libmv/libmv/numeric/poly_test.cc @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "libmv/numeric/numeric.h" #include "libmv/numeric/poly.h" +#include "libmv/numeric/numeric.h" #include "testing/testing.h" using namespace libmv; @@ -34,8 +34,8 @@ namespace { // // x^3 - (c+b+a) * x^2 + (a*b+(b+a)*c) * x - a*b*c = 0. // = p = q = r -void CoeffsForCubicZeros(double a, double b, double c, - double *p, double *q, double *r) { +void CoeffsForCubicZeros( + double a, double b, double c, double* p, double* q, double* r) { *p = -(c + b + a); *q = (a * b + (b + a) * c); *r = -a * b * c; @@ -45,35 +45,45 @@ TEST(Poly, SolveCubicPolynomial) { double a, b, c, aa, bb, cc; double p, q, r; - a = 1; b = 2; c = 3; + a = 1; + b = 2; + c = 3; CoeffsForCubicZeros(a, b, c, &p, &q, &r); ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); EXPECT_NEAR(a, aa, 1e-10); EXPECT_NEAR(b, bb, 1e-10); EXPECT_NEAR(c, cc, 1e-10); - a = 0; b = 1; c = 3; + a = 0; + b = 1; + c = 3; CoeffsForCubicZeros(a, b, c, &p, &q, &r); ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); EXPECT_NEAR(a, aa, 1e-10); EXPECT_NEAR(b, bb, 1e-10); EXPECT_NEAR(c, cc, 1e-10); - a = -10; b = 0; c = 1; + a = -10; + b = 0; + c = 1; CoeffsForCubicZeros(a, b, c, &p, &q, &r); ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); EXPECT_NEAR(a, aa, 1e-10); EXPECT_NEAR(b, bb, 1e-10); EXPECT_NEAR(c, cc, 1e-10); - a = -8; b = 1; c = 3; + a = -8; + b = 1; + c = 3; CoeffsForCubicZeros(a, b, c, &p, &q, &r); ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); EXPECT_NEAR(a, aa, 1e-10); EXPECT_NEAR(b, bb, 1e-10); EXPECT_NEAR(c, cc, 1e-10); - a = 28; b = 28; c = 105; + a = 28; + b = 28; + c = 105; CoeffsForCubicZeros(a, b, c, &p, &q, &r); ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); EXPECT_NEAR(a, aa, 1e-10); diff --git a/intern/libmv/libmv/simple_pipeline/bundle.cc b/intern/libmv/libmv/simple_pipeline/bundle.cc index 25a63c87e1b..e86c3bca57f 100644 --- a/intern/libmv/libmv/simple_pipeline/bundle.cc +++ b/intern/libmv/libmv/simple_pipeline/bundle.cc @@ -32,16 +32,16 @@ #include "libmv/multiview/projection.h" #include "libmv/numeric/numeric.h" #include "libmv/simple_pipeline/camera_intrinsics.h" -#include "libmv/simple_pipeline/reconstruction.h" -#include "libmv/simple_pipeline/tracks.h" #include "libmv/simple_pipeline/distortion_models.h" #include "libmv/simple_pipeline/packed_intrinsics.h" +#include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { namespace { -bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics *intrinsics) { +bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics* intrinsics) { const DistortionModelType distortion_model = intrinsics->GetDistortionModelType(); return (distortion_model == DISTORTION_MODEL_NUKE); @@ -59,12 +59,14 @@ bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics *intrinsics) { // The invariant_intrinsics are used to access intrinsics which are never // packed into parameter block: for example, distortion model type and image // dimension. -template +template void ApplyDistortionModelUsingIntrinsicsBlock( - const CameraIntrinsics *invariant_intrinsics, + const CameraIntrinsics* invariant_intrinsics, const T* const intrinsics_block, - const T& normalized_x, const T& normalized_y, - T* distorted_x, T* distorted_y) { + const T& normalized_x, + const T& normalized_y, + T* distorted_x, + T* distorted_y) { // Unpack the intrinsics. const T& focal_length = intrinsics_block[PackedIntrinsics::OFFSET_FOCAL_LENGTH]; @@ -76,65 +78,75 @@ void ApplyDistortionModelUsingIntrinsicsBlock( // TODO(keir): Do early bailouts for zero distortion; these are expensive // jet operations. switch (invariant_intrinsics->GetDistortionModelType()) { - case DISTORTION_MODEL_POLYNOMIAL: - { - const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; - const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; - const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3]; - const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1]; - const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2]; - - ApplyPolynomialDistortionModel(focal_length, - focal_length, - principal_point_x, - principal_point_y, - k1, k2, k3, - p1, p2, - normalized_x, normalized_y, - distorted_x, distorted_y); - return; - } - - case DISTORTION_MODEL_DIVISION: - { - const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; - const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; - - ApplyDivisionDistortionModel(focal_length, + case DISTORTION_MODEL_POLYNOMIAL: { + const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; + const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; + const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3]; + const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1]; + const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2]; + + ApplyPolynomialDistortionModel(focal_length, focal_length, principal_point_x, principal_point_y, - k1, k2, - normalized_x, normalized_y, - distorted_x, distorted_y); - return; - } + k1, + k2, + k3, + p1, + p2, + normalized_x, + normalized_y, + distorted_x, + distorted_y); + return; + } - case DISTORTION_MODEL_NUKE: - { - LOG(FATAL) << "Unsupported distortion model."; - return; - } + case DISTORTION_MODEL_DIVISION: { + const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; + const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; + + ApplyDivisionDistortionModel(focal_length, + focal_length, + principal_point_x, + principal_point_y, + k1, + k2, + normalized_x, + normalized_y, + distorted_x, + distorted_y); + return; + } - case DISTORTION_MODEL_BROWN: - { - const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; - const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; - const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3]; - const T& k4 = intrinsics_block[PackedIntrinsics::OFFSET_K4]; - const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1]; - const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2]; - - ApplyBrownDistortionModel(focal_length, - focal_length, - principal_point_x, - principal_point_y, - k1, k2, k3, k4, - p1, p2, - normalized_x, normalized_y, - distorted_x, distorted_y); - return; - } + case DISTORTION_MODEL_NUKE: { + LOG(FATAL) << "Unsupported distortion model."; + return; + } + + case DISTORTION_MODEL_BROWN: { + const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; + const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; + const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3]; + const T& k4 = intrinsics_block[PackedIntrinsics::OFFSET_K4]; + const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1]; + const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2]; + + ApplyBrownDistortionModel(focal_length, + focal_length, + principal_point_x, + principal_point_y, + k1, + k2, + k3, + k4, + p1, + p2, + normalized_x, + normalized_y, + distorted_x, + distorted_y); + return; + } } LOG(FATAL) << "Unknown distortion model."; @@ -152,12 +164,14 @@ void ApplyDistortionModelUsingIntrinsicsBlock( // The invariant_intrinsics are used to access intrinsics which are never // packed into parameter block: for example, distortion model type and image // dimension. -template +template void InvertDistortionModelUsingIntrinsicsBlock( - const CameraIntrinsics *invariant_intrinsics, + const CameraIntrinsics* invariant_intrinsics, const T* const intrinsics_block, - const T& image_x, const T& image_y, - T* normalized_x, T* normalized_y) { + const T& image_x, + const T& image_y, + T* normalized_x, + T* normalized_y) { // Unpack the intrinsics. const T& focal_length = intrinsics_block[PackedIntrinsics::OFFSET_FOCAL_LENGTH]; @@ -175,31 +189,35 @@ void InvertDistortionModelUsingIntrinsicsBlock( LOG(FATAL) << "Unsupported distortion model."; return; - case DISTORTION_MODEL_NUKE: - { - const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; - const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; - - InvertNukeDistortionModel(focal_length, - focal_length, - principal_point_x, - principal_point_y, - invariant_intrinsics->image_width(), - invariant_intrinsics->image_height(), - k1, k2, - image_x, image_y, - normalized_x, normalized_y); - return; - } + case DISTORTION_MODEL_NUKE: { + const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; + const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; + + InvertNukeDistortionModel(focal_length, + focal_length, + principal_point_x, + principal_point_y, + invariant_intrinsics->image_width(), + invariant_intrinsics->image_height(), + k1, + k2, + image_x, + image_y, + normalized_x, + normalized_y); + return; + } } LOG(FATAL) << "Unknown distortion model."; } -template +template void NormalizedToImageSpace(const T* const intrinsics_block, - const T& normalized_x, const T& normalized_y, - T* image_x, T* image_y) { + const T& normalized_x, + const T& normalized_y, + T* image_x, + T* image_y) { // Unpack the intrinsics. const T& focal_length = intrinsics_block[PackedIntrinsics::OFFSET_FOCAL_LENGTH]; @@ -219,11 +237,10 @@ void NormalizedToImageSpace(const T* const intrinsics_block, // This functor can only be used for distortion models which have analytically // defined Apply() function. struct ReprojectionErrorApplyIntrinsics { - ReprojectionErrorApplyIntrinsics( - const CameraIntrinsics *invariant_intrinsics, - const double observed_distorted_x, - const double observed_distorted_y, - const double weight) + ReprojectionErrorApplyIntrinsics(const CameraIntrinsics* invariant_intrinsics, + const double observed_distorted_x, + const double observed_distorted_y, + const double weight) : invariant_intrinsics_(invariant_intrinsics), observed_distorted_x_(observed_distorted_x), observed_distorted_y_(observed_distorted_y), @@ -253,11 +270,12 @@ struct ReprojectionErrorApplyIntrinsics { T yn = x[1] / x[2]; T predicted_distorted_x, predicted_distorted_y; - ApplyDistortionModelUsingIntrinsicsBlock( - invariant_intrinsics_, - intrinsics, - xn, yn, - &predicted_distorted_x, &predicted_distorted_y); + ApplyDistortionModelUsingIntrinsicsBlock(invariant_intrinsics_, + intrinsics, + xn, + yn, + &predicted_distorted_x, + &predicted_distorted_y); // The error is the difference between the predicted and observed position. residuals[0] = (predicted_distorted_x - T(observed_distorted_x_)) * weight_; @@ -265,7 +283,7 @@ struct ReprojectionErrorApplyIntrinsics { return true; } - const CameraIntrinsics *invariant_intrinsics_; + const CameraIntrinsics* invariant_intrinsics_; const double observed_distorted_x_; const double observed_distorted_y_; const double weight_; @@ -279,7 +297,7 @@ struct ReprojectionErrorApplyIntrinsics { // defined Invert() function. struct ReprojectionErrorInvertIntrinsics { ReprojectionErrorInvertIntrinsics( - const CameraIntrinsics *invariant_intrinsics, + const CameraIntrinsics* invariant_intrinsics, const double observed_distorted_x, const double observed_distorted_y, const double weight) @@ -295,8 +313,7 @@ struct ReprojectionErrorInvertIntrinsics { const T* const X, // Point coordinates 3x1. T* residuals) const { // Unpack the intrinsics. - const T& focal_length = - intrinsics[PackedIntrinsics::OFFSET_FOCAL_LENGTH]; + const T& focal_length = intrinsics[PackedIntrinsics::OFFSET_FOCAL_LENGTH]; const T& principal_point_x = intrinsics[PackedIntrinsics::OFFSET_PRINCIPAL_POINT_X]; const T& principal_point_y = @@ -327,14 +344,17 @@ struct ReprojectionErrorInvertIntrinsics { InvertDistortionModelUsingIntrinsicsBlock( invariant_intrinsics_, intrinsics, - T(observed_distorted_x_), T(observed_distorted_y_), - &observed_undistorted_normalized_x, &observed_undistorted_normalized_y); + T(observed_distorted_x_), + T(observed_distorted_y_), + &observed_undistorted_normalized_x, + &observed_undistorted_normalized_y); T observed_undistorted_image_x, observed_undistorted_image_y; - NormalizedToImageSpace( - intrinsics, - observed_undistorted_normalized_x, observed_undistorted_normalized_y, - &observed_undistorted_image_x, &observed_undistorted_image_y); + NormalizedToImageSpace(intrinsics, + observed_undistorted_normalized_x, + observed_undistorted_normalized_y, + &observed_undistorted_image_x, + &observed_undistorted_image_y); // The error is the difference between the predicted and observed position. residuals[0] = (predicted_x - observed_undistorted_image_x) * weight_; @@ -343,7 +363,7 @@ struct ReprojectionErrorInvertIntrinsics { return true; } - const CameraIntrinsics *invariant_intrinsics_; + const CameraIntrinsics* invariant_intrinsics_; const double observed_distorted_x_; const double observed_distorted_y_; const double weight_; @@ -356,22 +376,23 @@ void BundleIntrinsicsLogMessage(const int bundle_intrinsics) { } else { std::string bundling_message = ""; -#define APPEND_BUNDLING_INTRINSICS(name, flag) \ - if (bundle_intrinsics & flag) { \ - if (!bundling_message.empty()) { \ - bundling_message += ", "; \ - } \ - bundling_message += name; \ - } (void)0 +#define APPEND_BUNDLING_INTRINSICS(name, flag) \ + if (bundle_intrinsics & flag) { \ + if (!bundling_message.empty()) { \ + bundling_message += ", "; \ + } \ + bundling_message += name; \ + } \ + (void)0 - APPEND_BUNDLING_INTRINSICS("f", BUNDLE_FOCAL_LENGTH); + APPEND_BUNDLING_INTRINSICS("f", BUNDLE_FOCAL_LENGTH); APPEND_BUNDLING_INTRINSICS("px, py", BUNDLE_PRINCIPAL_POINT); - APPEND_BUNDLING_INTRINSICS("k1", BUNDLE_RADIAL_K1); - APPEND_BUNDLING_INTRINSICS("k2", BUNDLE_RADIAL_K2); - APPEND_BUNDLING_INTRINSICS("k3", BUNDLE_RADIAL_K3); - APPEND_BUNDLING_INTRINSICS("k4", BUNDLE_RADIAL_K4); - APPEND_BUNDLING_INTRINSICS("p1", BUNDLE_TANGENTIAL_P1); - APPEND_BUNDLING_INTRINSICS("p2", BUNDLE_TANGENTIAL_P2); + APPEND_BUNDLING_INTRINSICS("k1", BUNDLE_RADIAL_K1); + APPEND_BUNDLING_INTRINSICS("k2", BUNDLE_RADIAL_K2); + APPEND_BUNDLING_INTRINSICS("k3", BUNDLE_RADIAL_K3); + APPEND_BUNDLING_INTRINSICS("k4", BUNDLE_RADIAL_K4); + APPEND_BUNDLING_INTRINSICS("p1", BUNDLE_TANGENTIAL_P1); + APPEND_BUNDLING_INTRINSICS("p2", BUNDLE_TANGENTIAL_P2); LG << "Bundling " << bundling_message << "."; } @@ -383,7 +404,7 @@ void BundleIntrinsicsLogMessage(const int bundle_intrinsics) { // Element with key i matches to a rotation+translation for // camera at image i. map PackCamerasRotationAndTranslation( - const EuclideanReconstruction &reconstruction) { + const EuclideanReconstruction& reconstruction) { map all_cameras_R_t; vector all_cameras = reconstruction.AllCameras(); @@ -399,14 +420,13 @@ map PackCamerasRotationAndTranslation( // Convert cameras rotations fro mangle axis back to rotation matrix. void UnpackCamerasRotationAndTranslation( - const map &all_cameras_R_t, - EuclideanReconstruction *reconstruction) { - + const map& all_cameras_R_t, + EuclideanReconstruction* reconstruction) { for (map::value_type image_and_camera_R_T : all_cameras_R_t) { const int image = image_and_camera_R_T.first; const Vec6& camera_R_t = image_and_camera_R_T.second; - EuclideanCamera *camera = reconstruction->CameraForImage(image); + EuclideanCamera* camera = reconstruction->CameraForImage(image); if (!camera) { continue; } @@ -421,8 +441,8 @@ void UnpackCamerasRotationAndTranslation( // // TODO(sergey): currently uses dense Eigen matrices, best would // be to use sparse Eigen matrices -void CRSMatrixToEigenMatrix(const ceres::CRSMatrix &crs_matrix, - Mat *eigen_matrix) { +void CRSMatrixToEigenMatrix(const ceres::CRSMatrix& crs_matrix, + Mat* eigen_matrix) { eigen_matrix->resize(crs_matrix.num_rows, crs_matrix.num_cols); eigen_matrix->setZero(); @@ -439,11 +459,11 @@ void CRSMatrixToEigenMatrix(const ceres::CRSMatrix &crs_matrix, } } -void EuclideanBundlerPerformEvaluation(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - map *all_cameras_R_t, - ceres::Problem *problem, - BundleEvaluation *evaluation) { +void EuclideanBundlerPerformEvaluation(const Tracks& tracks, + EuclideanReconstruction* reconstruction, + map* all_cameras_R_t, + ceres::Problem* problem, + BundleEvaluation* evaluation) { int max_track = tracks.MaxTrack(); // Number of camera rotations equals to number of translation, int num_cameras = all_cameras_R_t->size(); @@ -451,7 +471,7 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks, vector minimized_points; for (int i = 0; i <= max_track; i++) { - EuclideanPoint *point = reconstruction->PointForTrack(i); + EuclideanPoint* point = reconstruction->PointForTrack(i); if (point) { // We need to know whether the track is a constant zero weight. // If it is so it wouldn't have a parameter block in the problem. @@ -477,16 +497,16 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks, evaluation->num_cameras = num_cameras; evaluation->num_points = num_points; - if (evaluation->evaluate_jacobian) { // Evaluate jacobian matrix. + if (evaluation->evaluate_jacobian) { // Evaluate jacobian matrix. ceres::CRSMatrix evaluated_jacobian; ceres::Problem::EvaluateOptions eval_options; // Cameras goes first in the ordering. int max_image = tracks.MaxImage(); for (int i = 0; i <= max_image; i++) { - const EuclideanCamera *camera = reconstruction->CameraForImage(i); + const EuclideanCamera* camera = reconstruction->CameraForImage(i); if (camera) { - double *current_camera_R_t = &(*all_cameras_R_t)[i](0); + double* current_camera_R_t = &(*all_cameras_R_t)[i](0); // All cameras are variable now. problem->SetParameterBlockVariable(current_camera_R_t); @@ -497,63 +517,65 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks, // Points goes at the end of ordering, for (int i = 0; i < minimized_points.size(); i++) { - EuclideanPoint *point = minimized_points.at(i); + EuclideanPoint* point = minimized_points.at(i); eval_options.parameter_blocks.push_back(&point->X(0)); } - problem->Evaluate(eval_options, - NULL, NULL, NULL, - &evaluated_jacobian); + problem->Evaluate(eval_options, NULL, NULL, NULL, &evaluated_jacobian); CRSMatrixToEigenMatrix(evaluated_jacobian, &evaluation->jacobian); } } -template -void AddResidualBlockToProblemImpl(const CameraIntrinsics *invariant_intrinsics, - double observed_x, double observed_y, +template +void AddResidualBlockToProblemImpl(const CameraIntrinsics* invariant_intrinsics, + double observed_x, + double observed_y, double weight, - double *intrinsics_block, - double *camera_R_t, - EuclideanPoint *point, + double* intrinsics_block, + double* camera_R_t, + EuclideanPoint* point, ceres::Problem* problem) { - problem->AddResidualBlock(new ceres::AutoDiffCostFunction< - CostFunction, 2, PackedIntrinsics::NUM_PARAMETERS, 6, 3>( - new CostFunction( - invariant_intrinsics, - observed_x, observed_y, - weight)), + problem->AddResidualBlock( + new ceres::AutoDiffCostFunction(new CostFunction( + invariant_intrinsics, observed_x, observed_y, weight)), NULL, intrinsics_block, camera_R_t, &point->X(0)); } -void AddResidualBlockToProblem(const CameraIntrinsics *invariant_intrinsics, - const Marker &marker, +void AddResidualBlockToProblem(const CameraIntrinsics* invariant_intrinsics, + const Marker& marker, double marker_weight, double* intrinsics_block, - double *camera_R_t, - EuclideanPoint *point, + double* camera_R_t, + EuclideanPoint* point, ceres::Problem* problem) { if (NeedUseInvertIntrinsicsPipeline(invariant_intrinsics)) { AddResidualBlockToProblemImpl( - invariant_intrinsics, - marker.x, marker.y, - marker_weight, - intrinsics_block, - camera_R_t, - point, - problem); + invariant_intrinsics, + marker.x, + marker.y, + marker_weight, + intrinsics_block, + camera_R_t, + point, + problem); } else { AddResidualBlockToProblemImpl( - invariant_intrinsics, - marker.x, marker.y, - marker_weight, - intrinsics_block, - camera_R_t, - point, - problem); + invariant_intrinsics, + marker.x, + marker.y, + marker_weight, + intrinsics_block, + camera_R_t, + point, + problem); } } @@ -566,25 +588,25 @@ void AddResidualBlockToProblem(const CameraIntrinsics *invariant_intrinsics, // // At this point we only need to bundle points positions, cameras // are to be totally still here. -void EuclideanBundlePointsOnly(const CameraIntrinsics *invariant_intrinsics, - const vector &markers, - map &all_cameras_R_t, +void EuclideanBundlePointsOnly(const CameraIntrinsics* invariant_intrinsics, + const vector& markers, + map& all_cameras_R_t, double* intrinsics_block, - EuclideanReconstruction *reconstruction) { + EuclideanReconstruction* reconstruction) { ceres::Problem::Options problem_options; ceres::Problem problem(problem_options); int num_residuals = 0; for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; - EuclideanCamera *camera = reconstruction->CameraForImage(marker.image); - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); + const Marker& marker = markers[i]; + EuclideanCamera* camera = reconstruction->CameraForImage(marker.image); + EuclideanPoint* point = reconstruction->PointForTrack(marker.track); if (camera == NULL || point == NULL) { continue; } // Rotation of camera denoted in angle axis followed with // camera translation. - double *current_camera_R_t = &all_cameras_R_t[camera->image](0); + double* current_camera_R_t = &all_cameras_R_t[camera->image](0); AddResidualBlockToProblem(invariant_intrinsics, marker, @@ -625,8 +647,8 @@ void EuclideanBundlePointsOnly(const CameraIntrinsics *invariant_intrinsics, } // namespace -void EuclideanBundle(const Tracks &tracks, - EuclideanReconstruction *reconstruction) { +void EuclideanBundle(const Tracks& tracks, + EuclideanReconstruction* reconstruction) { PolynomialCameraIntrinsics empty_intrinsics; EuclideanBundleCommonIntrinsics(tracks, BUNDLE_NO_INTRINSICS, @@ -636,13 +658,12 @@ void EuclideanBundle(const Tracks &tracks, NULL); } -void EuclideanBundleCommonIntrinsics( - const Tracks &tracks, - const int bundle_intrinsics, - const int bundle_constraints, - EuclideanReconstruction *reconstruction, - CameraIntrinsics *intrinsics, - BundleEvaluation *evaluation) { +void EuclideanBundleCommonIntrinsics(const Tracks& tracks, + const int bundle_intrinsics, + const int bundle_constraints, + EuclideanReconstruction* reconstruction, + CameraIntrinsics* intrinsics, + BundleEvaluation* evaluation) { LG << "Original intrinsics: " << *intrinsics; vector markers = tracks.AllMarkers(); @@ -661,19 +682,19 @@ void EuclideanBundleCommonIntrinsics( // Block for minimization has got the following structure: // <3 elements for angle-axis> <3 elements for translation> map all_cameras_R_t = - PackCamerasRotationAndTranslation(*reconstruction); + PackCamerasRotationAndTranslation(*reconstruction); // Parameterization used to restrict camera motion for modal solvers. - ceres::SubsetParameterization *constant_translation_parameterization = NULL; + ceres::SubsetParameterization* constant_translation_parameterization = NULL; if (bundle_constraints & BUNDLE_NO_TRANSLATION) { - std::vector constant_translation; + std::vector constant_translation; - // First three elements are rotation, ast three are translation. - constant_translation.push_back(3); - constant_translation.push_back(4); - constant_translation.push_back(5); + // First three elements are rotation, ast three are translation. + constant_translation.push_back(3); + constant_translation.push_back(4); + constant_translation.push_back(5); - constant_translation_parameterization = + constant_translation_parameterization = new ceres::SubsetParameterization(6, constant_translation); } @@ -683,16 +704,16 @@ void EuclideanBundleCommonIntrinsics( int num_residuals = 0; bool have_locked_camera = false; for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; - EuclideanCamera *camera = reconstruction->CameraForImage(marker.image); - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); + const Marker& marker = markers[i]; + EuclideanCamera* camera = reconstruction->CameraForImage(marker.image); + EuclideanPoint* point = reconstruction->PointForTrack(marker.track); if (camera == NULL || point == NULL) { continue; } // Rotation of camera denoted in angle axis followed with // camera translation. - double *current_camera_R_t = &all_cameras_R_t[camera->image](0); + double* current_camera_R_t = &all_cameras_R_t[camera->image](0); // Skip residual block for markers which does have absolutely // no affect on the final solution. @@ -706,7 +727,8 @@ void EuclideanBundleCommonIntrinsics( point, &problem); - // We lock the first camera to better deal with scene orientation ambiguity. + // We lock the first camera to better deal with scene orientation + // ambiguity. if (!have_locked_camera) { problem.SetParameterBlockConstant(current_camera_R_t); have_locked_camera = true; @@ -729,7 +751,7 @@ void EuclideanBundleCommonIntrinsics( } if (intrinsics->GetDistortionModelType() == DISTORTION_MODEL_DIVISION && - (bundle_intrinsics & BUNDLE_TANGENTIAL) != 0) { + (bundle_intrinsics & BUNDLE_TANGENTIAL) != 0) { LOG(FATAL) << "Division model doesn't support bundling " "of tangential distortion"; } @@ -745,29 +767,29 @@ void EuclideanBundleCommonIntrinsics( // constant using some macro trickery. std::vector constant_intrinsics; -#define MAYBE_SET_CONSTANT(bundle_enum, offset) \ - if (!(bundle_intrinsics & bundle_enum) || \ - !packed_intrinsics.IsParameterDefined(offset)) { \ - constant_intrinsics.push_back(offset); \ - } +#define MAYBE_SET_CONSTANT(bundle_enum, offset) \ + if (!(bundle_intrinsics & bundle_enum) || \ + !packed_intrinsics.IsParameterDefined(offset)) { \ + constant_intrinsics.push_back(offset); \ + } MAYBE_SET_CONSTANT(BUNDLE_FOCAL_LENGTH, PackedIntrinsics::OFFSET_FOCAL_LENGTH); MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, PackedIntrinsics::OFFSET_PRINCIPAL_POINT_X); MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, PackedIntrinsics::OFFSET_PRINCIPAL_POINT_Y); - MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K1, PackedIntrinsics::OFFSET_K1); - MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K2, PackedIntrinsics::OFFSET_K2); - MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K3, PackedIntrinsics::OFFSET_K3); - MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K4, PackedIntrinsics::OFFSET_K4); - MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P1, PackedIntrinsics::OFFSET_P1); - MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, PackedIntrinsics::OFFSET_P2); + MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K1, PackedIntrinsics::OFFSET_K1); + MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K2, PackedIntrinsics::OFFSET_K2); + MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K3, PackedIntrinsics::OFFSET_K3); + MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K4, PackedIntrinsics::OFFSET_K4); + MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P1, PackedIntrinsics::OFFSET_P1); + MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, PackedIntrinsics::OFFSET_P2); #undef MAYBE_SET_CONSTANT if (!constant_intrinsics.empty()) { - ceres::SubsetParameterization *subset_parameterization = - new ceres::SubsetParameterization(PackedIntrinsics::NUM_PARAMETERS, - constant_intrinsics); + ceres::SubsetParameterization* subset_parameterization = + new ceres::SubsetParameterization(PackedIntrinsics::NUM_PARAMETERS, + constant_intrinsics); problem.SetParameterization(intrinsics_block, subset_parameterization); } @@ -800,8 +822,8 @@ void EuclideanBundleCommonIntrinsics( LG << "Final intrinsics: " << *intrinsics; if (evaluation) { - EuclideanBundlerPerformEvaluation(tracks, reconstruction, &all_cameras_R_t, - &problem, evaluation); + EuclideanBundlerPerformEvaluation( + tracks, reconstruction, &all_cameras_R_t, &problem, evaluation); } // Separate step to adjust positions of tracks which are @@ -828,8 +850,8 @@ void EuclideanBundleCommonIntrinsics( } } -void ProjectiveBundle(const Tracks & /*tracks*/, - ProjectiveReconstruction * /*reconstruction*/) { +void ProjectiveBundle(const Tracks& /*tracks*/, + ProjectiveReconstruction* /*reconstruction*/) { // TODO(keir): Implement this! This can't work until we have a better bundler // than SSBA, since SSBA has no support for projective bundling. } diff --git a/intern/libmv/libmv/simple_pipeline/bundle.h b/intern/libmv/libmv/simple_pipeline/bundle.h index 5f420da0045..662313b396a 100644 --- a/intern/libmv/libmv/simple_pipeline/bundle.h +++ b/intern/libmv/libmv/simple_pipeline/bundle.h @@ -31,11 +31,8 @@ class ProjectiveReconstruction; class Tracks; struct BundleEvaluation { - BundleEvaluation() : - num_cameras(0), - num_points(0), - evaluate_jacobian(false) { - } + BundleEvaluation() + : num_cameras(0), num_points(0), evaluate_jacobian(false) {} // Number of cameras appeared in bundle adjustment problem int num_cameras; @@ -72,8 +69,8 @@ struct BundleEvaluation { \sa EuclideanResect, EuclideanIntersect, EuclideanReconstructTwoFrames */ -void EuclideanBundle(const Tracks &tracks, - EuclideanReconstruction *reconstruction); +void EuclideanBundle(const Tracks& tracks, + EuclideanReconstruction* reconstruction); /*! Refine camera poses and 3D coordinates using bundle adjustment. @@ -109,9 +106,7 @@ enum BundleIntrinsics { BUNDLE_RADIAL_K2 = (1 << 3), BUNDLE_RADIAL_K3 = (1 << 4), BUNDLE_RADIAL_K4 = (1 << 5), - BUNDLE_RADIAL = (BUNDLE_RADIAL_K1 | - BUNDLE_RADIAL_K2 | - BUNDLE_RADIAL_K3 | + BUNDLE_RADIAL = (BUNDLE_RADIAL_K1 | BUNDLE_RADIAL_K2 | BUNDLE_RADIAL_K3 | BUNDLE_RADIAL_K4), BUNDLE_TANGENTIAL_P1 = (1 << 6), @@ -122,13 +117,12 @@ enum BundleConstraints { BUNDLE_NO_CONSTRAINTS = 0, BUNDLE_NO_TRANSLATION = 1, }; -void EuclideanBundleCommonIntrinsics( - const Tracks &tracks, - const int bundle_intrinsics, - const int bundle_constraints, - EuclideanReconstruction *reconstruction, - CameraIntrinsics *intrinsics, - BundleEvaluation *evaluation = NULL); +void EuclideanBundleCommonIntrinsics(const Tracks& tracks, + const int bundle_intrinsics, + const int bundle_constraints, + EuclideanReconstruction* reconstruction, + CameraIntrinsics* intrinsics, + BundleEvaluation* evaluation = NULL); /*! Refine camera poses and 3D coordinates using bundle adjustment. @@ -147,10 +141,9 @@ void EuclideanBundleCommonIntrinsics( \sa ProjectiveResect, ProjectiveIntersect, ProjectiveReconstructTwoFrames */ -void ProjectiveBundle(const Tracks &tracks, - ProjectiveReconstruction *reconstruction); +void ProjectiveBundle(const Tracks& tracks, + ProjectiveReconstruction* reconstruction); } // namespace libmv -#endif // LIBMV_SIMPLE_PIPELINE_BUNDLE_H - +#endif // LIBMV_SIMPLE_PIPELINE_BUNDLE_H diff --git a/intern/libmv/libmv/simple_pipeline/callbacks.h b/intern/libmv/libmv/simple_pipeline/callbacks.h index 58f7b0d3cc9..a6855a9e5e7 100644 --- a/intern/libmv/libmv/simple_pipeline/callbacks.h +++ b/intern/libmv/libmv/simple_pipeline/callbacks.h @@ -26,7 +26,7 @@ namespace libmv { class ProgressUpdateCallback { public: virtual ~ProgressUpdateCallback() {} - virtual void invoke(double progress, const char *message) = 0; + virtual void invoke(double progress, const char* message) = 0; }; } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc index ccb6e3d34c8..b86e316b139 100644 --- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc +++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc @@ -29,13 +29,10 @@ namespace libmv { namespace internal { LookupWarpGrid::LookupWarpGrid() - : offset_(NULL), - width_(0), - height_(0), - overscan_(0.0), - threads_(1) {} + : offset_(NULL), width_(0), height_(0), overscan_(0.0), threads_(1) { +} -LookupWarpGrid::LookupWarpGrid(const LookupWarpGrid &from) +LookupWarpGrid::LookupWarpGrid(const LookupWarpGrid& from) : offset_(NULL), width_(from.width_), height_(from.height_), @@ -48,11 +45,11 @@ LookupWarpGrid::LookupWarpGrid(const LookupWarpGrid &from) } LookupWarpGrid::~LookupWarpGrid() { - delete [] offset_; + delete[] offset_; } void LookupWarpGrid::Reset() { - delete [] offset_; + delete[] offset_; offset_ = NULL; } @@ -64,16 +61,16 @@ void LookupWarpGrid::SetThreads(int threads) { } // namespace internal CameraIntrinsics::CameraIntrinsics() - : image_width_(0), - image_height_(0), - K_(Mat3::Identity()) {} + : image_width_(0), image_height_(0), K_(Mat3::Identity()) { +} -CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics &from) +CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics& from) : image_width_(from.image_width_), image_height_(from.image_height_), K_(from.K_), distort_(from.distort_), - undistort_(from.undistort_) {} + undistort_(from.undistort_) { +} // Set the image size in pixels. void CameraIntrinsics::SetImageSize(int width, int height) { @@ -89,16 +86,14 @@ void CameraIntrinsics::SetK(const Mat3 new_k) { } // Set both x and y focal length in pixels. -void CameraIntrinsics::SetFocalLength(double focal_x, - double focal_y) { +void CameraIntrinsics::SetFocalLength(double focal_x, double focal_y) { K_(0, 0) = focal_x; K_(1, 1) = focal_y; ResetLookupGrids(); } // Set principal point in pixels. -void CameraIntrinsics::SetPrincipalPoint(double cx, - double cy) { +void CameraIntrinsics::SetPrincipalPoint(double cx, double cy) { K_(0, 2) = cx; K_(1, 2) = cy; ResetLookupGrids(); @@ -112,16 +107,16 @@ void CameraIntrinsics::SetThreads(int threads) { void CameraIntrinsics::ImageSpaceToNormalized(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const { + double* normalized_x, + double* normalized_y) const { *normalized_x = (image_x - principal_point_x()) / focal_length_x(); *normalized_y = (image_y - principal_point_y()) / focal_length_y(); } void CameraIntrinsics::NormalizedToImageSpace(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const { + double* image_x, + double* image_y) const { *image_x = normalized_x * focal_length_x() + principal_point_x(); *image_y = normalized_y * focal_length_y() + principal_point_y(); } @@ -148,14 +143,13 @@ void CameraIntrinsics::Unpack(const PackedIntrinsics& packed_intrinsics) { // Polynomial model. -PolynomialCameraIntrinsics::PolynomialCameraIntrinsics() - : CameraIntrinsics() { +PolynomialCameraIntrinsics::PolynomialCameraIntrinsics() : CameraIntrinsics() { SetRadialDistortion(0.0, 0.0, 0.0); SetTangentialDistortion(0.0, 0.0); } PolynomialCameraIntrinsics::PolynomialCameraIntrinsics( - const PolynomialCameraIntrinsics &from) + const PolynomialCameraIntrinsics& from) : CameraIntrinsics(from) { SetRadialDistortion(from.k1(), from.k2(), from.k3()); SetTangentialDistortion(from.p1(), from.p2()); @@ -170,8 +164,7 @@ void PolynomialCameraIntrinsics::SetRadialDistortion(double k1, ResetLookupGrids(); } -void PolynomialCameraIntrinsics::SetTangentialDistortion(double p1, - double p2) { +void PolynomialCameraIntrinsics::SetTangentialDistortion(double p1, double p2) { parameters_[OFFSET_P1] = p1; parameters_[OFFSET_P2] = p2; ResetLookupGrids(); @@ -179,31 +172,36 @@ void PolynomialCameraIntrinsics::SetTangentialDistortion(double p1, void PolynomialCameraIntrinsics::ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const { + double* image_x, + double* image_y) const { ApplyPolynomialDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), k3(), - p1(), p2(), + k1(), + k2(), + k3(), + p1(), + p2(), normalized_x, normalized_y, image_x, image_y); } -void PolynomialCameraIntrinsics::InvertIntrinsics( - double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const { +void PolynomialCameraIntrinsics::InvertIntrinsics(double image_x, + double image_y, + double* normalized_x, + double* normalized_y) const { InvertPolynomialDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), k3(), - p1(), p2(), + k1(), + k2(), + k3(), + p1(), + p2(), image_x, image_y, normalized_x, @@ -230,25 +228,22 @@ void PolynomialCameraIntrinsics::Unpack( packed_intrinsics.GetK2(), packed_intrinsics.GetK3()); - SetTangentialDistortion(packed_intrinsics.GetP1(), - packed_intrinsics.GetP2()); + SetTangentialDistortion(packed_intrinsics.GetP1(), packed_intrinsics.GetP2()); } // Division model. -DivisionCameraIntrinsics::DivisionCameraIntrinsics() - : CameraIntrinsics() { +DivisionCameraIntrinsics::DivisionCameraIntrinsics() : CameraIntrinsics() { SetDistortion(0.0, 0.0); } DivisionCameraIntrinsics::DivisionCameraIntrinsics( - const DivisionCameraIntrinsics &from) + const DivisionCameraIntrinsics& from) : CameraIntrinsics(from) { SetDistortion(from.k1(), from.k1()); } -void DivisionCameraIntrinsics::SetDistortion(double k1, - double k2) { +void DivisionCameraIntrinsics::SetDistortion(double k1, double k2) { parameters_[OFFSET_K1] = k1; parameters_[OFFSET_K2] = k2; ResetLookupGrids(); @@ -256,13 +251,14 @@ void DivisionCameraIntrinsics::SetDistortion(double k1, void DivisionCameraIntrinsics::ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const { + double* image_x, + double* image_y) const { ApplyDivisionDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), + k1(), + k2(), normalized_x, normalized_y, image_x, @@ -271,21 +267,21 @@ void DivisionCameraIntrinsics::ApplyIntrinsics(double normalized_x, void DivisionCameraIntrinsics::InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const { + double* normalized_x, + double* normalized_y) const { InvertDivisionDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), + k1(), + k2(), image_x, image_y, normalized_x, normalized_y); } -void DivisionCameraIntrinsics::Pack( - PackedIntrinsics* packed_intrinsics) const { +void DivisionCameraIntrinsics::Pack(PackedIntrinsics* packed_intrinsics) const { CameraIntrinsics::Pack(packed_intrinsics); packed_intrinsics->SetK1(k1()); @@ -301,13 +297,11 @@ void DivisionCameraIntrinsics::Unpack( // Nuke model. -NukeCameraIntrinsics::NukeCameraIntrinsics() - : CameraIntrinsics() { +NukeCameraIntrinsics::NukeCameraIntrinsics() : CameraIntrinsics() { SetDistortion(0.0, 0.0); } -NukeCameraIntrinsics::NukeCameraIntrinsics( - const NukeCameraIntrinsics &from) +NukeCameraIntrinsics::NukeCameraIntrinsics(const NukeCameraIntrinsics& from) : CameraIntrinsics(from) { SetDistortion(from.k1(), from.k2()); } @@ -320,14 +314,16 @@ void NukeCameraIntrinsics::SetDistortion(double k1, double k2) { void NukeCameraIntrinsics::ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const { + double* image_x, + double* image_y) const { ApplyNukeDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - image_width(), image_height(), - k1(), k2(), + image_width(), + image_height(), + k1(), + k2(), normalized_x, normalized_y, image_x, @@ -335,31 +331,31 @@ void NukeCameraIntrinsics::ApplyIntrinsics(double normalized_x, } void NukeCameraIntrinsics::InvertIntrinsics(double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const { + double image_y, + double* normalized_x, + double* normalized_y) const { InvertNukeDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - image_width(), image_height(), - k1(), k2(), + image_width(), + image_height(), + k1(), + k2(), image_x, image_y, normalized_x, normalized_y); } -void NukeCameraIntrinsics::Pack( - PackedIntrinsics* packed_intrinsics) const { +void NukeCameraIntrinsics::Pack(PackedIntrinsics* packed_intrinsics) const { CameraIntrinsics::Pack(packed_intrinsics); packed_intrinsics->SetK1(k1()); packed_intrinsics->SetK2(k2()); } -void NukeCameraIntrinsics::Unpack( - const PackedIntrinsics& packed_intrinsics) { +void NukeCameraIntrinsics::Unpack(const PackedIntrinsics& packed_intrinsics) { CameraIntrinsics::Unpack(packed_intrinsics); SetDistortion(packed_intrinsics.GetK1(), packed_intrinsics.GetK2()); @@ -367,14 +363,12 @@ void NukeCameraIntrinsics::Unpack( // Brown model. -BrownCameraIntrinsics::BrownCameraIntrinsics() - : CameraIntrinsics() { +BrownCameraIntrinsics::BrownCameraIntrinsics() : CameraIntrinsics() { SetRadialDistortion(0.0, 0.0, 0.0, 0.0); SetTangentialDistortion(0.0, 0.0); } -BrownCameraIntrinsics::BrownCameraIntrinsics( - const BrownCameraIntrinsics &from) +BrownCameraIntrinsics::BrownCameraIntrinsics(const BrownCameraIntrinsics& from) : CameraIntrinsics(from) { SetRadialDistortion(from.k1(), from.k2(), from.k3(), from.k4()); SetTangentialDistortion(from.p1(), from.p2()); @@ -391,8 +385,7 @@ void BrownCameraIntrinsics::SetRadialDistortion(double k1, ResetLookupGrids(); } -void BrownCameraIntrinsics::SetTangentialDistortion(double p1, - double p2) { +void BrownCameraIntrinsics::SetTangentialDistortion(double p1, double p2) { parameters_[OFFSET_P1] = p1; parameters_[OFFSET_P2] = p2; ResetLookupGrids(); @@ -400,39 +393,45 @@ void BrownCameraIntrinsics::SetTangentialDistortion(double p1, void BrownCameraIntrinsics::ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const { + double* image_x, + double* image_y) const { ApplyBrownDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), k3(), k4(), - p1(), p2(), + k1(), + k2(), + k3(), + k4(), + p1(), + p2(), normalized_x, normalized_y, image_x, image_y); } -void BrownCameraIntrinsics::InvertIntrinsics( - double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const { +void BrownCameraIntrinsics::InvertIntrinsics(double image_x, + double image_y, + double* normalized_x, + double* normalized_y) const { InvertBrownDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), k3(), k4(), - p1(), p2(), + k1(), + k2(), + k3(), + k4(), + p1(), + p2(), image_x, image_y, normalized_x, normalized_y); } -void BrownCameraIntrinsics::Pack( - PackedIntrinsics* packed_intrinsics) const { +void BrownCameraIntrinsics::Pack(PackedIntrinsics* packed_intrinsics) const { CameraIntrinsics::Pack(packed_intrinsics); packed_intrinsics->SetK1(k1()); @@ -444,8 +443,7 @@ void BrownCameraIntrinsics::Pack( packed_intrinsics->SetP2(p2()); } -void BrownCameraIntrinsics::Unpack( - const PackedIntrinsics& packed_intrinsics) { +void BrownCameraIntrinsics::Unpack(const PackedIntrinsics& packed_intrinsics) { CameraIntrinsics::Unpack(packed_intrinsics); SetRadialDistortion(packed_intrinsics.GetK1(), @@ -453,72 +451,65 @@ void BrownCameraIntrinsics::Unpack( packed_intrinsics.GetK3(), packed_intrinsics.GetK4()); - SetTangentialDistortion(packed_intrinsics.GetP1(), - packed_intrinsics.GetP2()); + SetTangentialDistortion(packed_intrinsics.GetP1(), packed_intrinsics.GetP2()); } -std::ostream& operator <<(std::ostream &os, - const CameraIntrinsics &intrinsics) { +std::ostream& operator<<(std::ostream& os, const CameraIntrinsics& intrinsics) { if (intrinsics.focal_length_x() == intrinsics.focal_length_x()) { os << "f=" << intrinsics.focal_length(); } else { - os << "fx=" << intrinsics.focal_length_x() + os << "fx=" << intrinsics.focal_length_x() << " fy=" << intrinsics.focal_length_y(); } os << " cx=" << intrinsics.principal_point_x() << " cy=" << intrinsics.principal_point_y() - << " w=" << intrinsics.image_width() - << " h=" << intrinsics.image_height(); + << " w=" << intrinsics.image_width() << " h=" << intrinsics.image_height(); -#define PRINT_NONZERO_COEFFICIENT(intrinsics, coeff) \ - { \ - if (intrinsics->coeff() != 0.0) { \ - os << " " #coeff "=" << intrinsics->coeff(); \ - } \ - } (void) 0 +#define PRINT_NONZERO_COEFFICIENT(intrinsics, coeff) \ + { \ + if (intrinsics->coeff() != 0.0) { \ + os << " " #coeff "=" << intrinsics->coeff(); \ + } \ + } \ + (void)0 switch (intrinsics.GetDistortionModelType()) { - case DISTORTION_MODEL_POLYNOMIAL: - { - const PolynomialCameraIntrinsics *polynomial_intrinsics = - static_cast(&intrinsics); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k1); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k2); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k3); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p1); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p2); - break; - } - case DISTORTION_MODEL_DIVISION: - { - const DivisionCameraIntrinsics *division_intrinsics = - static_cast(&intrinsics); - PRINT_NONZERO_COEFFICIENT(division_intrinsics, k1); - PRINT_NONZERO_COEFFICIENT(division_intrinsics, k2); - break; - } - case DISTORTION_MODEL_NUKE: - { - const NukeCameraIntrinsics *nuke_intrinsics = - static_cast(&intrinsics); - PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k1); - PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k2); - break; - } - case DISTORTION_MODEL_BROWN: - { - const BrownCameraIntrinsics *brown_intrinsics = - static_cast(&intrinsics); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k1); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k2); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k3); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k4); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p1); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p2); - break; - } - default: - LOG(FATAL) << "Unknown distortion model."; + case DISTORTION_MODEL_POLYNOMIAL: { + const PolynomialCameraIntrinsics* polynomial_intrinsics = + static_cast(&intrinsics); + PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k1); + PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k2); + PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k3); + PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p1); + PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p2); + break; + } + case DISTORTION_MODEL_DIVISION: { + const DivisionCameraIntrinsics* division_intrinsics = + static_cast(&intrinsics); + PRINT_NONZERO_COEFFICIENT(division_intrinsics, k1); + PRINT_NONZERO_COEFFICIENT(division_intrinsics, k2); + break; + } + case DISTORTION_MODEL_NUKE: { + const NukeCameraIntrinsics* nuke_intrinsics = + static_cast(&intrinsics); + PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k1); + PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k2); + break; + } + case DISTORTION_MODEL_BROWN: { + const BrownCameraIntrinsics* brown_intrinsics = + static_cast(&intrinsics); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k1); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k2); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k3); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k4); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p1); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p2); + break; + } + default: LOG(FATAL) << "Unknown distortion model."; } #undef PRINT_NONZERO_COEFFICIENT diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h index ba67ec468dc..efe0735bd93 100644 --- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h +++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h @@ -43,11 +43,11 @@ namespace internal { class LookupWarpGrid { public: LookupWarpGrid(); - LookupWarpGrid(const LookupWarpGrid &from); + LookupWarpGrid(const LookupWarpGrid& from); ~LookupWarpGrid(); // Width and height og the image, measured in pixels. - int width() const { return width_; } + int width() const { return width_; } int height() const { return height_; } // Overscan factor of the image, so that @@ -61,8 +61,8 @@ class LookupWarpGrid { // // See comment for CameraIntrinsics::DistortBuffer to get more // details about what overscan is. - template - void Update(const CameraIntrinsics &intrinsics, + template + void Update(const CameraIntrinsics& intrinsics, int width, int height, double overscan); @@ -71,12 +71,12 @@ class LookupWarpGrid { // // See comment for CameraIntrinsics::DistortBuffer to get more // details about template type. - template - void Apply(const PixelType *input_buffer, + template + void Apply(const PixelType* input_buffer, int width, int height, int channels, - PixelType *output_buffer); + PixelType* output_buffer); // Reset lookup grids. // This will tag the grid for update without re-computing it. @@ -105,15 +105,15 @@ class LookupWarpGrid { // // width and height corresponds to a size of buffer which will // be warped later. - template - void Compute(const CameraIntrinsics &intrinsics, + template + void Compute(const CameraIntrinsics& intrinsics, int width, int height, double overscan); // This is a buffer which contains per-pixel offset of the // pixels from input buffer to correspond the warping function. - Offset *offset_; + Offset* offset_; // Dimensions of the image this lookup grid processes. int width_, height_; @@ -130,19 +130,19 @@ class LookupWarpGrid { class CameraIntrinsics { public: CameraIntrinsics(); - CameraIntrinsics(const CameraIntrinsics &from); + CameraIntrinsics(const CameraIntrinsics& from); virtual ~CameraIntrinsics() {} virtual DistortionModelType GetDistortionModelType() const = 0; - int image_width() const { return image_width_; } + int image_width() const { return image_width_; } int image_height() const { return image_height_; } - const Mat3 &K() const { return K_; } + const Mat3& K() const { return K_; } - double focal_length() const { return K_(0, 0); } - double focal_length_x() const { return K_(0, 0); } - double focal_length_y() const { return K_(1, 1); } + double focal_length() const { return K_(0, 0); } + double focal_length_x() const { return K_(0, 0); } + double focal_length_y() const { return K_(1, 1); } double principal_point_x() const { return K_(0, 2); } double principal_point_y() const { return K_(1, 2); } @@ -166,14 +166,14 @@ class CameraIntrinsics { // Convert image space coordinates to normalized. void ImageSpaceToNormalized(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const; + double* normalized_x, + double* normalized_y) const; // Convert normalized coordinates to image space. void NormalizedToImageSpace(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const; + double* image_x, + double* image_y) const; // Apply camera intrinsics to the normalized point to get image coordinates. // @@ -182,8 +182,8 @@ class CameraIntrinsics { // coordinates in pixels. virtual void ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const = 0; + double* image_x, + double* image_y) const = 0; // Invert camera intrinsics on the image point to get normalized coordinates. // @@ -191,8 +191,8 @@ class CameraIntrinsics { // coordinates to get normalized camera coordinates. virtual void InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const = 0; + double* normalized_x, + double* normalized_y) const = 0; virtual void Pack(PackedIntrinsics* packed_intrinsics) const; virtual void Unpack(const PackedIntrinsics& packed_intrinsics); @@ -218,13 +218,13 @@ class CameraIntrinsics { // But in fact PixelType might be any type for which multiplication by // a scalar and addition are implemented. For example PixelType might be // Vec3 as well. - template - void DistortBuffer(const PixelType *input_buffer, + template + void DistortBuffer(const PixelType* input_buffer, int width, int height, double overscan, int channels, - PixelType *output_buffer); + PixelType* output_buffer); // Undistort an image using the current camera instrinsics // @@ -247,13 +247,13 @@ class CameraIntrinsics { // But in fact PixelType might be any type for which multiplication by // a scalar and addition are implemented. For example PixelType might be // Vec3 as well. - template - void UndistortBuffer(const PixelType *input_buffer, + template + void UndistortBuffer(const PixelType* input_buffer, int width, int height, double overscan, int channels, - PixelType *output_buffer); + PixelType* output_buffer); private: // This is the size of the image. This is necessary to, for example, handle @@ -290,7 +290,7 @@ class PolynomialCameraIntrinsics : public CameraIntrinsics { }; PolynomialCameraIntrinsics(); - PolynomialCameraIntrinsics(const PolynomialCameraIntrinsics &from); + PolynomialCameraIntrinsics(const PolynomialCameraIntrinsics& from); DistortionModelType GetDistortionModelType() const override { return DISTORTION_MODEL_POLYNOMIAL; @@ -315,8 +315,8 @@ class PolynomialCameraIntrinsics : public CameraIntrinsics { // coordinates in pixels. void ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const override; + double* image_x, + double* image_y) const override; // Invert camera intrinsics on the image point to get normalized coordinates. // @@ -324,8 +324,8 @@ class PolynomialCameraIntrinsics : public CameraIntrinsics { // coordinates to get normalized camera coordinates. void InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const override; + double* normalized_x, + double* normalized_y) const override; virtual void Pack(PackedIntrinsics* packed_intrinsics) const override; virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override; @@ -352,7 +352,7 @@ class DivisionCameraIntrinsics : public CameraIntrinsics { }; DivisionCameraIntrinsics(); - DivisionCameraIntrinsics(const DivisionCameraIntrinsics &from); + DivisionCameraIntrinsics(const DivisionCameraIntrinsics& from); DistortionModelType GetDistortionModelType() const override { return DISTORTION_MODEL_DIVISION; @@ -371,8 +371,8 @@ class DivisionCameraIntrinsics : public CameraIntrinsics { // coordinates in pixels. void ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const override; + double* image_x, + double* image_y) const override; // Invert camera intrinsics on the image point to get normalized coordinates. // @@ -380,8 +380,8 @@ class DivisionCameraIntrinsics : public CameraIntrinsics { // coordinates to get normalized camera coordinates. void InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const override; + double* normalized_x, + double* normalized_y) const override; virtual void Pack(PackedIntrinsics* packed_intrinsics) const override; virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override; @@ -405,7 +405,7 @@ class NukeCameraIntrinsics : public CameraIntrinsics { }; NukeCameraIntrinsics(); - NukeCameraIntrinsics(const NukeCameraIntrinsics &from); + NukeCameraIntrinsics(const NukeCameraIntrinsics& from); DistortionModelType GetDistortionModelType() const override { return DISTORTION_MODEL_NUKE; @@ -424,8 +424,8 @@ class NukeCameraIntrinsics : public CameraIntrinsics { // coordinates in pixels. void ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const override; + double* image_x, + double* image_y) const override; // Invert camera intrinsics on the image point to get normalized coordinates. // @@ -433,8 +433,8 @@ class NukeCameraIntrinsics : public CameraIntrinsics { // coordinates to get normalized camera coordinates. void InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const override; + double* normalized_x, + double* normalized_y) const override; virtual void Pack(PackedIntrinsics* packed_intrinsics) const override; virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override; @@ -462,7 +462,7 @@ class BrownCameraIntrinsics : public CameraIntrinsics { }; BrownCameraIntrinsics(); - BrownCameraIntrinsics(const BrownCameraIntrinsics &from); + BrownCameraIntrinsics(const BrownCameraIntrinsics& from); DistortionModelType GetDistortionModelType() const override { return DISTORTION_MODEL_BROWN; @@ -488,8 +488,8 @@ class BrownCameraIntrinsics : public CameraIntrinsics { // coordinates in pixels. void ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const override; + double* image_x, + double* image_y) const override; // Invert camera intrinsics on the image point to get normalized coordinates. // @@ -497,8 +497,8 @@ class BrownCameraIntrinsics : public CameraIntrinsics { // coordinates to get normalized camera coordinates. void InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const override; + double* normalized_x, + double* normalized_y) const override; virtual void Pack(PackedIntrinsics* packed_intrinsics) const override; virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override; @@ -507,10 +507,8 @@ class BrownCameraIntrinsics : public CameraIntrinsics { double parameters_[NUM_PARAMETERS]; }; - /// A human-readable representation of the camera intrinsic parameters. -std::ostream& operator <<(std::ostream &os, - const CameraIntrinsics &intrinsics); +std::ostream& operator<<(std::ostream& os, const CameraIntrinsics& intrinsics); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h index e1b53992dfd..c8c4700f5c6 100644 --- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h +++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h @@ -25,11 +25,11 @@ namespace { // FIXME: C++ templates limitations makes thing complicated, // but maybe there is a simpler method. struct ApplyIntrinsicsFunction { - ApplyIntrinsicsFunction(const CameraIntrinsics &intrinsics, + ApplyIntrinsicsFunction(const CameraIntrinsics& intrinsics, double x, double y, - double *warp_x, - double *warp_y) { + double* warp_x, + double* warp_y) { double normalized_x, normalized_y; intrinsics.ImageSpaceToNormalized(x, y, &normalized_x, &normalized_y); intrinsics.ApplyIntrinsics(normalized_x, normalized_y, warp_x, warp_y); @@ -37,14 +37,15 @@ struct ApplyIntrinsicsFunction { }; struct InvertIntrinsicsFunction { - InvertIntrinsicsFunction(const CameraIntrinsics &intrinsics, + InvertIntrinsicsFunction(const CameraIntrinsics& intrinsics, double x, double y, - double *warp_x, - double *warp_y) { + double* warp_x, + double* warp_y) { double normalized_x, normalized_y; intrinsics.InvertIntrinsics(x, y, &normalized_x, &normalized_y); - intrinsics.NormalizedToImageSpace(normalized_x, normalized_y, warp_x, warp_y); + intrinsics.NormalizedToImageSpace( + normalized_x, normalized_y, warp_x, warp_y); } }; @@ -53,18 +54,18 @@ struct InvertIntrinsicsFunction { namespace internal { // TODO(MatthiasF): downsample lookup -template -void LookupWarpGrid::Compute(const CameraIntrinsics &intrinsics, +template +void LookupWarpGrid::Compute(const CameraIntrinsics& intrinsics, int width, int height, double overscan) { - double w = (double) width / (1.0 + overscan); - double h = (double) height / (1.0 + overscan); - double aspx = (double) w / intrinsics.image_width(); - double aspy = (double) h / intrinsics.image_height(); + double w = (double)width / (1.0 + overscan); + double h = (double)height / (1.0 + overscan); + double aspx = (double)w / intrinsics.image_width(); + double aspy = (double)h / intrinsics.image_height(); #if defined(_OPENMP) -# pragma omp parallel for schedule(static) num_threads(threads_) \ - if (threads_ > 1 && height > 100) +# pragma omp parallel for schedule(static) \ + num_threads(threads_) if (threads_ > 1 && height > 100) #endif for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { @@ -76,40 +77,47 @@ void LookupWarpGrid::Compute(const CameraIntrinsics &intrinsics, warp_y = warp_y * aspy + 0.5 * overscan * h; int ix = int(warp_x), iy = int(warp_y); int fx = round((warp_x - ix) * 256), fy = round((warp_y - iy) * 256); - if (fx == 256) { fx = 0; ix++; } // NOLINT - if (fy == 256) { fy = 0; iy++; } // NOLINT + if (fx == 256) { + fx = 0; + ix++; + } // NOLINT + if (fy == 256) { + fy = 0; + iy++; + } // NOLINT // Use nearest border pixel - if (ix < 0) { ix = 0, fx = 0; } // NOLINT - if (iy < 0) { iy = 0, fy = 0; } // NOLINT - if (ix >= width - 2) ix = width - 2; - if (iy >= height - 2) iy = height - 2; - - Offset offset = { (short) (ix - x), - (short) (iy - y), - (unsigned char) fx, - (unsigned char) fy }; + if (ix < 0) { + ix = 0, fx = 0; + } // NOLINT + if (iy < 0) { + iy = 0, fy = 0; + } // NOLINT + if (ix >= width - 2) + ix = width - 2; + if (iy >= height - 2) + iy = height - 2; + + Offset offset = {(short)(ix - x), + (short)(iy - y), + (unsigned char)fx, + (unsigned char)fy}; offset_[y * width + x] = offset; } } } -template -void LookupWarpGrid::Update(const CameraIntrinsics &intrinsics, +template +void LookupWarpGrid::Update(const CameraIntrinsics& intrinsics, int width, int height, double overscan) { - if (width_ != width || - height_ != height || - overscan_ != overscan) { + if (width_ != width || height_ != height || overscan_ != overscan) { Reset(); } if (offset_ == NULL) { offset_ = new Offset[width * height]; - Compute(intrinsics, - width, - height, - overscan); + Compute(intrinsics, width, height, overscan); } width_ = width; @@ -118,29 +126,30 @@ void LookupWarpGrid::Update(const CameraIntrinsics &intrinsics, } // TODO(MatthiasF): cubic B-Spline image sampling, bilinear lookup -template -void LookupWarpGrid::Apply(const PixelType *input_buffer, +template +void LookupWarpGrid::Apply(const PixelType* input_buffer, int width, int height, int channels, - PixelType *output_buffer) { + PixelType* output_buffer) { #if defined(_OPENMP) -# pragma omp parallel for schedule(static) num_threads(threads_) \ - if (threads_ > 1 && height > 100) +# pragma omp parallel for schedule(static) \ + num_threads(threads_) if (threads_ > 1 && height > 100) #endif for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Offset offset = offset_[y * width + x]; - const int pixel_index = ((y + offset.iy) * width + - (x + offset.ix)) * channels; - const PixelType *s = &input_buffer[pixel_index]; + const int pixel_index = + ((y + offset.iy) * width + (x + offset.ix)) * channels; + const PixelType* s = &input_buffer[pixel_index]; for (int i = 0; i < channels; i++) { output_buffer[(y * width + x) * channels + i] = - ((s[i] * (256 - offset.fx) + - s[channels + i] * offset.fx) * (256 - offset.fy) + - (s[width * channels + i] * (256 - offset.fx) + - s[width * channels + channels + i] * offset.fx) * offset.fy) - / (256 * 256); + ((s[i] * (256 - offset.fx) + s[channels + i] * offset.fx) * + (256 - offset.fy) + + (s[width * channels + i] * (256 - offset.fx) + + s[width * channels + channels + i] * offset.fx) * + offset.fy) / + (256 * 256); } } } @@ -148,45 +157,33 @@ void LookupWarpGrid::Apply(const PixelType *input_buffer, } // namespace internal -template -void CameraIntrinsics::DistortBuffer(const PixelType *input_buffer, +template +void CameraIntrinsics::DistortBuffer(const PixelType* input_buffer, int width, int height, double overscan, int channels, - PixelType *output_buffer) { + PixelType* output_buffer) { assert(channels >= 1); assert(channels <= 4); - distort_.Update(*this, - width, - height, - overscan); - distort_.Apply(input_buffer, - width, - height, - channels, - output_buffer); + distort_.Update(*this, width, height, overscan); + distort_.Apply( + input_buffer, width, height, channels, output_buffer); } -template -void CameraIntrinsics::UndistortBuffer(const PixelType *input_buffer, +template +void CameraIntrinsics::UndistortBuffer(const PixelType* input_buffer, int width, int height, double overscan, int channels, - PixelType *output_buffer) { + PixelType* output_buffer) { assert(channels >= 1); assert(channels <= 4); - undistort_.Update(*this, - width, - height, - overscan); - - undistort_.Apply(input_buffer, - width, - height, - channels, - output_buffer); + undistort_.Update(*this, width, height, overscan); + + undistort_.Apply( + input_buffer, width, height, channels, output_buffer); } } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc index 96d35a29ef8..cfcc2d16682 100644 --- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc +++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc @@ -22,10 +22,10 @@ #include -#include "testing/testing.h" #include "libmv/image/image.h" #include "libmv/image/image_drawing.h" #include "libmv/logging/logging.h" +#include "testing/testing.h" namespace libmv { @@ -59,26 +59,36 @@ TEST(PolynomialCameraIntrinsics, ApplyIntrinsics) { const int N = 5; double expected[N][N][2] = { - { {75.312500, -24.687500}, {338.982239, -62.035522}, - {640.000000, -72.929688}, {941.017761, -62.035522}, - {1204.687500, -24.687500}}, - - { {37.964478, 238.982239}, {323.664551, 223.664551}, - {640.000000, 219.193420}, {956.335449, 223.664551}, - {1242.035522, 238.982239}}, - - { {27.070312, 540.000000}, {319.193420, 540.000000}, - {640.000000, 540.000000}, {960.806580, 540.000000}, - {1252.929688, 540.000000}}, - - { {37.964478, 841.017761}, {323.664551, 856.335449}, - {640.000000, 860.806580}, {956.335449, 856.335449}, - {1242.035522, 841.017761}}, - - { {75.312500, 1104.687500}, {338.982239, 1142.035522}, - {640.000000, 1152.929688}, {941.017761, 1142.035522}, - {1204.687500, 1104.687500}} - }; + {{75.312500, -24.687500}, + {338.982239, -62.035522}, + {640.000000, -72.929688}, + {941.017761, -62.035522}, + {1204.687500, -24.687500}}, + + {{37.964478, 238.982239}, + {323.664551, 223.664551}, + {640.000000, 219.193420}, + {956.335449, 223.664551}, + {1242.035522, 238.982239}}, + + {{27.070312, 540.000000}, + {319.193420, 540.000000}, + {640.000000, 540.000000}, + {960.806580, 540.000000}, + {1252.929688, 540.000000}}, + + {{37.964478, 841.017761}, + {323.664551, 856.335449}, + {640.000000, 860.806580}, + {956.335449, 856.335449}, + {1242.035522, 841.017761}}, + + {{75.312500, 1104.687500}, + {338.982239, 1142.035522}, + {640.000000, 1152.929688}, + {941.017761, 1142.035522}, + {1204.687500, 1104.687500}}, + }; PolynomialCameraIntrinsics intrinsics; intrinsics.SetFocalLength(1300.0, 1300.0); @@ -89,12 +99,11 @@ TEST(PolynomialCameraIntrinsics, ApplyIntrinsics) { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { - double normalized_x = j * step - 0.5, - normalized_y = i * step - 0.5; + double normalized_x = j * step - 0.5, normalized_y = i * step - 0.5; double distorted_x, distorted_y; - intrinsics.ApplyIntrinsics(normalized_x, normalized_y, - &distorted_x, &distorted_y); + intrinsics.ApplyIntrinsics( + normalized_x, normalized_y, &distorted_x, &distorted_y); EXPECT_NEAR(expected[i][j][0], distorted_x, 1e-6); EXPECT_NEAR(expected[i][j][1], distorted_y, 1e-6); @@ -106,43 +115,51 @@ TEST(PolynomialCameraIntrinsics, InvertIntrinsics) { const int N = 5; double expected[N][N][2] = { - { {-0.524482, -0.437069}, {-0.226237, -0.403994}, - { 0.031876, -0.398446}, { 0.293917, -0.408218}, - { 0.632438, -0.465028}}, - - { {-0.493496, -0.189173}, {-0.219052, -0.179936}, - { 0.030975, -0.178107}, { 0.283742, -0.181280}, - { 0.574557, -0.194335}}, - - { {-0.488013, 0.032534}, {-0.217537, 0.031077}, - { 0.030781, 0.030781}, { 0.281635, 0.031293}, - { 0.566344, 0.033314}}, - - { {-0.498696, 0.257660}, {-0.220424, 0.244041}, - { 0.031150, 0.241409}, { 0.285660, 0.245985}, - { 0.582670, 0.265629}}, - - { {-0.550617, 0.532263}, {-0.230399, 0.477255}, - { 0.032380, 0.469510}, { 0.299986, 0.483311}, - { 0.684740, 0.584043}} - }; + {{-0.524482, -0.437069}, + {-0.226237, -0.403994}, + {0.031876, -0.398446}, + {0.293917, -0.408218}, + {0.632438, -0.465028}}, + + {{-0.493496, -0.189173}, + {-0.219052, -0.179936}, + {0.030975, -0.178107}, + {0.283742, -0.181280}, + {0.574557, -0.194335}}, + + {{-0.488013, 0.032534}, + {-0.217537, 0.031077}, + {0.030781, 0.030781}, + {0.281635, 0.031293}, + {0.566344, 0.033314}}, + + {{-0.498696, 0.257660}, + {-0.220424, 0.244041}, + {0.031150, 0.241409}, + {0.285660, 0.245985}, + {0.582670, 0.265629}}, + + {{-0.550617, 0.532263}, + {-0.230399, 0.477255}, + {0.032380, 0.469510}, + {0.299986, 0.483311}, + {0.684740, 0.584043}}, + }; PolynomialCameraIntrinsics intrinsics; intrinsics.SetFocalLength(1300.0, 1300.0); intrinsics.SetPrincipalPoint(600.0, 500.0); intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05); - double step_x = 1280.0 / (N - 1), - step_y = 1080.0 / (N - 1); + double step_x = 1280.0 / (N - 1), step_y = 1080.0 / (N - 1); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { - double distorted_x = j * step_x, - distorted_y = i * step_y; + double distorted_x = j * step_x, distorted_y = i * step_y; double normalized_x, normalized_y; - intrinsics.InvertIntrinsics(distorted_x, distorted_y, - &normalized_x, &normalized_y); + intrinsics.InvertIntrinsics( + distorted_x, distorted_y, &normalized_x, &normalized_y); EXPECT_NEAR(expected[i][j][0], normalized_x, 1e-6); EXPECT_NEAR(expected[i][j][1], normalized_y, 1e-6); @@ -190,10 +207,11 @@ TEST(PolynomialCameraIntrinsics, IdentityDistortBuffer) { FloatImage distorted_image(h, w); intrinsics.SetImageSize(w, h); intrinsics.SetFocalLength(10.0, 10.0); - intrinsics.SetPrincipalPoint((double) w / 2.0, (double) h / 2.0); + intrinsics.SetPrincipalPoint((double)w / 2.0, (double)h / 2.0); intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); intrinsics.DistortBuffer(image.Data(), - image.Width(), image.Height(), + image.Width(), + image.Height(), 0.0, image.Depth(), distorted_image.Data()); @@ -221,10 +239,11 @@ TEST(PolynomialCameraIntrinsics, IdentityUndistortBuffer) { FloatImage distorted_image(h, w); intrinsics.SetImageSize(w, h); intrinsics.SetFocalLength(10.0, 10.0); - intrinsics.SetPrincipalPoint((double) w / 2.0, (double) h / 2.0); + intrinsics.SetPrincipalPoint((double)w / 2.0, (double)h / 2.0); intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); intrinsics.UndistortBuffer(image.Data(), - image.Width(), image.Height(), + image.Width(), + image.Height(), 0.0, image.Depth(), distorted_image.Data()); diff --git a/intern/libmv/libmv/simple_pipeline/detect.cc b/intern/libmv/libmv/simple_pipeline/detect.cc index 46599a4c49e..0897c5598c6 100644 --- a/intern/libmv/libmv/simple_pipeline/detect.cc +++ b/intern/libmv/libmv/simple_pipeline/detect.cc @@ -22,14 +22,14 @@ ** ****************************************************************************/ -#include #include +#include #include #include "libmv/base/scoped_ptr.h" #include "libmv/image/array_nd.h" -#include "libmv/image/image_converter.h" #include "libmv/image/convolve.h" +#include "libmv/image/image_converter.h" #include "libmv/logging/logging.h" #include "libmv/simple_pipeline/detect.h" @@ -55,7 +55,7 @@ double kDefaultHarrisThreshold = 1e-5; class FeatureComparison { public: - bool operator() (const Feature &left, const Feature &right) const { + bool operator()(const Feature& left, const Feature& right) const { return right.score > left.score; } }; @@ -63,18 +63,17 @@ class FeatureComparison { // Filter the features so there are no features closer than // minimal distance to each other. // This is a naive implementation with O(n^2) asymptotic. -void FilterFeaturesByDistance(const vector &all_features, +void FilterFeaturesByDistance(const vector& all_features, int min_distance, - vector *detected_features) { + vector* detected_features) { const int min_distance_squared = min_distance * min_distance; // Use priority queue to sort the features by their score. // // Do this on copy of the input features to prevent possible // distortion in callee function behavior. - std::priority_queue, - FeatureComparison> priority_features; + std::priority_queue, FeatureComparison> + priority_features; for (int i = 0; i < all_features.size(); i++) { priority_features.push(all_features.at(i)); @@ -85,7 +84,7 @@ void FilterFeaturesByDistance(const vector &all_features, Feature a = priority_features.top(); for (int i = 0; i < detected_features->size(); i++) { - Feature &b = detected_features->at(i); + Feature& b = detected_features->at(i); if (Square(a.x - b.x) + Square(a.y - b.y) < min_distance_squared) { ok = false; break; @@ -100,9 +99,9 @@ void FilterFeaturesByDistance(const vector &all_features, } } -void DetectFAST(const FloatImage &grayscale_image, - const DetectOptions &options, - vector *detected_features) { +void DetectFAST(const FloatImage& grayscale_image, + const DetectOptions& options, + vector* detected_features) { #ifndef LIBMV_NO_FAST_DETECTOR const int min_distance = options.min_distance; const int min_trackness = options.fast_min_trackness; @@ -111,12 +110,14 @@ void DetectFAST(const FloatImage &grayscale_image, const int height = grayscale_image.Width() - 2 * margin; const int stride = grayscale_image.Width(); - scoped_array byte_image(FloatImageToUCharArray(grayscale_image)); + scoped_array byte_image( + FloatImageToUCharArray(grayscale_image)); const int byte_image_offset = margin * stride + margin; - // TODO(MatthiasF): Support targetting a feature count (binary search trackness) + // TODO(MatthiasF): Support targetting a feature count (binary search + // trackness) int num_features; - xy *all = fast9_detect(byte_image.get() + byte_image_offset, + xy* all = fast9_detect(byte_image.get() + byte_image_offset, width, height, stride, @@ -126,13 +127,13 @@ void DetectFAST(const FloatImage &grayscale_image, free(all); return; } - int *scores = fast9_score(byte_image.get() + byte_image_offset, + int* scores = fast9_score(byte_image.get() + byte_image_offset, stride, all, num_features, min_trackness); // TODO(MatthiasF): merge with close feature suppression - xy *nonmax = nonmax_suppression(all, scores, num_features, &num_features); + xy* nonmax = nonmax_suppression(all, scores, num_features, &num_features); free(all); // Remove too close features // TODO(MatthiasF): A resolution independent parameter would be better than @@ -152,89 +153,104 @@ void DetectFAST(const FloatImage &grayscale_image, free(scores); free(nonmax); #else - (void) grayscale_image; // Ignored. - (void) options; // Ignored. - (void) detected_features; // Ignored. + (void)grayscale_image; // Ignored. + (void)options; // Ignored. + (void)detected_features; // Ignored. LOG(FATAL) << "FAST detector is disabled in this build."; #endif } #ifdef __SSE2__ -static unsigned int SAD(const ubyte* imageA, const ubyte* imageB, - int strideA, int strideB) { +static unsigned int SAD(const ubyte* imageA, + const ubyte* imageB, + int strideA, + int strideB) { __m128i a = _mm_setzero_si128(); for (int i = 0; i < 16; i++) { - a = _mm_adds_epu16(a, - _mm_sad_epu8(_mm_loadu_si128((__m128i*)(imageA+i*strideA)), - _mm_loadu_si128((__m128i*)(imageB+i*strideB)))); + a = _mm_adds_epu16( + a, + _mm_sad_epu8(_mm_loadu_si128((__m128i*)(imageA + i * strideA)), + _mm_loadu_si128((__m128i*)(imageB + i * strideB)))); } return _mm_extract_epi16(a, 0) + _mm_extract_epi16(a, 4); } #else -static unsigned int SAD(const ubyte* imageA, const ubyte* imageB, - int strideA, int strideB) { +static unsigned int SAD(const ubyte* imageA, + const ubyte* imageB, + int strideA, + int strideB) { unsigned int sad = 0; for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { - sad += abs((int)imageA[i*strideA+j] - imageB[i*strideB+j]); + sad += abs((int)imageA[i * strideA + j] - imageB[i * strideB + j]); } } return sad; } #endif -void DetectMORAVEC(const FloatImage &grayscale_image, - const DetectOptions &options, - vector *detected_features) { +void DetectMORAVEC(const FloatImage& grayscale_image, + const DetectOptions& options, + vector* detected_features) { const int distance = options.min_distance; const int margin = options.margin; - const unsigned char *pattern = options.moravec_pattern; + const unsigned char* pattern = options.moravec_pattern; const int count = options.moravec_max_count; const int width = grayscale_image.Width() - 2 * margin; const int height = grayscale_image.Width() - 2 * margin; const int stride = grayscale_image.Width(); - scoped_array byte_image(FloatImageToUCharArray(grayscale_image)); + scoped_array byte_image( + FloatImageToUCharArray(grayscale_image)); unsigned short histogram[256]; memset(histogram, 0, sizeof(histogram)); - scoped_array scores(new ubyte[width*height]); - memset(scores.get(), 0, width*height); + scoped_array scores(new ubyte[width * height]); + memset(scores.get(), 0, width * height); const int r = 1; // radius for self similarity comparison - for (int y = distance; y < height-distance; y++) { - for (int x = distance; x < width-distance; x++) { - const ubyte* s = &byte_image[y*stride+x]; - int score = // low self-similarity with overlapping patterns - // OPTI: load pattern once + for (int y = distance; y < height - distance; y++) { + for (int x = distance; x < width - distance; x++) { + const ubyte* s = &byte_image[y * stride + x]; + // low self-similarity with overlapping patterns + // OPTI: load pattern once + // clang-format off + int score = SAD(s, s-r*stride-r, stride, stride)+SAD(s, s-r*stride, stride, stride)+SAD(s, s-r*stride+r, stride, stride)+ SAD(s, s -r, stride, stride)+ SAD(s, s +r, stride, stride)+ SAD(s, s+r*stride-r, stride, stride)+SAD(s, s+r*stride, stride, stride)+SAD(s, s+r*stride+r, stride, stride); + // clang-format on + score /= 256; // normalize - if (pattern) // find only features similar to pattern + if (pattern) // find only features similar to pattern score -= SAD(s, pattern, stride, 16); - if (score <= 16) continue; // filter very self-similar features + if (score <= 16) + continue; // filter very self-similar features score -= 16; // translate to score/histogram values - if (score>255) score=255; // clip - ubyte* c = &scores[y*width+x]; + if (score > 255) + score = 255; // clip + ubyte* c = &scores[y * width + x]; for (int i = -distance; i < 0; i++) { for (int j = -distance; j < distance; j++) { - int s = c[i*width+j]; - if (s == 0) continue; - if (s >= score) goto nonmax; - c[i*width+j] = 0; + int s = c[i * width + j]; + if (s == 0) + continue; + if (s >= score) + goto nonmax; + c[i * width + j] = 0; histogram[s]--; } } for (int i = 0, j = -distance; j < 0; j++) { - int s = c[i*width+j]; - if (s == 0) continue; - if (s >= score) goto nonmax; - c[i*width+j] = 0; + int s = c[i * width + j]; + if (s == 0) + continue; + if (s >= score) + goto nonmax; + c[i * width + j] = 0; histogram[s]--; } c[0] = score, histogram[score]++; - nonmax: - { } // Do nothing. + nonmax : {} // Do nothing. } } int min = 255, total = 0; @@ -254,18 +270,16 @@ void DetectMORAVEC(const FloatImage &grayscale_image, // Score calculation above uses top left corner of the // patch as the origin, here we need to convert this value // to a pattrn center by adding 8 pixels. - detected_features->push_back(Feature((float) x + 8.0f, - (float) y + 8.0f, - (float) s, - 16.0f)); + detected_features->push_back( + Feature((float)x + 8.0f, (float)y + 8.0f, (float)s, 16.0f)); } } } } -void DetectHarris(const FloatImage &grayscale_image, - const DetectOptions &options, - vector *detected_features) { +void DetectHarris(const FloatImage& grayscale_image, + const DetectOptions& options, + vector* detected_features) { const double alpha = 0.06; const double sigma = 0.9; @@ -281,9 +295,7 @@ void DetectHarris(const FloatImage &grayscale_image, MultiplyElements(gradient_y, gradient_y, &gradient_yy); MultiplyElements(gradient_x, gradient_y, &gradient_xy); - FloatImage gradient_xx_blurred, - gradient_yy_blurred, - gradient_xy_blurred; + FloatImage gradient_xx_blurred, gradient_yy_blurred, gradient_xy_blurred; ConvolveGaussian(gradient_xx, sigma, &gradient_xx_blurred); ConvolveGaussian(gradient_yy, sigma, &gradient_yy_blurred); ConvolveGaussian(gradient_xy, sigma, &gradient_xy_blurred); @@ -304,10 +316,8 @@ void DetectHarris(const FloatImage &grayscale_image, double traceA = A.trace(); double harris_function = detA - alpha * traceA * traceA; if (harris_function > threshold) { - all_features.push_back(Feature((float) x, - (float) y, - (float) harris_function, - 5.0f)); + all_features.push_back( + Feature((float)x, (float)y, (float)harris_function, 5.0f)); } } } @@ -318,17 +328,18 @@ void DetectHarris(const FloatImage &grayscale_image, } // namespace DetectOptions::DetectOptions() - : type(DetectOptions::HARRIS), - margin(0), - min_distance(120), - fast_min_trackness(kDefaultFastMinTrackness), - moravec_max_count(0), - moravec_pattern(NULL), - harris_threshold(kDefaultHarrisThreshold) {} - -void Detect(const FloatImage &image, - const DetectOptions &options, - vector *detected_features) { + : type(DetectOptions::HARRIS), + margin(0), + min_distance(120), + fast_min_trackness(kDefaultFastMinTrackness), + moravec_max_count(0), + moravec_pattern(NULL), + harris_threshold(kDefaultHarrisThreshold) { +} + +void Detect(const FloatImage& image, + const DetectOptions& options, + vector* detected_features) { // Currently all the detectors requires image to be grayscale. // Do it here to avoid code duplication. FloatImage grayscale_image; @@ -350,8 +361,7 @@ void Detect(const FloatImage &image, } } -std::ostream& operator <<(std::ostream &os, - const Feature &feature) { +std::ostream& operator<<(std::ostream& os, const Feature& feature) { os << "x: " << feature.x << ", y: " << feature.y; os << ", score: " << feature.score; os << ", size: " << feature.size; diff --git a/intern/libmv/libmv/simple_pipeline/detect.h b/intern/libmv/libmv/simple_pipeline/detect.h index 1035287bcf2..8ddf0025e4b 100644 --- a/intern/libmv/libmv/simple_pipeline/detect.h +++ b/intern/libmv/libmv/simple_pipeline/detect.h @@ -39,7 +39,7 @@ typedef unsigned char ubyte; struct Feature { Feature(float x, float y) : x(x), y(y) {} Feature(float x, float y, float score, float size) - : x(x), y(y), score(score), size(size) {} + : x(x), y(y), score(score), size(size) {} // Position of the feature in pixels from top-left corner. // Note: Libmv detector might eventually support subpixel precision. @@ -88,9 +88,9 @@ struct DetectOptions { // Find only features similar to this pattern. Only used by MORAVEC detector. // - // This is an image patch denoted in byte array with dimensions of 16px by 16px - // used to filter features by similarity to this patch. - unsigned char *moravec_pattern; + // This is an image patch denoted in byte array with dimensions of 16px by + // 16px used to filter features by similarity to this patch. + unsigned char* moravec_pattern; // Threshold value of the Harris function to add new featrue // to the result. @@ -101,12 +101,11 @@ struct DetectOptions { // // Image could have 1-4 channels, it'll be converted to a grayscale // by the detector function if needed. -void Detect(const FloatImage &image, - const DetectOptions &options, - vector *detected_features); +void Detect(const FloatImage& image, + const DetectOptions& options, + vector* detected_features); -std::ostream& operator <<(std::ostream &os, - const Feature &feature); +std::ostream& operator<<(std::ostream& os, const Feature& feature); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/detect_test.cc b/intern/libmv/libmv/simple_pipeline/detect_test.cc index b226ad96595..718598d04e1 100644 --- a/intern/libmv/libmv/simple_pipeline/detect_test.cc +++ b/intern/libmv/libmv/simple_pipeline/detect_test.cc @@ -20,14 +20,14 @@ #include "libmv/simple_pipeline/detect.h" -#include "testing/testing.h" #include "libmv/logging/logging.h" +#include "testing/testing.h" namespace libmv { namespace { -void PreformSinglePointTest(const DetectOptions &options) { +void PreformSinglePointTest(const DetectOptions& options) { // Prepare the image. FloatImage image(15, 15); image.fill(1.0); @@ -40,7 +40,7 @@ void PreformSinglePointTest(const DetectOptions &options) { // Check detected features matches our expectations. EXPECT_EQ(1, detected_features.size()); if (detected_features.size() == 1) { - Feature &feature = detected_features[0]; + Feature& feature = detected_features[0]; EXPECT_EQ(7, feature.x); EXPECT_EQ(7, feature.y); } @@ -83,8 +83,8 @@ void PreformCheckerBoardTest(const DetectOptions &options) { } #endif -void CheckExpectedFeatures(const vector &detected_features, - const vector &expected_features) { +void CheckExpectedFeatures(const vector& detected_features, + const vector& expected_features) { EXPECT_EQ(expected_features.size(), detected_features.size()); // That's unsafe to iterate over vectors when their lengths @@ -95,10 +95,10 @@ void CheckExpectedFeatures(const vector &detected_features, } for (int i = 0; i < expected_features.size(); ++i) { - const Feature &extected_feature = expected_features[i]; + const Feature& extected_feature = expected_features[i]; bool found = false; for (int j = 0; j < detected_features.size(); ++j) { - const Feature &detected_feature = detected_features[j]; + const Feature& detected_feature = detected_features[j]; if (extected_feature.x == detected_feature.x && extected_feature.y == detected_feature.y) { found = true; @@ -109,15 +109,14 @@ void CheckExpectedFeatures(const vector &detected_features, } } -void PreformSingleTriangleTest(const DetectOptions &options) { +void PreformSingleTriangleTest(const DetectOptions& options) { // Prepare the image. FloatImage image(15, 21); image.fill(1.0); int vertex_x = 10, vertex_y = 5; for (int i = 0; i < 6; ++i) { - int current_x = vertex_x - i, - current_y = vertex_y + i; + int current_x = vertex_x - i, current_y = vertex_y + i; for (int j = 0; j < i * 2 + 1; ++j, ++current_x) { image(current_y, current_x) = 0.0; } diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.cc b/intern/libmv/libmv/simple_pipeline/distortion_models.cc index f602234b630..4556e3ceaf9 100644 --- a/intern/libmv/libmv/simple_pipeline/distortion_models.cc +++ b/intern/libmv/libmv/simple_pipeline/distortion_models.cc @@ -41,25 +41,34 @@ struct InvertPolynomialIntrinsicsCostFunction { const double p2, const double image_x, const double image_y) - : focal_length_x_(focal_length_x), - focal_length_y_(focal_length_y), - principal_point_x_(principal_point_x), - principal_point_y_(principal_point_y), - k1_(k1), k2_(k2), k3_(k3), - p1_(p1), p2_(p2), - x_(image_x), y_(image_y) {} - - Vec2 operator()(const Vec2 &u) const { + : focal_length_x_(focal_length_x), + focal_length_y_(focal_length_y), + principal_point_x_(principal_point_x), + principal_point_y_(principal_point_y), + k1_(k1), + k2_(k2), + k3_(k3), + p1_(p1), + p2_(p2), + x_(image_x), + y_(image_y) {} + + Vec2 operator()(const Vec2& u) const { double xx, yy; ApplyPolynomialDistortionModel(focal_length_x_, focal_length_y_, principal_point_x_, principal_point_y_, - k1_, k2_, k3_, - p1_, p2_, - u(0), u(1), - &xx, &yy); + k1_, + k2_, + k3_, + p1_, + p2_, + u(0), + u(1), + &xx, + &yy); Vec2 fx; fx << (xx - x_), (yy - y_); @@ -87,23 +96,28 @@ struct InvertDivisionIntrinsicsCostFunction { const double k2, const double image_x, const double image_y) - : focal_length_x_(focal_length_x), - focal_length_y_(focal_length_y), - principal_point_x_(principal_point_x), - principal_point_y_(principal_point_y), - k1_(k1), k2_(k2), - x_(image_x), y_(image_y) {} - - Vec2 operator()(const Vec2 &u) const { + : focal_length_x_(focal_length_x), + focal_length_y_(focal_length_y), + principal_point_x_(principal_point_x), + principal_point_y_(principal_point_y), + k1_(k1), + k2_(k2), + x_(image_x), + y_(image_y) {} + + Vec2 operator()(const Vec2& u) const { double xx, yy; ApplyDivisionDistortionModel(focal_length_x_, focal_length_y_, principal_point_x_, principal_point_y_, - k1_, k2_, - u(0), u(1), - &xx, &yy); + k1_, + k2_, + u(0), + u(1), + &xx, + &yy); Vec2 fx; fx << (xx - x_), (yy - y_); @@ -134,25 +148,36 @@ struct InvertBrownIntrinsicsCostFunction { const double p2, const double image_x, const double image_y) - : focal_length_x_(focal_length_x), - focal_length_y_(focal_length_y), - principal_point_x_(principal_point_x), - principal_point_y_(principal_point_y), - k1_(k1), k2_(k2), k3_(k3), k4_(k4), - p1_(p1), p2_(p2), - x_(image_x), y_(image_y) {} - - Vec2 operator()(const Vec2 &u) const { + : focal_length_x_(focal_length_x), + focal_length_y_(focal_length_y), + principal_point_x_(principal_point_x), + principal_point_y_(principal_point_y), + k1_(k1), + k2_(k2), + k3_(k3), + k4_(k4), + p1_(p1), + p2_(p2), + x_(image_x), + y_(image_y) {} + + Vec2 operator()(const Vec2& u) const { double xx, yy; ApplyBrownDistortionModel(focal_length_x_, focal_length_y_, principal_point_x_, principal_point_y_, - k1_, k2_, k3_, k4_, - p1_, p2_, - u(0), u(1), - &xx, &yy); + k1_, + k2_, + k3_, + k4_, + p1_, + p2_, + u(0), + u(1), + &xx, + &yy); Vec2 fx; fx << (xx - x_), (yy - y_); @@ -180,8 +205,8 @@ void InvertPolynomialDistortionModel(const double focal_length_x, const double p2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y) { + double* normalized_x, + double* normalized_y) { // Compute the initial guess. For a camera with no distortion, this will also // be the final answer; the LM iteration will terminate immediately. Vec2 normalized; @@ -194,13 +219,17 @@ void InvertPolynomialDistortionModel(const double focal_length_x, focal_length_y, principal_point_x, principal_point_y, - k1, k2, k3, - p1, p2, - image_x, image_y); + k1, + k2, + k3, + p1, + p2, + image_x, + image_y); Solver::SolverParameters params; Solver solver(intrinsics_cost); - /*Solver::Results results =*/ solver.minimize(params, &normalized); + /*Solver::Results results =*/solver.minimize(params, &normalized); // TODO(keir): Better error handling. @@ -216,8 +245,8 @@ void InvertDivisionDistortionModel(const double focal_length_x, const double k2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y) { + double* normalized_x, + double* normalized_y) { // Compute the initial guess. For a camera with no distortion, this will also // be the final answer; the LM iteration will terminate immediately. Vec2 normalized; @@ -231,12 +260,14 @@ void InvertDivisionDistortionModel(const double focal_length_x, focal_length_y, principal_point_x, principal_point_y, - k1, k2, - image_x, image_y); + k1, + k2, + image_x, + image_y); Solver::SolverParameters params; Solver solver(intrinsics_cost); - /*Solver::Results results =*/ solver.minimize(params, &normalized); + /*Solver::Results results =*/solver.minimize(params, &normalized); // TODO(keir): Better error handling. @@ -256,8 +287,8 @@ void InvertBrownDistortionModel(const double focal_length_x, const double p2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y) { + double* normalized_x, + double* normalized_y) { // Compute the initial guess. For a camera with no distortion, this will also // be the final answer; the LM iteration will terminate immediately. Vec2 normalized; @@ -270,13 +301,18 @@ void InvertBrownDistortionModel(const double focal_length_x, focal_length_y, principal_point_x, principal_point_y, - k1, k2, k3, k4, - p1, p2, - image_x, image_y); + k1, + k2, + k3, + k4, + p1, + p2, + image_x, + image_y); Solver::SolverParameters params; Solver solver(intrinsics_cost); - /*Solver::Results results =*/ solver.minimize(params, &normalized); + /*Solver::Results results =*/solver.minimize(params, &normalized); // TODO(keir): Better error handling. @@ -299,31 +335,36 @@ struct ApplyNukeIntrinsicsCostFunction { const double k2, const double expected_normalized_x, const double expected_normalized_y) - : focal_length_x_(focal_length_x), - focal_length_y_(focal_length_y), - principal_point_x_(principal_point_x), - principal_point_y_(principal_point_y), - image_width_(image_width), - image_height_(image_height), - k1_(k1), k2_(k2), - expected_normalized_x_(expected_normalized_x), - expected_normalized_y_(expected_normalized_y) {} - - Vec2 operator()(const Vec2 &image_coordinate) const { + : focal_length_x_(focal_length_x), + focal_length_y_(focal_length_y), + principal_point_x_(principal_point_x), + principal_point_y_(principal_point_y), + image_width_(image_width), + image_height_(image_height), + k1_(k1), + k2_(k2), + expected_normalized_x_(expected_normalized_x), + expected_normalized_y_(expected_normalized_y) {} + + Vec2 operator()(const Vec2& image_coordinate) const { double actual_normalized_x, actual_normalized_y; InvertNukeDistortionModel(focal_length_x_, focal_length_y_, principal_point_x_, principal_point_y_, - image_width_, image_height_, - k1_, k2_, - image_coordinate(0), image_coordinate(1), - &actual_normalized_x, &actual_normalized_y); + image_width_, + image_height_, + k1_, + k2_, + image_coordinate(0), + image_coordinate(1), + &actual_normalized_x, + &actual_normalized_y); Vec2 fx; fx << (actual_normalized_x - expected_normalized_x_), - (actual_normalized_y - expected_normalized_y_); + (actual_normalized_y - expected_normalized_y_); return fx; } double focal_length_x_; @@ -346,8 +387,8 @@ void ApplyNukeDistortionModel(const double focal_length_x, const double k2, const double normalized_x, const double normalized_y, - double *image_x, - double *image_y) { + double* image_x, + double* image_y) { // Compute the initial guess. For a camera with no distortion, this will also // be the final answer; the LM iteration will terminate immediately. Vec2 image; @@ -363,12 +404,14 @@ void ApplyNukeDistortionModel(const double focal_length_x, principal_point_y, image_width, image_height, - k1, k2, - normalized_x, normalized_y); + k1, + k2, + normalized_x, + normalized_y); Solver::SolverParameters params; Solver solver(intrinsics_cost); - /*Solver::Results results =*/ solver.minimize(params, &image); + /*Solver::Results results =*/solver.minimize(params, &image); // TODO(keir): Better error handling. diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.h b/intern/libmv/libmv/simple_pipeline/distortion_models.h index 51300477956..5fe9fee8d54 100644 --- a/intern/libmv/libmv/simple_pipeline/distortion_models.h +++ b/intern/libmv/libmv/simple_pipeline/distortion_models.h @@ -46,37 +46,37 @@ void InvertPolynomialDistortionModel(const double focal_length_x, const double p2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y); + double* normalized_x, + double* normalized_y); // Apply camera intrinsics to the normalized point to get image coordinates. // This applies the radial lens distortion to a point which is in normalized // camera coordinates (i.e. the principal point is at (0, 0)) to get image // coordinates in pixels. Templated for use with autodifferentiation. template -inline void ApplyPolynomialDistortionModel(const T &focal_length_x, - const T &focal_length_y, - const T &principal_point_x, - const T &principal_point_y, - const T &k1, - const T &k2, - const T &k3, - const T &p1, - const T &p2, - const T &normalized_x, - const T &normalized_y, - T *image_x, - T *image_y) { +inline void ApplyPolynomialDistortionModel(const T& focal_length_x, + const T& focal_length_y, + const T& principal_point_x, + const T& principal_point_y, + const T& k1, + const T& k2, + const T& k3, + const T& p1, + const T& p2, + const T& normalized_x, + const T& normalized_y, + T* image_x, + T* image_y) { T x = normalized_x; T y = normalized_y; // Apply distortion to the normalized points to get (xd, yd). - T r2 = x*x + y*y; + T r2 = x * x + y * y; T r4 = r2 * r2; T r6 = r4 * r2; - T r_coeff = (T(1) + k1*r2 + k2*r4 + k3*r6); - T xd = x * r_coeff + T(2)*p1*x*y + p2*(r2 + T(2)*x*x); - T yd = y * r_coeff + T(2)*p2*x*y + p1*(r2 + T(2)*y*y); + T r_coeff = (T(1) + k1 * r2 + k2 * r4 + k3 * r6); + T xd = x * r_coeff + T(2) * p1 * x * y + p2 * (r2 + T(2) * x * x); + T yd = y * r_coeff + T(2) * p2 * x * y + p1 * (r2 + T(2) * y * y); // Apply focal length and principal point to get the final image coordinates. *image_x = focal_length_x * xd + principal_point_x; @@ -96,8 +96,8 @@ void InvertDivisionDistortionModel(const double focal_length_x, const double k2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y); + double* normalized_x, + double* normalized_y); // Apply camera intrinsics to the normalized point to get image coordinates. // This applies the radial lens distortion to a point which is in normalized @@ -106,20 +106,19 @@ void InvertDivisionDistortionModel(const double focal_length_x, // // Uses division distortion model. template -inline void ApplyDivisionDistortionModel(const T &focal_length_x, - const T &focal_length_y, - const T &principal_point_x, - const T &principal_point_y, - const T &k1, - const T &k2, - const T &normalized_x, - const T &normalized_y, - T *image_x, - T *image_y) { - +inline void ApplyDivisionDistortionModel(const T& focal_length_x, + const T& focal_length_y, + const T& principal_point_x, + const T& principal_point_y, + const T& k1, + const T& k2, + const T& normalized_x, + const T& normalized_y, + T* image_x, + T* image_y) { T x = normalized_x; T y = normalized_y; - T r2 = x*x + y*y; + T r2 = x * x + y * y; T r4 = r2 * r2; T xd = x / (T(1) + k1 * r2 + k2 * r4); @@ -136,18 +135,18 @@ inline void ApplyDivisionDistortionModel(const T &focal_length_x, // // Uses Nuke distortion model. template -void InvertNukeDistortionModel(const T &focal_length_x, - const T &focal_length_y, - const T &principal_point_x, - const T &principal_point_y, +void InvertNukeDistortionModel(const T& focal_length_x, + const T& focal_length_y, + const T& principal_point_x, + const T& principal_point_y, const int image_width, const int image_height, - const T &k1, - const T &k2, - const T &image_x, - const T &image_y, - T *normalized_x, - T *normalized_y) { + const T& k1, + const T& k2, + const T& image_x, + const T& image_y, + T* normalized_x, + T* normalized_y) { // According to the documentation: // // xu = xd / (1 + k0 * rd^2 + k1 * rd^4) @@ -174,9 +173,9 @@ void InvertNukeDistortionModel(const T &focal_length_x, const T xd = (image_x - principal_point_x) / max_half_image_size; const T yd = (image_y - principal_point_y) / max_half_image_size; - T rd2 = xd*xd + yd*yd; + T rd2 = xd * xd + yd * yd; T rd4 = rd2 * rd2; - T r_coeff = T(1) / (T(1) + k1*rd2 + k2*rd4); + T r_coeff = T(1) / (T(1) + k1 * rd2 + k2 * rd4); T xu = xd * r_coeff; T yu = yd * r_coeff; @@ -200,8 +199,8 @@ void ApplyNukeDistortionModel(const double focal_length_x, const double k2, const double normalized_x, const double normalized_y, - double *image_x, - double *image_y); + double* image_x, + double* image_y); // Invert camera intrinsics on the image point to get normalized coordinates. // This inverts the radial lens distortion to a point which is in image pixel @@ -218,24 +217,24 @@ void InvertBrownDistortionModel(const double focal_length_x, const double p2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y); + double* normalized_x, + double* normalized_y); template -inline void ApplyBrownDistortionModel(const T &focal_length_x, - const T &focal_length_y, - const T &principal_point_x, - const T &principal_point_y, - const T &k1, - const T &k2, - const T &k3, - const T &k4, - const T &p1, - const T &p2, - const T &normalized_x, - const T &normalized_y, - T *image_x, - T *image_y) { +inline void ApplyBrownDistortionModel(const T& focal_length_x, + const T& focal_length_y, + const T& principal_point_x, + const T& principal_point_y, + const T& k1, + const T& k2, + const T& k3, + const T& k4, + const T& p1, + const T& p2, + const T& normalized_x, + const T& normalized_y, + T* image_x, + T* image_y) { T x = normalized_x; T y = normalized_y; @@ -253,8 +252,8 @@ inline void ApplyBrownDistortionModel(const T &focal_length_x, // Apply focal length and principal point to get the final image coordinates. *image_x = focal_length_x * xd + principal_point_x; *image_y = focal_length_y * yd + principal_point_y; -} // namespace libmv +} // namespace libmv -} +} // namespace libmv #endif // LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_ diff --git a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc index 7a086c375d5..10ad0929007 100644 --- a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc +++ b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc @@ -32,8 +32,9 @@ namespace libmv { namespace { -void GetImagesInMarkers(const vector &markers, - int *image1, int *image2) { +void GetImagesInMarkers(const vector& markers, + int* image1, + int* image2) { if (markers.size() < 2) { return; } @@ -50,10 +51,11 @@ void GetImagesInMarkers(const vector &markers, } // namespace -bool EuclideanReconstructTwoFrames(const vector &markers, - EuclideanReconstruction *reconstruction) { +bool EuclideanReconstructTwoFrames(const vector& markers, + EuclideanReconstruction* reconstruction) { if (markers.size() < 16) { - LG << "Not enough markers to initialize from two frames: " << markers.size(); + LG << "Not enough markers to initialize from two frames: " + << markers.size(); return false; } @@ -76,10 +78,8 @@ bool EuclideanReconstructTwoFrames(const vector &markers, Mat3 R; Vec3 t; Mat3 K = Mat3::Identity(); - if (!MotionFromEssentialAndCorrespondence(E, - K, x1.col(0), - K, x2.col(0), - &R, &t)) { + if (!MotionFromEssentialAndCorrespondence( + E, K, x1.col(0), K, x2.col(0), &R, &t)) { LG << "Failed to compute R and t from E and K."; return false; } @@ -88,14 +88,14 @@ bool EuclideanReconstructTwoFrames(const vector &markers, reconstruction->InsertCamera(image1, Mat3::Identity(), Vec3::Zero()); reconstruction->InsertCamera(image2, R, t); - LG << "From two frame reconstruction got:\nR:\n" << R - << "\nt:" << t.transpose(); + LG << "From two frame reconstruction got:\nR:\n" + << R << "\nt:" << t.transpose(); return true; } namespace { -Mat3 DecodeF(const Vec9 &encoded_F) { +Mat3 DecodeF(const Vec9& encoded_F) { // Decode F and force it to be rank 2. Map full_rank_F(encoded_F.data(), 3, 3); Eigen::JacobiSVD svd(full_rank_F, @@ -110,22 +110,22 @@ Mat3 DecodeF(const Vec9 &encoded_F) { // doing a full SVD of F at each iteration. This uses sampson error. struct FundamentalSampsonCostFunction { public: - typedef Vec FMatrixType; + typedef Vec FMatrixType; typedef Vec9 XMatrixType; // Assumes markers are ordered by track. - explicit FundamentalSampsonCostFunction(const vector &markers) - : markers(markers) {} + explicit FundamentalSampsonCostFunction(const vector& markers) + : markers(markers) {} - Vec operator()(const Vec9 &encoded_F) const { + Vec operator()(const Vec9& encoded_F) const { // Decode F and force it to be rank 2. Mat3 F = DecodeF(encoded_F); Vec residuals(markers.size() / 2); residuals.setZero(); for (int i = 0; i < markers.size() / 2; ++i) { - const Marker &marker1 = markers[2*i + 0]; - const Marker &marker2 = markers[2*i + 1]; + const Marker& marker1 = markers[2 * i + 0]; + const Marker& marker2 = markers[2 * i + 1]; CHECK_EQ(marker1.track, marker2.track); Vec2 x1(marker1.x, marker1.y); Vec2 x2(marker2.x, marker2.y); @@ -134,13 +134,13 @@ struct FundamentalSampsonCostFunction { } return residuals; } - const vector &markers; + const vector& markers; }; } // namespace -bool ProjectiveReconstructTwoFrames(const vector &markers, - ProjectiveReconstruction *reconstruction) { +bool ProjectiveReconstructTwoFrames(const vector& markers, + ProjectiveReconstruction* reconstruction) { if (markers.size() < 16) { return false; } diff --git a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h index 32cd4285190..354db14971f 100644 --- a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h +++ b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h @@ -37,18 +37,19 @@ class ProjectiveReconstruction; tracks visible in both frames. The pose estimation of the camera for these frames will be inserted into \a *reconstruction. - \note The two frames need to have both enough parallax and enough common tracks - for accurate reconstruction. At least 8 tracks are suggested. - \note The origin of the coordinate system is defined to be the camera of - the first keyframe. - \note This assumes a calibrated reconstruction, e.g. the markers are - already corrected for camera intrinsics and radial distortion. + \note The two frames need to have both enough parallax and enough common + tracks for accurate reconstruction. At least 8 tracks are suggested. + \note The origin of the coordinate system is defined to be the camera of the + first keyframe. + \note This assumes a calibrated reconstruction, e.g. the + markers are already corrected for camera intrinsics and radial + distortion. \note This assumes an outlier-free set of markers. \sa EuclideanResect, EuclideanIntersect, EuclideanBundle */ -bool EuclideanReconstructTwoFrames(const vector &markers, - EuclideanReconstruction *reconstruction); +bool EuclideanReconstructTwoFrames(const vector& markers, + EuclideanReconstruction* reconstruction); /*! Initialize the \link ProjectiveReconstruction reconstruction \endlink using @@ -58,17 +59,17 @@ bool EuclideanReconstructTwoFrames(const vector &markers, tracks visible in both frames. An estimate of the projection matrices for the two frames will get added to the reconstruction. - \note The two frames need to have both enough parallax and enough common tracks - for accurate reconstruction. At least 8 tracks are suggested. - \note The origin of the coordinate system is defined to be the camera of - the first keyframe. + \note The two frames need to have both enough parallax and enough common + tracks for accurate reconstruction. At least 8 tracks are suggested. + \note The origin of the coordinate system is defined to be the camera of the + first keyframe. \note This assumes the markers are already corrected for radial distortion. \note This assumes an outlier-free set of markers. \sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle */ -bool ProjectiveReconstructTwoFrames(const vector &markers, - ProjectiveReconstruction *reconstruction); +bool ProjectiveReconstructTwoFrames(const vector& markers, + ProjectiveReconstruction* reconstruction); } // namespace libmv #endif // LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H diff --git a/intern/libmv/libmv/simple_pipeline/intersect.cc b/intern/libmv/libmv/simple_pipeline/intersect.cc index ddb713684a4..86efd26f778 100644 --- a/intern/libmv/libmv/simple_pipeline/intersect.cc +++ b/intern/libmv/libmv/simple_pipeline/intersect.cc @@ -22,11 +22,11 @@ #include "libmv/base/vector.h" #include "libmv/logging/logging.h" +#include "libmv/multiview/nviewtriangulation.h" #include "libmv/multiview/projection.h" #include "libmv/multiview/triangulation.h" -#include "libmv/multiview/nviewtriangulation.h" -#include "libmv/numeric/numeric.h" #include "libmv/numeric/levenberg_marquardt.h" +#include "libmv/numeric/numeric.h" #include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/tracks.h" @@ -38,12 +38,12 @@ namespace { class EuclideanIntersectCostFunctor { public: - EuclideanIntersectCostFunctor(const Marker &marker, - const EuclideanCamera &camera) + EuclideanIntersectCostFunctor(const Marker& marker, + const EuclideanCamera& camera) : marker_(marker), camera_(camera) {} - template - bool operator()(const T *X, T *residuals) const { + template + bool operator()(const T* X, T* residuals) const { typedef Eigen::Matrix Mat3; typedef Eigen::Matrix Vec3; @@ -60,14 +60,14 @@ class EuclideanIntersectCostFunctor { return true; } - const Marker &marker_; - const EuclideanCamera &camera_; + const Marker& marker_; + const EuclideanCamera& camera_; }; } // namespace -bool EuclideanIntersect(const vector &markers, - EuclideanReconstruction *reconstruction) { +bool EuclideanIntersect(const vector& markers, + EuclideanReconstruction* reconstruction) { if (markers.size() < 2) { return false; } @@ -78,7 +78,7 @@ bool EuclideanIntersect(const vector &markers, vector cameras; Mat34 P; for (int i = 0; i < markers.size(); ++i) { - EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image); + EuclideanCamera* camera = reconstruction->CameraForImage(markers[i].image); P_From_KRt(K, camera->R, camera->t, &P); cameras.push_back(P); } @@ -103,19 +103,19 @@ bool EuclideanIntersect(const vector &markers, // Add residual blocks to the problem. int num_residuals = 0; for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; + const Marker& marker = markers[i]; if (marker.weight != 0.0) { - const EuclideanCamera &camera = + const EuclideanCamera& camera = *reconstruction->CameraForImage(marker.image); problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - EuclideanIntersectCostFunctor, - 2, /* num_residuals */ - 3>(new EuclideanIntersectCostFunctor(marker, camera)), + new ceres::AutoDiffCostFunction( + new EuclideanIntersectCostFunctor(marker, camera)), NULL, &X(0)); - num_residuals++; + num_residuals++; } } @@ -126,9 +126,9 @@ bool EuclideanIntersect(const vector &markers, if (!num_residuals) { LG << "Skipping running minimizer with zero residuals"; - // We still add 3D point for the track regardless it was - // optimized or not. If track is a constant zero it'll use - // algebraic intersection result as a 3D coordinate. + // We still add 3D point for the track regardless it was + // optimized or not. If track is a constant zero it'll use + // algebraic intersection result as a 3D coordinate. Vec3 point = X.head<3>(); reconstruction->InsertPoint(markers[0].track, point); @@ -152,12 +152,12 @@ bool EuclideanIntersect(const vector &markers, // Try projecting the point; make sure it's in front of everyone. for (int i = 0; i < cameras.size(); ++i) { - const EuclideanCamera &camera = + const EuclideanCamera& camera = *reconstruction->CameraForImage(markers[i].image); Vec3 x = camera.R * X + camera.t; if (x(2) < 0) { - LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image - << ": " << x.transpose(); + LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image << ": " + << x.transpose(); return false; } } @@ -173,35 +173,35 @@ namespace { struct ProjectiveIntersectCostFunction { public: - typedef Vec FMatrixType; + typedef Vec FMatrixType; typedef Vec4 XMatrixType; ProjectiveIntersectCostFunction( - const vector &markers, - const ProjectiveReconstruction &reconstruction) - : markers(markers), reconstruction(reconstruction) {} + const vector& markers, + const ProjectiveReconstruction& reconstruction) + : markers(markers), reconstruction(reconstruction) {} - Vec operator()(const Vec4 &X) const { + Vec operator()(const Vec4& X) const { Vec residuals(2 * markers.size()); residuals.setZero(); for (int i = 0; i < markers.size(); ++i) { - const ProjectiveCamera &camera = + const ProjectiveCamera& camera = *reconstruction.CameraForImage(markers[i].image); Vec3 projected = camera.P * X; projected /= projected(2); - residuals[2*i + 0] = projected(0) - markers[i].x; - residuals[2*i + 1] = projected(1) - markers[i].y; + residuals[2 * i + 0] = projected(0) - markers[i].x; + residuals[2 * i + 1] = projected(1) - markers[i].y; } return residuals; } - const vector &markers; - const ProjectiveReconstruction &reconstruction; + const vector& markers; + const ProjectiveReconstruction& reconstruction; }; } // namespace -bool ProjectiveIntersect(const vector &markers, - ProjectiveReconstruction *reconstruction) { +bool ProjectiveIntersect(const vector& markers, + ProjectiveReconstruction* reconstruction) { if (markers.size() < 2) { return false; } @@ -209,7 +209,7 @@ bool ProjectiveIntersect(const vector &markers, // Get the cameras to use for the intersection. vector cameras; for (int i = 0; i < markers.size(); ++i) { - ProjectiveCamera *camera = reconstruction->CameraForImage(markers[i].image); + ProjectiveCamera* camera = reconstruction->CameraForImage(markers[i].image); cameras.push_back(camera->P); } @@ -232,16 +232,16 @@ bool ProjectiveIntersect(const vector &markers, Solver solver(triangulate_cost); Solver::Results results = solver.minimize(params, &X); - (void) results; // TODO(keir): Ensure results are good. + (void)results; // TODO(keir): Ensure results are good. // Try projecting the point; make sure it's in front of everyone. for (int i = 0; i < cameras.size(); ++i) { - const ProjectiveCamera &camera = + const ProjectiveCamera& camera = *reconstruction->CameraForImage(markers[i].image); Vec3 x = camera.P * X; if (x(2) < 0) { - LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image - << ": " << x.transpose(); + LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image << ": " + << x.transpose(); } } diff --git a/intern/libmv/libmv/simple_pipeline/intersect.h b/intern/libmv/libmv/simple_pipeline/intersect.h index 15d6f998557..aff3ffe66e2 100644 --- a/intern/libmv/libmv/simple_pipeline/intersect.h +++ b/intern/libmv/libmv/simple_pipeline/intersect.h @@ -22,8 +22,8 @@ #define LIBMV_SIMPLE_PIPELINE_INTERSECT_H #include "libmv/base/vector.h" -#include "libmv/simple_pipeline/tracks.h" #include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { @@ -38,7 +38,8 @@ namespace libmv { \a markers should contain all \link Marker markers \endlink belonging to tracks visible in all frames. \a reconstruction should contain the cameras for all frames. - The new \link Point points \endlink will be inserted in \a reconstruction. + The new \link Point points \endlink will be inserted in \a + reconstruction. \note This assumes a calibrated reconstruction, e.g. the markers are already corrected for camera intrinsics and radial distortion. @@ -46,8 +47,8 @@ namespace libmv { \sa EuclideanResect */ -bool EuclideanIntersect(const vector &markers, - EuclideanReconstruction *reconstruction); +bool EuclideanIntersect(const vector& markers, + EuclideanReconstruction* reconstruction); /*! Estimate the homogeneous coordinates of a track by intersecting rays. @@ -60,7 +61,8 @@ bool EuclideanIntersect(const vector &markers, \a markers should contain all \link Marker markers \endlink belonging to tracks visible in all frames. \a reconstruction should contain the cameras for all frames. - The new \link Point points \endlink will be inserted in \a reconstruction. + The new \link Point points \endlink will be inserted in \a + reconstruction. \note This assumes that radial distortion is already corrected for, but does not assume that e.g. focal length and principal point are @@ -69,8 +71,8 @@ bool EuclideanIntersect(const vector &markers, \sa Resect */ -bool ProjectiveIntersect(const vector &markers, - ProjectiveReconstruction *reconstruction); +bool ProjectiveIntersect(const vector& markers, + ProjectiveReconstruction* reconstruction); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/intersect_test.cc b/intern/libmv/libmv/simple_pipeline/intersect_test.cc index dd4fdc789af..447cc095cb0 100644 --- a/intern/libmv/libmv/simple_pipeline/intersect_test.cc +++ b/intern/libmv/libmv/simple_pipeline/intersect_test.cc @@ -22,10 +22,10 @@ #include -#include "testing/testing.h" +#include "libmv/logging/logging.h" #include "libmv/multiview/projection.h" #include "libmv/numeric/numeric.h" -#include "libmv/logging/logging.h" +#include "testing/testing.h" namespace libmv { @@ -40,13 +40,15 @@ TEST(Intersect, EuclideanIntersect) { // 0, 0, 1; Mat3 R1 = RotationAroundZ(-0.1); Mat3 R2 = RotationAroundX(-0.1); - Vec3 t1; t1 << 1, 1, 10; - Vec3 t2; t2 << -2, -1, 10; + Vec3 t1; + t1 << 1, 1, 10; + Vec3 t2; + t2 << -2, -1, 10; Mat34 P1, P2; P_From_KRt(K1, R1, t1, &P1); P_From_KRt(K2, R2, t2, &P2); - //Mat3 F; FundamentalFromProjections(P1, P2, &F); + // Mat3 F; FundamentalFromProjections(P1, P2, &F); Mat3X X; X.resize(3, 30); @@ -68,9 +70,9 @@ TEST(Intersect, EuclideanIntersect) { reconstruction.InsertCamera(2, R2, t2); vector markers; - Marker a = { 1, 0, x1.x(), x1.y(), 1.0 }; + Marker a = {1, 0, x1.x(), x1.y(), 1.0}; markers.push_back(a); - Marker b = { 2, 0, x2.x(), x2.y(), 1.0 }; + Marker b = {2, 0, x2.x(), x2.y(), 1.0}; markers.push_back(b); EuclideanIntersect(markers, &reconstruction); @@ -78,4 +80,4 @@ TEST(Intersect, EuclideanIntersect) { EXPECT_NEAR(0, DistanceLInfinity(estimated, expected), 1e-8); } } -} // namespace +} // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc b/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc index 241b5600505..5526d730651 100644 --- a/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc +++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc @@ -20,20 +20,20 @@ #include "libmv/simple_pipeline/keyframe_selection.h" -#include "libmv/numeric/numeric.h" #include "ceres/ceres.h" #include "libmv/logging/logging.h" -#include "libmv/multiview/homography.h" #include "libmv/multiview/fundamental.h" -#include "libmv/simple_pipeline/intersect.h" +#include "libmv/multiview/homography.h" +#include "libmv/numeric/numeric.h" #include "libmv/simple_pipeline/bundle.h" +#include "libmv/simple_pipeline/intersect.h" #include namespace libmv { namespace { -Mat3 IntrinsicsNormalizationMatrix(const CameraIntrinsics &intrinsics) { +Mat3 IntrinsicsNormalizationMatrix(const CameraIntrinsics& intrinsics) { Mat3 T = Mat3::Identity(), S = Mat3::Identity(); T(0, 2) = -intrinsics.principal_point_x(); @@ -56,7 +56,7 @@ Mat3 IntrinsicsNormalizationMatrix(const CameraIntrinsics &intrinsics) { // (k = 7 for a fundamental matrix or 8 for a homography) // r is the dimension of the data // (r = 4 for 2D correspondences between two frames) -double GRIC(const Vec &e, int d, int k, int r) { +double GRIC(const Vec& e, int d, int k, int r) { int n = e.rows(); double lambda1 = log(static_cast(r)); double lambda2 = log(static_cast(r * n)); @@ -89,7 +89,7 @@ double GRIC(const Vec &e, int d, int k, int r) { // // TODO(keir): Consider moving this into the numeric code, since this is not // related to keyframe selection. -Mat PseudoInverseWithClampedEigenvalues(const Mat &matrix, +Mat PseudoInverseWithClampedEigenvalues(const Mat& matrix, int num_eigenvalues_to_clamp) { Eigen::EigenSolver eigen_solver(matrix); Mat D = eigen_solver.pseudoEigenvalueMatrix(); @@ -112,27 +112,24 @@ Mat PseudoInverseWithClampedEigenvalues(const Mat &matrix, return V * D * V.inverse(); } -void FilterZeroWeightMarkersFromTracks(const Tracks &tracks, - Tracks *filtered_tracks) { +void FilterZeroWeightMarkersFromTracks(const Tracks& tracks, + Tracks* filtered_tracks) { vector all_markers = tracks.AllMarkers(); for (int i = 0; i < all_markers.size(); ++i) { - Marker &marker = all_markers[i]; + Marker& marker = all_markers[i]; if (marker.weight != 0.0) { - filtered_tracks->Insert(marker.image, - marker.track, - marker.x, - marker.y, - marker.weight); + filtered_tracks->Insert( + marker.image, marker.track, marker.x, marker.y, marker.weight); } } } } // namespace -void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, - const CameraIntrinsics &intrinsics, - vector &keyframes) { +void SelectKeyframesBasedOnGRICAndVariance(const Tracks& _tracks, + const CameraIntrinsics& intrinsics, + vector& keyframes) { // Mirza Tahir Ahmed, Matthew N. Dailey // Robust key frame extraction for 3D reconstruction from video streams // @@ -172,23 +169,21 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, candidate_image <= max_image; candidate_image++) { // Conjunction of all markers from both keyframes - vector all_markers = - filtered_tracks.MarkersInBothImages(current_keyframe, - candidate_image); + vector all_markers = filtered_tracks.MarkersInBothImages( + current_keyframe, candidate_image); // Match keypoints between frames current_keyframe and candidate_image vector tracked_markers = - filtered_tracks.MarkersForTracksInBothImages(current_keyframe, - candidate_image); + filtered_tracks.MarkersForTracksInBothImages(current_keyframe, + candidate_image); // Correspondences in normalized space Mat x1, x2; CoordinatesForMarkersInImage(tracked_markers, current_keyframe, &x1); CoordinatesForMarkersInImage(tracked_markers, candidate_image, &x2); - LG << "Found " << x1.cols() - << " correspondences between " << current_keyframe - << " and " << candidate_image; + LG << "Found " << x1.cols() << " correspondences between " + << current_keyframe << " and " << candidate_image; // Not enough points to construct fundamental matrix if (x1.cols() < 8 || x2.cols() < 8) @@ -199,9 +194,8 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, int Tf = all_markers.size(); double Rc = static_cast(Tc) / Tf; - LG << "Correspondence between " << current_keyframe - << " and " << candidate_image - << ": " << Rc; + LG << "Correspondence between " << current_keyframe << " and " + << candidate_image << ": " << Rc; if (Rc < Tmin || Rc > Tmax) continue; @@ -210,19 +204,15 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, // Estimate homography using default options. EstimateHomographyOptions estimate_homography_options; - EstimateHomography2DFromCorrespondences(x1, - x2, - estimate_homography_options, - &H); + EstimateHomography2DFromCorrespondences( + x1, x2, estimate_homography_options, &H); // Convert homography to original pixel space. H = N_inverse * H * N; EstimateFundamentalOptions estimate_fundamental_options; - EstimateFundamentalFromCorrespondences(x1, - x2, - estimate_fundamental_options, - &F); + EstimateFundamentalFromCorrespondences( + x1, x2, estimate_fundamental_options, &F); // Convert fundamental to original pixel space. F = N_inverse * F * N; @@ -238,11 +228,11 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, for (int i = 0; i < x1.cols(); i++) { Vec2 current_x1, current_x2; - intrinsics.NormalizedToImageSpace(x1(0, i), x1(1, i), - ¤t_x1(0), ¤t_x1(1)); + intrinsics.NormalizedToImageSpace( + x1(0, i), x1(1, i), ¤t_x1(0), ¤t_x1(1)); - intrinsics.NormalizedToImageSpace(x2(0, i), x2(1, i), - ¤t_x2(0), ¤t_x2(1)); + intrinsics.NormalizedToImageSpace( + x2(0, i), x2(1, i), ¤t_x2(0), ¤t_x2(1)); H_e(i) = SymmetricGeometricDistance(H, current_x1, current_x2); F_e(i) = SymmetricEpipolarDistance(F, current_x1, current_x2); @@ -255,10 +245,8 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, double GRIC_H = GRIC(H_e, 2, 8, 4); double GRIC_F = GRIC(F_e, 3, 7, 4); - LG << "GRIC values for frames " << current_keyframe - << " and " << candidate_image - << ", H-GRIC: " << GRIC_H - << ", F-GRIC: " << GRIC_F; + LG << "GRIC values for frames " << current_keyframe << " and " + << candidate_image << ", H-GRIC: " << GRIC_H << ", F-GRIC: " << GRIC_F; if (GRIC_H <= GRIC_F) continue; @@ -295,23 +283,19 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, Vec3 t; Mat3 K = Mat3::Identity(); - if (!MotionFromEssentialAndCorrespondence(E, - K, x1.col(0), - K, x2.col(0), - &R, &t)) { + if (!MotionFromEssentialAndCorrespondence( + E, K, x1.col(0), K, x2.col(0), &R, &t)) { LG << "Failed to compute R and t from E and K"; continue; } - LG << "Camera transform between frames " << current_keyframe - << " and " << candidate_image - << ":\nR:\n" << R - << "\nt:" << t.transpose(); + LG << "Camera transform between frames " << current_keyframe << " and " + << candidate_image << ":\nR:\n" + << R << "\nt:" << t.transpose(); // First camera is identity, second one is relative to it - reconstruction.InsertCamera(current_keyframe, - Mat3::Identity(), - Vec3::Zero()); + reconstruction.InsertCamera( + current_keyframe, Mat3::Identity(), Vec3::Zero()); reconstruction.InsertCamera(candidate_image, R, t); // Reconstruct 3D points @@ -349,7 +333,7 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, } double success_intersects_factor = - (double) intersects_success / intersects_total; + (double)intersects_success / intersects_total; if (success_intersects_factor < success_intersects_factor_best) { LG << "Skip keyframe candidate because of " @@ -372,7 +356,7 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, &empty_intrinsics, &evaluation); - Mat &jacobian = evaluation.jacobian; + Mat& jacobian = evaluation.jacobian; Mat JT_J = jacobian.transpose() * jacobian; // There are 7 degrees of freedom, so clamp them out. @@ -380,10 +364,10 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, Mat temp_derived = JT_J * JT_J_inv * JT_J; bool is_inversed = (temp_derived - JT_J).cwiseAbs2().sum() < - 1e-4 * std::min(temp_derived.cwiseAbs2().sum(), - JT_J.cwiseAbs2().sum()); + 1e-4 * std::min(temp_derived.cwiseAbs2().sum(), + JT_J.cwiseAbs2().sum()); - LG << "Check on inversed: " << (is_inversed ? "true" : "false" ) + LG << "Check on inversed: " << (is_inversed ? "true" : "false") << ", det(JT_J): " << JT_J.determinant(); if (!is_inversed) { @@ -400,8 +384,7 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, double Sc = static_cast(I + A) / Square(3 * I) * Sigma_P.trace(); - LG << "Expected estimation error between " - << current_keyframe << " and " + LG << "Expected estimation error between " << current_keyframe << " and " << candidate_image << ": " << Sc; // Pairing with a lower Sc indicates a better choice diff --git a/intern/libmv/libmv/simple_pipeline/keyframe_selection.h b/intern/libmv/libmv/simple_pipeline/keyframe_selection.h index 25253af32fe..a1b3910abd4 100644 --- a/intern/libmv/libmv/simple_pipeline/keyframe_selection.h +++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection.h @@ -22,8 +22,8 @@ #define LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_ #include "libmv/base/vector.h" -#include "libmv/simple_pipeline/tracks.h" #include "libmv/simple_pipeline/camera_intrinsics.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { @@ -43,10 +43,9 @@ namespace libmv { // \param intrinsics: is camera intrinsics. // \param keyframes: will contain all images number which are considered // good to be used for reconstruction. -void SelectKeyframesBasedOnGRICAndVariance( - const Tracks &tracks, - const CameraIntrinsics &intrinsics, - vector &keyframes); +void SelectKeyframesBasedOnGRICAndVariance(const Tracks& tracks, + const CameraIntrinsics& intrinsics, + vector& keyframes); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc b/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc index 9d88362cc88..983349c0c5a 100644 --- a/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc +++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc @@ -1,15 +1,15 @@ // Copyright (c) 2011 libmv authors. -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -20,9 +20,9 @@ #include "libmv/simple_pipeline/keyframe_selection.h" -#include "testing/testing.h" -#include "libmv/simple_pipeline/camera_intrinsics.h" #include "libmv/logging/logging.h" +#include "libmv/simple_pipeline/camera_intrinsics.h" +#include "testing/testing.h" namespace libmv { @@ -30,7 +30,7 @@ namespace libmv { // Should not be keyframe TEST(KeyframeSelection, SyntheticNeighborFrame) { PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(900.0,900.0); + intrinsics.SetFocalLength(900.0, 900.0); intrinsics.SetPrincipalPoint(640.0, 540.0); intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); @@ -66,25 +66,56 @@ TEST(KeyframeSelection, FabrikEingangNeighborFrames) { intrinsics.SetPrincipalPoint(960.000, 544.000); intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); - Marker markers[] = { - {1, 0, 737.599983, 646.397594, 1.0}, {2, 0, 737.906628, 648.113327, 1.0}, {1, 1, 863.045425, 646.081905, 1.0}, - {2, 1, 863.339767, 647.650040, 1.0}, {1, 2, 736.959972, 574.080151, 1.0}, {2, 2, 737.217350, 575.604900, 1.0}, - {1, 3, 864.097424, 573.374908, 1.0}, {2, 3, 864.383469, 574.900307, 1.0}, {1, 4, 789.429073, 631.677521, 1.0}, - {2, 4, 789.893131, 633.124451, 1.0}, {1, 5, 791.051960, 573.442028, 1.0}, {2, 5, 791.336575, 575.088890, 1.0}, - {1, 6, 738.973961, 485.130308, 1.0}, {2, 6, 739.435501, 486.734207, 1.0}, {1, 7, 862.403240, 514.866074, 1.0}, - {2, 7, 862.660618, 516.413261, 1.0}, {1, 8, 802.240162, 485.759838, 1.0}, {2, 8, 802.602253, 487.432899, 1.0}, - {1, 9, 754.340630, 500.624559, 1.0}, {2, 9, 754.559956, 502.079920, 1.0}, {1, 10, 849.398689, 484.480545, 1.0}, - {2, 10, 849.599934, 486.079937, 1.0}, {1, 11, 788.803768, 515.924391, 1.0}, {2, 11, 789.119911, 517.439932, 1.0}, - {1, 12, 838.733940, 558.212688, 1.0}, {2, 12, 839.039898, 559.679916, 1.0}, {1, 13, 760.014782, 575.194466, 1.0}, - {2, 13, 760.319881, 576.639904, 1.0}, {1, 14, 765.321636, 616.015957, 1.0}, {2, 14, 765.759945, 617.599915, 1.0}, - {1, 15, 800.963230, 660.032082, 1.0}, {2, 15, 801.279945, 661.759876, 1.0}, {1, 16, 846.321087, 602.313053, 1.0}, - {2, 16, 846.719913, 603.839878, 1.0}, {1, 17, 864.288311, 616.790524, 1.0}, {2, 17, 864.639931, 618.239918, 1.0}, - {1, 18, 800.006790, 602.573425, 1.0}, {2, 18, 800.319958, 604.159912, 1.0}, {1, 19, 739.026890, 617.944138, 1.0}, - {2, 19, 739.199924, 619.519924, 1.0}, {1, 20, 801.987419, 544.134888, 1.0}, {2, 20, 802.239933, 545.599911, 1.0}, - {1, 21, 753.619823, 542.961300, 1.0}, {2, 21, 753.919945, 544.639874, 1.0}, {1, 22, 787.921257, 499.910206, 1.0}, - {2, 22, 788.159924, 501.439917, 1.0}, {1, 23, 839.095459, 529.287903, 1.0}, {2, 23, 839.359932, 530.879934, 1.0}, - {1, 24, 811.760330, 630.732269, 1.0}, {2, 24, 812.159901, 632.319859, 1.0} - }; + Marker markers[] = {{1, 0, 737.599983, 646.397594, 1.0}, + {2, 0, 737.906628, 648.113327, 1.0}, + {1, 1, 863.045425, 646.081905, 1.0}, + {2, 1, 863.339767, 647.650040, 1.0}, + {1, 2, 736.959972, 574.080151, 1.0}, + {2, 2, 737.217350, 575.604900, 1.0}, + {1, 3, 864.097424, 573.374908, 1.0}, + {2, 3, 864.383469, 574.900307, 1.0}, + {1, 4, 789.429073, 631.677521, 1.0}, + {2, 4, 789.893131, 633.124451, 1.0}, + {1, 5, 791.051960, 573.442028, 1.0}, + {2, 5, 791.336575, 575.088890, 1.0}, + {1, 6, 738.973961, 485.130308, 1.0}, + {2, 6, 739.435501, 486.734207, 1.0}, + {1, 7, 862.403240, 514.866074, 1.0}, + {2, 7, 862.660618, 516.413261, 1.0}, + {1, 8, 802.240162, 485.759838, 1.0}, + {2, 8, 802.602253, 487.432899, 1.0}, + {1, 9, 754.340630, 500.624559, 1.0}, + {2, 9, 754.559956, 502.079920, 1.0}, + {1, 10, 849.398689, 484.480545, 1.0}, + {2, 10, 849.599934, 486.079937, 1.0}, + {1, 11, 788.803768, 515.924391, 1.0}, + {2, 11, 789.119911, 517.439932, 1.0}, + {1, 12, 838.733940, 558.212688, 1.0}, + {2, 12, 839.039898, 559.679916, 1.0}, + {1, 13, 760.014782, 575.194466, 1.0}, + {2, 13, 760.319881, 576.639904, 1.0}, + {1, 14, 765.321636, 616.015957, 1.0}, + {2, 14, 765.759945, 617.599915, 1.0}, + {1, 15, 800.963230, 660.032082, 1.0}, + {2, 15, 801.279945, 661.759876, 1.0}, + {1, 16, 846.321087, 602.313053, 1.0}, + {2, 16, 846.719913, 603.839878, 1.0}, + {1, 17, 864.288311, 616.790524, 1.0}, + {2, 17, 864.639931, 618.239918, 1.0}, + {1, 18, 800.006790, 602.573425, 1.0}, + {2, 18, 800.319958, 604.159912, 1.0}, + {1, 19, 739.026890, 617.944138, 1.0}, + {2, 19, 739.199924, 619.519924, 1.0}, + {1, 20, 801.987419, 544.134888, 1.0}, + {2, 20, 802.239933, 545.599911, 1.0}, + {1, 21, 753.619823, 542.961300, 1.0}, + {2, 21, 753.919945, 544.639874, 1.0}, + {1, 22, 787.921257, 499.910206, 1.0}, + {2, 22, 788.159924, 501.439917, 1.0}, + {1, 23, 839.095459, 529.287903, 1.0}, + {2, 23, 839.359932, 530.879934, 1.0}, + {1, 24, 811.760330, 630.732269, 1.0}, + {2, 24, 812.159901, 632.319859, 1.0}}; int num_markers = sizeof(markers) / sizeof(Marker); Tracks tracks; @@ -108,18 +139,34 @@ TEST(KeyframeSelection, FabrikEingangFarFrames) { intrinsics.SetPrincipalPoint(960.000, 544.000); intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); - Marker markers[] = { - {1, 0, 369.459200, 619.315258, 1.0}, {2, 0, 279.677496, 722.086842, 1.0}, {1, 1, 376.831970, 370.278397, 1.0}, - {2, 1, 221.695247, 460.065418, 1.0}, {1, 2, 1209.139023, 567.705605, 1.0}, {2, 2, 1080.760117, 659.230083, 1.0}, - {1, 3, 1643.495750, 903.620453, 1.0}, {2, 3, 1618.405037, 1015.374908, 1.0}, {1, 4, 1494.849815, 425.302460, 1.0}, - {2, 4, 1457.467575, 514.727587, 1.0}, {1, 5, 1794.637299, 328.728609, 1.0}, {2, 5, 1742.161446, 408.988636, 1.0}, - {1, 6, 1672.822723, 102.240358, 1.0}, {2, 6, 1539.287224, 153.536892, 1.0}, {1, 7, 1550.843925, 53.424943, 1.0}, - {2, 7, 1385.579109, 96.450085, 1.0}, {1, 8, 852.953281, 465.399578, 1.0}, {2, 8, 779.404564, 560.091843, 1.0}, - {1, 9, 906.853752, 299.827040, 1.0}, {2, 9, 786.923218, 385.570770, 1.0}, {1, 10, 406.322966, 87.556041, 1.0}, - {2, 10, 140.339413, 150.877481, 1.0}, {1, 11, 254.811573, 851.296478, 1.0}, {2, 11, 94.478302, 969.350189, 1.0}, - {1, 12, 729.087868, 806.092758, 1.0}, {2, 12, 606.212139, 919.876560, 1.0}, {1, 13, 1525.719452, 920.398083, 1.0}, - {2, 13, 1495.579720, 1031.971218, 1.0} - }; + Marker markers[] = {{1, 0, 369.459200, 619.315258, 1.0}, + {2, 0, 279.677496, 722.086842, 1.0}, + {1, 1, 376.831970, 370.278397, 1.0}, + {2, 1, 221.695247, 460.065418, 1.0}, + {1, 2, 1209.139023, 567.705605, 1.0}, + {2, 2, 1080.760117, 659.230083, 1.0}, + {1, 3, 1643.495750, 903.620453, 1.0}, + {2, 3, 1618.405037, 1015.374908, 1.0}, + {1, 4, 1494.849815, 425.302460, 1.0}, + {2, 4, 1457.467575, 514.727587, 1.0}, + {1, 5, 1794.637299, 328.728609, 1.0}, + {2, 5, 1742.161446, 408.988636, 1.0}, + {1, 6, 1672.822723, 102.240358, 1.0}, + {2, 6, 1539.287224, 153.536892, 1.0}, + {1, 7, 1550.843925, 53.424943, 1.0}, + {2, 7, 1385.579109, 96.450085, 1.0}, + {1, 8, 852.953281, 465.399578, 1.0}, + {2, 8, 779.404564, 560.091843, 1.0}, + {1, 9, 906.853752, 299.827040, 1.0}, + {2, 9, 786.923218, 385.570770, 1.0}, + {1, 10, 406.322966, 87.556041, 1.0}, + {2, 10, 140.339413, 150.877481, 1.0}, + {1, 11, 254.811573, 851.296478, 1.0}, + {2, 11, 94.478302, 969.350189, 1.0}, + {1, 12, 729.087868, 806.092758, 1.0}, + {2, 12, 606.212139, 919.876560, 1.0}, + {1, 13, 1525.719452, 920.398083, 1.0}, + {2, 13, 1495.579720, 1031.971218, 1.0}}; int num_markers = sizeof(markers) / sizeof(Marker); Tracks tracks; @@ -144,17 +191,35 @@ TEST(KeyframeSelection, CopterManualKeyFrames) { intrinsics.SetRadialDistortion(-0.08590, 0.0, 0.0); Marker markers[] = { - {1, 0, 645.792694, 403.115931, 1.0}, {2, 0, 630.641174, 307.996409, 1.0}, {1, 1, 783.469086, 403.904328, 1.0}, - {2, 1, 766.001129, 308.998225, 1.0}, {1, 2, 650.000000, 160.000001, 1.0}, {1, 3, 785.225906, 158.619039, 1.0}, - {2, 3, 767.526474, 70.449695, 1.0}, {1, 4, 290.640526, 382.335634, 1.0}, {2, 4, 273.001728, 86.993319, 1.0}, - {1, 5, 291.162739, 410.602684, 1.0}, {2, 5, 273.287849, 111.937487, 1.0}, {1, 6, 136.919317, 349.895797, 1.0}, - {1, 7, 490.844345, 47.572222, 1.0}, {1, 8, 454.406433, 488.935761, 1.0}, {1, 9, 378.655815, 618.522248, 1.0}, - {2, 9, 357.061806, 372.265077, 1.0}, {1, 10, 496.011391, 372.668824, 1.0}, {2, 10, 477.979164, 222.986112, 1.0}, - {1, 11, 680.060272, 256.103625, 1.0}, {2, 11, 670.587540, 204.830453, 1.0}, {1, 12, 1070.817108, 218.775322, 1.0}, - {2, 12, 1046.129913, 128.969783, 1.0}, {1, 14, 242.516403, 596.048512, 1.0}, {2, 14, 224.182606, 248.272154, 1.0}, - {1, 15, 613.936272, 287.519073, 1.0}, {2, 15, 600.467644, 196.085722, 1.0}, {1, 31, 844.637451, 256.354315, 1.0}, + {1, 0, 645.792694, 403.115931, 1.0}, + {2, 0, 630.641174, 307.996409, 1.0}, + {1, 1, 783.469086, 403.904328, 1.0}, + {2, 1, 766.001129, 308.998225, 1.0}, + {1, 2, 650.000000, 160.000001, 1.0}, + {1, 3, 785.225906, 158.619039, 1.0}, + {2, 3, 767.526474, 70.449695, 1.0}, + {1, 4, 290.640526, 382.335634, 1.0}, + {2, 4, 273.001728, 86.993319, 1.0}, + {1, 5, 291.162739, 410.602684, 1.0}, + {2, 5, 273.287849, 111.937487, 1.0}, + {1, 6, 136.919317, 349.895797, 1.0}, + {1, 7, 490.844345, 47.572222, 1.0}, + {1, 8, 454.406433, 488.935761, 1.0}, + {1, 9, 378.655815, 618.522248, 1.0}, + {2, 9, 357.061806, 372.265077, 1.0}, + {1, 10, 496.011391, 372.668824, 1.0}, + {2, 10, 477.979164, 222.986112, 1.0}, + {1, 11, 680.060272, 256.103625, 1.0}, + {2, 11, 670.587540, 204.830453, 1.0}, + {1, 12, 1070.817108, 218.775322, 1.0}, + {2, 12, 1046.129913, 128.969783, 1.0}, + {1, 14, 242.516403, 596.048512, 1.0}, + {2, 14, 224.182606, 248.272154, 1.0}, + {1, 15, 613.936272, 287.519073, 1.0}, + {2, 15, 600.467644, 196.085722, 1.0}, + {1, 31, 844.637451, 256.354315, 1.0}, {2, 31, 823.200150, 165.714952, 1.0}, - }; + }; int num_markers = sizeof(markers) / sizeof(Marker); Tracks tracks; @@ -180,52 +245,140 @@ TEST(KeyframeSelection, ElevatorManualKeyframesFrames) { intrinsics.SetRadialDistortion(-0.034, 0.0, 0.0); Marker markers[] = { - {1, 2, 1139.861412, 1034.634984, 1.0}, {2, 2, 1143.512192, 1065.355718, 1.0}, {1, 3, 1760.821953, 644.658036, 1.0}, - {2, 3, 1770.901108, 697.899928, 1.0}, {1, 4, 858.071823, 1068.520746, 1.0}, {1, 6, 1633.952408, 797.050145, 1.0}, - {2, 6, 1642.508469, 849.157140, 1.0}, {1, 8, 1716.695824, 451.805491, 1.0}, {2, 8, 1726.513939, 502.095687, 1.0}, - {1, 9, 269.577627, 724.986935, 1.0}, {2, 9, 269.424820, 764.154246, 1.0}, {1, 10, 1891.321907, 706.948843, 1.0}, - {2, 10, 1903.338547, 766.068377, 1.0}, {1, 12, 1806.227074, 956.089604, 1.0}, {2, 12, 1816.619568, 1013.767376, 1.0}, - {1, 14, 269.544153, 1002.333570, 1.0}, {2, 14, 269.367542, 1043.509254, 1.0}, {1, 15, 1402.772141, 281.392962, 1.0}, - {2, 15, 1409.089165, 318.731629, 1.0}, {1, 16, 195.877233, 919.454341, 1.0}, {2, 16, 192.531109, 997.367899, 1.0}, - {1, 17, 1789.584045, 120.036661, 1.0}, {2, 17, 1800.391846, 167.822964, 1.0}, {1, 18, 999.363213, 765.004807, 1.0}, - {2, 18, 1002.345772, 790.560122, 1.0}, {1, 19, 647.342491, 1044.805727, 1.0}, {2, 19, 649.328041, 1058.682940, 1.0}, - {1, 20, 1365.486832, 440.901829, 1.0}, {2, 20, 1371.413040, 477.888730, 1.0}, {1, 21, 1787.125282, 301.431606, 1.0}, - {2, 21, 1798.527260, 355.224531, 1.0}, {1, 22, 1257.805824, 932.797258, 1.0}, {2, 22, 1263.017578, 969.376774, 1.0}, - {1, 23, 961.969528, 843.148112, 1.0}, {2, 23, 964.869461, 868.587620, 1.0}, {1, 24, 158.076110, 1052.643592, 1.0}, - {1, 25, 1072.884521, 1005.296981, 1.0}, {2, 25, 1076.091156, 1032.776856, 1.0}, {1, 26, 1107.656937, 526.577228, 1.0}, - {2, 26, 1111.618423, 555.524454, 1.0}, {1, 27, 1416.410751, 529.857581, 1.0}, {2, 27, 1422.663574, 570.025957, 1.0}, - {1, 28, 1498.673630, 1005.453086, 1.0}, {2, 28, 1505.381813, 1051.827149, 1.0}, {1, 29, 1428.647804, 652.473629, 1.0}, - {2, 29, 1434.898224, 692.715390, 1.0}, {1, 30, 1332.318764, 503.673599, 1.0}, {2, 30, 1338.000069, 540.507967, 1.0}, - {1, 32, 1358.642693, 709.837904, 1.0}, {2, 32, 1364.231529, 748.678265, 1.0}, {1, 33, 1850.911560, 460.475668, 1.0}, - {2, 33, 1862.221413, 512.797347, 1.0}, {1, 34, 1226.117821, 607.053959, 1.0}, {2, 34, 1230.736084, 641.091449, 1.0}, - {1, 35, 619.598236, 523.341744, 1.0}, {2, 35, 621.601124, 554.453287, 1.0}, {1, 36, 956.591492, 958.223183, 1.0}, - {2, 36, 959.289265, 983.289263, 1.0}, {1, 37, 1249.922218, 419.095856, 1.0}, {2, 37, 1255.005913, 452.556177, 1.0}, - {1, 39, 1300.528450, 386.251166, 1.0}, {2, 39, 1305.957413, 420.185595, 1.0}, {1, 40, 1128.689919, 972.558346, 1.0}, - {2, 40, 1132.413712, 1003.984737, 1.0}, {1, 41, 503.304749, 1053.504388, 1.0}, {2, 41, 505.019703, 1069.175613, 1.0}, - {1, 42, 1197.352982, 472.681564, 1.0}, {2, 42, 1201.910706, 503.459880, 1.0}, {1, 43, 1794.391022, 383.911400, 1.0}, - {2, 43, 1805.324135, 436.116468, 1.0}, {1, 44, 789.641418, 1058.045647, 1.0}, {1, 45, 1376.575241, 928.714979, 1.0}, - {2, 45, 1381.995850, 969.511957, 1.0}, {1, 46, 1598.023567, 93.975592, 1.0}, {2, 46, 1606.937141, 136.827035, 1.0}, - {1, 47, 1455.550232, 762.128685, 1.0}, {2, 47, 1462.014313, 805.164878, 1.0}, {1, 48, 1357.123489, 354.460326, 1.0}, - {2, 48, 1363.071899, 390.363121, 1.0}, {1, 49, 939.792652, 781.549895, 1.0}, {2, 49, 942.802620, 806.164012, 1.0}, - {1, 50, 1380.251083, 805.948620, 1.0}, {2, 50, 1385.637932, 845.592098, 1.0}, {1, 51, 1021.769943, 1049.802361, 1.0}, - {1, 52, 1065.634918, 608.099055, 1.0}, {2, 52, 1069.142189, 635.361736, 1.0}, {1, 53, 624.324188, 463.202863, 1.0}, - {2, 53, 626.395454, 494.994088, 1.0}, {1, 54, 1451.459885, 881.557624, 1.0}, {2, 54, 1457.679634, 924.345531, 1.0}, - {1, 55, 1201.885986, 1057.079022, 1.0}, {1, 56, 581.157532, 947.661438, 1.0}, {2, 56, 583.242359, 960.831449, 1.0}, - {1, 58, 513.593102, 954.175858, 1.0}, {2, 58, 515.470047, 971.309574, 1.0}, {1, 59, 928.069038, 901.774421, 1.0}, - {2, 59, 930.847950, 925.613744, 1.0}, {1, 60, 1065.860023, 740.395389, 1.0}, {2, 60, 1069.484253, 768.971086, 1.0}, - {1, 61, 990.479393, 906.264632, 1.0}, {2, 61, 993.217506, 933.088803, 1.0}, {1, 62, 1776.196747, 776.278453, 1.0}, - {2, 62, 1786.292496, 831.136880, 1.0}, {1, 63, 834.454365, 1012.449725, 1.0}, {2, 63, 836.868324, 1033.451807, 1.0}, - {1, 64, 1355.190697, 869.184809, 1.0}, {2, 64, 1360.736618, 909.773347, 1.0}, {1, 65, 702.072487, 897.519686, 1.0}, - {2, 65, 704.203377, 911.931131, 1.0}, {1, 66, 1214.022903, 856.199934, 1.0}, {2, 66, 1218.109016, 890.753052, 1.0}, - {1, 67, 327.676048, 236.814036, 1.0}, {2, 67, 328.335285, 277.251878, 1.0}, {1, 68, 289.064083, 454.793912, 1.0}, - {2, 68, 288.651924, 498.882444, 1.0}, {1, 69, 1626.240692, 278.374350, 1.0}, {2, 69, 1634.131508, 315.853672, 1.0}, - {1, 70, 1245.375710, 734.862142, 1.0}, {2, 70, 1250.047417, 769.670885, 1.0}, {1, 71, 497.015305, 510.718904, 1.0}, - {2, 71, 498.682308, 541.070201, 1.0}, {1, 72, 1280.542030, 153.939185, 1.0}, {2, 72, 1286.993637, 198.436196, 1.0}, - {1, 73, 1534.748840, 138.601043, 1.0}, {2, 73, 1542.961349, 180.170819, 1.0}, {1, 74, 1477.412682, 200.608061, 1.0}, - {2, 74, 1484.683914, 240.413260, 1.0}, {1, 76, 450.637321, 407.279642, 1.0}, {2, 76, 451.695642, 441.666291, 1.0}, - {1, 78, 246.981239, 220.786298, 1.0}, {2, 78, 244.524879, 290.016564, 1.0}, {1, 79, 36.696489, 420.023407, 1.0}, + {1, 2, 1139.861412, 1034.634984, 1.0}, + {2, 2, 1143.512192, 1065.355718, 1.0}, + {1, 3, 1760.821953, 644.658036, 1.0}, + {2, 3, 1770.901108, 697.899928, 1.0}, + {1, 4, 858.071823, 1068.520746, 1.0}, + {1, 6, 1633.952408, 797.050145, 1.0}, + {2, 6, 1642.508469, 849.157140, 1.0}, + {1, 8, 1716.695824, 451.805491, 1.0}, + {2, 8, 1726.513939, 502.095687, 1.0}, + {1, 9, 269.577627, 724.986935, 1.0}, + {2, 9, 269.424820, 764.154246, 1.0}, + {1, 10, 1891.321907, 706.948843, 1.0}, + {2, 10, 1903.338547, 766.068377, 1.0}, + {1, 12, 1806.227074, 956.089604, 1.0}, + {2, 12, 1816.619568, 1013.767376, 1.0}, + {1, 14, 269.544153, 1002.333570, 1.0}, + {2, 14, 269.367542, 1043.509254, 1.0}, + {1, 15, 1402.772141, 281.392962, 1.0}, + {2, 15, 1409.089165, 318.731629, 1.0}, + {1, 16, 195.877233, 919.454341, 1.0}, + {2, 16, 192.531109, 997.367899, 1.0}, + {1, 17, 1789.584045, 120.036661, 1.0}, + {2, 17, 1800.391846, 167.822964, 1.0}, + {1, 18, 999.363213, 765.004807, 1.0}, + {2, 18, 1002.345772, 790.560122, 1.0}, + {1, 19, 647.342491, 1044.805727, 1.0}, + {2, 19, 649.328041, 1058.682940, 1.0}, + {1, 20, 1365.486832, 440.901829, 1.0}, + {2, 20, 1371.413040, 477.888730, 1.0}, + {1, 21, 1787.125282, 301.431606, 1.0}, + {2, 21, 1798.527260, 355.224531, 1.0}, + {1, 22, 1257.805824, 932.797258, 1.0}, + {2, 22, 1263.017578, 969.376774, 1.0}, + {1, 23, 961.969528, 843.148112, 1.0}, + {2, 23, 964.869461, 868.587620, 1.0}, + {1, 24, 158.076110, 1052.643592, 1.0}, + {1, 25, 1072.884521, 1005.296981, 1.0}, + {2, 25, 1076.091156, 1032.776856, 1.0}, + {1, 26, 1107.656937, 526.577228, 1.0}, + {2, 26, 1111.618423, 555.524454, 1.0}, + {1, 27, 1416.410751, 529.857581, 1.0}, + {2, 27, 1422.663574, 570.025957, 1.0}, + {1, 28, 1498.673630, 1005.453086, 1.0}, + {2, 28, 1505.381813, 1051.827149, 1.0}, + {1, 29, 1428.647804, 652.473629, 1.0}, + {2, 29, 1434.898224, 692.715390, 1.0}, + {1, 30, 1332.318764, 503.673599, 1.0}, + {2, 30, 1338.000069, 540.507967, 1.0}, + {1, 32, 1358.642693, 709.837904, 1.0}, + {2, 32, 1364.231529, 748.678265, 1.0}, + {1, 33, 1850.911560, 460.475668, 1.0}, + {2, 33, 1862.221413, 512.797347, 1.0}, + {1, 34, 1226.117821, 607.053959, 1.0}, + {2, 34, 1230.736084, 641.091449, 1.0}, + {1, 35, 619.598236, 523.341744, 1.0}, + {2, 35, 621.601124, 554.453287, 1.0}, + {1, 36, 956.591492, 958.223183, 1.0}, + {2, 36, 959.289265, 983.289263, 1.0}, + {1, 37, 1249.922218, 419.095856, 1.0}, + {2, 37, 1255.005913, 452.556177, 1.0}, + {1, 39, 1300.528450, 386.251166, 1.0}, + {2, 39, 1305.957413, 420.185595, 1.0}, + {1, 40, 1128.689919, 972.558346, 1.0}, + {2, 40, 1132.413712, 1003.984737, 1.0}, + {1, 41, 503.304749, 1053.504388, 1.0}, + {2, 41, 505.019703, 1069.175613, 1.0}, + {1, 42, 1197.352982, 472.681564, 1.0}, + {2, 42, 1201.910706, 503.459880, 1.0}, + {1, 43, 1794.391022, 383.911400, 1.0}, + {2, 43, 1805.324135, 436.116468, 1.0}, + {1, 44, 789.641418, 1058.045647, 1.0}, + {1, 45, 1376.575241, 928.714979, 1.0}, + {2, 45, 1381.995850, 969.511957, 1.0}, + {1, 46, 1598.023567, 93.975592, 1.0}, + {2, 46, 1606.937141, 136.827035, 1.0}, + {1, 47, 1455.550232, 762.128685, 1.0}, + {2, 47, 1462.014313, 805.164878, 1.0}, + {1, 48, 1357.123489, 354.460326, 1.0}, + {2, 48, 1363.071899, 390.363121, 1.0}, + {1, 49, 939.792652, 781.549895, 1.0}, + {2, 49, 942.802620, 806.164012, 1.0}, + {1, 50, 1380.251083, 805.948620, 1.0}, + {2, 50, 1385.637932, 845.592098, 1.0}, + {1, 51, 1021.769943, 1049.802361, 1.0}, + {1, 52, 1065.634918, 608.099055, 1.0}, + {2, 52, 1069.142189, 635.361736, 1.0}, + {1, 53, 624.324188, 463.202863, 1.0}, + {2, 53, 626.395454, 494.994088, 1.0}, + {1, 54, 1451.459885, 881.557624, 1.0}, + {2, 54, 1457.679634, 924.345531, 1.0}, + {1, 55, 1201.885986, 1057.079022, 1.0}, + {1, 56, 581.157532, 947.661438, 1.0}, + {2, 56, 583.242359, 960.831449, 1.0}, + {1, 58, 513.593102, 954.175858, 1.0}, + {2, 58, 515.470047, 971.309574, 1.0}, + {1, 59, 928.069038, 901.774421, 1.0}, + {2, 59, 930.847950, 925.613744, 1.0}, + {1, 60, 1065.860023, 740.395389, 1.0}, + {2, 60, 1069.484253, 768.971086, 1.0}, + {1, 61, 990.479393, 906.264632, 1.0}, + {2, 61, 993.217506, 933.088803, 1.0}, + {1, 62, 1776.196747, 776.278453, 1.0}, + {2, 62, 1786.292496, 831.136880, 1.0}, + {1, 63, 834.454365, 1012.449725, 1.0}, + {2, 63, 836.868324, 1033.451807, 1.0}, + {1, 64, 1355.190697, 869.184809, 1.0}, + {2, 64, 1360.736618, 909.773347, 1.0}, + {1, 65, 702.072487, 897.519686, 1.0}, + {2, 65, 704.203377, 911.931131, 1.0}, + {1, 66, 1214.022903, 856.199934, 1.0}, + {2, 66, 1218.109016, 890.753052, 1.0}, + {1, 67, 327.676048, 236.814036, 1.0}, + {2, 67, 328.335285, 277.251878, 1.0}, + {1, 68, 289.064083, 454.793912, 1.0}, + {2, 68, 288.651924, 498.882444, 1.0}, + {1, 69, 1626.240692, 278.374350, 1.0}, + {2, 69, 1634.131508, 315.853672, 1.0}, + {1, 70, 1245.375710, 734.862142, 1.0}, + {2, 70, 1250.047417, 769.670885, 1.0}, + {1, 71, 497.015305, 510.718904, 1.0}, + {2, 71, 498.682308, 541.070201, 1.0}, + {1, 72, 1280.542030, 153.939185, 1.0}, + {2, 72, 1286.993637, 198.436196, 1.0}, + {1, 73, 1534.748840, 138.601043, 1.0}, + {2, 73, 1542.961349, 180.170819, 1.0}, + {1, 74, 1477.412682, 200.608061, 1.0}, + {2, 74, 1484.683914, 240.413260, 1.0}, + {1, 76, 450.637321, 407.279642, 1.0}, + {2, 76, 451.695642, 441.666291, 1.0}, + {1, 78, 246.981239, 220.786298, 1.0}, + {2, 78, 244.524879, 290.016564, 1.0}, + {1, 79, 36.696489, 420.023407, 1.0}, {2, 79, 21.364746, 591.245492, 1.0}, - }; + }; int num_markers = sizeof(markers) / sizeof(Marker); Tracks tracks; @@ -249,41 +402,110 @@ TEST(KeyframeSelection, ElevatorReconstructionVarianceTest) { intrinsics.SetRadialDistortion(-0.034, 0.0, 0.0); Marker markers[] = { - {1, 0, 182.999997, 1047.000010, 1.0}, {2, 0, 181.475730, 1052.091079, 1.0}, {3, 0, 181.741562, 1057.893341, 1.0}, - {4, 0, 183.190498, 1068.310440, 1.0}, {1, 1, 271.000013, 666.000009, 1.0}, {2, 1, 270.596180, 668.665760, 1.0}, - {3, 1, 270.523510, 671.559069, 1.0}, {4, 1, 271.856518, 676.818151, 1.0}, {5, 1, 268.989000, 727.051570, 1.0}, - {1, 2, 264.999990, 1018.000031, 1.0}, {2, 2, 264.020061, 1021.157591, 1.0}, {3, 2, 264.606056, 1024.823506, 1.0}, - {4, 2, 266.200933, 1031.168690, 1.0}, {1, 3, 270.000000, 938.000014, 1.0}, {2, 3, 269.022617, 941.153390, 1.0}, - {3, 3, 269.605579, 944.454954, 1.0}, {4, 3, 271.281366, 949.452167, 1.0}, {5, 3, 268.963480, 1004.417453, 1.0}, - {1, 4, 200.999994, 799.000003, 1.0}, {2, 4, 199.841366, 803.891838, 1.0}, {3, 4, 200.262208, 809.323246, 1.0}, - {4, 4, 201.456513, 819.271195, 1.0}, {5, 4, 195.026493, 924.363234, 1.0}, {1, 5, 1775.000038, 49.999998, 1.0}, - {2, 5, 1775.255127, 53.718264, 1.0}, {3, 5, 1776.449890, 55.951670, 1.0}, {4, 5, 1778.815727, 61.923309, 1.0}, - {5, 5, 1790.274124, 123.074923, 1.0}, {1, 6, 164.000001, 927.999988, 1.0}, {2, 6, 162.665462, 933.169527, 1.0}, - {3, 6, 163.067923, 938.577182, 1.0}, {4, 6, 164.370360, 948.840945, 1.0}, {5, 6, 157.199407, 1057.762341, 1.0}, - {1, 7, 618.000011, 477.999998, 1.0}, {2, 7, 617.583504, 480.124243, 1.0}, {3, 7, 618.356495, 482.441897, 1.0}, - {4, 7, 619.792500, 486.428132, 1.0}, {5, 7, 619.546051, 525.222627, 1.0}, {1, 8, 499.999981, 1036.999984, 1.0}, - {2, 8, 499.080162, 1038.720160, 1.0}, {3, 8, 499.949398, 1039.014344, 1.0}, {4, 8, 501.828003, 1041.286647, 1.0}, - {5, 8, 502.777576, 1055.196369, 1.0}, {1, 9, 1587.000046, 31.999999, 1.0}, {2, 9, 1586.988373, 34.635853, 1.0}, - {3, 9, 1588.155899, 37.444186, 1.0}, {4, 9, 1589.973106, 42.492081, 1.0}, {5, 9, 1598.683205, 96.526332, 1.0}, - {1, 10, 622.999992, 416.999999, 1.0}, {2, 10, 622.449017, 419.233485, 1.0}, {3, 10, 623.283234, 421.500703, 1.0}, - {4, 10, 624.620132, 425.537406, 1.0}, {5, 10, 624.290829, 465.078338, 1.0}, {1, 11, 577.999992, 931.999998, 1.0}, - {2, 11, 577.042294, 932.872703, 1.0}, {3, 11, 577.832451, 934.045451, 1.0}, {4, 11, 579.729137, 935.735435, 1.0}, - {5, 11, 580.691242, 948.396256, 1.0}, {1, 12, 510.999985, 931.999998, 1.0}, {2, 12, 510.111237, 933.152146, 1.0}, - {3, 12, 510.797081, 934.454219, 1.0}, {4, 12, 512.647362, 936.595910, 1.0}, {5, 12, 513.247204, 955.144157, 1.0}, - {1, 13, 330.459995, 177.059993, 1.0}, {2, 13, 329.876347, 179.615586, 1.0}, {3, 13, 330.681696, 182.757810, 1.0}, - {4, 13, 331.345053, 187.903853, 1.0}, {5, 13, 327.824135, 239.611639, 1.0}, {1, 14, 291.813097, 388.516195, 1.0}, - {2, 14, 290.984058, 391.382725, 1.0}, {3, 14, 291.526737, 394.778595, 1.0}, {4, 14, 292.763815, 400.310973, 1.0}, - {5, 14, 288.714552, 457.548015, 1.0}, {1, 15, 496.491680, 466.534005, 1.0}, {2, 15, 495.909519, 468.518561, 1.0}, - {3, 15, 496.588383, 470.853596, 1.0}, {4, 15, 497.976780, 474.731458, 1.0}, {5, 15, 496.998882, 512.568694, 1.0}, - {1, 16, 1273.000031, 89.000000, 1.0}, {2, 16, 1272.951965, 92.003637, 1.0}, {3, 16, 1273.934784, 94.972191, 1.0}, - {4, 16, 1275.493584, 100.139952, 1.0}, {5, 16, 1281.003571, 156.880163, 1.0}, {1, 17, 1524.713173, 78.852922, 1.0}, - {2, 17, 1524.782066, 81.427142, 1.0}, {3, 17, 1525.759048, 84.057939, 1.0}, {4, 17, 1527.579689, 88.966550, 1.0}, - {5, 17, 1535.262451, 141.186054, 1.0}, {1, 18, 1509.425011, 94.371824, 1.0}, {1, 19, 451.000013, 357.000003, 1.0}, - {2, 19, 450.354881, 359.312410, 1.0}, {3, 19, 451.107473, 361.837088, 1.0}, {4, 19, 452.186537, 366.318061, 1.0}, - {5, 19, 450.507660, 409.257599, 1.0}, {1, 20, 254.004936, 114.784185, 1.0}, {2, 20, 253.291512, 119.288486, 1.0}, - {3, 20, 253.745584, 124.114957, 1.0}, {4, 20, 254.453287, 132.795120, 1.0}, {5, 20, 246.772242, 225.165337, 1.0}, - {1, 21, 65.262880, 147.889409, 1.0}, {2, 21, 63.634465, 157.656807, 1.0}, {3, 21, 63.306799, 169.067053, 1.0}, - {4, 21, 62.462311, 189.724241, 1.0}, {5, 21, 35.396615, 430.308380, 1.0}, + {1, 0, 182.999997, 1047.000010, 1.0}, + {2, 0, 181.475730, 1052.091079, 1.0}, + {3, 0, 181.741562, 1057.893341, 1.0}, + {4, 0, 183.190498, 1068.310440, 1.0}, + {1, 1, 271.000013, 666.000009, 1.0}, + {2, 1, 270.596180, 668.665760, 1.0}, + {3, 1, 270.523510, 671.559069, 1.0}, + {4, 1, 271.856518, 676.818151, 1.0}, + {5, 1, 268.989000, 727.051570, 1.0}, + {1, 2, 264.999990, 1018.000031, 1.0}, + {2, 2, 264.020061, 1021.157591, 1.0}, + {3, 2, 264.606056, 1024.823506, 1.0}, + {4, 2, 266.200933, 1031.168690, 1.0}, + {1, 3, 270.000000, 938.000014, 1.0}, + {2, 3, 269.022617, 941.153390, 1.0}, + {3, 3, 269.605579, 944.454954, 1.0}, + {4, 3, 271.281366, 949.452167, 1.0}, + {5, 3, 268.963480, 1004.417453, 1.0}, + {1, 4, 200.999994, 799.000003, 1.0}, + {2, 4, 199.841366, 803.891838, 1.0}, + {3, 4, 200.262208, 809.323246, 1.0}, + {4, 4, 201.456513, 819.271195, 1.0}, + {5, 4, 195.026493, 924.363234, 1.0}, + {1, 5, 1775.000038, 49.999998, 1.0}, + {2, 5, 1775.255127, 53.718264, 1.0}, + {3, 5, 1776.449890, 55.951670, 1.0}, + {4, 5, 1778.815727, 61.923309, 1.0}, + {5, 5, 1790.274124, 123.074923, 1.0}, + {1, 6, 164.000001, 927.999988, 1.0}, + {2, 6, 162.665462, 933.169527, 1.0}, + {3, 6, 163.067923, 938.577182, 1.0}, + {4, 6, 164.370360, 948.840945, 1.0}, + {5, 6, 157.199407, 1057.762341, 1.0}, + {1, 7, 618.000011, 477.999998, 1.0}, + {2, 7, 617.583504, 480.124243, 1.0}, + {3, 7, 618.356495, 482.441897, 1.0}, + {4, 7, 619.792500, 486.428132, 1.0}, + {5, 7, 619.546051, 525.222627, 1.0}, + {1, 8, 499.999981, 1036.999984, 1.0}, + {2, 8, 499.080162, 1038.720160, 1.0}, + {3, 8, 499.949398, 1039.014344, 1.0}, + {4, 8, 501.828003, 1041.286647, 1.0}, + {5, 8, 502.777576, 1055.196369, 1.0}, + {1, 9, 1587.000046, 31.999999, 1.0}, + {2, 9, 1586.988373, 34.635853, 1.0}, + {3, 9, 1588.155899, 37.444186, 1.0}, + {4, 9, 1589.973106, 42.492081, 1.0}, + {5, 9, 1598.683205, 96.526332, 1.0}, + {1, 10, 622.999992, 416.999999, 1.0}, + {2, 10, 622.449017, 419.233485, 1.0}, + {3, 10, 623.283234, 421.500703, 1.0}, + {4, 10, 624.620132, 425.537406, 1.0}, + {5, 10, 624.290829, 465.078338, 1.0}, + {1, 11, 577.999992, 931.999998, 1.0}, + {2, 11, 577.042294, 932.872703, 1.0}, + {3, 11, 577.832451, 934.045451, 1.0}, + {4, 11, 579.729137, 935.735435, 1.0}, + {5, 11, 580.691242, 948.396256, 1.0}, + {1, 12, 510.999985, 931.999998, 1.0}, + {2, 12, 510.111237, 933.152146, 1.0}, + {3, 12, 510.797081, 934.454219, 1.0}, + {4, 12, 512.647362, 936.595910, 1.0}, + {5, 12, 513.247204, 955.144157, 1.0}, + {1, 13, 330.459995, 177.059993, 1.0}, + {2, 13, 329.876347, 179.615586, 1.0}, + {3, 13, 330.681696, 182.757810, 1.0}, + {4, 13, 331.345053, 187.903853, 1.0}, + {5, 13, 327.824135, 239.611639, 1.0}, + {1, 14, 291.813097, 388.516195, 1.0}, + {2, 14, 290.984058, 391.382725, 1.0}, + {3, 14, 291.526737, 394.778595, 1.0}, + {4, 14, 292.763815, 400.310973, 1.0}, + {5, 14, 288.714552, 457.548015, 1.0}, + {1, 15, 496.491680, 466.534005, 1.0}, + {2, 15, 495.909519, 468.518561, 1.0}, + {3, 15, 496.588383, 470.853596, 1.0}, + {4, 15, 497.976780, 474.731458, 1.0}, + {5, 15, 496.998882, 512.568694, 1.0}, + {1, 16, 1273.000031, 89.000000, 1.0}, + {2, 16, 1272.951965, 92.003637, 1.0}, + {3, 16, 1273.934784, 94.972191, 1.0}, + {4, 16, 1275.493584, 100.139952, 1.0}, + {5, 16, 1281.003571, 156.880163, 1.0}, + {1, 17, 1524.713173, 78.852922, 1.0}, + {2, 17, 1524.782066, 81.427142, 1.0}, + {3, 17, 1525.759048, 84.057939, 1.0}, + {4, 17, 1527.579689, 88.966550, 1.0}, + {5, 17, 1535.262451, 141.186054, 1.0}, + {1, 18, 1509.425011, 94.371824, 1.0}, + {1, 19, 451.000013, 357.000003, 1.0}, + {2, 19, 450.354881, 359.312410, 1.0}, + {3, 19, 451.107473, 361.837088, 1.0}, + {4, 19, 452.186537, 366.318061, 1.0}, + {5, 19, 450.507660, 409.257599, 1.0}, + {1, 20, 254.004936, 114.784185, 1.0}, + {2, 20, 253.291512, 119.288486, 1.0}, + {3, 20, 253.745584, 124.114957, 1.0}, + {4, 20, 254.453287, 132.795120, 1.0}, + {5, 20, 246.772242, 225.165337, 1.0}, + {1, 21, 65.262880, 147.889409, 1.0}, + {2, 21, 63.634465, 157.656807, 1.0}, + {3, 21, 63.306799, 169.067053, 1.0}, + {4, 21, 62.462311, 189.724241, 1.0}, + {5, 21, 35.396615, 430.308380, 1.0}, }; int num_markers = sizeof(markers) / sizeof(Marker); @@ -304,4 +526,4 @@ TEST(KeyframeSelection, ElevatorReconstructionVarianceTest) { } } -} // namespace libmv +} // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver.cc b/intern/libmv/libmv/simple_pipeline/modal_solver.cc index 687c328b004..845b299e31e 100644 --- a/intern/libmv/libmv/simple_pipeline/modal_solver.cc +++ b/intern/libmv/libmv/simple_pipeline/modal_solver.cc @@ -34,7 +34,7 @@ namespace libmv { namespace { -void ProjectMarkerOnSphere(const Marker &marker, Vec3 &X) { +void ProjectMarkerOnSphere(const Marker& marker, Vec3& X) { X(0) = marker.x; X(1) = marker.y; X(2) = 1.0; @@ -42,12 +42,14 @@ void ProjectMarkerOnSphere(const Marker &marker, Vec3 &X) { X *= 5.0 / X.norm(); } -void ModalSolverLogProgress(ProgressUpdateCallback *update_callback, - double progress) { +void ModalSolverLogProgress(ProgressUpdateCallback* update_callback, + double progress) { if (update_callback) { char message[256]; - snprintf(message, sizeof(message), "Solving progress %d%%", + snprintf(message, + sizeof(message), + "Solving progress %d%%", (int)(progress * 100)); update_callback->invoke(progress, message); @@ -58,25 +60,27 @@ struct ModalReprojectionError { ModalReprojectionError(double observed_x, double observed_y, const double weight, - const Vec3 &bundle) - : observed_x_(observed_x), observed_y_(observed_y), - weight_(weight), bundle_(bundle) { } + const Vec3& bundle) + : observed_x_(observed_x), + observed_y_(observed_y), + weight_(weight), + bundle_(bundle) {} // TODO(keir): This should support bundling focal length as well. template bool operator()(const T* quaternion, T* residuals) const { // Convert bundle position from double to T. - T X[3] = { T(bundle_(0)), T(bundle_(1)), T(bundle_(2)) }; + T X[3] = {T(bundle_(0)), T(bundle_(1)), T(bundle_(2))}; // Compute the point position in camera coordinates: x = RX. T x[3]; // This flips the sense of the quaternion, to adhere to Blender conventions. T quaternion_inverse[4] = { - quaternion[0], - -quaternion[1], - -quaternion[2], - -quaternion[3], + quaternion[0], + -quaternion[1], + -quaternion[2], + -quaternion[3], }; ceres::QuaternionRotatePoint(quaternion_inverse, X, x); @@ -99,9 +103,9 @@ struct ModalReprojectionError { }; } // namespace -void ModalSolver(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback) { +void ModalSolver(const Tracks& tracks, + EuclideanReconstruction* reconstruction, + ProgressUpdateCallback* update_callback) { int max_image = tracks.MaxImage(); int max_track = tracks.MaxTrack(); @@ -116,7 +120,7 @@ void ModalSolver(const Tracks &tracks, for (int image = 0; image <= max_image; ++image) { vector all_markers = tracks.MarkersInImage(image); - ModalSolverLogProgress(update_callback, (float) image / max_image); + ModalSolverLogProgress(update_callback, (float)image / max_image); // Skip empty images without doing anything. if (all_markers.size() == 0) { @@ -133,8 +137,8 @@ void ModalSolver(const Tracks &tracks, // 3D positions. Mat x1, x2; for (int i = 0; i < all_markers.size(); ++i) { - Marker &marker = all_markers[i]; - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); + Marker& marker = all_markers[i]; + EuclideanPoint* point = reconstruction->PointForTrack(marker.track); if (point) { Vec3 X; ProjectMarkerOnSphere(marker, X); @@ -168,8 +172,7 @@ void ModalSolver(const Tracks &tracks, ceres::AngleAxisToQuaternion(&angle_axis(0), &quaternion(0)); - LG << "Analytically computed quaternion " - << quaternion.transpose(); + LG << "Analytically computed quaternion " << quaternion.transpose(); } // STEP 2: Refine rotation with Ceres. @@ -181,17 +184,15 @@ void ModalSolver(const Tracks &tracks, int num_residuals = 0; for (int i = 0; i < all_markers.size(); ++i) { - Marker &marker = all_markers[i]; - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); + Marker& marker = all_markers[i]; + EuclideanPoint* point = reconstruction->PointForTrack(marker.track); if (point && marker.weight != 0.0) { - problem.AddResidualBlock(new ceres::AutoDiffCostFunction< - ModalReprojectionError, - 2, /* num_residuals */ - 4>(new ModalReprojectionError(marker.x, - marker.y, - marker.weight, - point->X)), + problem.AddResidualBlock( + new ceres::AutoDiffCostFunction(new ModalReprojectionError( + marker.x, marker.y, marker.weight, point->X)), NULL, &quaternion(0)); num_residuals++; diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver.h b/intern/libmv/libmv/simple_pipeline/modal_solver.h index 9801fd21d81..f7ce394b4b2 100644 --- a/intern/libmv/libmv/simple_pipeline/modal_solver.h +++ b/intern/libmv/libmv/simple_pipeline/modal_solver.h @@ -21,9 +21,9 @@ #ifndef LIBMV_SIMPLE_PIPELINE_MODAL_SOLVER_H_ #define LIBMV_SIMPLE_PIPELINE_MODAL_SOLVER_H_ -#include "libmv/simple_pipeline/tracks.h" -#include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/callbacks.h" +#include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { @@ -39,9 +39,9 @@ namespace libmv { Reconstructed cameras and projected bundles would be added to reconstruction object. */ -void ModalSolver(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback = NULL); +void ModalSolver(const Tracks& tracks, + EuclideanReconstruction* reconstruction, + ProgressUpdateCallback* update_callback = NULL); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc b/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc index b4cae8defb2..0acf978e6f5 100644 --- a/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc +++ b/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc @@ -20,10 +20,10 @@ #include "libmv/simple_pipeline/modal_solver.h" -#include "testing/testing.h" #include "libmv/logging/logging.h" #include "libmv/simple_pipeline/bundle.h" #include "libmv/simple_pipeline/camera_intrinsics.h" +#include "testing/testing.h" #include @@ -38,14 +38,21 @@ TEST(ModalSolver, SyntheticCubeSceneMotion) { intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); Marker markers[] = { - {1, 0, 212.172775, 354.713538, 1.0}, {2, 0, 773.468399, 358.735306, 1.0}, - {1, 1, 62.415197, 287.905354, 1.0}, {2, 1, 619.103336, 324.402537, 1.0}, - {1, 2, 206.847939, 237.567925, 1.0}, {2, 2, 737.496986, 247.881383, 1.0}, - {1, 3, 351.743889, 316.415906, 1.0}, {2, 3, 908.779621, 290.703617, 1.0}, - {1, 4, 232.941413, 54.265443, 1.0}, {2, 4, 719.444847, 63.062531, 1.0}, - {1, 5, 96.391611, 119.283537, 1.0}, {2, 5, 611.413136, 160.890715, 1.0}, - {1, 6, 363.444958, 150.838144, 1.0}, {2, 6, 876.374531, 114.916206, 1.0}, - }; + {1, 0, 212.172775, 354.713538, 1.0}, + {2, 0, 773.468399, 358.735306, 1.0}, + {1, 1, 62.415197, 287.905354, 1.0}, + {2, 1, 619.103336, 324.402537, 1.0}, + {1, 2, 206.847939, 237.567925, 1.0}, + {2, 2, 737.496986, 247.881383, 1.0}, + {1, 3, 351.743889, 316.415906, 1.0}, + {2, 3, 908.779621, 290.703617, 1.0}, + {1, 4, 232.941413, 54.265443, 1.0}, + {2, 4, 719.444847, 63.062531, 1.0}, + {1, 5, 96.391611, 119.283537, 1.0}, + {2, 5, 611.413136, 160.890715, 1.0}, + {1, 6, 363.444958, 150.838144, 1.0}, + {2, 6, 876.374531, 114.916206, 1.0}, + }; int num_markers = sizeof(markers) / sizeof(Marker); Tracks tracks; @@ -65,12 +72,14 @@ TEST(ModalSolver, SyntheticCubeSceneMotion) { NULL); Mat3 expected_rotation; + // clang-format off expected_rotation << 0.98215101743472, 0.17798354937546, 0.06083777694542, -0.16875283983360, 0.97665300495333, -0.13293376908719, -0.08307742172243, 0.12029448893171, 0.98925597189636; + // clang-format on - Mat3 &first_camera_R = reconstruction.CameraForImage(1)->R; - Mat3 &second_camera_R = reconstruction.CameraForImage(2)->R; + Mat3& first_camera_R = reconstruction.CameraForImage(1)->R; + Mat3& second_camera_R = reconstruction.CameraForImage(2)->R; EXPECT_TRUE(Mat3::Identity().isApprox(first_camera_R, kTolerance)); EXPECT_TRUE(expected_rotation.isApprox(second_camera_R, kTolerance)); diff --git a/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h b/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h index cbea599fccd..79fa3ab8379 100644 --- a/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h +++ b/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h @@ -40,7 +40,7 @@ class PackedIntrinsics { OFFSET_FOCAL_LENGTH, OFFSET_PRINCIPAL_POINT_X, OFFSET_PRINCIPAL_POINT_Y, - + // Distortion model coefficients. OFFSET_K1, OFFSET_K2, @@ -48,7 +48,7 @@ class PackedIntrinsics { OFFSET_K4, OFFSET_P1, OFFSET_P2, - + // Number of parameters which are to be stored in the block. NUM_PARAMETERS, }; @@ -66,12 +66,12 @@ class PackedIntrinsics { // point. #define DEFINE_PARAMETER(parameter_name) \ - void Set ## parameter_name(double value) { \ - SetParameter(OFFSET_ ## parameter_name, value); \ - } \ - double Get ## parameter_name() const { \ - return GetParameter(OFFSET_ ## parameter_name); \ + void Set##parameter_name(double value) { \ + SetParameter(OFFSET_##parameter_name, value); \ } \ + double Get##parameter_name() const { \ + return GetParameter(OFFSET_##parameter_name); \ + } DEFINE_PARAMETER(K1) DEFINE_PARAMETER(K2) @@ -94,11 +94,11 @@ class PackedIntrinsics { // All intrinsics parameters packed into a single block. // Use OFFSET_FOO indexes to access corresponding values. - array parameters_; + array parameters_; // Indexed by parameter offset, set to truth if the value of the parameter is // explicitly specified. - array known_parameters_; + array known_parameters_; }; } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/pipeline.cc b/intern/libmv/libmv/simple_pipeline/pipeline.cc index 728601f3732..5d52aeb7406 100644 --- a/intern/libmv/libmv/simple_pipeline/pipeline.cc +++ b/intern/libmv/libmv/simple_pipeline/pipeline.cc @@ -24,11 +24,11 @@ #include "libmv/logging/logging.h" #include "libmv/simple_pipeline/bundle.h" +#include "libmv/simple_pipeline/camera_intrinsics.h" #include "libmv/simple_pipeline/intersect.h" -#include "libmv/simple_pipeline/resect.h" #include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/resect.h" #include "libmv/simple_pipeline/tracks.h" -#include "libmv/simple_pipeline/camera_intrinsics.h" #ifdef _MSC_VER # define snprintf _snprintf @@ -46,24 +46,25 @@ struct EuclideanPipelineRoutines { typedef EuclideanCamera Camera; typedef EuclideanPoint Point; - static void Bundle(const Tracks &tracks, - EuclideanReconstruction *reconstruction) { + static void Bundle(const Tracks& tracks, + EuclideanReconstruction* reconstruction) { EuclideanBundle(tracks, reconstruction); } - static bool Resect(const vector &markers, - EuclideanReconstruction *reconstruction, bool final_pass) { + static bool Resect(const vector& markers, + EuclideanReconstruction* reconstruction, + bool final_pass) { return EuclideanResect(markers, reconstruction, final_pass); } - static bool Intersect(const vector &markers, - EuclideanReconstruction *reconstruction) { + static bool Intersect(const vector& markers, + EuclideanReconstruction* reconstruction) { return EuclideanIntersect(markers, reconstruction); } - static Marker ProjectMarker(const EuclideanPoint &point, - const EuclideanCamera &camera, - const CameraIntrinsics &intrinsics) { + static Marker ProjectMarker(const EuclideanPoint& point, + const EuclideanCamera& camera, + const CameraIntrinsics& intrinsics) { Vec3 projected = camera.R * point.X + camera.t; projected /= projected(2); @@ -84,26 +85,27 @@ struct ProjectivePipelineRoutines { typedef ProjectiveCamera Camera; typedef ProjectivePoint Point; - static void Bundle(const Tracks &tracks, - ProjectiveReconstruction *reconstruction) { + static void Bundle(const Tracks& tracks, + ProjectiveReconstruction* reconstruction) { ProjectiveBundle(tracks, reconstruction); } - static bool Resect(const vector &markers, - ProjectiveReconstruction *reconstruction, bool final_pass) { - (void) final_pass; // Ignored. + static bool Resect(const vector& markers, + ProjectiveReconstruction* reconstruction, + bool final_pass) { + (void)final_pass; // Ignored. return ProjectiveResect(markers, reconstruction); } - static bool Intersect(const vector &markers, - ProjectiveReconstruction *reconstruction) { + static bool Intersect(const vector& markers, + ProjectiveReconstruction* reconstruction) { return ProjectiveIntersect(markers, reconstruction); } - static Marker ProjectMarker(const ProjectivePoint &point, - const ProjectiveCamera &camera, - const CameraIntrinsics &intrinsics) { + static Marker ProjectMarker(const ProjectivePoint& point, + const ProjectiveCamera& camera, + const CameraIntrinsics& intrinsics) { Vec3 projected = camera.P * point.X; projected /= projected(2); @@ -122,28 +124,33 @@ struct ProjectivePipelineRoutines { } // namespace static void CompleteReconstructionLogProgress( - ProgressUpdateCallback *update_callback, + ProgressUpdateCallback* update_callback, double progress, - const char *step = NULL) { + const char* step = NULL) { if (update_callback) { char message[256]; if (step) - snprintf(message, sizeof(message), "Completing solution %d%% | %s", - (int)(progress*100), step); + snprintf(message, + sizeof(message), + "Completing solution %d%% | %s", + (int)(progress * 100), + step); else - snprintf(message, sizeof(message), "Completing solution %d%%", - (int)(progress*100)); + snprintf(message, + sizeof(message), + "Completing solution %d%%", + (int)(progress * 100)); update_callback->invoke(progress, message); } } -template +template void InternalCompleteReconstruction( - const Tracks &tracks, - typename PipelineRoutines::Reconstruction *reconstruction, - ProgressUpdateCallback *update_callback = NULL) { + const Tracks& tracks, + typename PipelineRoutines::Reconstruction* reconstruction, + ProgressUpdateCallback* update_callback = NULL) { int max_track = tracks.MaxTrack(); int max_image = tracks.MaxImage(); int num_resects = -1; @@ -173,7 +180,7 @@ void InternalCompleteReconstruction( << " reconstructed markers for track " << track; if (reconstructed_markers.size() >= 2) { CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image)); + (double)tot_resects / (max_image)); if (PipelineRoutines::Intersect(reconstructed_markers, reconstruction)) { num_intersects++; @@ -184,9 +191,8 @@ void InternalCompleteReconstruction( } } if (num_intersects) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image), - "Bundling..."); + CompleteReconstructionLogProgress( + update_callback, (double)tot_resects / (max_image), "Bundling..."); PipelineRoutines::Bundle(tracks, reconstruction); LG << "Ran Bundle() after intersections."; } @@ -212,9 +218,9 @@ void InternalCompleteReconstruction( << " reconstructed markers for image " << image; if (reconstructed_markers.size() >= 5) { CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image)); - if (PipelineRoutines::Resect(reconstructed_markers, - reconstruction, false)) { + (double)tot_resects / (max_image)); + if (PipelineRoutines::Resect( + reconstructed_markers, reconstruction, false)) { num_resects++; tot_resects++; LG << "Ran Resect() for image " << image; @@ -224,9 +230,8 @@ void InternalCompleteReconstruction( } } if (num_resects) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image), - "Bundling..."); + CompleteReconstructionLogProgress( + update_callback, (double)tot_resects / (max_image), "Bundling..."); PipelineRoutines::Bundle(tracks, reconstruction); } LG << "Did " << num_resects << " resects."; @@ -249,9 +254,9 @@ void InternalCompleteReconstruction( } if (reconstructed_markers.size() >= 5) { CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image)); - if (PipelineRoutines::Resect(reconstructed_markers, - reconstruction, true)) { + (double)tot_resects / (max_image)); + if (PipelineRoutines::Resect( + reconstructed_markers, reconstruction, true)) { num_resects++; LG << "Ran final Resect() for image " << image; } else { @@ -260,27 +265,26 @@ void InternalCompleteReconstruction( } } if (num_resects) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image), - "Bundling..."); + CompleteReconstructionLogProgress( + update_callback, (double)tot_resects / (max_image), "Bundling..."); PipelineRoutines::Bundle(tracks, reconstruction); } } -template +template double InternalReprojectionError( - const Tracks &image_tracks, - const typename PipelineRoutines::Reconstruction &reconstruction, - const CameraIntrinsics &intrinsics) { + const Tracks& image_tracks, + const typename PipelineRoutines::Reconstruction& reconstruction, + const CameraIntrinsics& intrinsics) { int num_skipped = 0; int num_reprojected = 0; double total_error = 0.0; vector markers = image_tracks.AllMarkers(); for (int i = 0; i < markers.size(); ++i) { double weight = markers[i].weight; - const typename PipelineRoutines::Camera *camera = + const typename PipelineRoutines::Camera* camera = reconstruction.CameraForImage(markers[i].image); - const typename PipelineRoutines::Point *point = + const typename PipelineRoutines::Point* point = reconstruction.PointForTrack(markers[i].track); if (!camera || !point || weight == 0.0) { num_skipped++; @@ -295,24 +299,25 @@ double InternalReprojectionError( const int N = 100; char line[N]; - snprintf(line, N, - "image %-3d track %-3d " - "x %7.1f y %7.1f " - "rx %7.1f ry %7.1f " - "ex %7.1f ey %7.1f" - " e %7.1f", - markers[i].image, - markers[i].track, - markers[i].x, - markers[i].y, - reprojected_marker.x, - reprojected_marker.y, - ex, - ey, - sqrt(ex*ex + ey*ey)); + snprintf(line, + N, + "image %-3d track %-3d " + "x %7.1f y %7.1f " + "rx %7.1f ry %7.1f " + "ex %7.1f ey %7.1f" + " e %7.1f", + markers[i].image, + markers[i].track, + markers[i].x, + markers[i].y, + reprojected_marker.x, + reprojected_marker.y, + ex, + ey, + sqrt(ex * ex + ey * ey)); VLOG(1) << line; - total_error += sqrt(ex*ex + ey*ey); + total_error += sqrt(ex * ex + ey * ey); } LG << "Skipped " << num_skipped << " markers."; LG << "Reprojected " << num_reprojected << " markers."; @@ -321,46 +326,41 @@ double InternalReprojectionError( return total_error / num_reprojected; } -double EuclideanReprojectionError(const Tracks &image_tracks, - const EuclideanReconstruction &reconstruction, - const CameraIntrinsics &intrinsics) { - return InternalReprojectionError(image_tracks, - reconstruction, - intrinsics); +double EuclideanReprojectionError(const Tracks& image_tracks, + const EuclideanReconstruction& reconstruction, + const CameraIntrinsics& intrinsics) { + return InternalReprojectionError( + image_tracks, reconstruction, intrinsics); } double ProjectiveReprojectionError( - const Tracks &image_tracks, - const ProjectiveReconstruction &reconstruction, - const CameraIntrinsics &intrinsics) { - return InternalReprojectionError(image_tracks, - reconstruction, - intrinsics); + const Tracks& image_tracks, + const ProjectiveReconstruction& reconstruction, + const CameraIntrinsics& intrinsics) { + return InternalReprojectionError( + image_tracks, reconstruction, intrinsics); } -void EuclideanCompleteReconstruction(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback) { - InternalCompleteReconstruction(tracks, - reconstruction, - update_callback); +void EuclideanCompleteReconstruction(const Tracks& tracks, + EuclideanReconstruction* reconstruction, + ProgressUpdateCallback* update_callback) { + InternalCompleteReconstruction( + tracks, reconstruction, update_callback); } -void ProjectiveCompleteReconstruction(const Tracks &tracks, - ProjectiveReconstruction *reconstruction) { +void ProjectiveCompleteReconstruction( + const Tracks& tracks, ProjectiveReconstruction* reconstruction) { InternalCompleteReconstruction(tracks, reconstruction); } -void InvertIntrinsicsForTracks(const Tracks &raw_tracks, - const CameraIntrinsics &camera_intrinsics, - Tracks *calibrated_tracks) { +void InvertIntrinsicsForTracks(const Tracks& raw_tracks, + const CameraIntrinsics& camera_intrinsics, + Tracks* calibrated_tracks) { vector markers = raw_tracks.AllMarkers(); for (int i = 0; i < markers.size(); ++i) { - camera_intrinsics.InvertIntrinsics(markers[i].x, - markers[i].y, - &(markers[i].x), - &(markers[i].y)); + camera_intrinsics.InvertIntrinsics( + markers[i].x, markers[i].y, &(markers[i].x), &(markers[i].y)); } *calibrated_tracks = Tracks(markers); } diff --git a/intern/libmv/libmv/simple_pipeline/pipeline.h b/intern/libmv/libmv/simple_pipeline/pipeline.h index 4d1bd00c51f..d6b43536d46 100644 --- a/intern/libmv/libmv/simple_pipeline/pipeline.h +++ b/intern/libmv/libmv/simple_pipeline/pipeline.h @@ -22,8 +22,8 @@ #define LIBMV_SIMPLE_PIPELINE_PIPELINE_H_ #include "libmv/simple_pipeline/callbacks.h" -#include "libmv/simple_pipeline/tracks.h" #include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { @@ -47,9 +47,9 @@ namespace libmv { \sa EuclideanResect, EuclideanIntersect, EuclideanBundle */ void EuclideanCompleteReconstruction( - const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback = NULL); + const Tracks& tracks, + EuclideanReconstruction* reconstruction, + ProgressUpdateCallback* update_callback = NULL); /*! Estimate camera matrices and homogeneous 3D coordinates for all frames and @@ -71,27 +71,26 @@ void EuclideanCompleteReconstruction( \sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle */ -void ProjectiveCompleteReconstruction(const Tracks &tracks, - ProjectiveReconstruction *reconstruction); - +void ProjectiveCompleteReconstruction(const Tracks& tracks, + ProjectiveReconstruction* reconstruction); class CameraIntrinsics; // TODO(keir): Decide if we want these in the public API, and if so, what the // appropriate include file is. -double EuclideanReprojectionError(const Tracks &image_tracks, - const EuclideanReconstruction &reconstruction, - const CameraIntrinsics &intrinsics); +double EuclideanReprojectionError(const Tracks& image_tracks, + const EuclideanReconstruction& reconstruction, + const CameraIntrinsics& intrinsics); double ProjectiveReprojectionError( - const Tracks &image_tracks, - const ProjectiveReconstruction &reconstruction, - const CameraIntrinsics &intrinsics); + const Tracks& image_tracks, + const ProjectiveReconstruction& reconstruction, + const CameraIntrinsics& intrinsics); -void InvertIntrinsicsForTracks(const Tracks &raw_tracks, - const CameraIntrinsics &camera_intrinsics, - Tracks *calibrated_tracks); +void InvertIntrinsicsForTracks(const Tracks& raw_tracks, + const CameraIntrinsics& camera_intrinsics, + Tracks* calibrated_tracks); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction.cc b/intern/libmv/libmv/simple_pipeline/reconstruction.cc index 851eedb5bb1..584f7440caf 100644 --- a/intern/libmv/libmv/simple_pipeline/reconstruction.cc +++ b/intern/libmv/libmv/simple_pipeline/reconstruction.cc @@ -19,20 +19,21 @@ // IN THE SOFTWARE. #include "libmv/simple_pipeline/reconstruction.h" -#include "libmv/numeric/numeric.h" #include "libmv/logging/logging.h" +#include "libmv/numeric/numeric.h" namespace libmv { -EuclideanReconstruction::EuclideanReconstruction() {} +EuclideanReconstruction::EuclideanReconstruction() { +} EuclideanReconstruction::EuclideanReconstruction( - const EuclideanReconstruction &other) { + const EuclideanReconstruction& other) { image_to_cameras_map_ = other.image_to_cameras_map_; points_ = other.points_; } -EuclideanReconstruction &EuclideanReconstruction::operator=( - const EuclideanReconstruction &other) { +EuclideanReconstruction& EuclideanReconstruction::operator=( + const EuclideanReconstruction& other) { if (&other != this) { image_to_cameras_map_ = other.image_to_cameras_map_; points_ = other.points_; @@ -41,9 +42,9 @@ EuclideanReconstruction &EuclideanReconstruction::operator=( } void EuclideanReconstruction::InsertCamera(int image, - const Mat3 &R, - const Vec3 &t) { - LG << "InsertCamera " << image << ":\nR:\n"<< R << "\nt:\n" << t; + const Mat3& R, + const Vec3& t) { + LG << "InsertCamera " << image << ":\nR:\n" << R << "\nt:\n" << t; EuclideanCamera camera; camera.image = image; @@ -53,7 +54,7 @@ void EuclideanReconstruction::InsertCamera(int image, image_to_cameras_map_.insert(make_pair(image, camera)); } -void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) { +void EuclideanReconstruction::InsertPoint(int track, const Vec3& X) { LG << "InsertPoint " << track << ":\n" << X; if (track >= points_.size()) { points_.resize(track + 1); @@ -62,13 +63,12 @@ void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) { points_[track].X = X; } -EuclideanCamera *EuclideanReconstruction::CameraForImage(int image) { - return const_cast( - static_cast( - this)->CameraForImage(image)); +EuclideanCamera* EuclideanReconstruction::CameraForImage(int image) { + return const_cast( + static_cast(this)->CameraForImage(image)); } -const EuclideanCamera *EuclideanReconstruction::CameraForImage( +const EuclideanCamera* EuclideanReconstruction::CameraForImage( int image) const { ImageToCameraMap::const_iterator it = image_to_cameras_map_.find(image); if (it == image_to_cameras_map_.end()) { @@ -86,16 +86,16 @@ vector EuclideanReconstruction::AllCameras() const { return cameras; } -EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) { - return const_cast( - static_cast(this)->PointForTrack(track)); +EuclideanPoint* EuclideanReconstruction::PointForTrack(int track) { + return const_cast( + static_cast(this)->PointForTrack(track)); } -const EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) const { +const EuclideanPoint* EuclideanReconstruction::PointForTrack(int track) const { if (track < 0 || track >= points_.size()) { return NULL; } - const EuclideanPoint *point = &points_[track]; + const EuclideanPoint* point = &points_[track]; if (point->track == -1) { return NULL; } @@ -112,8 +112,8 @@ vector EuclideanReconstruction::AllPoints() const { return points; } -void ProjectiveReconstruction::InsertCamera(int image, const Mat34 &P) { - LG << "InsertCamera " << image << ":\nP:\n"<< P; +void ProjectiveReconstruction::InsertCamera(int image, const Mat34& P) { + LG << "InsertCamera " << image << ":\nP:\n" << P; ProjectiveCamera camera; camera.image = image; @@ -122,7 +122,7 @@ void ProjectiveReconstruction::InsertCamera(int image, const Mat34 &P) { image_to_cameras_map_.insert(make_pair(image, camera)); } -void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) { +void ProjectiveReconstruction::InsertPoint(int track, const Vec4& X) { LG << "InsertPoint " << track << ":\n" << X; if (track >= points_.size()) { points_.resize(track + 1); @@ -131,17 +131,17 @@ void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) { points_[track].X = X; } -ProjectiveCamera *ProjectiveReconstruction::CameraForImage(int image) { - return const_cast( - static_cast( - this)->CameraForImage(image)); +ProjectiveCamera* ProjectiveReconstruction::CameraForImage(int image) { + return const_cast( + static_cast(this)->CameraForImage( + image)); } -const ProjectiveCamera *ProjectiveReconstruction::CameraForImage( +const ProjectiveCamera* ProjectiveReconstruction::CameraForImage( int image) const { ImageToCameraMap::const_iterator it = image_to_cameras_map_.find(image); if (it == image_to_cameras_map_.end()) { - return NULL; + return NULL; } return &it->second; } @@ -155,16 +155,17 @@ vector ProjectiveReconstruction::AllCameras() const { return cameras; } -ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) { - return const_cast( - static_cast(this)->PointForTrack(track)); +ProjectivePoint* ProjectiveReconstruction::PointForTrack(int track) { + return const_cast( + static_cast(this)->PointForTrack(track)); } -const ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) const { +const ProjectivePoint* ProjectiveReconstruction::PointForTrack( + int track) const { if (track < 0 || track >= points_.size()) { return NULL; } - const ProjectivePoint *point = &points_[track]; + const ProjectivePoint* point = &points_[track]; if (point->track == -1) { return NULL; } diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction.h b/intern/libmv/libmv/simple_pipeline/reconstruction.h index 544aeac042e..56b2ba34c91 100644 --- a/intern/libmv/libmv/simple_pipeline/reconstruction.h +++ b/intern/libmv/libmv/simple_pipeline/reconstruction.h @@ -21,14 +21,15 @@ #ifndef LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_ #define LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_ -#include "libmv/base/vector.h" #include "libmv/base/map.h" +#include "libmv/base/vector.h" #include "libmv/numeric/numeric.h" namespace libmv { /*! - A EuclideanCamera is the location and rotation of the camera viewing \a image. + A EuclideanCamera is the location and rotation of the camera viewing \a + image. \a image identify which image from \link Tracks this camera represents. \a R is a 3x3 matrix representing the rotation of the camera. @@ -38,7 +39,7 @@ namespace libmv { */ struct EuclideanCamera { EuclideanCamera() : image(-1) {} - EuclideanCamera(const EuclideanCamera &c) : image(c.image), R(c.R), t(c.t) {} + EuclideanCamera(const EuclideanCamera& c) : image(c.image), R(c.R), t(c.t) {} int image; Mat3 R; @@ -55,7 +56,7 @@ struct EuclideanCamera { */ struct EuclideanPoint { EuclideanPoint() : track(-1) {} - EuclideanPoint(const EuclideanPoint &p) : track(p.track), X(p.X) {} + EuclideanPoint(const EuclideanPoint& p) : track(p.track), X(p.X) {} int track; Vec3 X; }; @@ -78,9 +79,9 @@ class EuclideanReconstruction { EuclideanReconstruction(); /// Copy constructor. - EuclideanReconstruction(const EuclideanReconstruction &other); + EuclideanReconstruction(const EuclideanReconstruction& other); - EuclideanReconstruction &operator=(const EuclideanReconstruction &other); + EuclideanReconstruction& operator=(const EuclideanReconstruction& other); /*! Insert a camera into the set. If there is already a camera for the given @@ -92,7 +93,7 @@ class EuclideanReconstruction { \note You should use the same \a image identifier as in \link Tracks. */ - void InsertCamera(int image, const Mat3 &R, const Vec3 &t); + void InsertCamera(int image, const Mat3& R, const Vec3& t); /*! Insert a point into the reconstruction. If there is already a point for @@ -104,18 +105,18 @@ class EuclideanReconstruction { \note You should use the same \a track identifier as in \link Tracks. */ - void InsertPoint(int track, const Vec3 &X); + void InsertPoint(int track, const Vec3& X); /// Returns a pointer to the camera corresponding to \a image. - EuclideanCamera *CameraForImage(int image); - const EuclideanCamera *CameraForImage(int image) const; + EuclideanCamera* CameraForImage(int image); + const EuclideanCamera* CameraForImage(int image) const; /// Returns all cameras. vector AllCameras() const; /// Returns a pointer to the point corresponding to \a track. - EuclideanPoint *PointForTrack(int track); - const EuclideanPoint *PointForTrack(int track) const; + EuclideanPoint* PointForTrack(int track); + const EuclideanPoint* PointForTrack(int track) const; /// Returns all points. vector AllPoints() const; @@ -139,7 +140,7 @@ class EuclideanReconstruction { */ struct ProjectiveCamera { ProjectiveCamera() : image(-1) {} - ProjectiveCamera(const ProjectiveCamera &c) : image(c.image), P(c.P) {} + ProjectiveCamera(const ProjectiveCamera& c) : image(c.image), P(c.P) {} int image; Mat34 P; @@ -155,7 +156,7 @@ struct ProjectiveCamera { */ struct ProjectivePoint { ProjectivePoint() : track(-1) {} - ProjectivePoint(const ProjectivePoint &p) : track(p.track), X(p.X) {} + ProjectivePoint(const ProjectivePoint& p) : track(p.track), X(p.X) {} int track; Vec4 X; }; @@ -184,7 +185,7 @@ class ProjectiveReconstruction { \note You should use the same \a image identifier as in \link Tracks. */ - void InsertCamera(int image, const Mat34 &P); + void InsertCamera(int image, const Mat34& P); /*! Insert a point into the reconstruction. If there is already a point for @@ -196,18 +197,18 @@ class ProjectiveReconstruction { \note You should use the same \a track identifier as in \link Tracks. */ - void InsertPoint(int track, const Vec4 &X); + void InsertPoint(int track, const Vec4& X); /// Returns a pointer to the camera corresponding to \a image. - ProjectiveCamera *CameraForImage(int image); - const ProjectiveCamera *CameraForImage(int image) const; + ProjectiveCamera* CameraForImage(int image); + const ProjectiveCamera* CameraForImage(int image) const; /// Returns all cameras. vector AllCameras() const; /// Returns a pointer to the point corresponding to \a track. - ProjectivePoint *PointForTrack(int track); - const ProjectivePoint *PointForTrack(int track) const; + ProjectivePoint* PointForTrack(int track); + const ProjectivePoint* PointForTrack(int track) const; /// Returns all points. vector AllPoints() const; diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc index 40ac23be7a2..04fbb536d31 100644 --- a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc +++ b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc @@ -23,7 +23,7 @@ namespace libmv { -void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction) { +void EuclideanScaleToUnity(EuclideanReconstruction* reconstruction) { vector all_cameras = reconstruction->AllCameras(); vector all_points = reconstruction->AllPoints(); @@ -53,14 +53,14 @@ void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction) { // Rescale cameras positions. for (int i = 0; i < all_cameras.size(); ++i) { int image = all_cameras[i].image; - EuclideanCamera *camera = reconstruction->CameraForImage(image); + EuclideanCamera* camera = reconstruction->CameraForImage(image); camera->t = camera->t * scale_factor; } // Rescale points positions. for (int i = 0; i < all_points.size(); ++i) { int track = all_points[i].track; - EuclideanPoint *point = reconstruction->PointForTrack(track); + EuclideanPoint* point = reconstruction->PointForTrack(track); point->X = point->X * scale_factor; } } diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h index f2349ff5146..c164878ee25 100644 --- a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h +++ b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h @@ -29,7 +29,7 @@ namespace libmv { Scale euclidean reconstruction in a way variance of camera centers equals to one. */ -void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction); +void EuclideanScaleToUnity(EuclideanReconstruction* reconstruction); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/resect.cc b/intern/libmv/libmv/simple_pipeline/resect.cc index e73fc44df2a..b5736767edd 100644 --- a/intern/libmv/libmv/simple_pipeline/resect.cc +++ b/intern/libmv/libmv/simple_pipeline/resect.cc @@ -25,17 +25,17 @@ #include "libmv/base/vector.h" #include "libmv/logging/logging.h" #include "libmv/multiview/euclidean_resection.h" -#include "libmv/multiview/resection.h" #include "libmv/multiview/projection.h" -#include "libmv/numeric/numeric.h" +#include "libmv/multiview/resection.h" #include "libmv/numeric/levenberg_marquardt.h" +#include "libmv/numeric/numeric.h" #include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/tracks.h" namespace libmv { namespace { -Mat2X PointMatrixFromMarkers(const vector &markers) { +Mat2X PointMatrixFromMarkers(const vector& markers) { Mat2X points(2, markers.size()); for (int i = 0; i < markers.size(); ++i) { points(0, i) = markers[i].x; @@ -53,19 +53,19 @@ Mat2X PointMatrixFromMarkers(const vector &markers) { // axis to rotate around and the magnitude is the amount of the rotation. struct EuclideanResectCostFunction { public: - typedef Vec FMatrixType; + typedef Vec FMatrixType; typedef Vec6 XMatrixType; - EuclideanResectCostFunction(const vector &markers, - const EuclideanReconstruction &reconstruction, - const Mat3 &initial_R) - : markers(markers), - reconstruction(reconstruction), - initial_R(initial_R) {} + EuclideanResectCostFunction(const vector& markers, + const EuclideanReconstruction& reconstruction, + const Mat3& initial_R) + : markers(markers), + reconstruction(reconstruction), + initial_R(initial_R) {} // dRt has dR (delta R) encoded as a euler vector in the first 3 parameters, // followed by t in the next 3 parameters. - Vec operator()(const Vec6 &dRt) const { + Vec operator()(const Vec6& dRt) const { // Unpack R, t from dRt. Mat3 R = RotationFromEulerVector(dRt.head<3>()) * initial_R; Vec3 t = dRt.tail<3>(); @@ -74,25 +74,26 @@ struct EuclideanResectCostFunction { Vec residuals(2 * markers.size()); residuals.setZero(); for (int i = 0; i < markers.size(); ++i) { - const EuclideanPoint &point = + const EuclideanPoint& point = *reconstruction.PointForTrack(markers[i].track); Vec3 projected = R * point.X + t; projected /= projected(2); - residuals[2*i + 0] = projected(0) - markers[i].x; - residuals[2*i + 1] = projected(1) - markers[i].y; + residuals[2 * i + 0] = projected(0) - markers[i].x; + residuals[2 * i + 1] = projected(1) - markers[i].y; } return residuals; } - const vector &markers; - const EuclideanReconstruction &reconstruction; - const Mat3 &initial_R; + const vector& markers; + const EuclideanReconstruction& reconstruction; + const Mat3& initial_R; }; } // namespace -bool EuclideanResect(const vector &markers, - EuclideanReconstruction *reconstruction, bool final_pass) { +bool EuclideanResect(const vector& markers, + EuclideanReconstruction* reconstruction, + bool final_pass) { if (markers.size() < 5) { return false; } @@ -106,9 +107,9 @@ bool EuclideanResect(const vector &markers, Mat3 R; Vec3 t; - if (0 || !euclidean_resection::EuclideanResection( - points_2d, points_3d, &R, &t, - euclidean_resection::RESECTION_EPNP)) { + if (0 || + !euclidean_resection::EuclideanResection( + points_2d, points_3d, &R, &t, euclidean_resection::RESECTION_EPNP)) { // printf("Resection for image %d failed\n", markers[0].image); LG << "Resection for image " << markers[0].image << " failed;" << " trying fallback projective resection."; @@ -116,7 +117,8 @@ bool EuclideanResect(const vector &markers, LG << "No fallback; failing resection for " << markers[0].image; return false; - if (!final_pass) return false; + if (!final_pass) + return false; // Euclidean resection failed. Fall back to projective resection, which is // less reliable but better conditioned when there are many points. Mat34 P; @@ -173,7 +175,9 @@ bool EuclideanResect(const vector &markers, t = dRt.tail<3>(); LG << "Resection for image " << markers[0].image << " got:\n" - << "R:\n" << R << "\nt:\n" << t; + << "R:\n" + << R << "\nt:\n" + << t; reconstruction->InsertCamera(markers[0].image, R, t); return true; } @@ -186,15 +190,14 @@ namespace { // freedom drift. struct ProjectiveResectCostFunction { public: - typedef Vec FMatrixType; + typedef Vec FMatrixType; typedef Vec12 XMatrixType; - ProjectiveResectCostFunction(const vector &markers, - const ProjectiveReconstruction &reconstruction) - : markers(markers), - reconstruction(reconstruction) {} + ProjectiveResectCostFunction(const vector& markers, + const ProjectiveReconstruction& reconstruction) + : markers(markers), reconstruction(reconstruction) {} - Vec operator()(const Vec12 &vector_P) const { + Vec operator()(const Vec12& vector_P) const { // Unpack P from vector_P. Map P(vector_P.data(), 3, 4); @@ -202,24 +205,24 @@ struct ProjectiveResectCostFunction { Vec residuals(2 * markers.size()); residuals.setZero(); for (int i = 0; i < markers.size(); ++i) { - const ProjectivePoint &point = + const ProjectivePoint& point = *reconstruction.PointForTrack(markers[i].track); Vec3 projected = P * point.X; projected /= projected(2); - residuals[2*i + 0] = projected(0) - markers[i].x; - residuals[2*i + 1] = projected(1) - markers[i].y; + residuals[2 * i + 0] = projected(0) - markers[i].x; + residuals[2 * i + 1] = projected(1) - markers[i].y; } return residuals; } - const vector &markers; - const ProjectiveReconstruction &reconstruction; + const vector& markers; + const ProjectiveReconstruction& reconstruction; }; } // namespace -bool ProjectiveResect(const vector &markers, - ProjectiveReconstruction *reconstruction) { +bool ProjectiveResect(const vector& markers, + ProjectiveReconstruction* reconstruction) { if (markers.size() < 5) { return false; } @@ -263,7 +266,8 @@ bool ProjectiveResect(const vector &markers, P = Map(vector_P.data(), 3, 4); LG << "Resection for image " << markers[0].image << " got:\n" - << "P:\n" << P; + << "P:\n" + << P; reconstruction->InsertCamera(markers[0].image, P); return true; } diff --git a/intern/libmv/libmv/simple_pipeline/resect.h b/intern/libmv/libmv/simple_pipeline/resect.h index f13d2e2d425..13c3d66bd37 100644 --- a/intern/libmv/libmv/simple_pipeline/resect.h +++ b/intern/libmv/libmv/simple_pipeline/resect.h @@ -22,8 +22,8 @@ #define LIBMV_SIMPLE_PIPELINE_RESECT_H #include "libmv/base/vector.h" -#include "libmv/simple_pipeline/tracks.h" #include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { @@ -51,8 +51,9 @@ namespace libmv { \sa EuclideanIntersect, EuclideanReconstructTwoFrames */ -bool EuclideanResect(const vector &markers, - EuclideanReconstruction *reconstruction, bool final_pass); +bool EuclideanResect(const vector& markers, + EuclideanReconstruction* reconstruction, + bool final_pass); /*! Estimate the projective pose of a camera from 2D to 3D correspondences. @@ -78,8 +79,8 @@ bool EuclideanResect(const vector &markers, \sa ProjectiveIntersect, ProjectiveReconstructTwoFrames */ -bool ProjectiveResect(const vector &markers, - ProjectiveReconstruction *reconstruction); +bool ProjectiveResect(const vector& markers, + ProjectiveReconstruction* reconstruction); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/resect_test.cc b/intern/libmv/libmv/simple_pipeline/resect_test.cc index 811edd282d8..ecf3f9b673d 100644 --- a/intern/libmv/libmv/simple_pipeline/resect_test.cc +++ b/intern/libmv/libmv/simple_pipeline/resect_test.cc @@ -153,7 +153,7 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { // not precise enough with only 4 points. // // TODO(jmichot): Reenable this test when there is nonlinear refinement. -#if 0 +# if 0 R_output.setIdentity(); T_output.setZero(); @@ -163,7 +163,7 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);*/ -#endif +# endif } // TODO(jmichot): Reduce the code duplication here with the code above. diff --git a/intern/libmv/libmv/simple_pipeline/tracks.cc b/intern/libmv/libmv/simple_pipeline/tracks.cc index d5d009708ba..66243807a4b 100644 --- a/intern/libmv/libmv/simple_pipeline/tracks.cc +++ b/intern/libmv/libmv/simple_pipeline/tracks.cc @@ -21,31 +21,31 @@ #include "libmv/simple_pipeline/tracks.h" #include -#include #include +#include #include "libmv/numeric/numeric.h" namespace libmv { -Tracks::Tracks(const Tracks &other) { +Tracks::Tracks(const Tracks& other) { markers_ = other.markers_; } -Tracks::Tracks(const vector &markers) : markers_(markers) {} +Tracks::Tracks(const vector& markers) : markers_(markers) { +} void Tracks::Insert(int image, int track, double x, double y, double weight) { // TODO(keir): Wow, this is quadratic for repeated insertions. Fix this by // adding a smarter data structure like a set<>. for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].image == image && - markers_[i].track == track) { + if (markers_[i].image == image && markers_[i].track == track) { markers_[i].x = x; markers_[i].y = y; return; } } - Marker marker = { image, track, x, y, weight }; + Marker marker = {image, track, x, y, weight}; markers_.push_back(marker); } @@ -101,15 +101,17 @@ vector Tracks::MarkersForTracksInBothImages(int image1, std::sort(image2_tracks.begin(), image2_tracks.end()); std::vector intersection; - std::set_intersection(image1_tracks.begin(), image1_tracks.end(), - image2_tracks.begin(), image2_tracks.end(), + std::set_intersection(image1_tracks.begin(), + image1_tracks.end(), + image2_tracks.begin(), + image2_tracks.end(), std::back_inserter(intersection)); vector markers; for (int i = 0; i < markers_.size(); ++i) { if ((markers_[i].image == image1 || markers_[i].image == image2) && - std::binary_search(intersection.begin(), intersection.end(), - markers_[i].track)) { + std::binary_search( + intersection.begin(), intersection.end(), markers_[i].track)) { markers.push_back(markers_[i]); } } @@ -122,7 +124,7 @@ Marker Tracks::MarkerInImageForTrack(int image, int track) const { return markers_[i]; } } - Marker null = { -1, -1, -1, -1, 0.0 }; + Marker null = {-1, -1, -1, -1, 0.0}; return null; } @@ -168,12 +170,12 @@ int Tracks::NumMarkers() const { return markers_.size(); } -void CoordinatesForMarkersInImage(const vector &markers, +void CoordinatesForMarkersInImage(const vector& markers, int image, - Mat *coordinates) { + Mat* coordinates) { vector coords; for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; + const Marker& marker = markers[i]; if (markers[i].image == image) { coords.push_back(Vec2(marker.x, marker.y)); } diff --git a/intern/libmv/libmv/simple_pipeline/tracks.h b/intern/libmv/libmv/simple_pipeline/tracks.h index 752d2790a1c..c3df3a223d8 100644 --- a/intern/libmv/libmv/simple_pipeline/tracks.h +++ b/intern/libmv/libmv/simple_pipeline/tracks.h @@ -36,7 +36,8 @@ namespace libmv { \a weight is used by bundle adjustment and weight means how much the track affects on a final solution. - \note Markers are typically aggregated with the help of the \link Tracks class. + \note Markers are typically aggregated with the help of the \link Tracks + class. \sa Tracks */ @@ -56,19 +57,20 @@ struct Marker { images, which must get created before any 3D reconstruction can take place. The container has several fast lookups for queries typically needed for - structure from motion algorithms, such as \link MarkersForTracksInBothImages(). + structure from motion algorithms, such as \link + MarkersForTracksInBothImages(). \sa Marker */ class Tracks { public: - Tracks() { } + Tracks() {} // Copy constructor for a tracks object. - Tracks(const Tracks &other); + Tracks(const Tracks& other); /// Construct a new tracks object using the given markers to start. - explicit Tracks(const vector &markers); + explicit Tracks(const vector& markers); /*! Inserts a marker into the set. If there is already a marker for the given @@ -129,9 +131,9 @@ class Tracks { vector markers_; }; -void CoordinatesForMarkersInImage(const vector &markers, +void CoordinatesForMarkersInImage(const vector& markers, int image, - Mat *coordinates); + Mat* coordinates); } // namespace libmv diff --git a/intern/libmv/libmv/threading/threading.h b/intern/libmv/libmv/threading/threading.h index f23bf6f172c..da625e02424 100644 --- a/intern/libmv/libmv/threading/threading.h +++ b/intern/libmv/libmv/threading/threading.h @@ -31,7 +31,7 @@ namespace libmv { #if COMPILER_SUPPORTS_CXX11 -using mutex = std::mutex; +using mutex = std::mutex; using scoped_lock = std::unique_lock; using condition_variable = std::condition_variable; #else diff --git a/intern/libmv/libmv/tracking/brute_region_tracker.cc b/intern/libmv/libmv/tracking/brute_region_tracker.cc index 85aecb7f633..7007fb9440b 100644 --- a/intern/libmv/libmv/tracking/brute_region_tracker.cc +++ b/intern/libmv/libmv/tracking/brute_region_tracker.cc @@ -25,31 +25,30 @@ #endif #include "libmv/base/aligned_malloc.h" -#include "libmv/image/image.h" #include "libmv/image/convolve.h" #include "libmv/image/correlation.h" +#include "libmv/image/image.h" #include "libmv/image/sample.h" #include "libmv/logging/logging.h" namespace libmv { namespace { -bool RegionIsInBounds(const FloatImage &image1, - double x, double y, +bool RegionIsInBounds(const FloatImage& image1, + double x, + double y, int half_window_size) { // Check the minimum coordinates. int min_x = floor(x) - half_window_size - 1; int min_y = floor(y) - half_window_size - 1; - if (min_x < 0.0 || - min_y < 0.0) { + if (min_x < 0.0 || min_y < 0.0) { return false; } // Check the maximum coordinates. int max_x = ceil(x) + half_window_size + 1; int max_y = ceil(y) + half_window_size + 1; - if (max_x > image1.cols() || - max_y > image1.rows()) { + if (max_x > image1.cols() || max_y > image1.rows()) { return false; } @@ -69,14 +68,15 @@ bool RegionIsInBounds(const FloatImage &image1, // and "b", since the SSE load instructionst will pull in memory past the end // of the arrays if their size is not a multiple of 16. inline static __m128i SumOfAbsoluteDifferencesContiguousSSE( - const unsigned char *a, // aligned - const unsigned char *b, // not aligned + const unsigned char* a, // aligned + const unsigned char* b, // not aligned unsigned int size, __m128i sad) { // Do the bulk of the work as 16-way integer operations. for (unsigned int j = 0; j < size / 16; j++) { - sad = _mm_add_epi32(sad, _mm_sad_epu8( _mm_load_si128 ((__m128i*)(a + 16 * j)), - _mm_loadu_si128((__m128i*)(b + 16 * j)))); + sad = _mm_add_epi32(sad, + _mm_sad_epu8(_mm_load_si128((__m128i*)(a + 16 * j)), + _mm_loadu_si128((__m128i*)(b + 16 * j)))); } // Handle the trailing end. // TODO(keir): Benchmark to verify that the below SSE is a win compared to a @@ -90,32 +90,63 @@ inline static __m128i SumOfAbsoluteDifferencesContiguousSSE( unsigned int remainder = size % 16u; if (remainder) { unsigned int j = size / 16; - __m128i a_trail = _mm_load_si128 ((__m128i*)(a + 16 * j)); + __m128i a_trail = _mm_load_si128((__m128i*)(a + 16 * j)); __m128i b_trail = _mm_loadu_si128((__m128i*)(b + 16 * j)); __m128i mask; switch (remainder) { -#define X 0xff - case 1: mask = _mm_setr_epi8(X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 2: mask = _mm_setr_epi8(X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 3: mask = _mm_setr_epi8(X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 4: mask = _mm_setr_epi8(X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 5: mask = _mm_setr_epi8(X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 6: mask = _mm_setr_epi8(X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 7: mask = _mm_setr_epi8(X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 8: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 9: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0); break; - case 10: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0); break; - case 11: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0); break; - case 12: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0); break; - case 13: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0); break; - case 14: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0); break; - case 15: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0); break; +# define X 0xff + case 1: + mask = _mm_setr_epi8(X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 2: + mask = _mm_setr_epi8(X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 3: + mask = _mm_setr_epi8(X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 4: + mask = _mm_setr_epi8(X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 5: + mask = _mm_setr_epi8(X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 6: + mask = _mm_setr_epi8(X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 7: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 8: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 9: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0); + break; + case 10: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0); + break; + case 11: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0); + break; + case 12: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0); + break; + case 13: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0); + break; + case 14: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0); + break; + case 15: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0); + break; // To silence compiler warning. default: mask = _mm_setzero_si128(); break; -#undef X +# undef X } - sad = _mm_add_epi32(sad, _mm_sad_epu8(_mm_and_si128(mask, a_trail), - _mm_and_si128(mask, b_trail))); + sad = _mm_add_epi32(sad, + _mm_sad_epu8(_mm_and_si128(mask, a_trail), + _mm_and_si128(mask, b_trail))); } return sad; } @@ -124,13 +155,12 @@ inline static __m128i SumOfAbsoluteDifferencesContiguousSSE( // Computes the sum of absolute differences between pattern and image. Pattern // must be 16-byte aligned, and the stride must be a multiple of 16. The image // does pointer does not have to be aligned. -int SumOfAbsoluteDifferencesContiguousImage( - const unsigned char *pattern, - unsigned int pattern_width, - unsigned int pattern_height, - unsigned int pattern_stride, - const unsigned char *image, - unsigned int image_stride) { +int SumOfAbsoluteDifferencesContiguousImage(const unsigned char* pattern, + unsigned int pattern_width, + unsigned int pattern_height, + unsigned int pattern_stride, + const unsigned char* image, + unsigned int image_stride) { #ifdef __SSE2__ // TODO(keir): Add interleaved accumulation, where accumulation is done into // two or more SSE registers that then get combined at the end. This reduces @@ -145,8 +175,7 @@ int SumOfAbsoluteDifferencesContiguousImage( sad); } return _mm_cvtsi128_si32( - _mm_add_epi32(sad, - _mm_shuffle_epi32(sad, _MM_SHUFFLE(3, 0, 1, 2)))); + _mm_add_epi32(sad, _mm_shuffle_epi32(sad, _MM_SHUFFLE(3, 0, 1, 2)))); #else int sad = 0; for (int r = 0; r < pattern_height; ++r) { @@ -161,12 +190,13 @@ int SumOfAbsoluteDifferencesContiguousImage( // Sample a region of size width, height centered at x,y in image, converting // from float to byte in the process. Samples from the first channel. Puts // result into *pattern. -void SampleRectangularPattern(const FloatImage &image, - double x, double y, +void SampleRectangularPattern(const FloatImage& image, + double x, + double y, int width, int height, int pattern_stride, - unsigned char *pattern) { + unsigned char* pattern) { // There are two cases for width and height: even or odd. If it's odd, then // the bounds [-width / 2, width / 2] works as expected. However, for even, // this results in one extra access past the end. So use < instead of <= in @@ -175,7 +205,7 @@ void SampleRectangularPattern(const FloatImage &image, int end_height = (height / 2) + (height % 2); for (int r = -height / 2; r < end_height; ++r) { for (int c = -width / 2; c < end_width; ++c) { - pattern[pattern_stride * (r + height / 2) + c + width / 2] = + pattern[pattern_stride * (r + height / 2) + c + width / 2] = SampleLinear(image, y + r, x + c, 0) * 255.0; } } @@ -195,30 +225,30 @@ inline int PadToAlignment(int x, int alignment) { // is returned in *pattern_stride. // // NOTE: Caller must free *pattern with aligned_malloc() from above. -void SampleSquarePattern(const FloatImage &image, - double x, double y, +void SampleSquarePattern(const FloatImage& image, + double x, + double y, int half_width, - unsigned char **pattern, - int *pattern_stride) { + unsigned char** pattern, + int* pattern_stride) { int width = 2 * half_width + 1; // Allocate an aligned block with padding on the end so each row of the // pattern starts on a 16-byte boundary. *pattern_stride = PadToAlignment(width, 16); int pattern_size_bytes = *pattern_stride * width; - *pattern = static_cast( - aligned_malloc(pattern_size_bytes, 16)); - SampleRectangularPattern(image, x, y, width, width, - *pattern_stride, - *pattern); + *pattern = + static_cast(aligned_malloc(pattern_size_bytes, 16)); + SampleRectangularPattern( + image, x, y, width, width, *pattern_stride, *pattern); } // NOTE: Caller must free *image with aligned_malloc() from above. -void FloatArrayToByteArrayWithPadding(const FloatImage &float_image, - unsigned char **image, - int *image_stride) { +void FloatArrayToByteArrayWithPadding(const FloatImage& float_image, + unsigned char** image, + int* image_stride) { // Allocate enough so that accessing 16 elements past the end is fine. *image_stride = float_image.Width() + 16; - *image = static_cast( + *image = static_cast( aligned_malloc(*image_stride * float_image.Height(), 16)); for (int i = 0; i < float_image.Height(); ++i) { for (int j = 0; j < float_image.Width(); ++j) { @@ -235,10 +265,12 @@ void FloatArrayToByteArrayWithPadding(const FloatImage &float_image, // values for every hypothesis looks like. // // TODO(keir): Priority queue for multiple hypothesis. -bool BruteRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool BruteRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { if (!RegionIsInBounds(image1, x1, y1, half_window_size)) { LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1 << ", hw=" << half_window_size << "."; @@ -252,28 +284,28 @@ bool BruteRegionTracker::Track(const FloatImage &image1, BlurredImageAndDerivativesChannels(image2, 0.9, &image_and_gradient2); // Sample the pattern to get it aligned to an image grid. - unsigned char *pattern; + unsigned char* pattern; int pattern_stride; - SampleSquarePattern(image_and_gradient1, x1, y1, half_window_size, - &pattern, - &pattern_stride); + SampleSquarePattern( + image_and_gradient1, x1, y1, half_window_size, &pattern, &pattern_stride); // Convert the search area directly to bytes without sampling. - unsigned char *search_area; + unsigned char* search_area; int search_area_stride; - FloatArrayToByteArrayWithPadding(image_and_gradient2, &search_area, - &search_area_stride); + FloatArrayToByteArrayWithPadding( + image_and_gradient2, &search_area, &search_area_stride); // Try all possible locations inside the search area. Yes, everywhere. int best_i = -1, best_j = -1, best_sad = INT_MAX; for (int i = 0; i < image2.Height() - pattern_width; ++i) { for (int j = 0; j < image2.Width() - pattern_width; ++j) { - int sad = SumOfAbsoluteDifferencesContiguousImage(pattern, - pattern_width, - pattern_width, - pattern_stride, - search_area + search_area_stride * i + j, - search_area_stride); + int sad = SumOfAbsoluteDifferencesContiguousImage( + pattern, + pattern_width, + pattern_width, + pattern_stride, + search_area + search_area_stride * i + j, + search_area_stride); if (sad < best_sad) { best_i = i; best_j = j; @@ -309,16 +341,23 @@ bool BruteRegionTracker::Track(const FloatImage &image1, } Array3Df image_and_gradient1_sampled, image_and_gradient2_sampled; - SamplePattern(image_and_gradient1, x1, y1, half_window_size, 3, + SamplePattern(image_and_gradient1, + x1, + y1, + half_window_size, + 3, &image_and_gradient1_sampled); - SamplePattern(image_and_gradient2, *x2, *y2, half_window_size, 3, + SamplePattern(image_and_gradient2, + *x2, + *y2, + half_window_size, + 3, &image_and_gradient2_sampled); // Compute the Pearson product-moment correlation coefficient to check // for sanity. double correlation = PearsonProductMomentCorrelation( - image_and_gradient1_sampled, - image_and_gradient2_sampled); + image_and_gradient1_sampled, image_and_gradient2_sampled); LG << "Final correlation: " << correlation; diff --git a/intern/libmv/libmv/tracking/brute_region_tracker.h b/intern/libmv/libmv/tracking/brute_region_tracker.h index a699c42ee92..183dc6df07b 100644 --- a/intern/libmv/libmv/tracking/brute_region_tracker.h +++ b/intern/libmv/libmv/tracking/brute_region_tracker.h @@ -27,17 +27,17 @@ namespace libmv { struct BruteRegionTracker : public RegionTracker { - BruteRegionTracker() - : half_window_size(4), - minimum_correlation(0.78) {} + BruteRegionTracker() : half_window_size(4), minimum_correlation(0.78) {} virtual ~BruteRegionTracker() {} // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; // No point in creating getters or setters. int half_window_size; diff --git a/intern/libmv/libmv/tracking/hybrid_region_tracker.cc b/intern/libmv/libmv/tracking/hybrid_region_tracker.cc index ea3b0f5bfc0..f0392643a6c 100644 --- a/intern/libmv/libmv/tracking/hybrid_region_tracker.cc +++ b/intern/libmv/libmv/tracking/hybrid_region_tracker.cc @@ -20,17 +20,19 @@ #include "libmv/tracking/hybrid_region_tracker.h" -#include "libmv/image/image.h" #include "libmv/image/convolve.h" +#include "libmv/image/image.h" #include "libmv/image/sample.h" #include "libmv/logging/logging.h" namespace libmv { -bool HybridRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool HybridRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { double x2_coarse = *x2; double y2_coarse = *y2; if (!coarse_tracker_->Track(image1, image2, x1, y1, &x2_coarse, &y2_coarse)) { diff --git a/intern/libmv/libmv/tracking/hybrid_region_tracker.h b/intern/libmv/libmv/tracking/hybrid_region_tracker.h index 967d2afd1e5..2730d2dbbf2 100644 --- a/intern/libmv/libmv/tracking/hybrid_region_tracker.h +++ b/intern/libmv/libmv/tracking/hybrid_region_tracker.h @@ -21,8 +21,8 @@ #ifndef LIBMV_REGION_TRACKING_HYBRID_REGION_TRACKER_H_ #define LIBMV_REGION_TRACKING_HYBRID_REGION_TRACKER_H_ -#include "libmv/image/image.h" #include "libmv/base/scoped_ptr.h" +#include "libmv/image/image.h" #include "libmv/tracking/region_tracker.h" namespace libmv { @@ -30,18 +30,19 @@ namespace libmv { // TODO(keir): Documentation! class HybridRegionTracker : public RegionTracker { public: - HybridRegionTracker(RegionTracker *coarse_tracker, - RegionTracker *fine_tracker) - : coarse_tracker_(coarse_tracker), - fine_tracker_(fine_tracker) {} + HybridRegionTracker(RegionTracker* coarse_tracker, + RegionTracker* fine_tracker) + : coarse_tracker_(coarse_tracker), fine_tracker_(fine_tracker) {} virtual ~HybridRegionTracker() {} // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; scoped_ptr coarse_tracker_; scoped_ptr fine_tracker_; diff --git a/intern/libmv/libmv/tracking/kalman_filter.h b/intern/libmv/libmv/tracking/kalman_filter.h index 9841f0e912c..b1312d0e027 100644 --- a/intern/libmv/libmv/tracking/kalman_filter.h +++ b/intern/libmv/libmv/tracking/kalman_filter.h @@ -19,13 +19,14 @@ // IN THE SOFTWARE. #ifndef LIBMV_TRACKING_KALMAN_FILTER_H_ +#define LIBMV_TRACKING_KALMAN_FILTER_H_ #include "libmv/numeric/numeric.h" namespace mv { // A Kalman filter with order N and observation size K. -template +template class KalmanFilter { public: struct State { @@ -38,54 +39,47 @@ class KalmanFilter { const T* observation_data, const T* process_covariance_data, const T* default_measurement_covariance_data) - : state_transition_matrix_( - Eigen::Matrix(state_transition_data)), - observation_matrix_( - Eigen::Matrix(observation_data)), - process_covariance_( - Eigen::Matrix(process_covariance_data)), - default_measurement_covariance_( - Eigen::Matrix( - default_measurement_covariance_data)) { - } + : state_transition_matrix_( + Eigen::Matrix(state_transition_data)), + observation_matrix_( + Eigen::Matrix(observation_data)), + process_covariance_( + Eigen::Matrix(process_covariance_data)), + default_measurement_covariance_(Eigen::Matrix( + default_measurement_covariance_data)) {} - KalmanFilter( - const Eigen::Matrix &state_transition_matrix, - const Eigen::Matrix &observation_matrix, - const Eigen::Matrix &process_covariance, - const Eigen::Matrix &default_measurement_covariance) - : state_transition_matrix_(state_transition_matrix), - observation_matrix_(observation_matrix), - process_covariance_(process_covariance), - default_measurement_covariance_(default_measurement_covariance) { - } + KalmanFilter(const Eigen::Matrix& state_transition_matrix, + const Eigen::Matrix& observation_matrix, + const Eigen::Matrix& process_covariance, + const Eigen::Matrix& default_measurement_covariance) + : state_transition_matrix_(state_transition_matrix), + observation_matrix_(observation_matrix), + process_covariance_(process_covariance), + default_measurement_covariance_(default_measurement_covariance) {} // Advances the system according to the current state estimate. - void Step(State *state) const { + void Step(State* state) const { state->mean = state_transition_matrix_ * state->mean; - state->covariance = state_transition_matrix_ * - state->covariance * - state_transition_matrix_.transpose() + + state->covariance = state_transition_matrix_ * state->covariance * + state_transition_matrix_.transpose() + process_covariance_; } // Updates a state with a new measurement. - void Update(const Eigen::Matrix &measurement_mean, - const Eigen::Matrix &measurement_covariance, - State *state) const { + void Update(const Eigen::Matrix& measurement_mean, + const Eigen::Matrix& measurement_covariance, + State* state) const { // Calculate the innovation, which is a distribution over prediction error. - Eigen::Matrix innovation_mean = measurement_mean - - observation_matrix_ * - state->mean; + Eigen::Matrix innovation_mean = + measurement_mean - observation_matrix_ * state->mean; Eigen::Matrix innovation_covariance = - observation_matrix_ * - state->covariance * - observation_matrix_.transpose() + + observation_matrix_ * state->covariance * + observation_matrix_.transpose() + measurement_covariance; // Calculate the Kalman gain. Eigen::Matrix kalman_gain = state->covariance * - observation_matrix_.transpose() * + observation_matrix_.transpose() * innovation_covariance.inverse(); // Update the state mean and covariance. @@ -95,8 +89,8 @@ class KalmanFilter { state->covariance; } - void Update(State *state, - const Eigen::Matrix &measurement_mean) const { + void Update(State* state, + const Eigen::Matrix& measurement_mean) const { Update(state, measurement_mean, default_measurement_covariance_); } diff --git a/intern/libmv/libmv/tracking/klt_region_tracker.cc b/intern/libmv/libmv/tracking/klt_region_tracker.cc index dbbf9f0b996..df1ded65489 100644 --- a/intern/libmv/libmv/tracking/klt_region_tracker.cc +++ b/intern/libmv/libmv/tracking/klt_region_tracker.cc @@ -20,10 +20,10 @@ #include "libmv/tracking/klt_region_tracker.h" -#include "libmv/logging/logging.h" -#include "libmv/image/image.h" #include "libmv/image/convolve.h" +#include "libmv/image/image.h" #include "libmv/image/sample.h" +#include "libmv/logging/logging.h" namespace libmv { @@ -33,16 +33,18 @@ namespace libmv { // TODO(keir): The calls to SampleLinear() do boundary checking that should // instead happen outside the loop. Since this is the innermost loop, the extra // bounds checking hurts performance. -static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, - const Array3Df &image_and_gradient2, - double x1, double y1, - double x2, double y2, +static void ComputeTrackingEquation(const Array3Df& image_and_gradient1, + const Array3Df& image_and_gradient2, + double x1, + double y1, + double x2, + double y2, int half_width, - float *gxx, - float *gxy, - float *gyy, - float *ex, - float *ey) { + float* gxx, + float* gxy, + float* gyy, + float* ex, + float* ey) { *gxx = *gxy = *gyy = 0; *ex = *ey = 0; for (int r = -half_width; r <= half_width; ++r) { @@ -51,8 +53,8 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, float yy1 = y1 + r; float xx2 = x2 + c; float yy2 = y2 + r; - float I = SampleLinear(image_and_gradient1, yy1, xx1, 0); - float J = SampleLinear(image_and_gradient2, yy2, xx2, 0); + float I = SampleLinear(image_and_gradient1, yy1, xx1, 0); + float J = SampleLinear(image_and_gradient2, yy2, xx2, 0); float gx = SampleLinear(image_and_gradient2, yy2, xx2, 1); float gy = SampleLinear(image_and_gradient2, yy2, xx2, 2); *gxx += gx * gx; @@ -64,22 +66,21 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, } } -static bool RegionIsInBounds(const FloatImage &image1, - double x, double y, - int half_window_size) { +static bool RegionIsInBounds(const FloatImage& image1, + double x, + double y, + int half_window_size) { // Check the minimum coordinates. int min_x = floor(x) - half_window_size - 1; int min_y = floor(y) - half_window_size - 1; - if (min_x < 0.0 || - min_y < 0.0) { + if (min_x < 0.0 || min_y < 0.0) { return false; } // Check the maximum coordinates. int max_x = ceil(x) + half_window_size + 1; int max_y = ceil(y) + half_window_size + 1; - if (max_x > image1.cols() || - max_y > image1.rows()) { + if (max_x > image1.cols() || max_y > image1.rows()) { return false; } @@ -87,10 +88,12 @@ static bool RegionIsInBounds(const FloatImage &image1, return true; } -bool KltRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool KltRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { if (!RegionIsInBounds(image1, x1, y1, half_window_size)) { LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1 << ", hw=" << half_window_size << "."; @@ -116,10 +119,16 @@ bool KltRegionTracker::Track(const FloatImage &image1, float gxx, gxy, gyy, ex, ey; ComputeTrackingEquation(image_and_gradient1, image_and_gradient2, - x1, y1, - *x2, *y2, + x1, + y1, + *x2, + *y2, half_window_size, - &gxx, &gxy, &gyy, &ex, &ey); + &gxx, + &gxy, + &gyy, + &ex, + &ey); // Solve the tracking equation // diff --git a/intern/libmv/libmv/tracking/klt_region_tracker.h b/intern/libmv/libmv/tracking/klt_region_tracker.h index 43977757084..07ed1b7155c 100644 --- a/intern/libmv/libmv/tracking/klt_region_tracker.h +++ b/intern/libmv/libmv/tracking/klt_region_tracker.h @@ -37,10 +37,12 @@ struct KltRegionTracker : public RegionTracker { virtual ~KltRegionTracker() {} // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; // No point in creating getters or setters. int half_window_size; diff --git a/intern/libmv/libmv/tracking/pyramid_region_tracker.cc b/intern/libmv/libmv/tracking/pyramid_region_tracker.cc index 4db501050f3..52764a535e0 100644 --- a/intern/libmv/libmv/tracking/pyramid_region_tracker.cc +++ b/intern/libmv/libmv/tracking/pyramid_region_tracker.cc @@ -29,8 +29,9 @@ namespace libmv { -static void MakePyramid(const FloatImage &image, int num_levels, - std::vector *pyramid) { +static void MakePyramid(const FloatImage& image, + int num_levels, + std::vector* pyramid) { pyramid->resize(num_levels); (*pyramid)[0] = image; for (int i = 1; i < num_levels; ++i) { @@ -38,10 +39,12 @@ static void MakePyramid(const FloatImage &image, int num_levels, } } -bool PyramidRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool PyramidRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { // Shrink the guessed x and y location to match the coarsest level + 1 (which // when gets corrected in the loop). *x2 /= pow(2., num_levels_); @@ -71,8 +74,8 @@ bool PyramidRegionTracker::Track(const FloatImage &image1, // Track the point on this level with the base tracker. LG << "Tracking on level " << i; - bool succeeded = tracker_->Track(pyramid1[i], pyramid2[i], xx, yy, - &x2_new, &y2_new); + bool succeeded = + tracker_->Track(pyramid1[i], pyramid2[i], xx, yy, &x2_new, &y2_new); if (!succeeded) { if (i == 0) { diff --git a/intern/libmv/libmv/tracking/pyramid_region_tracker.h b/intern/libmv/libmv/tracking/pyramid_region_tracker.h index 1f9675469f4..5fe21c95904 100644 --- a/intern/libmv/libmv/tracking/pyramid_region_tracker.h +++ b/intern/libmv/libmv/tracking/pyramid_region_tracker.h @@ -21,21 +21,24 @@ #ifndef LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_ #define LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_ -#include "libmv/image/image.h" #include "libmv/base/scoped_ptr.h" +#include "libmv/image/image.h" #include "libmv/tracking/region_tracker.h" namespace libmv { class PyramidRegionTracker : public RegionTracker { public: - PyramidRegionTracker(RegionTracker *tracker, int num_levels) + PyramidRegionTracker(RegionTracker* tracker, int num_levels) : tracker_(tracker), num_levels_(num_levels) {} - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; + private: scoped_ptr tracker_; int num_levels_; diff --git a/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc b/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc index d90a1012237..2fcf292e404 100644 --- a/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc +++ b/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc @@ -19,8 +19,8 @@ // IN THE SOFTWARE. #include "libmv/tracking/pyramid_region_tracker.h" -#include "libmv/tracking/klt_region_tracker.h" #include "libmv/image/image.h" +#include "libmv/tracking/klt_region_tracker.h" #include "testing/testing.h" namespace libmv { @@ -55,8 +55,7 @@ TEST(PyramidKltRegionTracker, Track) { KltRegionTracker tracker; tracker.half_window_size = half_window_size; - EXPECT_FALSE(tracker.Track(image1, image2, x1, y1, - &x2_actual, &y2_actual)); + EXPECT_FALSE(tracker.Track(image1, image2, x1, y1, &x2_actual, &y2_actual)); } // Verify that it works with the pyramid tracker. @@ -64,12 +63,11 @@ TEST(PyramidKltRegionTracker, Track) { double x2_actual = x1; double y2_actual = y1; - KltRegionTracker *klt_tracker = new KltRegionTracker; + KltRegionTracker* klt_tracker = new KltRegionTracker; klt_tracker->half_window_size = half_window_size; PyramidRegionTracker tracker(klt_tracker, 3); - EXPECT_TRUE(tracker.Track(image1, image2, x1, y1, - &x2_actual, &y2_actual)); + EXPECT_TRUE(tracker.Track(image1, image2, x1, y1, &x2_actual, &y2_actual)); EXPECT_NEAR(x2_actual, x2, 0.001); EXPECT_NEAR(y2_actual, y2, 0.001); diff --git a/intern/libmv/libmv/tracking/region_tracker.h b/intern/libmv/libmv/tracking/region_tracker.h index 4f7574df1a3..e753ac8be6c 100644 --- a/intern/libmv/libmv/tracking/region_tracker.h +++ b/intern/libmv/libmv/tracking/region_tracker.h @@ -37,10 +37,12 @@ class RegionTracker { image2. If no guess is available, (\a x1, \a y1) is a good start. Returns true on success, false otherwise */ - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const = 0; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const = 0; }; } // namespace libmv diff --git a/intern/libmv/libmv/tracking/retrack_region_tracker.cc b/intern/libmv/libmv/tracking/retrack_region_tracker.cc index 4d230086d28..9152078053c 100644 --- a/intern/libmv/libmv/tracking/retrack_region_tracker.cc +++ b/intern/libmv/libmv/tracking/retrack_region_tracker.cc @@ -25,10 +25,12 @@ namespace libmv { -bool RetrackRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool RetrackRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { // Track forward, getting x2 and y2. if (!tracker_->Track(image1, image2, x1, y1, x2, y2)) { return false; diff --git a/intern/libmv/libmv/tracking/retrack_region_tracker.h b/intern/libmv/libmv/tracking/retrack_region_tracker.h index ab05f320834..504cf697349 100644 --- a/intern/libmv/libmv/tracking/retrack_region_tracker.h +++ b/intern/libmv/libmv/tracking/retrack_region_tracker.h @@ -21,8 +21,8 @@ #ifndef LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_ #define LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_ -#include "libmv/image/image.h" #include "libmv/base/scoped_ptr.h" +#include "libmv/image/image.h" #include "libmv/tracking/region_tracker.h" namespace libmv { @@ -31,13 +31,16 @@ namespace libmv { // track that doesn't track backwards to the starting point. class RetrackRegionTracker : public RegionTracker { public: - RetrackRegionTracker(RegionTracker *tracker, double tolerance) + RetrackRegionTracker(RegionTracker* tracker, double tolerance) : tracker_(tracker), tolerance_(tolerance) {} - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; + private: scoped_ptr tracker_; double tolerance_; diff --git a/intern/libmv/libmv/tracking/track_region.cc b/intern/libmv/libmv/tracking/track_region.cc index 895c9a1e23d..403b4088174 100644 --- a/intern/libmv/libmv/tracking/track_region.cc +++ b/intern/libmv/libmv/tracking/track_region.cc @@ -27,14 +27,14 @@ #include "libmv/tracking/track_region.h" -#include #include +#include #include #include "ceres/ceres.h" -#include "libmv/logging/logging.h" +#include "libmv/image/convolve.h" #include "libmv/image/image.h" #include "libmv/image/sample.h" -#include "libmv/image/convolve.h" +#include "libmv/logging/logging.h" #include "libmv/multiview/homography.h" #include "libmv/numeric/numeric.h" @@ -44,57 +44,45 @@ namespace ceres { // A jet traits class to make it easier to work with mixed auto / numeric diff. -template +template struct JetOps { - static bool IsScalar() { - return true; - } - static T GetScalar(const T& t) { - return t; - } - static void SetScalar(const T& scalar, T* t) { - *t = scalar; - } - static void ScaleDerivative(double scale_by, T *value) { + static bool IsScalar() { return true; } + static T GetScalar(const T& t) { return t; } + static void SetScalar(const T& scalar, T* t) { *t = scalar; } + static void ScaleDerivative(double scale_by, T* value) { // For double, there is no derivative to scale. - (void) scale_by; // Ignored. - (void) value; // Ignored. + (void)scale_by; // Ignored. + (void)value; // Ignored. } }; -template -struct JetOps > { - static bool IsScalar() { - return false; - } - static T GetScalar(const Jet& t) { - return t.a; - } - static void SetScalar(const T& scalar, Jet* t) { - t->a = scalar; - } - static void ScaleDerivative(double scale_by, Jet *value) { +template +struct JetOps> { + static bool IsScalar() { return false; } + static T GetScalar(const Jet& t) { return t.a; } + static void SetScalar(const T& scalar, Jet* t) { t->a = scalar; } + static void ScaleDerivative(double scale_by, Jet* value) { value->v *= scale_by; } }; -template +template struct Chain { - static ArgumentType Rule(const FunctionType &f, + static ArgumentType Rule(const FunctionType& f, const FunctionType dfdx[kNumArgs], const ArgumentType x[kNumArgs]) { // In the default case of scalars, there's nothing to do since there are no // derivatives to propagate. - (void) dfdx; // Ignored. - (void) x; // Ignored. + (void)dfdx; // Ignored. + (void)x; // Ignored. return f; } }; // XXX Add documentation here! -template -struct Chain > { - static Jet Rule(const FunctionType &f, +template +struct Chain> { + static Jet Rule(const FunctionType& f, const FunctionType dfdx[kNumArgs], const Jet x[kNumArgs]) { // x is itself a function of another variable ("z"); what this function @@ -107,8 +95,8 @@ struct Chain > { } // Map the input gradient dfdx into an Eigen row vector. - Eigen::Map > - vector_dfdx(dfdx, 1, kNumArgs); + Eigen::Map> vector_dfdx( + dfdx, 1, kNumArgs); // Now apply the chain rule to obtain df/dz. Combine the derivative with // the scalar part to obtain f with full derivative information. @@ -123,9 +111,9 @@ struct Chain > { namespace libmv { +using ceres::Chain; using ceres::Jet; using ceres::JetOps; -using ceres::Chain; TrackRegionOptions::TrackRegionOptions() : mode(TRANSLATION), @@ -144,17 +132,12 @@ TrackRegionOptions::TrackRegionOptions() namespace { // TODO(keir): Consider adding padding. -template -bool InBounds(const FloatImage &image, - const T &x, - const T &y) { - return 0.0 <= x && x < image.Width() && - 0.0 <= y && y < image.Height(); +template +bool InBounds(const FloatImage& image, const T& x, const T& y) { + return 0.0 <= x && x < image.Width() && 0.0 <= y && y < image.Height(); } -bool AllInBounds(const FloatImage &image, - const double *x, - const double *y) { +bool AllInBounds(const FloatImage& image, const double* x, const double* y) { for (int i = 0; i < 4; ++i) { if (!InBounds(image, x[i], y[i])) { return false; @@ -166,10 +149,10 @@ bool AllInBounds(const FloatImage &image, // Sample the image at position (x, y) but use the gradient, if present, to // propagate derivatives from x and y. This is needed to integrate the numeric // image gradients with Ceres's autodiff framework. -template -static T SampleWithDerivative(const FloatImage &image_and_gradient, - const T &x, - const T &y) { +template +static T SampleWithDerivative(const FloatImage& image_and_gradient, + const T& x, + const T& y) { float scalar_x = JetOps::GetScalar(x); float scalar_y = JetOps::GetScalar(y); @@ -184,18 +167,23 @@ static T SampleWithDerivative(const FloatImage &image_and_gradient, // For the derivative case, sample the gradient as well. SampleLinear(image_and_gradient, scalar_y, scalar_x, sample); } - T xy[2] = { x, y }; + T xy[2] = {x, y}; return Chain::Rule(sample[0], sample + 1, xy); } -template +template class TerminationCheckingCallback : public ceres::IterationCallback { public: - TerminationCheckingCallback(const TrackRegionOptions &options, + TerminationCheckingCallback(const TrackRegionOptions& options, const FloatImage& image2, - const Warp &warp, - const double *x1, const double *y1) - : options_(options), image2_(image2), warp_(warp), x1_(x1), y1_(y1), + const Warp& warp, + const double* x1, + const double* y1) + : options_(options), + image2_(image2), + warp_(warp), + x1_(x1), + y1_(y1), have_last_successful_step_(false) {} virtual ceres::CallbackReturnType operator()( @@ -229,7 +217,7 @@ class TerminationCheckingCallback : public ceres::IterationCallback { for (int i = 0; i < 4; ++i) { double dx = x2[i] - x2_last_successful_[i]; double dy = y2[i] - y2_last_successful_[i]; - double change_pixels = dx*dx + dy*dy; + double change_pixels = dx * dx + dy * dy; if (change_pixels > max_change_pixels) { max_change_pixels = change_pixels; } @@ -255,27 +243,27 @@ class TerminationCheckingCallback : public ceres::IterationCallback { } private: - const TrackRegionOptions &options_; - const FloatImage &image2_; - const Warp &warp_; - const double *x1_; - const double *y1_; + const TrackRegionOptions& options_; + const FloatImage& image2_; + const Warp& warp_; + const double* x1_; + const double* y1_; bool have_last_successful_step_; double x2_last_successful_[4]; double y2_last_successful_[4]; }; -template +template class PixelDifferenceCostFunctor { public: - PixelDifferenceCostFunctor(const TrackRegionOptions &options, - const FloatImage &image_and_gradient1, - const FloatImage &image_and_gradient2, - const Mat3 &canonical_to_image1, + PixelDifferenceCostFunctor(const TrackRegionOptions& options, + const FloatImage& image_and_gradient1, + const FloatImage& image_and_gradient2, + const Mat3& canonical_to_image1, int num_samples_x, int num_samples_y, - const Warp &warp) + const Warp& warp) : options_(options), image_and_gradient1_(image_and_gradient1), image_and_gradient2_(image_and_gradient2), @@ -322,8 +310,8 @@ class PixelDifferenceCostFunctor { src_mean_ /= num_samples; } - template - bool operator()(const T *warp_parameters, T *residuals) const { + template + bool operator()(const T* warp_parameters, T* residuals) const { if (options_.image1_mask != NULL) { VLOG(2) << "Using a mask."; } @@ -333,8 +321,7 @@ class PixelDifferenceCostFunctor { T dst_mean = T(1.0); if (options_.use_normalized_intensities) { - ComputeNormalizingCoefficient(warp_parameters, - &dst_mean); + ComputeNormalizingCoefficient(warp_parameters, &dst_mean); } int cursor = 0; @@ -374,9 +361,8 @@ class PixelDifferenceCostFunctor { &image2_position[1]); // Sample the destination, propagating derivatives. - T dst_sample = SampleWithDerivative(image_and_gradient2_, - image2_position[0], - image2_position[1]); + T dst_sample = SampleWithDerivative( + image_and_gradient2_, image2_position[0], image2_position[1]); // Sample the source. This is made complicated by ESM mode. T src_sample; @@ -386,8 +372,8 @@ class PixelDifferenceCostFunctor { // better convergence. Copy the derivative of the warp parameters // onto the jets for the image1 position. This is the ESM hack. T image1_position_jet[2] = { - image2_position[0], // Order is x, y. This matches the - image2_position[1] // derivative order in the patch. + image2_position[0], // Order is x, y. This matches the + image2_position[1] // derivative order in the patch. }; JetOps::SetScalar(image1_position[0], image1_position_jet + 0); JetOps::SetScalar(image1_position[1], image1_position_jet + 1); @@ -433,9 +419,9 @@ class PixelDifferenceCostFunctor { } // For normalized matching, the average and - template - void ComputeNormalizingCoefficient(const T *warp_parameters, - T *dst_mean) const { + template + void ComputeNormalizingCoefficient(const T* warp_parameters, + T* dst_mean) const { *dst_mean = T(0.0); double num_samples = 0.0; for (int r = 0; r < num_samples_y_; ++r) { @@ -462,14 +448,12 @@ class PixelDifferenceCostFunctor { &image2_position[0], &image2_position[1]); - // Sample the destination, propagating derivatives. // TODO(keir): This accumulation can, surprisingly, be done as a // pre-pass by using integral images. This is complicated by the need // to store the jets in the integral image, but it is possible. - T dst_sample = SampleWithDerivative(image_and_gradient2_, - image2_position[0], - image2_position[1]); + T dst_sample = SampleWithDerivative( + image_and_gradient2_, image2_position[0], image2_position[1]); // Weight the sample by the mask, if one is present. if (options_.image1_mask != NULL) { @@ -486,10 +470,10 @@ class PixelDifferenceCostFunctor { // TODO(keir): Consider also computing the cost here. double PearsonProductMomentCorrelationCoefficient( - const double *warp_parameters) const { + const double* warp_parameters) const { for (int i = 0; i < Warp::NUM_PARAMETERS; ++i) { - VLOG(2) << "Correlation warp_parameters[" << i << "]: " - << warp_parameters[i]; + VLOG(2) << "Correlation warp_parameters[" << i + << "]: " << warp_parameters[i]; } // The single-pass PMCC computation is somewhat numerically unstable, but @@ -537,9 +521,9 @@ class PixelDifferenceCostFunctor { } sX += x; sY += y; - sXX += x*x; - sYY += y*y; - sXY += x*y; + sXX += x * x; + sYY += y * y; + sXY += x * y; } } // Normalize. @@ -549,25 +533,24 @@ class PixelDifferenceCostFunctor { sYY /= num_samples; sXY /= num_samples; - double var_x = sXX - sX*sX; - double var_y = sYY - sY*sY; - double covariance_xy = sXY - sX*sY; + double var_x = sXX - sX * sX; + double var_y = sYY - sY * sY; + double covariance_xy = sXY - sX * sY; double correlation = covariance_xy / sqrt(var_x * var_y); - LG << "Covariance xy: " << covariance_xy - << ", var 1: " << var_x << ", var 2: " << var_y - << ", correlation: " << correlation; + LG << "Covariance xy: " << covariance_xy << ", var 1: " << var_x + << ", var 2: " << var_y << ", correlation: " << correlation; return correlation; } private: - const TrackRegionOptions &options_; - const FloatImage &image_and_gradient1_; - const FloatImage &image_and_gradient2_; - const Mat3 &canonical_to_image1_; + const TrackRegionOptions& options_; + const FloatImage& image_and_gradient1_; + const FloatImage& image_and_gradient2_; + const Mat3& canonical_to_image1_; int num_samples_x_; int num_samples_y_; - const Warp &warp_; + const Warp& warp_; double src_mean_; FloatImage pattern_and_gradient_; @@ -579,15 +562,15 @@ class PixelDifferenceCostFunctor { FloatImage pattern_mask_; }; -template +template class WarpRegularizingCostFunctor { public: - WarpRegularizingCostFunctor(const TrackRegionOptions &options, - const double *x1, - const double *y1, - const double *x2_original, - const double *y2_original, - const Warp &warp) + WarpRegularizingCostFunctor(const TrackRegionOptions& options, + const double* x1, + const double* y1, + const double* x2_original, + const double* y2_original, + const Warp& warp) : options_(options), x1_(x1), y1_(y1), @@ -606,11 +589,11 @@ class WarpRegularizingCostFunctor { original_centroid_[1] /= 4; } - template - bool operator()(const T *warp_parameters, T *residuals) const { - T dst_centroid[2] = { T(0.0), T(0.0) }; + template + bool operator()(const T* warp_parameters, T* residuals) const { + T dst_centroid[2] = {T(0.0), T(0.0)}; for (int i = 0; i < 4; ++i) { - T image1_position[2] = { T(x1_[i]), T(y1_[i]) }; + T image1_position[2] = {T(x1_[i]), T(y1_[i])}; T image2_position[2]; warp_.Forward(warp_parameters, T(x1_[i]), @@ -643,28 +626,30 @@ class WarpRegularizingCostFunctor { return true; } - const TrackRegionOptions &options_; - const double *x1_; - const double *y1_; - const double *x2_original_; - const double *y2_original_; + const TrackRegionOptions& options_; + const double* x1_; + const double* y1_; + const double* x2_original_; + const double* y2_original_; double original_centroid_[2]; - const Warp &warp_; + const Warp& warp_; }; // Compute the warp from rectangular coordinates, where one corner is the // origin, and the opposite corner is at (num_samples_x, num_samples_y). -Mat3 ComputeCanonicalHomography(const double *x1, - const double *y1, +Mat3 ComputeCanonicalHomography(const double* x1, + const double* y1, int num_samples_x, int num_samples_y) { Mat canonical(2, 4); - canonical << 0, num_samples_x, num_samples_x, 0, - 0, 0, num_samples_y, num_samples_y; + canonical << 0, num_samples_x, num_samples_x, 0, 0, 0, num_samples_y, + num_samples_y; Mat xy1(2, 4); + // clang-format off xy1 << x1[0], x1[1], x1[2], x1[3], y1[0], y1[1], y1[2], y1[3]; + // clang-format om Mat3 H; if (!Homography2DFromCorrespondencesLinear(canonical, xy1, &H, 1e-12)) { @@ -675,7 +660,7 @@ Mat3 ComputeCanonicalHomography(const double *x1, class Quad { public: - Quad(const double *x, const double *y) : x_(x), y_(y) { + Quad(const double* x, const double* y) : x_(x), y_(y) { // Compute the centroid and store it. centroid_ = Vec2(0.0, 0.0); for (int i = 0; i < 4; ++i) { @@ -685,9 +670,7 @@ class Quad { } // The centroid of the four points representing the quad. - const Vec2& Centroid() const { - return centroid_; - } + const Vec2& Centroid() const { return centroid_; } // The average magnitude of the four points relative to the centroid. double Scale() const { @@ -703,22 +686,24 @@ class Quad { } private: - const double *x_; - const double *y_; + const double* x_; + const double* y_; Vec2 centroid_; }; struct TranslationWarp { - TranslationWarp(const double *x1, const double *y1, - const double *x2, const double *y2) { + TranslationWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) { Vec2 t = Quad(x2, y2).Centroid() - Quad(x1, y1).Centroid(); parameters[0] = t[0]; parameters[1] = t[1]; } - template - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { + template + void Forward( + const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const { *x2 = x1 + warp_parameters[0]; *y2 = y1 + warp_parameters[1]; } @@ -729,8 +714,10 @@ struct TranslationWarp { }; struct TranslationScaleWarp { - TranslationScaleWarp(const double *x1, const double *y1, - const double *x2, const double *y2) + TranslationScaleWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) : q1(x1, y1) { Quad q2(x2, y2); @@ -746,9 +733,9 @@ struct TranslationScaleWarp { // The strange way of parameterizing the translation and scaling is to make // the knobs that the optimizer sees easy to adjust. This is less important // for the scaling case than the rotation case. - template - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { + template + void Forward( + const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const { // Make the centroid of Q1 the origin. const T x1_origin = x1 - q1.Centroid()(0); const T y1_origin = y1 - q1.Centroid()(1); @@ -775,15 +762,17 @@ struct TranslationScaleWarp { }; // Assumes the given points are already zero-centroid and the same size. -Mat2 OrthogonalProcrustes(const Mat2 &correlation_matrix) { +Mat2 OrthogonalProcrustes(const Mat2& correlation_matrix) { Eigen::JacobiSVD svd(correlation_matrix, Eigen::ComputeFullU | Eigen::ComputeFullV); return svd.matrixV() * svd.matrixU().transpose(); } struct TranslationRotationWarp { - TranslationRotationWarp(const double *x1, const double *y1, - const double *x2, const double *y2) + TranslationRotationWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) : q1(x1, y1) { Quad q2(x2, y2); @@ -816,9 +805,9 @@ struct TranslationRotationWarp { // // Instead, use the parameterization below that offers a parameterization // that exposes the degrees of freedom in a way amenable to optimization. - template - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { + template + void Forward( + const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const { // Make the centroid of Q1 the origin. const T x1_origin = x1 - q1.Centroid()(0); const T y1_origin = y1 - q1.Centroid()(1); @@ -847,8 +836,10 @@ struct TranslationRotationWarp { }; struct TranslationRotationScaleWarp { - TranslationRotationScaleWarp(const double *x1, const double *y1, - const double *x2, const double *y2) + TranslationRotationScaleWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) : q1(x1, y1) { Quad q2(x2, y2); @@ -884,9 +875,9 @@ struct TranslationRotationScaleWarp { // // Instead, use the parameterization below that offers a parameterization // that exposes the degrees of freedom in a way amenable to optimization. - template - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { + template + void Forward( + const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const { // Make the centroid of Q1 the origin. const T x1_origin = x1 - q1.Centroid()(0); const T y1_origin = y1 - q1.Centroid()(1); @@ -921,8 +912,10 @@ struct TranslationRotationScaleWarp { }; struct AffineWarp { - AffineWarp(const double *x1, const double *y1, - const double *x2, const double *y2) + AffineWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) : q1(x1, y1) { Quad q2(x2, y2); @@ -938,8 +931,8 @@ struct AffineWarp { Vec2 v1 = q1.CornerRelativeToCentroid(i); Vec2 v2 = q2.CornerRelativeToCentroid(i); - Q1.row(2 * i + 0) << v1[0], v1[1], 0, 0; - Q1.row(2 * i + 1) << 0, 0, v1[0], v1[1]; + Q1.row(2 * i + 0) << v1[0], v1[1], 0, 0; + Q1.row(2 * i + 1) << 0, 0, v1[0], v1[1]; Q2(2 * i + 0) = v2[0]; Q2(2 * i + 1) = v2[1]; @@ -957,8 +950,8 @@ struct AffineWarp { } // See comments in other parameterizations about why the centroid is used. - template - void Forward(const T *p, const T &x1, const T& y1, T *x2, T* y2) const { + template + void Forward(const T* p, const T& x1, const T& y1, T* x2, T* y2) const { // Make the centroid of Q1 the origin. const T x1_origin = x1 - q1.Centroid()(0); const T y1_origin = y1 - q1.Centroid()(1); @@ -985,15 +978,21 @@ struct AffineWarp { }; struct HomographyWarp { - HomographyWarp(const double *x1, const double *y1, - const double *x2, const double *y2) { + HomographyWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) { Mat quad1(2, 4); + // clang-format off quad1 << x1[0], x1[1], x1[2], x1[3], y1[0], y1[1], y1[2], y1[3]; + // clang-format on Mat quad2(2, 4); + // clang-format off quad2 << x2[0], x2[1], x2[2], x2[3], y2[0], y2[1], y2[2], y2[3]; + // clang-format on Mat3 H; if (!Homography2DFromCorrespondencesLinear(quad1, quad2, &H, 1e-12)) { @@ -1014,13 +1013,12 @@ struct HomographyWarp { } } - template - static void Forward(const T *p, - const T &x1, const T& y1, T *x2, T* y2) { + template + static void Forward(const T* p, const T& x1, const T& y1, T* x2, T* y2) { // Homography warp with manual 3x3 matrix multiply. - const T xx2 = (1.0 + p[0]) * x1 + p[1] * y1 + p[2]; - const T yy2 = p[3] * x1 + (1.0 + p[4]) * y1 + p[5]; - const T zz2 = p[6] * x1 + p[7] * y1 + 1.0; + const T xx2 = (1.0 + p[0]) * x1 + p[1] * y1 + p[2]; + const T yy2 = p[3] * x1 + (1.0 + p[4]) * y1 + p[5]; + const T zz2 = p[6] * x1 + p[7] * y1 + 1.0; *x2 = xx2 / zz2; *y2 = yy2 / zz2; } @@ -1036,11 +1034,14 @@ struct HomographyWarp { // // The idea is to take the maximum x or y distance. This may be oversampling. // TODO(keir): Investigate the various choices; perhaps average is better? -void PickSampling(const double *x1, const double *y1, - const double *x2, const double *y2, - int *num_samples_x, int *num_samples_y) { - (void) x2; // Ignored. - (void) y2; // Ignored. +void PickSampling(const double* x1, + const double* y1, + const double* x2, + const double* y2, + int* num_samples_x, + int* num_samples_y) { + (void)x2; // Ignored. + (void)y2; // Ignored. Vec2 a0(x1[0], y1[0]); Vec2 a1(x1[1], y1[1]); @@ -1053,18 +1054,10 @@ void PickSampling(const double *x1, const double *y1, Vec2 b3(x1[3], y1[3]); double x_dimensions[4] = { - (a1 - a0).norm(), - (a3 - a2).norm(), - (b1 - b0).norm(), - (b3 - b2).norm() - }; + (a1 - a0).norm(), (a3 - a2).norm(), (b1 - b0).norm(), (b3 - b2).norm()}; double y_dimensions[4] = { - (a3 - a0).norm(), - (a1 - a2).norm(), - (b3 - b0).norm(), - (b1 - b2).norm() - }; + (a3 - a0).norm(), (a1 - a2).norm(), (b3 - b0).norm(), (b1 - b2).norm()}; const double kScaleFactor = 1.0; *num_samples_x = static_cast( kScaleFactor * *std::max_element(x_dimensions, x_dimensions + 4)); @@ -1074,17 +1067,18 @@ void PickSampling(const double *x1, const double *y1, << ", num_samples_y: " << *num_samples_y; } -bool SearchAreaTooBigForDescent(const FloatImage &image2, - const double *x2, const double *y2) { +bool SearchAreaTooBigForDescent(const FloatImage& image2, + const double* x2, + const double* y2) { // TODO(keir): Check the bounds and enable only when it makes sense. - (void) image2; // Ignored. - (void) x2; // Ignored. - (void) y2; // Ignored. + (void)image2; // Ignored. + (void)x2; // Ignored. + (void)y2; // Ignored. return true; } -bool PointOnRightHalfPlane(const Vec2 &a, const Vec2 &b, double x, double y) { +bool PointOnRightHalfPlane(const Vec2& a, const Vec2& b, double x, double y) { Vec2 ba = b - a; return ((Vec2(x, y) - b).transpose() * Vec2(-ba.y(), ba.x())) > 0; } @@ -1102,7 +1096,7 @@ bool PointOnRightHalfPlane(const Vec2 &a, const Vec2 &b, double x, double y) { // y // // The implementation does up to four half-plane comparisons. -bool PointInQuad(const double *xs, const double *ys, double x, double y) { +bool PointInQuad(const double* xs, const double* ys, double x, double y) { Vec2 a0(xs[0], ys[0]); Vec2 a1(xs[1], ys[1]); Vec2 a2(xs[2], ys[2]); @@ -1116,24 +1110,27 @@ bool PointInQuad(const double *xs, const double *ys, double x, double y) { // This makes it possible to map between Eigen float arrays and FloatImage // without using comparisons. -typedef Eigen::Array FloatArray; +typedef Eigen::Array + FloatArray; // This creates a pattern in the frame of image2, from the pixel is image1, // based on the initial guess represented by the two quads x1, y1, and x2, y2. -template -void CreateBrutePattern(const double *x1, const double *y1, - const double *x2, const double *y2, - const FloatImage &image1, - const FloatImage *image1_mask, - FloatArray *pattern, - FloatArray *mask, - int *origin_x, - int *origin_y) { +template +void CreateBrutePattern(const double* x1, + const double* y1, + const double* x2, + const double* y2, + const FloatImage& image1, + const FloatImage* image1_mask, + FloatArray* pattern, + FloatArray* mask, + int* origin_x, + int* origin_y) { // Get integer bounding box of quad2 in image2. int min_x = static_cast(floor(*std::min_element(x2, x2 + 4))); int min_y = static_cast(floor(*std::min_element(y2, y2 + 4))); - int max_x = static_cast(ceil (*std::max_element(x2, x2 + 4))); - int max_y = static_cast(ceil (*std::max_element(y2, y2 + 4))); + int max_x = static_cast(ceil(*std::max_element(x2, x2 + 4))); + int max_y = static_cast(ceil(*std::max_element(y2, y2 + 4))); int w = max_x - min_x; int h = max_y - min_y; @@ -1154,9 +1151,8 @@ void CreateBrutePattern(const double *x1, const double *y1, double dst_y = r; double src_x; double src_y; - inverse_warp.Forward(inverse_warp.parameters, - dst_x, dst_y, - &src_x, &src_y); + inverse_warp.Forward( + inverse_warp.parameters, dst_x, dst_y, &src_x, &src_y); if (PointInQuad(x1, y1, src_x, src_y)) { (*pattern)(i, j) = SampleLinear(image1, src_y, src_x); @@ -1191,24 +1187,32 @@ void CreateBrutePattern(const double *x1, const double *y1, // pattern, when doing brute initialization. Unfortunately that implies a // totally different warping interface, since access to more than a the source // and current destination frame is necessary. -template -bool BruteTranslationOnlyInitialize(const FloatImage &image1, - const FloatImage *image1_mask, - const FloatImage &image2, +template +bool BruteTranslationOnlyInitialize(const FloatImage& image1, + const FloatImage* image1_mask, + const FloatImage& image2, const int num_extra_points, const bool use_normalized_intensities, - const double *x1, const double *y1, - double *x2, double *y2) { + const double* x1, + const double* y1, + double* x2, + double* y2) { // Create the pattern to match in the space of image2, assuming our inital // guess isn't too far from the template in image1. If there is no image1 // mask, then the resulting mask is binary. FloatArray pattern; FloatArray mask; int origin_x = -1, origin_y = -1; - CreateBrutePattern(x1, y1, x2, y2, - image1, image1_mask, - &pattern, &mask, - &origin_x, &origin_y); + CreateBrutePattern(x1, + y1, + x2, + y2, + image1, + image1_mask, + &pattern, + &mask, + &origin_x, + &origin_y); // For normalization, premultiply the pattern by the inverse pattern mean. double mask_sum = 1.0; @@ -1251,8 +1255,10 @@ bool BruteTranslationOnlyInitialize(const FloatImage &image1, // instead, reducing the mean calculation to an O(1) operation. double inverse_search_mean = mask_sum / ((mask * search.block(r, c, h, w)).sum()); - sad = (mask * (pattern - (search.block(r, c, h, w) * - inverse_search_mean))).abs().sum(); + sad = (mask * + (pattern - (search.block(r, c, h, w) * inverse_search_mean))) + .abs() + .sum(); } else { sad = (mask * (pattern - search.block(r, c, h, w))).abs().sum(); } @@ -1274,9 +1280,8 @@ bool BruteTranslationOnlyInitialize(const FloatImage &image1, << "best_c: " << best_c << ", best_r: " << best_r << ", " << "origin_x: " << origin_x << ", origin_y: " << origin_y << ", " << "dc: " << (best_c - origin_x) << ", " - << "dr: " << (best_r - origin_y) - << ", tried " << ((image2.Height() - h) * (image2.Width() - w)) - << " shifts."; + << "dr: " << (best_r - origin_y) << ", tried " + << ((image2.Height() - h) * (image2.Width() - w)) << " shifts."; // Apply the shift. for (int i = 0; i < 4 + num_extra_points; ++i) { @@ -1286,8 +1291,10 @@ bool BruteTranslationOnlyInitialize(const FloatImage &image1, return true; } -void CopyQuad(double *src_x, double *src_y, - double *dst_x, double *dst_y, +void CopyQuad(double* src_x, + double* src_y, + double* dst_x, + double* dst_y, int num_extra_points) { for (int i = 0; i < 4 + num_extra_points; ++i) { dst_x[i] = src_x[i]; @@ -1297,16 +1304,18 @@ void CopyQuad(double *src_x, double *src_y, } // namespace -template -void TemplatedTrackRegion(const FloatImage &image1, - const FloatImage &image2, - const double *x1, const double *y1, - const TrackRegionOptions &options, - double *x2, double *y2, - TrackRegionResult *result) { +template +void TemplatedTrackRegion(const FloatImage& image1, + const FloatImage& image2, + const double* x1, + const double* y1, + const TrackRegionOptions& options, + double* x2, + double* y2, + TrackRegionResult* result) { for (int i = 0; i < 4 + options.num_extra_points; ++i) { - LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); guess (" - << x2[i] << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) << ", " + LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); guess (" << x2[i] + << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) << ", " << (y2[i] - y1[i]) << ")."; } @@ -1322,9 +1331,14 @@ void TemplatedTrackRegion(const FloatImage &image1, double y2_first_try[5]; CopyQuad(x2, y2, x2_first_try, y2_first_try, options.num_extra_points); - TemplatedTrackRegion(image1, image2, - x1, y1, modified_options, - x2_first_try, y2_first_try, result); + TemplatedTrackRegion(image1, + image2, + x1, + y1, + modified_options, + x2_first_try, + y2_first_try, + result); // Of the things that can happen in the first pass, don't try the brute // pass (and second attempt) if the error is one of the terminations below. @@ -1368,22 +1382,25 @@ void TemplatedTrackRegion(const FloatImage &image1, // Prepare the image and gradient. Array3Df image_and_gradient1; Array3Df image_and_gradient2; - BlurredImageAndDerivativesChannels(image1, options.sigma, - &image_and_gradient1); - BlurredImageAndDerivativesChannels(image2, options.sigma, - &image_and_gradient2); + BlurredImageAndDerivativesChannels( + image1, options.sigma, &image_and_gradient1); + BlurredImageAndDerivativesChannels( + image2, options.sigma, &image_and_gradient2); // Possibly do a brute-force translation-only initialization. if (SearchAreaTooBigForDescent(image2, x2, y2) && options.use_brute_initialization) { LG << "Running brute initialization..."; - bool found_any_alignment = BruteTranslationOnlyInitialize( - image_and_gradient1, - options.image1_mask, - image2, - options.num_extra_points, - options.use_normalized_intensities, - x1, y1, x2, y2); + bool found_any_alignment = + BruteTranslationOnlyInitialize(image_and_gradient1, + options.image1_mask, + image2, + options.num_extra_points, + options.use_normalized_intensities, + x1, + y1, + x2, + y2); if (!found_any_alignment) { LG << "Brute failed to find an alignment; pattern too small. " << "Failing entire track operation."; @@ -1391,9 +1408,9 @@ void TemplatedTrackRegion(const FloatImage &image1, return; } for (int i = 0; i < 4; ++i) { - LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); brute (" - << x2[i] << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) - << ", " << (y2[i] - y1[i]) << ")."; + LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); brute (" << x2[i] + << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) << ", " + << (y2[i] - y1[i]) << ")."; } } @@ -1408,14 +1425,13 @@ void TemplatedTrackRegion(const FloatImage &image1, PickSampling(x1, y1, x2, y2, &num_samples_x, &num_samples_y); // Compute the warp from rectangular coordinates. - Mat3 canonical_homography = ComputeCanonicalHomography(x1, y1, - num_samples_x, - num_samples_y); + Mat3 canonical_homography = + ComputeCanonicalHomography(x1, y1, num_samples_x, num_samples_y); ceres::Problem problem; // Construct the warp cost function. AutoDiffCostFunction takes ownership. - PixelDifferenceCostFunctor *pixel_difference_cost_function = + PixelDifferenceCostFunctor* pixel_difference_cost_function = new PixelDifferenceCostFunctor(options, image_and_gradient1, image_and_gradient2, @@ -1424,28 +1440,24 @@ void TemplatedTrackRegion(const FloatImage &image1, num_samples_y, warp); problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - PixelDifferenceCostFunctor, - ceres::DYNAMIC, - Warp::NUM_PARAMETERS>(pixel_difference_cost_function, - num_samples_x * num_samples_y), - NULL, - warp.parameters); + new ceres::AutoDiffCostFunction, + ceres::DYNAMIC, + Warp::NUM_PARAMETERS>( + pixel_difference_cost_function, num_samples_x * num_samples_y), + NULL, + warp.parameters); // Construct the regularizing cost function if (options.regularization_coefficient != 0.0) { - WarpRegularizingCostFunctor *regularizing_warp_cost_function = - new WarpRegularizingCostFunctor(options, - x1, y2, - x2_original, - y2_original, - warp); + WarpRegularizingCostFunctor* regularizing_warp_cost_function = + new WarpRegularizingCostFunctor( + options, x1, y2, x2_original, y2_original, warp); problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - WarpRegularizingCostFunctor, - 8 /* num_residuals */, - Warp::NUM_PARAMETERS>(regularizing_warp_cost_function), + new ceres::AutoDiffCostFunction, + 8 /* num_residuals */, + Warp::NUM_PARAMETERS>( + regularizing_warp_cost_function), NULL, warp.parameters); } @@ -1488,10 +1500,10 @@ void TemplatedTrackRegion(const FloatImage &image1, return; } -#define HANDLE_TERMINATION(termination_enum) \ - if (summary.termination_type == ceres::termination_enum) { \ - result->termination = TrackRegionResult::termination_enum; \ - return; \ +#define HANDLE_TERMINATION(termination_enum) \ + if (summary.termination_type == ceres::termination_enum) { \ + result->termination = TrackRegionResult::termination_enum; \ + return; \ } // Avoid computing correlation for tracking failures. @@ -1499,8 +1511,9 @@ void TemplatedTrackRegion(const FloatImage &image1, // Otherwise, run a final correlation check. if (options.minimum_correlation > 0.0) { - result->correlation = pixel_difference_cost_function-> - PearsonProductMomentCorrelationCoefficient(warp.parameters); + result->correlation = + pixel_difference_cost_function + ->PearsonProductMomentCorrelationCoefficient(warp.parameters); if (result->correlation < options.minimum_correlation) { LG << "Failing with insufficient correlation."; result->termination = TrackRegionResult::INSUFFICIENT_CORRELATION; @@ -1523,36 +1536,39 @@ void TemplatedTrackRegion(const FloatImage &image1, #undef HANDLE_TERMINATION }; -void TrackRegion(const FloatImage &image1, - const FloatImage &image2, - const double *x1, const double *y1, - const TrackRegionOptions &options, - double *x2, double *y2, - TrackRegionResult *result) { +void TrackRegion(const FloatImage& image1, + const FloatImage& image2, + const double* x1, + const double* y1, + const TrackRegionOptions& options, + double* x2, + double* y2, + TrackRegionResult* result) { // Enum is necessary due to templated nature of autodiff. -#define HANDLE_MODE(mode_enum, mode_type) \ - if (options.mode == TrackRegionOptions::mode_enum) { \ - TemplatedTrackRegion(image1, image2, \ - x1, y1, \ - options, \ - x2, y2, \ - result); \ - return; \ +#define HANDLE_MODE(mode_enum, mode_type) \ + if (options.mode == TrackRegionOptions::mode_enum) { \ + TemplatedTrackRegion( \ + image1, image2, x1, y1, options, x2, y2, result); \ + return; \ } - HANDLE_MODE(TRANSLATION, TranslationWarp); - HANDLE_MODE(TRANSLATION_SCALE, TranslationScaleWarp); - HANDLE_MODE(TRANSLATION_ROTATION, TranslationRotationWarp); + HANDLE_MODE(TRANSLATION, TranslationWarp); + HANDLE_MODE(TRANSLATION_SCALE, TranslationScaleWarp); + HANDLE_MODE(TRANSLATION_ROTATION, TranslationRotationWarp); HANDLE_MODE(TRANSLATION_ROTATION_SCALE, TranslationRotationScaleWarp); - HANDLE_MODE(AFFINE, AffineWarp); - HANDLE_MODE(HOMOGRAPHY, HomographyWarp); + HANDLE_MODE(AFFINE, AffineWarp); + HANDLE_MODE(HOMOGRAPHY, HomographyWarp); #undef HANDLE_MODE } -bool SamplePlanarPatch(const FloatImage &image, - const double *xs, const double *ys, - int num_samples_x, int num_samples_y, - FloatImage *mask, FloatImage *patch, - double *warped_position_x, double *warped_position_y) { +bool SamplePlanarPatch(const FloatImage& image, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + FloatImage* mask, + FloatImage* patch, + double* warped_position_x, + double* warped_position_y) { // Bail early if the points are outside the image. if (!AllInBounds(image, xs, ys)) { LG << "Can't sample patch: out of bounds."; @@ -1563,9 +1579,8 @@ bool SamplePlanarPatch(const FloatImage &image, patch->Resize(num_samples_y, num_samples_x, image.Depth()); // Compute the warp from rectangular coordinates. - Mat3 canonical_homography = ComputeCanonicalHomography(xs, ys, - num_samples_x, - num_samples_y); + Mat3 canonical_homography = + ComputeCanonicalHomography(xs, ys, num_samples_x, num_samples_y); // Walk over the coordinates in the canonical space, sampling from the image // in the original space and copying the result into the patch. @@ -1573,12 +1588,11 @@ bool SamplePlanarPatch(const FloatImage &image, for (int c = 0; c < num_samples_x; ++c) { Vec3 image_position = canonical_homography * Vec3(c, r, 1); image_position /= image_position(2); - SampleLinear(image, image_position(1), - image_position(0), - &(*patch)(r, c, 0)); + SampleLinear( + image, image_position(1), image_position(0), &(*patch)(r, c, 0)); if (mask) { - float mask_value = SampleLinear(*mask, image_position(1), - image_position(0), 0); + float mask_value = + SampleLinear(*mask, image_position(1), image_position(0), 0); for (int d = 0; d < image.Depth(); d++) (*patch)(r, c, d) *= mask_value; diff --git a/intern/libmv/libmv/tracking/track_region.h b/intern/libmv/libmv/tracking/track_region.h index 61dce22bcb8..7868e3b8b77 100644 --- a/intern/libmv/libmv/tracking/track_region.h +++ b/intern/libmv/libmv/tracking/track_region.h @@ -19,6 +19,7 @@ // IN THE SOFTWARE. #ifndef LIBMV_TRACKING_TRACK_REGION_H_ +#define LIBMV_TRACKING_TRACK_REGION_H_ #include "libmv/image/image.h" #include "libmv/image/sample.h" @@ -107,7 +108,7 @@ struct TrackRegionOptions { // If non-null, this is used as the pattern mask. It should match the size of // image1, even though only values inside the image1 quad are examined. The // values must be in the range 0.0 to 0.1. - FloatImage *image1_mask; + FloatImage* image1_mask; }; struct TrackRegionResult { @@ -128,8 +129,7 @@ struct TrackRegionResult { Termination termination; bool is_usable() { - return termination == CONVERGENCE || - termination == NO_CONVERGENCE; + return termination == CONVERGENCE || termination == NO_CONVERGENCE; } int num_iterations; @@ -140,12 +140,14 @@ struct TrackRegionResult { }; // Always needs 4 correspondences. -void TrackRegion(const FloatImage &image1, - const FloatImage &image2, - const double *x1, const double *y1, - const TrackRegionOptions &options, - double *x2, double *y2, - TrackRegionResult *result); +void TrackRegion(const FloatImage& image1, + const FloatImage& image2, + const double* x1, + const double* y1, + const TrackRegionOptions& options, + double* x2, + double* y2, + TrackRegionResult* result); // Sample a "canonical" version of the passed planar patch, using bilinear // sampling. The passed corners must be within the image, and have at least two @@ -156,11 +158,15 @@ void TrackRegion(const FloatImage &image1, // the size of image. // Warped coordinates of marker's position would be returned in // warped_position_x and warped_position_y -bool SamplePlanarPatch(const FloatImage &image, - const double *xs, const double *ys, - int num_samples_x, int num_samples_y, - FloatImage *mask, FloatImage *patch, - double *warped_position_x, double *warped_position_y); +bool SamplePlanarPatch(const FloatImage& image, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + FloatImage* mask, + FloatImage* patch, + double* warped_position_x, + double* warped_position_y); } // namespace libmv diff --git a/intern/libmv/libmv/tracking/trklt_region_tracker.cc b/intern/libmv/libmv/tracking/trklt_region_tracker.cc index 05ef3d1d272..7ffa7555467 100644 --- a/intern/libmv/libmv/tracking/trklt_region_tracker.cc +++ b/intern/libmv/libmv/tracking/trklt_region_tracker.cc @@ -20,27 +20,29 @@ #include "libmv/tracking/trklt_region_tracker.h" -#include "libmv/logging/logging.h" -#include "libmv/numeric/numeric.h" -#include "libmv/image/image.h" #include "libmv/image/convolve.h" +#include "libmv/image/image.h" #include "libmv/image/sample.h" +#include "libmv/logging/logging.h" +#include "libmv/numeric/numeric.h" namespace libmv { // TODO(keir): Switch this to use the smarter LM loop like in ESM. // Computes U and e from the Ud = e equation (number 14) from the paper. -static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, - const Array3Df &image_and_gradient2, - double x1, double y1, - double x2, double y2, +static void ComputeTrackingEquation(const Array3Df& image_and_gradient1, + const Array3Df& image_and_gradient2, + double x1, + double y1, + double x2, + double y2, int half_width, double lambda, - Mat2f *U, - Vec2f *e) { + Mat2f* U, + Vec2f* e) { Mat2f A, B, C, D; - A = B = C = D = Mat2f::Zero(); + A = B = C = D = Mat2f::Zero(); Vec2f R, S, V, W; R = S = V = W = Vec2f::Zero(); @@ -57,9 +59,9 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, Vec2f gI, gJ; gI << SampleLinear(image_and_gradient1, yy1, xx1, 1), - SampleLinear(image_and_gradient1, yy1, xx1, 2); + SampleLinear(image_and_gradient1, yy1, xx1, 2); gJ << SampleLinear(image_and_gradient2, yy2, xx2, 1), - SampleLinear(image_and_gradient2, yy2, xx2, 2); + SampleLinear(image_and_gradient2, yy2, xx2, 2); // Equation 15 from the paper. A += gI * gI.transpose(); @@ -77,26 +79,25 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, Mat2f Di = B.transpose().inverse(); // Equation 14 from the paper. - *U = A*Di*C + lambda*Di*C - 0.5*B; - *e = (A + lambda*Mat2f::Identity())*Di*(V - W) + 0.5*(S - R); + *U = A * Di * C + lambda * Di * C - 0.5 * B; + *e = (A + lambda * Mat2f::Identity()) * Di * (V - W) + 0.5 * (S - R); } -static bool RegionIsInBounds(const FloatImage &image1, - double x, double y, - int half_window_size) { +static bool RegionIsInBounds(const FloatImage& image1, + double x, + double y, + int half_window_size) { // Check the minimum coordinates. int min_x = floor(x) - half_window_size - 1; int min_y = floor(y) - half_window_size - 1; - if (min_x < 0.0 || - min_y < 0.0) { + if (min_x < 0.0 || min_y < 0.0) { return false; } // Check the maximum coordinates. int max_x = ceil(x) + half_window_size + 1; int max_y = ceil(y) + half_window_size + 1; - if (max_x > image1.cols() || - max_y > image1.rows()) { + if (max_x > image1.cols() || max_y > image1.rows()) { return false; } @@ -104,10 +105,12 @@ static bool RegionIsInBounds(const FloatImage &image1, return true; } -bool TrkltRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool TrkltRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { if (!RegionIsInBounds(image1, x1, y1, half_window_size)) { LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1 << ", hw=" << half_window_size << "."; @@ -134,11 +137,14 @@ bool TrkltRegionTracker::Track(const FloatImage &image1, Vec2f e; ComputeTrackingEquation(image_and_gradient1, image_and_gradient2, - x1, y1, - *x2, *y2, + x1, + y1, + *x2, + *y2, half_window_size, lambda, - &U, &e); + &U, + &e); // Solve the linear system for the best update to x2 and y2. d = U.lu().solve(e); @@ -161,7 +167,6 @@ bool TrkltRegionTracker::Track(const FloatImage &image1, LG << "x=" << *x2 << ", y=" << *y2 << ", dx=" << d[0] << ", dy=" << d[1] << ", det=" << determinant; - // If the update is small, then we probably found the target. if (d.squaredNorm() < min_update_squared_distance) { LG << "Successful track in " << i << " iterations."; diff --git a/intern/libmv/libmv/tracking/trklt_region_tracker.h b/intern/libmv/libmv/tracking/trklt_region_tracker.h index 26d0621aa02..a9cf5580f61 100644 --- a/intern/libmv/libmv/tracking/trklt_region_tracker.h +++ b/intern/libmv/libmv/tracking/trklt_region_tracker.h @@ -46,10 +46,12 @@ struct TrkltRegionTracker : public RegionTracker { virtual ~TrkltRegionTracker() {} // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; // No point in creating getters or setters. int half_window_size; -- cgit v1.2.3 From fe35551df2d874d51073b1dc4a582a1962255949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 5 Mar 2021 15:00:56 +0100 Subject: Asset Browser Space API: add `activate_asset_by_id()` function Add an RNA function `activate_asset_by_id(asset_id: ID, deferred: bool)` to the File Browser space type, which intended to be used to activate an asset's entry as identified by its `ID *`. Calling it changes the active asset, but only if the given ID can actually be found. The activation can be deferred (by passing `deferred=True`) until the next refresh operation has finished. This is necessary when an asset has just been added, as it will be loaded by the filebrowser in a background job. Reviewed By: Severin Differential Revision: https://developer.blender.org/D10549 --- source/blender/blenkernel/intern/screen.c | 1 + source/blender/editors/include/ED_fileselect.h | 7 +++ source/blender/editors/space_file/file_intern.h | 15 +++++++ source/blender/editors/space_file/filelist.c | 11 ++--- source/blender/editors/space_file/filelist.h | 2 + source/blender/editors/space_file/filesel.c | 60 +++++++++++++++++++++++++ source/blender/editors/space_file/space_file.c | 51 ++++++++++++++++++--- source/blender/makesdna/DNA_space_types.h | 5 +++ source/blender/makesrna/intern/rna_internal.h | 1 + source/blender/makesrna/intern/rna_space.c | 2 + source/blender/makesrna/intern/rna_space_api.c | 21 +++++++++ source/blender/windowmanager/WM_types.h | 1 + 12 files changed, 166 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 8b911143668..623f3a349d8 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -1681,6 +1681,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area) sfile->op = NULL; sfile->previews_timer = NULL; sfile->tags = 0; + sfile->runtime = NULL; BLO_read_data_address(reader, &sfile->params); BLO_read_data_address(reader, &sfile->asset_params); } diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 7538dac1354..983ae94b637 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -145,6 +145,13 @@ void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile); bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile); +struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile); + +/* Activate the file that corresponds to the given ID. + * Pass deferred=true to wait for the next refresh before activating. */ +void ED_fileselect_activate_by_id(struct SpaceFile *sfile, + struct ID *asset_id, + const bool deferred); void ED_fileselect_window_params_get(const struct wmWindow *win, int win_size[2], diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 56fb588776e..deb32812f44 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -112,6 +112,21 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v); void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params); +typedef void *onReloadFnData; +typedef void (*onReloadFn)(struct SpaceFile *space_data, onReloadFnData custom_data); +typedef struct SpaceFile_Runtime { + /* Called once after the file browser has reloaded. Reset to NULL after calling. + * Use file_on_reload_callback_register() to register a callback. */ + onReloadFn on_reload; + onReloadFnData on_reload_custom_data; +} SpaceFile_Runtime; + +/* Register an on-reload callback function. Note that there can only be one such function at a + * time; registering a new one will overwrite the previous one. */ +void file_on_reload_callback_register(struct SpaceFile *sfile, + onReloadFn callback, + onReloadFnData custom_data); + /* file_panels.c */ void file_tool_props_region_panels_register(struct ARegionType *art); void file_execute_region_panels_register(struct ARegionType *art); diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 33c37875372..518fc777c67 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1990,9 +1990,7 @@ static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry) filelist_entry_free(entry); } -static FileDirEntry *filelist_file_ex(struct FileList *filelist, - const int index, - const bool use_request) +FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request) { FileDirEntry *ret = NULL, *old; FileListEntryCache *cache = &filelist->filelist_cache; @@ -3464,7 +3462,7 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) filelist_readjob_endjob(flrj); filelist_readjob_free(flrj); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED, NULL); return; } @@ -3476,7 +3474,10 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) WM_JOB_PROGRESS, WM_JOB_TYPE_FILESEL_READDIR); WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free); - WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST); + WM_jobs_timer(wm_job, + 0.01, + NC_SPACE | ND_SPACE_FILE_LIST, + NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED); WM_jobs_callbacks( wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob); diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 16984bb6e43..7eecd7a05de 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -93,6 +93,8 @@ void filelist_setdir(struct FileList *filelist, char *r_dir); int filelist_files_ensure(struct FileList *filelist); int filelist_needs_reading(struct FileList *filelist); FileDirEntry *filelist_file(struct FileList *filelist, int index); +FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request); + int filelist_file_findpath(struct FileList *filelist, const char *file); struct ID *filelist_file_get_id(const struct FileDirEntry *file); FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 6917893ab5f..7015ca970a3 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -454,6 +454,66 @@ bool ED_fileselect_is_asset_browser(const SpaceFile *sfile) return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS); } +struct ID *ED_fileselect_active_asset_get(const SpaceFile *sfile) +{ + if (!ED_fileselect_is_asset_browser(sfile)) { + return NULL; + } + + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + const FileDirEntry *file = filelist_file(sfile->files, params->active_file); + if (file == NULL) { + return NULL; + } + + return filelist_file_get_id(file); +} + +static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data) +{ + ID *asset_id = (ID *)custom_data; + ED_fileselect_activate_by_id(sfile, asset_id, false); +} + +void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool deferred) +{ + if (!ED_fileselect_is_asset_browser(sfile)) { + return; + } + + /* If there are filelist operations running now ("pending" true) or soon ("force reset" true), + * there is a fair chance that the to-be-activated ID will only be present after these operations + * have completed. Defer activation until then. */ + if (deferred || filelist_pending(sfile->files) || filelist_needs_force_reset(sfile->files)) { + /* This should be thread-safe, as this function is likely called from the main thread, and + * notifiers (which cause a call to the on-reload callback function) are handled on the main + * thread as well. */ + file_on_reload_callback_register(sfile, on_reload_activate_by_id, asset_id); + return; + } + + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + struct FileList *files = sfile->files; + + const int num_files_filtered = filelist_files_ensure(files); + for (int file_index = 0; file_index < num_files_filtered; ++file_index) { + const FileDirEntry *file = filelist_file_ex(files, file_index, false); + + if (filelist_file_get_id(file) != asset_id) { + filelist_entry_select_set(files, file, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); + continue; + } + + params->active_file = file_index; + filelist_entry_select_set(files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + + /* Keep looping to deselect the other files. */ + } + + WM_main_add_notifier(NC_ASSET | NA_ACTIVATED, NULL); + WM_main_add_notifier(NC_ASSET | NA_SELECTED, NULL); +} + /* The subset of FileSelectParams.flag items we store into preferences. Note that FILE_SORT_ALPHA * may also be remembered, but only conditionally. */ #define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index b175844a710..2c9c2688e88 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -173,6 +173,7 @@ static void file_free(SpaceLink *sl) MEM_SAFE_FREE(sfile->params); MEM_SAFE_FREE(sfile->asset_params); + MEM_SAFE_FREE(sfile->runtime); if (sfile->layout) { MEM_freeN(sfile->layout); @@ -188,6 +189,10 @@ static void file_init(wmWindowManager *UNUSED(wm), ScrArea *area) if (sfile->layout) { sfile->layout->dirty = true; } + + if (sfile->runtime == NULL) { + sfile->runtime = MEM_callocN(sizeof(*sfile->runtime), __func__); + } } static void file_exit(wmWindowManager *wm, ScrArea *area) @@ -209,6 +214,7 @@ static SpaceLink *file_duplicate(SpaceLink *sl) /* clear or remove stuff from old */ sfilen->op = NULL; /* file window doesn't own operators */ + sfilen->runtime = NULL; sfilen->previews_timer = NULL; sfilen->smoothscroll_timer = NULL; @@ -392,6 +398,26 @@ static void file_refresh(const bContext *C, ScrArea *area) ED_area_tag_redraw(area); } +void file_on_reload_callback_register(SpaceFile *sfile, + onReloadFn callback, + onReloadFnData custom_data) +{ + sfile->runtime->on_reload = callback; + sfile->runtime->on_reload_custom_data = custom_data; +} + +static void file_on_reload_callback_call(SpaceFile *sfile) +{ + if (sfile->runtime->on_reload == NULL) { + return; + } + + sfile->runtime->on_reload(sfile, sfile->runtime->on_reload_custom_data); + + sfile->runtime->on_reload = NULL; + sfile->runtime->on_reload_custom_data = NULL; +} + static void file_listener(const wmSpaceTypeListenerParams *params) { ScrArea *area = params->area; @@ -419,12 +445,26 @@ static void file_listener(const wmSpaceTypeListenerParams *params) } break; } + switch (wmn->action) { + case NA_JOB_FINISHED: + file_on_reload_callback_call(sfile); + break; + } break; case NC_ASSET: { - if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { - /* Full refresh of the file list if local asset data was changed. Refreshing this view is - * cheap and users expect this to be updated immediately. */ - file_tag_reset_list(area, sfile); + switch (wmn->action) { + case NA_SELECTED: + case NA_ACTIVATED: + ED_area_tag_refresh(area); + break; + case NA_ADDED: + case NA_REMOVED: + if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { + /* Full refresh of the file list if local asset data was changed. Refreshing this view + * is cheap and users expect this to be updated immediately. */ + file_tag_reset_list(area, sfile); + } + break; } break; } @@ -464,8 +504,7 @@ static void file_main_region_listener(const wmRegionListenerParams *params) } break; case NC_ID: - if (ELEM(wmn->action, NA_RENAME)) { - /* In case the filelist shows ID names. */ + if (ELEM(wmn->action, NA_SELECTED, NA_ACTIVATED, NA_RENAME)) { ED_region_tag_redraw(region); } break; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index dc1775b09c6..856fa569645 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -66,6 +66,9 @@ typedef struct SpaceProperties_Runtime SpaceProperties_Runtime; /* Defined in `node_intern.h`. */ typedef struct SpaceNode_Runtime SpaceNode_Runtime; +/* Defined in `file_intern.h`. */ +typedef struct SpaceFile_Runtime SpaceFile_Runtime; + /* -------------------------------------------------------------------- */ /** \name SpaceLink (Base) * \{ */ @@ -846,6 +849,8 @@ typedef struct SpaceFile { short recentnr, bookmarknr; short systemnr, system_bookmarknr; + + SpaceFile_Runtime *runtime; } SpaceFile; /* SpaceFile.browse_mode (File Space Browsing Mode) */ diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index bfcb0039ca8..95972dd444f 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -424,6 +424,7 @@ void RNA_api_window(struct StructRNA *srna); void RNA_api_wm(struct StructRNA *srna); void RNA_api_space_node(struct StructRNA *srna); void RNA_api_space_text(struct StructRNA *srna); +void RNA_api_space_filebrowser(struct StructRNA *srna); void RNA_api_region_view3d(struct StructRNA *srna); void RNA_api_texture(struct StructRNA *srna); void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastrip); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 409a2f097ed..5312aea9295 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -6569,6 +6569,8 @@ static void rna_def_space_filebrowser(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update( prop, NC_SPACE | ND_SPACE_FILE_PARAMS, "rna_FileBrowser_FSMenu_active_update"); + + RNA_api_space_filebrowser(srna); } static void rna_def_space_info(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c index e4c0ade1533..205a88edf84 100644 --- a/source/blender/makesrna/intern/rna_space_api.c +++ b/source/blender/makesrna/intern/rna_space_api.c @@ -27,6 +27,7 @@ # include "BKE_global.h" +# include "ED_fileselect.h" # include "ED_screen.h" # include "ED_text.h" @@ -115,4 +116,24 @@ void RNA_api_space_text(StructRNA *srna) RNA_def_function_output(func, parm); } +void RNA_api_space_filebrowser(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + func = RNA_def_function(srna, "activate_asset_by_id", "ED_fileselect_activate_by_id"); + RNA_def_function_ui_description(func, "Activate the asset entry that represents the given ID"); + + parm = RNA_def_property(func, "id_to_activate", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(parm, "ID"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + parm = RNA_def_boolean( + func, + "deferred", + 0, + "", + "Whether to activate the ID immediately (false) or after the file browser refreshes (true)"); +} + #endif diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index f12832faa45..084ca2d2df5 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -461,6 +461,7 @@ typedef struct wmNotifier { #define NA_SELECTED 6 #define NA_ACTIVATED 7 #define NA_PAINTING 8 +#define NA_JOB_FINISHED 9 /* ************** Gesture Manager data ************** */ -- cgit v1.2.3 From 8d0fbcd6dfe736f556b4e7f4aaf04536ee192dcb Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 5 Mar 2021 16:09:19 +0100 Subject: Nodes: move vector rotate node to C++ This makes it easier to add an implementation that can be used in Geometry Nodes. There should be no functional changes. --- source/blender/nodes/CMakeLists.txt | 2 +- .../nodes/shader/nodes/node_shader_vector_rotate.c | 80 ------------------ .../shader/nodes/node_shader_vector_rotate.cc | 94 ++++++++++++++++++++++ 3 files changed, 95 insertions(+), 81 deletions(-) delete mode 100644 source/blender/nodes/shader/nodes/node_shader_vector_rotate.c create mode 100644 source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 50e29d4a447..e21959d839c 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -259,7 +259,7 @@ set(SRC shader/nodes/node_shader_vectTransform.c shader/nodes/node_shader_vector_displacement.c shader/nodes/node_shader_vector_math.cc - shader/nodes/node_shader_vector_rotate.c + shader/nodes/node_shader_vector_rotate.cc shader/nodes/node_shader_vertex_color.c shader/nodes/node_shader_volume_absorption.c shader/nodes/node_shader_volume_info.c diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c deleted file mode 100644 index b2132c59cde..00000000000 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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) 2013 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup shdnodes - */ - -#include "../node_shader_util.h" - -/* **************** Vector Rotate ******************** */ -static bNodeSocketTemplate sh_node_vector_rotate_in[] = { - {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, - {SOCK_VECTOR, N_("Center"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE}, - {SOCK_VECTOR, N_("Axis"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, PROP_NONE}, - {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_ANGLE, PROP_NONE}, - {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER}, - {-1, ""}}; - -static bNodeSocketTemplate sh_node_vector_rotate_out[] = {{SOCK_VECTOR, N_("Vector")}, {-1, ""}}; - -static int gpu_shader_vector_rotate(GPUMaterial *mat, - bNode *node, - bNodeExecData *UNUSED(execdata), - GPUNodeStack *in, - GPUNodeStack *out) -{ - - static const char *names[] = { - [NODE_VECTOR_ROTATE_TYPE_AXIS] = "node_vector_rotate_axis_angle", - [NODE_VECTOR_ROTATE_TYPE_AXIS_X] = "node_vector_rotate_axis_x", - [NODE_VECTOR_ROTATE_TYPE_AXIS_Y] = "node_vector_rotate_axis_y", - [NODE_VECTOR_ROTATE_TYPE_AXIS_Z] = "node_vector_rotate_axis_z", - [NODE_VECTOR_ROTATE_TYPE_EULER_XYZ] = "node_vector_rotate_euler_xyz", - }; - - if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) { - float invert = (node->custom2) ? -1.0 : 1.0; - return GPU_stack_link(mat, node, names[node->custom1], in, out, GPU_constant(&invert)); - } - - return 0; -} - -static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node) -{ - bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation"); - nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); - bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis"); - nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS)); - bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle"); - nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); -} - -void register_node_type_sh_vector_rotate(void) -{ - static bNodeType ntype; - - sh_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, sh_node_vector_rotate_in, sh_node_vector_rotate_out); - node_type_gpu(&ntype, gpu_shader_vector_rotate); - node_type_update(&ntype, node_shader_update_vector_rotate); - - nodeRegisterType(&ntype); -} diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc new file mode 100644 index 00000000000..d6ead5a8b99 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -0,0 +1,94 @@ +/* + * 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) 2013 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup shdnodes + */ + +#include "../node_shader_util.h" + +/* **************** Vector Rotate ******************** */ +static bNodeSocketTemplate sh_node_vector_rotate_in[] = { + {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + {SOCK_VECTOR, N_("Center"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE}, + {SOCK_VECTOR, N_("Axis"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, PROP_NONE}, + {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_ANGLE, PROP_NONE}, + {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER}, + {-1, ""}}; + +static bNodeSocketTemplate sh_node_vector_rotate_out[] = { + {SOCK_VECTOR, N_("Vector")}, + {-1, ""}, +}; + +static const char *gpu_shader_get_name(int mode) +{ + switch (mode) { + case NODE_VECTOR_ROTATE_TYPE_AXIS: + return "node_vector_rotate_axis_angle"; + case NODE_VECTOR_ROTATE_TYPE_AXIS_X: + return "node_vector_rotate_axis_x"; + case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: + return "node_vector_rotate_axis_y"; + case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: + return "node_vector_rotate_axis_z"; + case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: + return "node_vector_rotate_euler_xyz"; + } + + return nullptr; +} + +static int gpu_shader_vector_rotate(GPUMaterial *mat, + bNode *node, + bNodeExecData *UNUSED(execdata), + GPUNodeStack *in, + GPUNodeStack *out) +{ + const char *name = gpu_shader_get_name(node->custom1); + + if (name != nullptr) { + float invert = (node->custom2) ? -1.0 : 1.0; + return GPU_stack_link(mat, node, name, in, out, GPU_constant(&invert)); + } + + return 0; +} + +static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation"); + nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); + bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis"); + nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS)); + bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle"); + nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); +} + +void register_node_type_sh_vector_rotate(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0); + node_type_socket_templates(&ntype, sh_node_vector_rotate_in, sh_node_vector_rotate_out); + node_type_gpu(&ntype, gpu_shader_vector_rotate); + node_type_update(&ntype, node_shader_update_vector_rotate); + + nodeRegisterType(&ntype); +} -- cgit v1.2.3 From bf030decd42fd9eb35f59a5b724d87403917bc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 5 Mar 2021 16:35:08 +0100 Subject: Animation: add function to apply a pose from an Action Add `BKE_pose_apply_action(object, action, anim_eval_context)` function and expose in RNA as `Pose.apply_action(action, evaluation_time)`. This makes it possible to do the following: - Have a rig in pose mode. - Select a subset of the bones. - Have some Action loaded that contains the pose you want to apply. - Run `C.object.pose.apply_pose_from_action(D.actions['PoseName'])` - The selected bones are now posed as determined by the Action. Just like Blender's current pose library, having no bones selected acts the same as having all bones selected. Manifest Task: T86159 Reviewed By: Severin Differential Revision: https://developer.blender.org/D10578 --- source/blender/blenkernel/BKE_armature.h | 8 ++ source/blender/blenkernel/CMakeLists.txt | 1 + source/blender/blenkernel/intern/armature_pose.cc | 133 ++++++++++++++++++++++ source/blender/makesrna/intern/rna_pose_api.c | 52 ++++++++- 4 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 source/blender/blenkernel/intern/armature_pose.cc diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index db44a771095..f5face2120e 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -27,6 +27,8 @@ extern "C" { #endif +struct AnimationEvalContext; +struct bAction; struct BMEditMesh; struct Bone; struct Depsgraph; @@ -193,6 +195,12 @@ void BKE_pose_where_is_bone(struct Depsgraph *depsgraph, bool do_extra); void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan); +/* Evaluate the action and apply it to the pose. If any pose bones are selected, only FCurves that + * relate to those bones are evaluated. */ +void BKE_pose_apply_action(struct Object *ob, + struct bAction *action, + struct AnimationEvalContext *anim_eval_context); + /* get_objectspace_bone_matrix has to be removed still */ void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4][4], diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 1e7986eedd9..c954d0670f0 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -77,6 +77,7 @@ set(SRC intern/appdir.c intern/armature.c intern/armature_deform.c + intern/armature_pose.cc intern/armature_update.c intern/asset.cc intern/attribute.c diff --git a/source/blender/blenkernel/intern/armature_pose.cc b/source/blender/blenkernel/intern/armature_pose.cc new file mode 100644 index 00000000000..a9613da2335 --- /dev/null +++ b/source/blender/blenkernel/intern/armature_pose.cc @@ -0,0 +1,133 @@ +/* + * 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 Blender Foundation. + * All rights reserved. + * + * Defines and code for core node types + */ + +/** \file + * \ingroup bke + */ + +#include "BKE_animsys.h" +#include "BKE_armature.h" + +#include "BLI_set.hh" + +#include "DNA_action_types.h" +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_object_types.h" + +#include "RNA_access.h" + +namespace { +using BoneNameSet = blender::Set; + +// Forward declarations. +BoneNameSet pose_apply_find_selected_bones(const bPose *pose); +void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, + const BoneNameSet &selected_bone_names); +void pose_apply_restore_fcurves(bAction *action); +} // namespace + +void BKE_pose_apply_action(struct Object *ob, + struct bAction *action, + struct AnimationEvalContext *anim_eval_context) +{ + bPose *pose = ob->pose; + if (pose == NULL) { + return; + } + + const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(pose); + const bool limit_to_selected_bones = !selected_bone_names.is_empty(); + + if (limit_to_selected_bones) { + /* Mute all FCurves that are not associated with selected bones. This separates the concept of + * bone selection from the FCurve evaluation code. */ + pose_apply_disable_fcurves_for_unselected_bones(action, selected_bone_names); + } + + /* Apply the Action. */ + PointerRNA pose_owner_ptr; + RNA_id_pointer_create(&ob->id, &pose_owner_ptr); + animsys_evaluate_action(&pose_owner_ptr, action, anim_eval_context, false); + + if (limit_to_selected_bones) { + pose_apply_restore_fcurves(action); + } +} + +namespace { +BoneNameSet pose_apply_find_selected_bones(const bPose *pose) +{ + BoneNameSet selected_bone_names; + bool all_bones_selected = true; + bool no_bones_selected = true; + + LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { + const bool is_selected = (pchan->bone->flag & BONE_SELECTED) != 0 && + (pchan->bone->flag & BONE_HIDDEN_P) == 0; + all_bones_selected &= is_selected; + no_bones_selected &= !is_selected; + + if (is_selected) { + /* Bone names are unique, so no need to check for duplicates. */ + selected_bone_names.add_new(pchan->name); + } + } + + /* If no bones are selected, act as if all are. */ + if (all_bones_selected || no_bones_selected) { + return BoneNameSet(); /* An empty set means "ignore bone selection". */ + } + return selected_bone_names; +} + +void pose_apply_restore_fcurves(bAction *action) +{ + /* TODO(Sybren): Restore the FCurve flags, instead of just erasing the 'disabled' flag. */ + LISTBASE_FOREACH (FCurve *, fcu, &action->curves) { + fcu->flag &= ~FCURVE_DISABLED; + } +} + +void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, + const BoneNameSet &selected_bone_names) +{ + LISTBASE_FOREACH (FCurve *, fcu, &action->curves) { + if (!fcu->rna_path || !strstr(fcu->rna_path, "pose.bones[")) { + continue; + } + + /* Get bone name, and check if this bone is selected. */ + char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); + if (!bone_name) { + continue; + } + const bool is_selected = selected_bone_names.contains(bone_name); + MEM_freeN(bone_name); + if (is_selected) { + continue; + } + + fcu->flag |= FCURVE_DISABLED; + } +} + +} // namespace diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c index 59704b00391..d93972aa0ad 100644 --- a/source/blender/makesrna/intern/rna_pose_api.c +++ b/source/blender/makesrna/intern/rna_pose_api.c @@ -38,9 +38,14 @@ #ifdef RNA_RUNTIME -/* #include "DNA_anim_types.h" */ +# include "BKE_animsys.h" # include "BKE_armature.h" -# include "DNA_action_types.h" /* bPose */ +# include "BKE_context.h" + +# include "DNA_action_types.h" +# include "DNA_anim_types.h" + +# include "BLI_ghash.h" static float rna_PoseBone_do_envelope(bPoseChannel *chan, float *vec) { @@ -102,12 +107,49 @@ static void rna_PoseBone_compute_bbone_handles(bPoseChannel *pchan, BKE_pchan_bbone_handles_compute( ¶ms, ret_h1, ret_roll1, ret_h2, ret_roll2, ease || offsets, offsets); } + +static void rna_Pose_apply_pose_from_action(ID *pose_owner, + bContext *C, + bAction *action, + const float evaluation_time) +{ + BLI_assert(GS(pose_owner->name) == ID_OB); + Object *pose_owner_ob = (Object *)pose_owner; + + AnimationEvalContext anim_eval_context = {CTX_data_depsgraph_pointer(C), evaluation_time}; + BKE_pose_apply_action(pose_owner_ob, action, &anim_eval_context); + + /* Do NOT tag with ID_RECALC_ANIMATION, as that would overwrite the just-applied pose. */ + DEG_id_tag_update(pose_owner, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pose_owner); +} + #else -void RNA_api_pose(StructRNA *UNUSED(srna)) +void RNA_api_pose(StructRNA *srna) { - /* FunctionRNA *func; */ - /* PropertyRNA *parm; */ + FunctionRNA *func; + PropertyRNA *parm; + + func = RNA_def_function(srna, "apply_pose_from_action", "rna_Pose_apply_pose_from_action"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT); + RNA_def_function_ui_description( + func, + "Apply the given action to this pose by evaluating it at a specific time. Only updates the " + "pose of selected bones, or all bones if none are selected"); + + parm = RNA_def_pointer(func, "action", "Action", "Action", "The Action containing the pose"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + parm = RNA_def_float(func, + "evaluation_time", + 0.0f, + -FLT_MAX, + FLT_MAX, + "Evaluation Time", + "Time at which the given action is evaluated to obtain the pose", + -FLT_MAX, + FLT_MAX); } void RNA_api_pose_channel(StructRNA *srna) -- cgit v1.2.3 From 3d3a5bb89240ef160d2a63da85eae937eb578e53 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 14:15:43 +0100 Subject: Cleanup: Remove using statements. --- source/blender/compositor/intern/COM_ExecutionGroup.cpp | 6 +++--- source/blender/compositor/intern/COM_ExecutionGroup.h | 4 +--- source/blender/compositor/intern/COM_ExecutionSystem.cpp | 8 ++++---- source/blender/compositor/intern/COM_ExecutionSystem.h | 4 ++-- source/blender/compositor/intern/COM_NodeOperationBuilder.h | 2 -- source/blender/compositor/intern/COM_WorkScheduler.cpp | 4 ++-- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index 9c21c91c370..bc0dd4f4ad2 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -374,7 +374,7 @@ void ExecutionGroup::execute(ExecutionSystem *graph) MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber) { rcti rect; - vector memoryproxies; + std::vector memoryproxies; unsigned int index; determineChunkRect(&rect, chunkNumber); @@ -545,7 +545,7 @@ bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChun } // chunk is nor executed nor scheduled. - vector memoryProxies; + std::vector memoryProxies; this->determineDependingMemoryProxies(&memoryProxies); rcti rect; @@ -586,7 +586,7 @@ void ExecutionGroup::determineDependingAreaOfInterest(rcti *input, this->getOutputOperation()->determineDependingAreaOfInterest(input, readOperation, output); } -void ExecutionGroup::determineDependingMemoryProxies(vector *memoryProxies) +void ExecutionGroup::determineDependingMemoryProxies(std::vector *memoryProxies) { unsigned int index; for (index = 0; index < this->m_cachedReadOperations.size(); index++) { diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h index dd079415d09..a311d2681d4 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.h +++ b/source/blender/compositor/intern/COM_ExecutionGroup.h @@ -30,8 +30,6 @@ #include "COM_NodeOperation.h" #include -using std::vector; - class ExecutionSystem; class MemoryProxy; class ReadBufferOperation; @@ -405,7 +403,7 @@ class ExecutionGroup { * \note the area of the MemoryProxy.creator that has to be executed. * \param memoryProxies: result */ - void determineDependingMemoryProxies(vector *memoryProxies); + void determineDependingMemoryProxies(std::vector *memoryProxies); /** * \brief Determine the rect (minx, maxx, miny, maxy) of a chunk. diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp index 4c0c7d2103e..6fbcd4259c9 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp @@ -135,7 +135,7 @@ void ExecutionSystem::execute() DebugInfo::execute_started(this); unsigned int order = 0; - for (vector::iterator iter = this->m_operations.begin(); + for (std::vector::iterator iter = this->m_operations.begin(); iter != this->m_operations.end(); ++iter) { NodeOperation *operation = *iter; @@ -202,7 +202,7 @@ void ExecutionSystem::execute() void ExecutionSystem::executeGroups(CompositorPriority priority) { unsigned int index; - vector executionGroups; + std::vector executionGroups; this->findOutputExecutionGroup(&executionGroups, priority); for (index = 0; index < executionGroups.size(); index++) { @@ -211,7 +211,7 @@ void ExecutionSystem::executeGroups(CompositorPriority priority) } } -void ExecutionSystem::findOutputExecutionGroup(vector *result, +void ExecutionSystem::findOutputExecutionGroup(std::vector *result, CompositorPriority priority) const { unsigned int index; @@ -223,7 +223,7 @@ void ExecutionSystem::findOutputExecutionGroup(vector *result, } } -void ExecutionSystem::findOutputExecutionGroup(vector *result) const +void ExecutionSystem::findOutputExecutionGroup(std::vector *result) const { unsigned int index; for (index = 0; index < this->m_groups.size(); index++) { diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index d03f9b86bb6..d18125ebc50 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -137,13 +137,13 @@ class ExecutionSystem { /** * find all execution group with output nodes */ - void findOutputExecutionGroup(vector *result, + void findOutputExecutionGroup(std::vector *result, CompositorPriority priority) const; /** * find all execution group with output nodes */ - void findOutputExecutionGroup(vector *result) const; + void findOutputExecutionGroup(std::vector *result) const; public: /** diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h index 5dd4022b127..0d362af4512 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h @@ -24,8 +24,6 @@ #include "COM_NodeGraph.h" -using std::vector; - class CompositorContext; class Node; diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp index 9ca704afdea..a70b6ba4abe 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.cpp +++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp @@ -48,7 +48,7 @@ static ThreadLocal(CPUDevice *) g_thread_device; static struct { /** \brief list of all CPUDevices. for every hardware thread an instance of CPUDevice is created */ - vector cpu_devices; + std::vector cpu_devices; #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE /** \brief list of all thread for every CPUDevice in cpudevices a thread exists. */ @@ -62,7 +62,7 @@ static struct { cl_program opencl_program; /** \brief list of all OpenCLDevices. for every OpenCL GPU device an instance of OpenCLDevice is * created. */ - vector gpu_devices; + std::vector gpu_devices; /** \brief list of all thread for every GPUDevice in cpudevices a thread exists. */ ListBase gpu_threads; /** \brief all scheduled work for the GPU. */ -- cgit v1.2.3 From ba5961b4cda402389c7c3092a1bd092d9fd98bb2 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 14:54:32 +0100 Subject: Cleanup: use MIN2/MAX2 in compositor. --- .../compositor/intern/COM_ExecutionGroup.cpp | 14 ++-- .../blender/compositor/intern/COM_MemoryBuffer.cpp | 11 +-- .../compositor/intern/COM_NodeOperation.cpp | 8 +- .../blender/compositor/intern/COM_NodeOperation.h | 8 +- .../blender/compositor/intern/COM_OpenCLDevice.cpp | 6 +- .../blender/compositor/intern/COM_OpenCLDevice.h | 8 +- .../compositor/nodes/COM_SwitchViewNode.cpp | 2 +- .../operations/COM_BokehBlurOperation.cpp | 22 ++--- .../compositor/operations/COM_BokehBlurOperation.h | 4 +- .../compositor/operations/COM_BoxMaskOperation.cpp | 2 +- .../operations/COM_ChannelMatteOperation.cpp | 4 +- .../operations/COM_ChannelMatteOperation.h | 4 +- .../operations/COM_ColorBalanceASCCDLOperation.cpp | 2 +- .../operations/COM_ColorBalanceLGGOperation.cpp | 2 +- .../operations/COM_ColorCorrectionOperation.cpp | 2 +- .../operations/COM_ColorSpillOperation.cpp | 2 +- .../COM_ConvertDepthToRadiusOperation.cpp | 6 +- .../COM_ConvolutionEdgeFilterOperation.cpp | 8 +- .../operations/COM_ConvolutionFilterOperation.cpp | 8 +- .../compositor/operations/COM_CropOperation.cpp | 8 +- .../operations/COM_DilateErodeOperation.cpp | 96 +++++++++++----------- .../operations/COM_DilateErodeOperation.h | 8 +- .../operations/COM_DirectionalBlurOperation.cpp | 4 +- .../operations/COM_DirectionalBlurOperation.h | 4 +- .../operations/COM_EllipseMaskOperation.cpp | 2 +- .../operations/COM_FastGaussianBlurOperation.cpp | 2 +- .../operations/COM_GaussianBokehBlurOperation.cpp | 4 +- .../operations/COM_GaussianXBlurOperation.cpp | 4 +- .../operations/COM_GaussianXBlurOperation.h | 4 +- .../operations/COM_GaussianYBlurOperation.cpp | 4 +- .../operations/COM_GaussianYBlurOperation.h | 4 +- .../operations/COM_GlareThresholdOperation.cpp | 6 +- .../operations/COM_KeyingBlurOperation.cpp | 6 +- .../operations/COM_KeyingDespillOperation.cpp | 4 +- .../compositor/operations/COM_KeyingOperation.cpp | 4 +- .../operations/COM_LuminanceMatteOperation.cpp | 2 +- .../compositor/operations/COM_MaskOperation.h | 2 +- .../operations/COM_MathBaseOperation.cpp | 4 +- .../compositor/operations/COM_MixOperation.cpp | 6 +- .../compositor/operations/COM_OpenCLKernels.cl | 38 ++++----- .../compositor/operations/COM_RotateOperation.cpp | 8 +- .../operations/COM_SunBeamsOperation.cpp | 2 +- .../compositor/operations/COM_TonemapOperation.cpp | 6 +- .../COM_VariableSizeBokehBlurOperation.cpp | 22 ++--- .../COM_VariableSizeBokehBlurOperation.h | 4 +- .../operations/COM_WriteBufferOperation.cpp | 4 +- .../operations/COM_ZCombineOperation.cpp | 4 +- 47 files changed, 191 insertions(+), 198 deletions(-) diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index bc0dd4f4ad2..dc12248899d 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -143,7 +143,7 @@ void ExecutionGroup::initExecution() if (operation->isReadBufferOperation()) { ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; this->m_cachedReadOperations.push_back(readOperation); - maxNumber = max(maxNumber, readOperation->getOffset()); + maxNumber = MAX2(maxNumber, readOperation->getOffset()); } } maxNumber++; @@ -452,13 +452,13 @@ inline void ExecutionGroup::determineChunkRect(rcti *rect, else { const unsigned int minx = xChunk * this->m_chunkSize + this->m_viewerBorder.xmin; const unsigned int miny = yChunk * this->m_chunkSize + this->m_viewerBorder.ymin; - const unsigned int width = min((unsigned int)this->m_viewerBorder.xmax, this->m_width); - const unsigned int height = min((unsigned int)this->m_viewerBorder.ymax, this->m_height); + const unsigned int width = MIN2((unsigned int)this->m_viewerBorder.xmax, this->m_width); + const unsigned int height = MIN2((unsigned int)this->m_viewerBorder.ymax, this->m_height); BLI_rcti_init(rect, - min(minx, this->m_width), - min(minx + this->m_chunkSize, width), - min(miny, this->m_height), - min(miny + this->m_chunkSize, height)); + MIN2(minx, this->m_width), + MIN2(minx + this->m_chunkSize, width), + MIN2(miny, this->m_height), + MIN2(miny + this->m_chunkSize, height)); } } diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cpp index a13db6bb09e..17a73efeab2 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cpp @@ -20,9 +20,6 @@ #include "MEM_guardedalloc.h" -using std::max; -using std::min; - static unsigned int determine_num_channels(DataType datatype) { switch (datatype) { @@ -156,10 +153,10 @@ void MemoryBuffer::copyContentFrom(MemoryBuffer *otherBuffer) return; } unsigned int otherY; - unsigned int minX = max(this->m_rect.xmin, otherBuffer->m_rect.xmin); - unsigned int maxX = min(this->m_rect.xmax, otherBuffer->m_rect.xmax); - unsigned int minY = max(this->m_rect.ymin, otherBuffer->m_rect.ymin); - unsigned int maxY = min(this->m_rect.ymax, otherBuffer->m_rect.ymax); + unsigned int minX = MAX2(this->m_rect.xmin, otherBuffer->m_rect.xmin); + unsigned int maxX = MIN2(this->m_rect.xmax, otherBuffer->m_rect.xmax); + unsigned int minY = MAX2(this->m_rect.ymin, otherBuffer->m_rect.ymin); + unsigned int maxY = MIN2(this->m_rect.ymax, otherBuffer->m_rect.ymax); int offset; int otherOffset; diff --git a/source/blender/compositor/intern/COM_NodeOperation.cpp b/source/blender/compositor/intern/COM_NodeOperation.cpp index 1a30806f28c..ce7d3a6389e 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.cpp +++ b/source/blender/compositor/intern/COM_NodeOperation.cpp @@ -182,10 +182,10 @@ bool NodeOperation::determineDependingAreaOfInterest(rcti *input, first = false; } else { - output->xmin = min(output->xmin, tempOutput.xmin); - output->ymin = min(output->ymin, tempOutput.ymin); - output->xmax = max(output->xmax, tempOutput.xmax); - output->ymax = max(output->ymax, tempOutput.ymax); + output->xmin = MIN2(output->xmin, tempOutput.xmin); + output->ymin = MIN2(output->ymin, tempOutput.ymin); + output->xmax = MAX2(output->xmax, tempOutput.xmax); + output->ymax = MAX2(output->ymax, tempOutput.ymax); } } } diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index 0ce7c1389bd..f26279e2869 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -33,10 +33,6 @@ #include "clew.h" -using std::list; -using std::max; -using std::min; - class OpenCLDevice; class ReadBufferOperation; class WriteBufferOperation; @@ -239,8 +235,8 @@ class NodeOperation : public SocketReader { MemoryBuffer * /*outputMemoryBuffer*/, cl_mem /*clOutputBuffer*/, MemoryBuffer ** /*inputMemoryBuffers*/, - list * /*clMemToCleanUp*/, - list * /*clKernelsToCleanUp*/) + std::list * /*clMemToCleanUp*/, + std::list * /*clKernelsToCleanUp*/) { } virtual void deinitExecution(); diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp index acfe800e433..2082c87da8c 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp +++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp @@ -79,7 +79,7 @@ void OpenCLDevice::execute(WorkPackage *work) cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list *cleanup, + std::list *cleanup, MemoryBuffer **inputMemoryBuffers, SocketReader *reader) { @@ -111,7 +111,7 @@ const cl_image_format *OpenCLDevice::determineImageFormat(MemoryBuffer *memoryBu cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list *cleanup, + std::list *cleanup, MemoryBuffer **inputMemoryBuffers, ReadBufferOperation *reader) { @@ -258,7 +258,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, } cl_kernel OpenCLDevice::COM_clCreateKernel(const char *kernelname, - list *clKernelsToCleanUp) + std::list *clKernelsToCleanUp) { cl_int error; cl_kernel kernel = clCreateKernel(this->m_program, kernelname, &error); diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h index d502f5aa34b..e4fd397b4e8 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.h +++ b/source/blender/compositor/intern/COM_OpenCLDevice.h @@ -25,8 +25,6 @@ class OpenCLDevice; #include "COM_WorkScheduler.h" #include "clew.h" -using std::list; - /** * \brief device representing an GPU OpenCL device. * an instance of this class represents a single cl_device @@ -107,13 +105,13 @@ class OpenCLDevice : public Device { cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list *cleanup, + std::list *cleanup, MemoryBuffer **inputMemoryBuffers, SocketReader *reader); cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list *cleanup, + std::list *cleanup, MemoryBuffer **inputMemoryBuffers, ReadBufferOperation *reader); void COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel kernel, @@ -130,5 +128,5 @@ class OpenCLDevice : public Device { MemoryBuffer *outputMemoryBuffer, int offsetIndex, NodeOperation *operation); - cl_kernel COM_clCreateKernel(const char *kernelname, list *clKernelsToCleanUp); + cl_kernel COM_clCreateKernel(const char *kernelname, std::list *clKernelsToCleanUp); }; diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp b/source/blender/compositor/nodes/COM_SwitchViewNode.cpp index e4a946e2e9d..e534ebfac9a 100644 --- a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp +++ b/source/blender/compositor/nodes/COM_SwitchViewNode.cpp @@ -33,7 +33,7 @@ void SwitchViewNode::convertToOperations(NodeConverter &converter, /* 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); + nr = MAX2(nr, 0); result = converter.addInputProxy(getInputSocket(nr), false); converter.mapOutputSocket(getOutputSocket(0), result); diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp index f7b7816e1a1..a8ad2a11790 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp @@ -62,7 +62,7 @@ void BokehBlurOperation::initExecution() int width = this->m_inputBokehProgram->getWidth(); int height = this->m_inputBokehProgram->getHeight(); - float dimension = min(width, height); + float dimension = MIN2(width, height); this->m_bokehMidX = width / 2.0f; this->m_bokehMidY = height / 2.0f; @@ -84,7 +84,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) int bufferwidth = inputBuffer->getWidth(); int bufferstartx = inputBuffer->getRect()->xmin; int bufferstarty = inputBuffer->getRect()->ymin; - const float max_dim = max(this->getWidth(), this->getHeight()); + const float max_dim = MAX2(this->getWidth(), this->getHeight()); int pixelSize = this->m_size * max_dim / 100.0f; zero_v4(color_accum); @@ -99,10 +99,10 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) int maxy = y + pixelSize; int minx = x - pixelSize; int maxx = x + pixelSize; - miny = max(miny, inputBuffer->getRect()->ymin); - minx = max(minx, inputBuffer->getRect()->xmin); - maxy = min(maxy, inputBuffer->getRect()->ymax); - maxx = min(maxx, inputBuffer->getRect()->xmax); + miny = MAX2(miny, inputBuffer->getRect()->ymin); + minx = MAX2(minx, inputBuffer->getRect()->xmin); + maxy = MIN2(maxy, inputBuffer->getRect()->ymax); + maxx = MIN2(maxx, inputBuffer->getRect()->xmax); int step = getStep(); int offsetadd = getOffsetAdd() * COM_NUM_CHANNELS_COLOR; @@ -144,7 +144,7 @@ bool BokehBlurOperation::determineDependingAreaOfInterest(rcti *input, { rcti newInput; rcti bokehInput; - const float max_dim = max(this->getWidth(), this->getHeight()); + const float max_dim = MAX2(this->getWidth(), this->getHeight()); if (this->m_sizeavailable) { newInput.xmax = input->xmax + (this->m_size * max_dim / 100.0f); @@ -193,14 +193,14 @@ void BokehBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list * /*clKernelsToCleanUp*/) + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) { cl_kernel kernel = device->COM_clCreateKernel("bokehBlurKernel", nullptr); if (!this->m_sizeavailable) { updateSize(); } - const float max_dim = max(this->getWidth(), this->getHeight()); + const float max_dim = MAX2(this->getWidth(), this->getHeight()); cl_int radius = this->m_size * max_dim / 100.0f; cl_int step = this->getStep(); @@ -235,7 +235,7 @@ void BokehBlurOperation::determineResolution(unsigned int resolution[2], { NodeOperation::determineResolution(resolution, preferredResolution); if (this->m_extend_bounds) { - const float max_dim = max(resolution[0], resolution[1]); + const float max_dim = MAX2(resolution[0], resolution[1]); resolution[0] += 2 * this->m_size * max_dim / 100.0f; resolution[1] += 2 * this->m_size * max_dim / 100.0f; } diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.h b/source/blender/compositor/operations/COM_BokehBlurOperation.h index 335574a381d..a2e320dfdad 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.h @@ -67,8 +67,8 @@ class BokehBlurOperation : public NodeOperation, public QualityStepHelper { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list *clKernelsToCleanUp); + std::list *clMemToCleanUp, + std::list *clKernelsToCleanUp); void setExtendBounds(bool extend_bounds) { diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp b/source/blender/compositor/operations/COM_BoxMaskOperation.cpp index 662b08bdee9..bb10f3425e2 100644 --- a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_BoxMaskOperation.cpp @@ -64,7 +64,7 @@ void BoxMaskOperation::executePixelSampled(float output[4], float x, float y, Pi switch (this->m_maskType) { case CMP_NODE_MASKTYPE_ADD: if (inside) { - output[0] = max(inputMask[0], inputValue[0]); + output[0] = MAX2(inputMask[0], inputValue[0]); } else { output[0] = inputMask[0]; diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp b/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp index a2c6fd47771..15375589888 100644 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp @@ -95,7 +95,7 @@ void ChannelMatteOperation::executePixelSampled(float output[4], this->m_inputImageProgram->readSampled(inColor, x, y, sampler); /* matte operation */ - alpha = inColor[this->m_ids[0]] - max(inColor[this->m_ids[1]], inColor[this->m_ids[2]]); + alpha = inColor[this->m_ids[0]] - MAX2(inColor[this->m_ids[1]], inColor[this->m_ids[2]]); /* flip because 0.0 is transparent, not 1.0 */ alpha = 1.0f - alpha; @@ -116,5 +116,5 @@ void ChannelMatteOperation::executePixelSampled(float output[4], */ /* Don't make something that was more transparent less transparent. */ - output[0] = min(alpha, inColor[3]); + output[0] = MIN2(alpha, inColor[3]); } diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.h b/source/blender/compositor/operations/COM_ChannelMatteOperation.h index 24a5e03a1bf..9a0b888b5a2 100644 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.h +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.h @@ -38,12 +38,12 @@ class ChannelMatteOperation : public NodeOperation { float m_limit_range; /** ids to use for the operations (max and simple) - * alpha = in[ids[0]] - max(in[ids[1]], in[ids[2]]) + * alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]]) * the simple operation is using: * alpha = in[ids[0]] - in[ids[1]] * but to use the same formula and operation for both we do: * ids[2] = ids[1] - * alpha = in[ids[0]] - max(in[ids[1]], in[ids[2]]) + * alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]]) */ int m_ids[3]; diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp index f9eaaf6f7a0..44eef1e19cd 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp @@ -59,7 +59,7 @@ void ColorBalanceASCCDLOperation::executePixelSampled(float output[4], this->m_inputColorOperation->readSampled(inputColor, x, y, sampler); float fac = value[0]; - fac = min(1.0f, fac); + fac = MIN2(1.0f, fac); const float mfac = 1.0f - fac; output[0] = mfac * inputColor[0] + diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp index df44e87a86a..934b7e51aee 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp @@ -64,7 +64,7 @@ void ColorBalanceLGGOperation::executePixelSampled(float output[4], this->m_inputColorOperation->readSampled(inputColor, x, y, sampler); float fac = value[0]; - fac = min(1.0f, fac); + fac = MIN2(1.0f, fac); const float mfac = 1.0f - fac; output[0] = mfac * inputColor[0] + diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp index 60343c28662..02c109e8acd 100644 --- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp @@ -66,7 +66,7 @@ void ColorCorrectionOperation::executePixelSampled(float output[4], float r, g, b; float value = inputMask[0]; - value = min(1.0f, value); + value = MIN2(1.0f, value); const float mvalue = 1.0f - value; float levelShadows = 0.0; diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp b/source/blender/compositor/operations/COM_ColorSpillOperation.cpp index 050792d8dab..8139d71c637 100644 --- a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorSpillOperation.cpp @@ -90,7 +90,7 @@ void ColorSpillOperation::executePixelSampled(float output[4], float input[4]; this->m_inputFacReader->readSampled(fac, x, y, sampler); this->m_inputImageReader->readSampled(input, x, y, sampler); - float rfac = min(1.0f, fac[0]); + float rfac = MIN2(1.0f, fac[0]); float map; switch (this->m_spillMethod) { diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp index fe395ecae9e..abf423cc48a 100644 --- a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp @@ -63,13 +63,13 @@ void ConvertDepthToRadiusOperation::initExecution() (this->getHeight() / (float)this->getWidth()) : (this->getWidth() / (float)this->getHeight()); this->m_aperture = 0.5f * (this->m_cam_lens / (this->m_aspect * cam_sensor)) / this->m_fStop; - const float minsz = min(getWidth(), getHeight()); + const float minsz = MIN2(getWidth(), getHeight()); this->m_dof_sp = minsz / ((cam_sensor / 2.0f) / - this->m_cam_lens); // <- == aspect * min(img->x, img->y) / tan(0.5f * fov); + this->m_cam_lens); // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov); if (this->m_blurPostOperation) { - m_blurPostOperation->setSigma(min(m_aperture * 128.0f, this->m_maxRadius)); + m_blurPostOperation->setSigma(MIN2(m_aperture * 128.0f, this->m_maxRadius)); } } diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp index 1c2570cd251..a5f2ae404e3 100644 --- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp @@ -92,8 +92,8 @@ void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, output[3] = in2[3]; /* Make sure we don't return negative color. */ - output[0] = max(output[0], 0.0f); - output[1] = max(output[1], 0.0f); - output[2] = max(output[2], 0.0f); - output[3] = max(output[3], 0.0f); + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); + output[3] = MAX2(output[3], 0.0f); } diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp index 7e35f6fb4f6..425e87ffa7e 100644 --- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp @@ -105,10 +105,10 @@ void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, voi output[3] = output[3] * value[0] + in2[3] * mval; /* Make sure we don't return negative color. */ - output[0] = max(output[0], 0.0f); - output[1] = max(output[1], 0.0f); - output[2] = max(output[2], 0.0f); - output[3] = max(output[3], 0.0f); + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); + output[3] = MAX2(output[3], 0.0f); } bool ConvolutionFilterOperation::determineDependingAreaOfInterest( diff --git a/source/blender/compositor/operations/COM_CropOperation.cpp b/source/blender/compositor/operations/COM_CropOperation.cpp index 408f588871e..9364557169c 100644 --- a/source/blender/compositor/operations/COM_CropOperation.cpp +++ b/source/blender/compositor/operations/COM_CropOperation.cpp @@ -54,10 +54,10 @@ void CropBaseOperation::updateArea() local_settings.y2 = height - 1; } - this->m_xmax = max(local_settings.x1, local_settings.x2) + 1; - this->m_xmin = min(local_settings.x1, local_settings.x2); - this->m_ymax = max(local_settings.y1, local_settings.y2) + 1; - this->m_ymin = min(local_settings.y1, local_settings.y2); + this->m_xmax = MAX2(local_settings.x1, local_settings.x2) + 1; + this->m_xmin = MIN2(local_settings.x1, local_settings.x2); + this->m_ymax = MAX2(local_settings.y1, local_settings.y2) + 1; + this->m_ymin = MIN2(local_settings.y1, local_settings.y2); } else { this->m_xmax = 0; diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp index b2dfb558028..fbe9fe8ea27 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp @@ -41,7 +41,7 @@ void DilateErodeThresholdOperation::initExecution() } else { if (this->m_inset * 2 > this->m_distance) { - this->m_scope = max(this->m_inset * 2 - this->m_distance, this->m_distance); + this->m_scope = MAX2(this->m_inset * 2 - this->m_distance, this->m_distance); } else { this->m_scope = this->m_distance; @@ -71,10 +71,10 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); rcti *rect = inputBuffer->getRect(); - const int minx = max(x - this->m_scope, rect->xmin); - const int miny = max(y - this->m_scope, rect->ymin); - const int maxx = min(x + this->m_scope, rect->xmax); - const int maxy = min(y + this->m_scope, rect->ymax); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); const int bufferWidth = BLI_rcti_size_x(rect); int offset; @@ -87,7 +87,7 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, if (buffer[offset] < sw) { const float dx = xi - x; const float dis = dx * dx + dy * dy; - mindist = min(mindist, dis); + mindist = MIN2(mindist, dis); } offset++; } @@ -102,7 +102,7 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, if (buffer[offset] > sw) { const float dx = xi - x; const float dis = dx * dx + dy * dy; - mindist = min(mindist, dis); + mindist = MIN2(mindist, dis); } offset++; } @@ -191,10 +191,10 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void * MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); rcti *rect = inputBuffer->getRect(); - const int minx = max(x - this->m_scope, rect->xmin); - const int miny = max(y - this->m_scope, rect->ymin); - const int maxx = min(x + this->m_scope, rect->xmax); - const int maxy = min(y + this->m_scope, rect->ymax); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); const int bufferWidth = BLI_rcti_size_x(rect); int offset; @@ -207,7 +207,7 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void * const float dx = xi - x; const float dis = dx * dx + dy * dy; if (dis <= mindist) { - value = max(buffer[offset], value); + value = MAX2(buffer[offset], value); } offset++; } @@ -238,8 +238,8 @@ void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list * /*clKernelsToCleanUp*/) + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) { cl_kernel dilateKernel = device->COM_clCreateKernel("dilateKernel", nullptr); @@ -270,10 +270,10 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); rcti *rect = inputBuffer->getRect(); - const int minx = max(x - this->m_scope, rect->xmin); - const int miny = max(y - this->m_scope, rect->ymin); - const int maxx = min(x + this->m_scope, rect->xmax); - const int maxy = min(y + this->m_scope, rect->ymax); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); const int bufferWidth = BLI_rcti_size_x(rect); int offset; @@ -286,7 +286,7 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d const float dx = xi - x; const float dis = dx * dx + dy * dy; if (dis <= mindist) { - value = min(buffer[offset], value); + value = MIN2(buffer[offset], value); } offset++; } @@ -298,8 +298,8 @@ void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list * /*clKernelsToCleanUp*/) + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) { cl_kernel erodeKernel = device->COM_clCreateKernel("erodeKernel", nullptr); @@ -360,10 +360,10 @@ void *DilateStepOperation::initializeTileData(rcti *rect) int half_window = this->m_iterations; int window = half_window * 2 + 1; - int xmin = max(0, rect->xmin - half_window); - int ymin = max(0, rect->ymin - half_window); - int xmax = min(width, rect->xmax + half_window); - int ymax = min(height, rect->ymax + half_window); + int xmin = MAX2(0, rect->xmin - half_window); + int ymin = MAX2(0, rect->ymin - half_window); + int xmax = MIN2(width, rect->xmax + half_window); + int ymax = MIN2(height, rect->ymax + half_window); int bwidth = rect->xmax - rect->xmin; int bheight = rect->ymax - rect->ymin; @@ -378,7 +378,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect) // single row or column of input values, padded with FLT_MAX's to // simplify the logic. float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); - float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window), + float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window), "dilate erode buf"); // The following is based on the van Herk/Gil-Werman algorithm for morphology operations. @@ -396,13 +396,13 @@ void *DilateStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (x = 1; x < window; x++) { - temp[window - 1 - x] = max(temp[window - x], buf[start - x]); - temp[window - 1 + x] = max(temp[window + x - 2], buf[start + x]); + temp[window - 1 - x] = MAX2(temp[window - x], buf[start - x]); + temp[window - 1 + x] = MAX2(temp[window + x - 2], buf[start + x]); } start = half_window + (i - 1) * window + 1; - for (x = -min(0, start); x < window - max(0, start + window - bwidth); x++) { - rectf[bwidth * (y - ymin) + (start + x)] = max(temp[x], temp[x + window - 1]); + for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) { + rectf[bwidth * (y - ymin) + (start + x)] = MAX2(temp[x], temp[x + window - 1]); } } } @@ -421,13 +421,14 @@ void *DilateStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (y = 1; y < window; y++) { - temp[window - 1 - y] = max(temp[window - y], buf[start - y]); - temp[window - 1 + y] = max(temp[window + y - 2], buf[start + y]); + temp[window - 1 - y] = MAX2(temp[window - y], buf[start - y]); + temp[window - 1 + y] = MAX2(temp[window + y - 2], buf[start + y]); } start = half_window + (i - 1) * window + 1; - for (y = -min(0, start); y < window - max(0, start + window - bheight); y++) { - rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = max(temp[y], temp[y + window - 1]); + for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) { + rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MAX2(temp[y], + temp[y + window - 1]); } } } @@ -489,10 +490,10 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) int half_window = this->m_iterations; int window = half_window * 2 + 1; - int xmin = max(0, rect->xmin - half_window); - int ymin = max(0, rect->ymin - half_window); - int xmax = min(width, rect->xmax + half_window); - int ymax = min(height, rect->ymax + half_window); + int xmin = MAX2(0, rect->xmin - half_window); + int ymin = MAX2(0, rect->ymin - half_window); + int xmax = MIN2(width, rect->xmax + half_window); + int ymax = MIN2(height, rect->ymax + half_window); int bwidth = rect->xmax - rect->xmin; int bheight = rect->ymax - rect->ymin; @@ -507,7 +508,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) // single row or column of input values, padded with FLT_MAX's to // simplify the logic. float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); - float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window), + float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window), "dilate erode buf"); // The following is based on the van Herk/Gil-Werman algorithm for morphology operations. @@ -525,13 +526,13 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (x = 1; x < window; x++) { - temp[window - 1 - x] = min(temp[window - x], buf[start - x]); - temp[window - 1 + x] = min(temp[window + x - 2], buf[start + x]); + temp[window - 1 - x] = MIN2(temp[window - x], buf[start - x]); + temp[window - 1 + x] = MIN2(temp[window + x - 2], buf[start + x]); } start = half_window + (i - 1) * window + 1; - for (x = -min(0, start); x < window - max(0, start + window - bwidth); x++) { - rectf[bwidth * (y - ymin) + (start + x)] = min(temp[x], temp[x + window - 1]); + for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) { + rectf[bwidth * (y - ymin) + (start + x)] = MIN2(temp[x], temp[x + window - 1]); } } } @@ -550,13 +551,14 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (y = 1; y < window; y++) { - temp[window - 1 - y] = min(temp[window - y], buf[start - y]); - temp[window - 1 + y] = min(temp[window + y - 2], buf[start + y]); + temp[window - 1 - y] = MIN2(temp[window - y], buf[start - y]); + temp[window - 1 + y] = MIN2(temp[window + y - 2], buf[start + y]); } start = half_window + (i - 1) * window + 1; - for (y = -min(0, start); y < window - max(0, start + window - bheight); y++) { - rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = min(temp[y], temp[y + window - 1]); + for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) { + rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MIN2(temp[y], + temp[y + window - 1]); } } } diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.h b/source/blender/compositor/operations/COM_DilateErodeOperation.h index 2af5c8990ee..35f9be89220 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.h +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.h @@ -115,8 +115,8 @@ class DilateDistanceOperation : public NodeOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list *clKernelsToCleanUp); + std::list *clMemToCleanUp, + std::list *clKernelsToCleanUp); }; class ErodeDistanceOperation : public DilateDistanceOperation { public: @@ -131,8 +131,8 @@ class ErodeDistanceOperation : public DilateDistanceOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list *clKernelsToCleanUp); + std::list *clMemToCleanUp, + std::list *clKernelsToCleanUp); }; class DilateStepOperation : public NodeOperation { diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp index c0b9c9b6f1d..3f0cd4ef255 100644 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp @@ -100,8 +100,8 @@ void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list * /*clKernelsToCleanUp*/) + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) { cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", nullptr); diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h index fdb7b82779e..0c220f0e239 100644 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h @@ -61,6 +61,6 @@ class DirectionalBlurOperation : public NodeOperation, public QualityStepHelper MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list *clKernelsToCleanUp); + std::list *clMemToCleanUp, + std::list *clKernelsToCleanUp); }; diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp b/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp index 38541f91fc8..a6985a40625 100644 --- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp @@ -73,7 +73,7 @@ void EllipseMaskOperation::executePixelSampled(float output[4], switch (this->m_maskType) { case CMP_NODE_MASKTYPE_ADD: if (inside) { - output[0] = max(inputMask[0], inputValue[0]); + output[0] = MAX2(inputMask[0], inputValue[0]); } else { output[0] = inputMask[0]; diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp index 157c595afcb..b3c1b6b4413 100644 --- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp @@ -209,7 +209,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, (void)0 // intermediate buffers - sz = max(src_width, src_height); + sz = MAX2(src_width, src_height); X = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss X buf"); Y = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss Y buf"); W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf"); diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp index d489c64953e..ca3173001cb 100644 --- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp @@ -256,7 +256,7 @@ void GaussianBlurReferenceOperation::initExecution() void GaussianBlurReferenceOperation::updateGauss() { int i; - int x = max(m_filtersizex, m_filtersizey); + int x = MAX2(m_filtersizex, m_filtersizey); m_maintabs = (float **)MEM_mallocN(x * sizeof(float *), "gauss array"); for (i = 0; i < x; i++) { m_maintabs[i] = make_gausstab(i + 1, i + 1); @@ -333,7 +333,7 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y, void GaussianBlurReferenceOperation::deinitExecution() { int x, i; - x = max(this->m_filtersizex, this->m_filtersizey); + x = MAX2(this->m_filtersizex, this->m_filtersizey); for (i = 0; i < x; i++) { MEM_freeN(this->m_maintabs[i]); } diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp index 90333f7dd79..596d439658c 100644 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp @@ -122,8 +122,8 @@ void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list * /*clKernelsToCleanUp*/) + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) { cl_kernel gaussianXBlurOperationKernel = device->COM_clCreateKernel( "gaussianXBlurOperationKernel", nullptr); diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h index b2bcd79e716..78ea6aa3cc2 100644 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h @@ -42,8 +42,8 @@ class GaussianXBlurOperation : public BlurBaseOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list *clKernelsToCleanUp); + std::list *clMemToCleanUp, + std::list *clKernelsToCleanUp); /** * \brief initialize the execution diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp index c5b3cf24239..55c1551ca42 100644 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp @@ -122,8 +122,8 @@ void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list * /*clKernelsToCleanUp*/) + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) { cl_kernel gaussianYBlurOperationKernel = device->COM_clCreateKernel( "gaussianYBlurOperationKernel", nullptr); diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h index d921780876a..8e7440b6fe4 100644 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h @@ -42,8 +42,8 @@ class GaussianYBlurOperation : public BlurBaseOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list *clKernelsToCleanUp); + std::list *clMemToCleanUp, + std::list *clKernelsToCleanUp); /** * \brief initialize the execution diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp index 1a1922f828c..cfa4b99cd70 100644 --- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp @@ -54,9 +54,9 @@ void GlareThresholdOperation::executePixelSampled(float output[4], output[1] -= threshold; output[2] -= threshold; - output[0] = max(output[0], 0.0f); - output[1] = max(output[1], 0.0f); - output[2] = max(output[2], 0.0f); + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); } else { zero_v3(output); diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp index 72bf86facfb..c9cc8ebc045 100644 --- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp @@ -50,7 +50,7 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data float average = 0.0f; if (this->m_axis == 0) { - const int start = max(0, x - this->m_size + 1), end = min(bufferWidth, x + this->m_size); + const int start = MAX2(0, x - this->m_size + 1), end = MIN2(bufferWidth, x + this->m_size); for (int cx = start; cx < end; cx++) { int bufferIndex = (y * bufferWidth + cx); average += buffer[bufferIndex]; @@ -58,8 +58,8 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data } } else { - const int start = max(0, y - this->m_size + 1), - end = min(inputBuffer->getHeight(), y + this->m_size); + const int start = MAX2(0, y - this->m_size + 1), + end = MIN2(inputBuffer->getHeight(), y + this->m_size); for (int cy = start; cy < end; cy++) { int bufferIndex = (cy * bufferWidth + x); average += buffer[bufferIndex]; diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp b/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp index b9bb316462d..f4d0d6c6a00 100644 --- a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp +++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp @@ -63,8 +63,8 @@ void KeyingDespillOperation::executePixelSampled(float output[4], const int other_1 = (screen_primary_channel + 1) % 3; const int other_2 = (screen_primary_channel + 2) % 3; - const int min_channel = min(other_1, other_2); - const int max_channel = max(other_1, other_2); + const int min_channel = MIN2(other_1, other_2); + const int max_channel = MAX2(other_1, other_2); float average_value, amount; diff --git a/source/blender/compositor/operations/COM_KeyingOperation.cpp b/source/blender/compositor/operations/COM_KeyingOperation.cpp index 9ef4217d300..94e65181207 100644 --- a/source/blender/compositor/operations/COM_KeyingOperation.cpp +++ b/source/blender/compositor/operations/COM_KeyingOperation.cpp @@ -30,8 +30,8 @@ static float get_pixel_saturation(const float pixelColor[4], const int other_1 = (primary_channel + 1) % 3; const int other_2 = (primary_channel + 2) % 3; - const int min_channel = min(other_1, other_2); - const int max_channel = max(other_1, other_2); + const int min_channel = MIN2(other_1, other_2); + const int max_channel = MAX2(other_1, other_2); const float val = screen_balance * pixelColor[min_channel] + (1.0f - screen_balance) * pixelColor[max_channel]; diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp index 096930d0a83..2bd7493625e 100644 --- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp @@ -54,7 +54,7 @@ void LuminanceMatteOperation::executePixelSampled(float output[4], float alpha; /* one line thread-friend algorithm: - * output[0] = min(inputValue[3], min(1.0f, max(0.0f, ((luminance - low) / (high - low)))); + * output[0] = MIN2(inputValue[3], MIN2(1.0f, MAX2(0.0f, ((luminance - low) / (high - low)))); */ /* test range */ diff --git a/source/blender/compositor/operations/COM_MaskOperation.h b/source/blender/compositor/operations/COM_MaskOperation.h index eba14d10373..67e6b64315c 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.h +++ b/source/blender/compositor/operations/COM_MaskOperation.h @@ -84,7 +84,7 @@ class MaskOperation : public NodeOperation { void setMotionBlurSamples(int samples) { - this->m_rasterMaskHandleTot = min(max(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX); + this->m_rasterMaskHandleTot = MIN2(MAX2(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX); } void setMotionBlurShutter(float shutter) { diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cpp index dbec6dd1874..692c1e70462 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cpp @@ -351,7 +351,7 @@ void MathMinimumOperation::executePixelSampled(float output[4], this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - output[0] = min(inputValue1[0], inputValue2[0]); + output[0] = MIN2(inputValue1[0], inputValue2[0]); clampIfNeeded(output); } @@ -367,7 +367,7 @@ void MathMaximumOperation::executePixelSampled(float output[4], this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - output[0] = max(inputValue1[0], inputValue2[0]); + output[0] = MAX2(inputValue1[0], inputValue2[0]); clampIfNeeded(output); } diff --git a/source/blender/compositor/operations/COM_MixOperation.cpp b/source/blender/compositor/operations/COM_MixOperation.cpp index 76a66727a75..11df0900345 100644 --- a/source/blender/compositor/operations/COM_MixOperation.cpp +++ b/source/blender/compositor/operations/COM_MixOperation.cpp @@ -523,9 +523,9 @@ void MixGlareOperation::executePixelSampled(float output[4], inputColor1[2] = 0.0f; } - output[0] = mf * max(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f); - output[1] = mf * max(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f); - output[2] = mf * max(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f); + output[0] = mf * MAX2(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f); + output[1] = mf * MAX2(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f); + output[2] = mf * MAX2(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f); output[3] = inputColor1[3]; clampIfNeeded(output); diff --git a/source/blender/compositor/operations/COM_OpenCLKernels.cl b/source/blender/compositor/operations/COM_OpenCLKernels.cl index ebe8a6d08ec..b31153abd1e 100644 --- a/source/blender/compositor/operations/COM_OpenCLKernels.cl +++ b/source/blender/compositor/operations/COM_OpenCLKernels.cl @@ -48,8 +48,8 @@ __kernel void bokehBlurKernel(__read_only image2d_t boundingBox, __read_only ima if (tempBoundingBox > 0.0f && radius > 0 ) { const int2 bokehImageDim = get_image_dim(bokehImage); const int2 bokehImageCenter = bokehImageDim/2; - const int2 minXY = max(realCoordinate - radius, zero); - const int2 maxXY = min(realCoordinate + radius, dimension); + const int2 minXY = MAX2(realCoordinate - radius, zero); + const int2 maxXY = MIN2(realCoordinate + radius, dimension); int nx, ny; float2 uv; @@ -97,10 +97,10 @@ __kernel void defocusKernel(__read_only image2d_t inputImage, __read_only image2 float4 multiplier_accum = {1.0f, 1.0f, 1.0f, 1.0f}; float4 color_accum; - int minx = max(realCoordinate.s0 - maxBlurScalar, 0); - int miny = max(realCoordinate.s1 - maxBlurScalar, 0); - int maxx = min(realCoordinate.s0 + maxBlurScalar, dimension.s0); - int maxy = min(realCoordinate.s1 + maxBlurScalar, dimension.s1); + int minx = MAX2(realCoordinate.s0 - maxBlurScalar, 0); + int miny = MAX2(realCoordinate.s1 - maxBlurScalar, 0); + int maxx = MIN2(realCoordinate.s0 + maxBlurScalar, dimension.s0); + int maxy = MIN2(realCoordinate.s1 + maxBlurScalar, dimension.s1); { int2 inputCoordinate = realCoordinate - offsetInput; @@ -116,7 +116,7 @@ __kernel void defocusKernel(__read_only image2d_t inputImage, __read_only image2 float dx = nx - realCoordinate.s0; if (dx != 0 || dy != 0) { inputCoordinate.s0 = nx - offsetInput.s0; - size = min(read_imagef(inputSize, SAMPLER_NEAREST, inputCoordinate).s0 * scalar, size_center); + size = MIN2(read_imagef(inputSize, SAMPLER_NEAREST, inputCoordinate).s0 * scalar, size_center); if (size > threshold) { if (size >= fabs(dx) && size >= fabs(dy)) { float2 uv = {256.0f + dx * 255.0f / size, @@ -157,8 +157,8 @@ __kernel void dilateKernel(__read_only image2d_t inputImage, __write_only image coords += offset; const int2 realCoordinate = coords + offsetOutput; - const int2 minXY = max(realCoordinate - scope, zero); - const int2 maxXY = min(realCoordinate + scope, dimension); + const int2 minXY = MAX2(realCoordinate - scope, zero); + const int2 maxXY = MIN2(realCoordinate + scope, dimension); float value = 0.0f; int nx, ny; @@ -170,7 +170,7 @@ __kernel void dilateKernel(__read_only image2d_t inputImage, __write_only image const float deltaX = (realCoordinate.x - nx); const float measuredDistance = deltaX * deltaX + deltaY * deltaY; if (measuredDistance <= distanceSquared) { - value = max(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0); + value = MAX2(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0); } } } @@ -188,8 +188,8 @@ __kernel void erodeKernel(__read_only image2d_t inputImage, __write_only image2 coords += offset; const int2 realCoordinate = coords + offsetOutput; - const int2 minXY = max(realCoordinate - scope, zero); - const int2 maxXY = min(realCoordinate + scope, dimension); + const int2 minXY = MAX2(realCoordinate - scope, zero); + const int2 maxXY = MIN2(realCoordinate + scope, dimension); float value = 1.0f; int nx, ny; @@ -201,7 +201,7 @@ __kernel void erodeKernel(__read_only image2d_t inputImage, __write_only image2 const float deltaY = (realCoordinate.y - ny); const float measuredDistance = deltaX * deltaX+deltaY * deltaY; if (measuredDistance <= distanceSquared) { - value = min(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0); + value = MIN2(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0); } } } @@ -268,10 +268,10 @@ __kernel void gaussianXBlurOperationKernel(__read_only image2d_t inputImage, int2 inputCoordinate = realCoordinate - offsetInput; float weight = 0.0f; - int xmin = max(realCoordinate.x - filter_size, 0) - offsetInput.x; - int xmax = min(realCoordinate.x + filter_size + 1, dimension.x) - offsetInput.x; + int xmin = MAX2(realCoordinate.x - filter_size, 0) - offsetInput.x; + int xmax = MIN2(realCoordinate.x + filter_size + 1, dimension.x) - offsetInput.x; - for (int nx = xmin, i = max(filter_size - realCoordinate.x, 0); nx < xmax; ++nx, ++i) { + for (int nx = xmin, i = MAX2(filter_size - realCoordinate.x, 0); nx < xmax; ++nx, ++i) { float w = gausstab[i]; inputCoordinate.x = nx; color += read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate) * w; @@ -299,10 +299,10 @@ __kernel void gaussianYBlurOperationKernel(__read_only image2d_t inputImage, int2 inputCoordinate = realCoordinate - offsetInput; float weight = 0.0f; - int ymin = max(realCoordinate.y - filter_size, 0) - offsetInput.y; - int ymax = min(realCoordinate.y + filter_size + 1, dimension.y) - offsetInput.y; + int ymin = MAX2(realCoordinate.y - filter_size, 0) - offsetInput.y; + int ymax = MIN2(realCoordinate.y + filter_size + 1, dimension.y) - offsetInput.y; - for (int ny = ymin, i = max(filter_size - realCoordinate.y, 0); ny < ymax; ++ny, ++i) { + for (int ny = ymin, i = MAX2(filter_size - realCoordinate.y, 0); ny < ymax; ++ny, ++i) { float w = gausstab[i]; inputCoordinate.y = ny; color += read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate) * w; diff --git a/source/blender/compositor/operations/COM_RotateOperation.cpp b/source/blender/compositor/operations/COM_RotateOperation.cpp index 7a21e960c13..9a1f54a6e10 100644 --- a/source/blender/compositor/operations/COM_RotateOperation.cpp +++ b/source/blender/compositor/operations/COM_RotateOperation.cpp @@ -93,10 +93,10 @@ bool RotateOperation::determineDependingAreaOfInterest(rcti *input, const float y2 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymin); const float y3 = this->m_centerY + (-this->m_sine * dxmin + this->m_cosine * dymax); const float y4 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymax); - const float minx = min(x1, min(x2, min(x3, x4))); - const float maxx = max(x1, max(x2, max(x3, x4))); - const float miny = min(y1, min(y2, min(y3, y4))); - const float maxy = max(y1, max(y2, max(y3, y4))); + const float minx = MIN2(x1, MIN2(x2, MIN2(x3, x4))); + const float maxx = MAX2(x1, MAX2(x2, MAX2(x3, x4))); + const float miny = MIN2(y1, MIN2(y2, MIN2(y3, y4))); + const float maxy = MAX2(y1, MAX2(y2, MAX2(y3, y4))); newInput.xmax = ceil(maxx) + 1; newInput.xmin = floor(minx) - 1; diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp index 7cfa4de7a61..28811d479a5 100644 --- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp @@ -33,7 +33,7 @@ void SunBeamsOperation::initExecution() /* convert to pixels */ this->m_source_px[0] = this->m_data.source[0] * this->getWidth(); this->m_source_px[1] = this->m_data.source[1] * this->getHeight(); - this->m_ray_length_px = this->m_data.ray_length * max(this->getWidth(), this->getHeight()); + this->m_ray_length_px = this->m_data.ray_length * MAX2(this->getWidth(), this->getHeight()); } /** diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cpp b/source/blender/compositor/operations/COM_TonemapOperation.cpp index cb0fc747dcb..4c1d285a69f 100644 --- a/source/blender/compositor/operations/COM_TonemapOperation.cpp +++ b/source/blender/compositor/operations/COM_TonemapOperation.cpp @@ -51,9 +51,9 @@ void TonemapOperation::executePixel(float output[4], int x, int y, void *data) output[2] /= ((db == 0.0f) ? 1.0f : db); const float igm = avg->igm; if (igm != 0.0f) { - output[0] = powf(max(output[0], 0.0f), igm); - output[1] = powf(max(output[1], 0.0f), igm); - output[2] = powf(max(output[2], 0.0f), igm); + output[0] = powf(MAX2(output[0], 0.0f), igm); + output[1] = powf(MAX2(output[1], 0.0f), igm); + output[2] = powf(MAX2(output[2], 0.0f), igm); } } void PhotoreceptorTonemapOperation::executePixel(float output[4], int x, int y, void *data) diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp index 414b5bd980a..909a2f73d25 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp @@ -74,7 +74,7 @@ void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect) this->determineDependingAreaOfInterest( rect, (ReadBufferOperation *)this->m_inputSizeProgram, &rect2); - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; data->maxBlurScalar = (int)(data->size->getMaximumValue(&rect2) * scalar); @@ -102,7 +102,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, float multiplier_accum[4]; float color_accum[4]; - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; int maxBlurScalar = tileData->maxBlurScalar; @@ -120,10 +120,10 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, int maxx = search[2]; int maxy = search[3]; #else - int minx = max(x - maxBlurScalar, 0); - int miny = max(y - maxBlurScalar, 0); - int maxx = min(x + maxBlurScalar, (int)m_width); - int maxy = min(y + maxBlurScalar, (int)m_height); + int minx = MAX2(x - maxBlurScalar, 0); + int miny = MAX2(y - maxBlurScalar, 0); + int maxx = MIN2(x + maxBlurScalar, (int)m_width); + int maxy = MIN2(y + maxBlurScalar, (int)m_height); #endif { inputSizeBuffer->readNoCheck(tempSize, x, y); @@ -145,7 +145,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, int offsetColorNxNy = offsetValueNxNy * COM_NUM_CHANNELS_COLOR; for (int nx = minx; nx < maxx; nx += addXStepValue) { if (nx != x || ny != y) { - float size = min(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center); + float size = MIN2(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center); if (size > this->m_threshold) { float dx = nx - x; if (size > fabsf(dx) && size > fabsf(dy)) { @@ -185,8 +185,8 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list * /*clKernelsToCleanUp*/) + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) { cl_kernel defocusKernel = device->COM_clCreateKernel("defocusKernel", nullptr); @@ -197,7 +197,7 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *sizeMemoryBuffer = this->m_inputSizeProgram->getInputMemoryBuffer( inputMemoryBuffers); - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); cl_float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; maxBlur = (cl_int)min_ff(sizeMemoryBuffer->getMaximumValue() * scalar, (float)this->m_maxBlur); @@ -235,7 +235,7 @@ bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest( rcti newInput; rcti bokehInput; - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; int maxBlurScalar = this->m_maxBlur * scalar; diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h index 258b5d385c0..fe927f791fa 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h @@ -80,8 +80,8 @@ class VariableSizeBokehBlurOperation : public NodeOperation, public QualityStepH MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list *clMemToCleanUp, - list *clKernelsToCleanUp); + std::list *clMemToCleanUp, + std::list *clKernelsToCleanUp); }; #ifdef COM_DEFOCUS_SEARCH diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp index 9fb995bf463..8d38dbfe180 100644 --- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp @@ -143,9 +143,9 @@ void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, } // STEP 2 - list *clMemToCleanUp = new list(); + std::list *clMemToCleanUp = new std::list(); clMemToCleanUp->push_back(clOutputBuffer); - list *clKernelsToCleanUp = new list(); + std::list *clKernelsToCleanUp = new std::list(); this->m_input->executeOpenCL(device, outputBuffer, diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cpp b/source/blender/compositor/operations/COM_ZCombineOperation.cpp index 22a37a4583e..26d3f2c7dc4 100644 --- a/source/blender/compositor/operations/COM_ZCombineOperation.cpp +++ b/source/blender/compositor/operations/COM_ZCombineOperation.cpp @@ -83,7 +83,7 @@ void ZCombineAlphaOperation::executePixelSampled(float output[4], output[0] = fac * color1[0] + ifac * color2[0]; output[1] = fac * color1[1] + ifac * color2[1]; output[2] = fac * color1[2] + ifac * color2[2]; - output[3] = max(color1[3], color2[3]); + output[3] = MAX2(color1[3], color2[3]); } void ZCombineOperation::deinitExecution() @@ -149,7 +149,7 @@ void ZCombineMaskAlphaOperation::executePixelSampled(float output[4], output[0] = color1[0] * mfac + color2[0] * fac; output[1] = color1[1] * mfac + color2[1] * fac; output[2] = color1[2] * mfac + color2[2] * fac; - output[3] = max(color1[3], color2[3]); + output[3] = MAX2(color1[3], color2[3]); } void ZCombineMaskOperation::deinitExecution() -- cgit v1.2.3 From 6ebd34c8026d30628755ddd9323f271a3e1457ae Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 15:06:49 +0100 Subject: Cleanup: Make WorkPackage a struct --- source/blender/compositor/intern/COM_CPUDevice.cpp | 4 ++-- .../blender/compositor/intern/COM_OpenCLDevice.cpp | 4 ++-- .../blender/compositor/intern/COM_WorkPackage.cpp | 6 ++--- source/blender/compositor/intern/COM_WorkPackage.h | 28 ++++------------------ 4 files changed, 12 insertions(+), 30 deletions(-) diff --git a/source/blender/compositor/intern/COM_CPUDevice.cpp b/source/blender/compositor/intern/COM_CPUDevice.cpp index 7ea12866148..b520a437008 100644 --- a/source/blender/compositor/intern/COM_CPUDevice.cpp +++ b/source/blender/compositor/intern/COM_CPUDevice.cpp @@ -24,8 +24,8 @@ CPUDevice::CPUDevice(int thread_id) : m_thread_id(thread_id) void CPUDevice::execute(WorkPackage *work) { - const unsigned int chunkNumber = work->getChunkNumber(); - ExecutionGroup *executionGroup = work->getExecutionGroup(); + const unsigned int chunkNumber = work->chunk_number; + ExecutionGroup *executionGroup = work->execution_group; rcti rect; executionGroup->determineChunkRect(&rect, chunkNumber); diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp index 2082c87da8c..34450366aec 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp +++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp @@ -61,8 +61,8 @@ void OpenCLDevice::deinitialize() void OpenCLDevice::execute(WorkPackage *work) { - const unsigned int chunkNumber = work->getChunkNumber(); - ExecutionGroup *executionGroup = work->getExecutionGroup(); + const unsigned int chunkNumber = work->chunk_number; + ExecutionGroup *executionGroup = work->execution_group; rcti rect; executionGroup->determineChunkRect(&rect, chunkNumber); diff --git a/source/blender/compositor/intern/COM_WorkPackage.cpp b/source/blender/compositor/intern/COM_WorkPackage.cpp index 795f8d88d50..60684f2c45c 100644 --- a/source/blender/compositor/intern/COM_WorkPackage.cpp +++ b/source/blender/compositor/intern/COM_WorkPackage.cpp @@ -18,8 +18,8 @@ #include "COM_WorkPackage.h" -WorkPackage::WorkPackage(ExecutionGroup *group, unsigned int chunkNumber) +WorkPackage::WorkPackage(ExecutionGroup *execution_group, unsigned int chunk_number) { - this->m_executionGroup = group; - this->m_chunkNumber = chunkNumber; + this->execution_group = execution_group; + this->chunk_number = chunk_number; } diff --git a/source/blender/compositor/intern/COM_WorkPackage.h b/source/blender/compositor/intern/COM_WorkPackage.h index f4370aa41be..81616e123b2 100644 --- a/source/blender/compositor/intern/COM_WorkPackage.h +++ b/source/blender/compositor/intern/COM_WorkPackage.h @@ -27,41 +27,23 @@ class ExecutionGroup; * \brief contains data about work that can be scheduled * \see WorkScheduler */ -class WorkPackage { - private: +struct WorkPackage { /** * \brief executionGroup with the operations-setup to be evaluated */ - ExecutionGroup *m_executionGroup; + ExecutionGroup *execution_group; /** * \brief number of the chunk to be executed */ - unsigned int m_chunkNumber; + unsigned int chunk_number; - public: /** * constructor * \param group: the ExecutionGroup - * \param chunkNumber: the number of the chunk + * \param chunk_number: the number of the chunk */ - WorkPackage(ExecutionGroup *group, unsigned int chunkNumber); - - /** - * \brief get the ExecutionGroup - */ - ExecutionGroup *getExecutionGroup() const - { - return this->m_executionGroup; - } - - /** - * \brief get the number of the chunk - */ - unsigned int getChunkNumber() const - { - return this->m_chunkNumber; - } + WorkPackage(ExecutionGroup *group, unsigned int chunk_number); #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("COM:WorkPackage") -- cgit v1.2.3 From 8b2fb7aeed5572a815322ac241cd8361321f2376 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 15:12:39 +0100 Subject: Cleanup: Remove unused method. --- source/blender/compositor/intern/COM_ExecutionSystem.cpp | 11 ----------- source/blender/compositor/intern/COM_ExecutionSystem.h | 5 ----- 2 files changed, 16 deletions(-) diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp index 6fbcd4259c9..3da2523bfdb 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp @@ -222,14 +222,3 @@ void ExecutionSystem::findOutputExecutionGroup(std::vector *re } } } - -void ExecutionSystem::findOutputExecutionGroup(std::vector *result) const -{ - unsigned int index; - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *group = this->m_groups[index]; - if (group->isOutputExecutionGroup()) { - result->push_back(group); - } - } -} diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index d18125ebc50..8b69caf106f 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -140,11 +140,6 @@ class ExecutionSystem { void findOutputExecutionGroup(std::vector *result, CompositorPriority priority) const; - /** - * find all execution group with output nodes - */ - void findOutputExecutionGroup(std::vector *result) const; - public: /** * \brief Create a new ExecutionSystem and initialize it with the -- cgit v1.2.3 From 3d4a844a50744815d234c96dd72af675f478dbe1 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 15:25:05 +0100 Subject: Cleanup: ExecutionSystem::find_output_execution_groups. --- .../compositor/intern/COM_ExecutionSystem.cpp | 29 ++++++++++------------ .../compositor/intern/COM_ExecutionSystem.h | 6 ++--- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp index 3da2523bfdb..9d6359e9cb3 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp @@ -179,10 +179,10 @@ void ExecutionSystem::execute() WorkScheduler::start(this->m_context); - executeGroups(COM_PRIORITY_HIGH); + execute_groups(COM_PRIORITY_HIGH); if (!this->getContext().isFastCalculation()) { - executeGroups(COM_PRIORITY_MEDIUM); - executeGroups(COM_PRIORITY_LOW); + execute_groups(COM_PRIORITY_MEDIUM); + execute_groups(COM_PRIORITY_LOW); } WorkScheduler::finish(); @@ -199,26 +199,23 @@ void ExecutionSystem::execute() } } -void ExecutionSystem::executeGroups(CompositorPriority priority) +void ExecutionSystem::execute_groups(CompositorPriority priority) { - unsigned int index; - std::vector executionGroups; - this->findOutputExecutionGroup(&executionGroups, priority); - - for (index = 0; index < executionGroups.size(); index++) { - ExecutionGroup *group = executionGroups[index]; + blender::Vector execution_groups = find_output_execution_groups(priority); + for (ExecutionGroup *group : execution_groups) { group->execute(this); } } -void ExecutionSystem::findOutputExecutionGroup(std::vector *result, - CompositorPriority priority) const +blender::Vector ExecutionSystem::find_output_execution_groups( + CompositorPriority priority) const { - unsigned int index; - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *group = this->m_groups[index]; + blender::Vector result; + + for (ExecutionGroup *group : m_groups) { if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) { - result->push_back(group); + result.append(group); } } + return result; } diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index 8b69caf106f..dd68edd4793 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -137,8 +137,8 @@ class ExecutionSystem { /** * find all execution group with output nodes */ - void findOutputExecutionGroup(std::vector *result, - CompositorPriority priority) const; + blender::Vector find_output_execution_groups( + CompositorPriority priority) const; public: /** @@ -181,7 +181,7 @@ class ExecutionSystem { } private: - void executeGroups(CompositorPriority priority); + void execute_groups(CompositorPriority priority); /* allow the DebugInfo class to look at internals */ friend class DebugInfo; -- cgit v1.2.3 From e1d9b095e4f55022e579d246997b48ec2dd409e0 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 15:35:43 +0100 Subject: Cleanup: Use enum class for eChunkExecutionState. --- source/blender/compositor/COM_compositor.h | 6 ++--- .../compositor/intern/COM_ExecutionGroup.cpp | 26 +++++++++++----------- .../blender/compositor/intern/COM_ExecutionGroup.h | 18 +++++++-------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h index ba66d7f0dfe..4aae5471858 100644 --- a/source/blender/compositor/COM_compositor.h +++ b/source/blender/compositor/COM_compositor.h @@ -113,11 +113,11 @@ extern "C" { * * When the chunk-order is determined, the first few chunks will be checked if they can be scheduled. * Chunks can have three states: - * - [@ref ChunkExecutionState.COM_ES_NOT_SCHEDULED]: + * - [@ref eChunkExecutionState.NOT_SCHEDULED]: * Chunk is not yet scheduled, or dependencies are not met. - * - [@ref ChunkExecutionState.COM_ES_SCHEDULED]: + * - [@ref eChunkExecutionState.SCHEDULED]: * All dependencies are met, chunk is scheduled, but not finished. - * - [@ref ChunkExecutionState.COM_ES_EXECUTED]: + * - [@ref eChunkExecutionState.EXECUTED]: * Chunk is finished. * * \see ExecutionGroup.execute diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index dc12248899d..b8cacd7138d 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -129,10 +129,10 @@ void ExecutionGroup::initExecution() this->m_chunkExecutionStates = nullptr; if (this->m_numberOfChunks != 0) { - this->m_chunkExecutionStates = (ChunkExecutionState *)MEM_mallocN( - sizeof(ChunkExecutionState) * this->m_numberOfChunks, __func__); + this->m_chunkExecutionStates = (eChunkExecutionState *)MEM_mallocN( + sizeof(eChunkExecutionState) * this->m_numberOfChunks, __func__); for (index = 0; index < this->m_numberOfChunks; index++) { - this->m_chunkExecutionStates[index] = COM_ES_NOT_SCHEDULED; + this->m_chunkExecutionStates[index] = eChunkExecutionState::NOT_SCHEDULED; } } @@ -338,8 +338,8 @@ void ExecutionGroup::execute(ExecutionSystem *graph) chunkNumber = chunkOrder[index]; int yChunk = chunkNumber / this->m_numberOfXChunks; int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks); - const ChunkExecutionState state = this->m_chunkExecutionStates[chunkNumber]; - if (state == COM_ES_NOT_SCHEDULED) { + const eChunkExecutionState state = this->m_chunkExecutionStates[chunkNumber]; + if (state == eChunkExecutionState::NOT_SCHEDULED) { scheduleChunkWhenPossible(graph, xChunk, yChunk); finished = false; startEvaluated = true; @@ -349,12 +349,12 @@ void ExecutionGroup::execute(ExecutionSystem *graph) bTree->update_draw(bTree->udh); } } - else if (state == COM_ES_SCHEDULED) { + else if (state == eChunkExecutionState::SCHEDULED) { finished = false; startEvaluated = true; numberEvaluated++; } - else if (state == COM_ES_EXECUTED && !startEvaluated) { + else if (state == eChunkExecutionState::EXECUTED && !startEvaluated) { startIndex = index + 1; } } @@ -405,8 +405,8 @@ MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *mem void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers) { - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) { - this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED; + if (this->m_chunkExecutionStates[chunkNumber] == eChunkExecutionState::SCHEDULED) { + this->m_chunkExecutionStates[chunkNumber] = eChunkExecutionState::EXECUTED; } atomic_add_and_fetch_u(&this->m_chunksFinished, 1); @@ -517,8 +517,8 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber) { - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_NOT_SCHEDULED) { - this->m_chunkExecutionStates[chunkNumber] = COM_ES_SCHEDULED; + if (this->m_chunkExecutionStates[chunkNumber] == eChunkExecutionState::NOT_SCHEDULED) { + this->m_chunkExecutionStates[chunkNumber] = eChunkExecutionState::SCHEDULED; WorkScheduler::schedule(this, chunkNumber); return true; } @@ -535,12 +535,12 @@ bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChun } int chunkNumber = yChunk * this->m_numberOfXChunks + xChunk; // chunk is already executed - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_EXECUTED) { + if (this->m_chunkExecutionStates[chunkNumber] == eChunkExecutionState::EXECUTED) { return true; } // chunk is scheduled, but not executed - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) { + if (this->m_chunkExecutionStates[chunkNumber] == eChunkExecutionState::SCHEDULED) { return false; } diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h index a311d2681d4..bfd745d8320 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.h +++ b/source/blender/compositor/intern/COM_ExecutionGroup.h @@ -39,20 +39,20 @@ class Device; * \brief the execution state of a chunk in an ExecutionGroup * \ingroup Execution */ -typedef enum ChunkExecutionState { +enum class eChunkExecutionState { /** * \brief chunk is not yet scheduled */ - COM_ES_NOT_SCHEDULED = 0, + NOT_SCHEDULED = 0, /** * \brief chunk is scheduled, but not yet executed */ - COM_ES_SCHEDULED = 1, + SCHEDULED = 1, /** * \brief chunk is executed. */ - COM_ES_EXECUTED = 2, -} ChunkExecutionState; + EXECUTED = 2, +}; /** * \brief Class ExecutionGroup is a group of Operations that are executed as one. @@ -150,11 +150,11 @@ class ExecutionGroup { /** * \brief the chunkExecutionStates holds per chunk the execution state. this state can be - * - COM_ES_NOT_SCHEDULED: not scheduled - * - COM_ES_SCHEDULED: scheduled - * - COM_ES_EXECUTED: executed + * - eChunkExecutionState::NOT_SCHEDULED: not scheduled + * - eChunkExecutionState::SCHEDULED: scheduled + * - eChunkExecutionState::EXECUTED: executed */ - ChunkExecutionState *m_chunkExecutionStates; + eChunkExecutionState *m_chunkExecutionStates; /** * \brief indicator when this ExecutionGroup has valid Operations in its vector for Execution -- cgit v1.2.3 From fde150fee476e16ee6130618ed1ea2598913f1b6 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 15:46:31 +0100 Subject: Cleanup: Use std::Vector for chunk execution status. --- .../compositor/intern/COM_ExecutionGroup.cpp | 69 +++++++++++----------- .../blender/compositor/intern/COM_ExecutionGroup.h | 6 +- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index b8cacd7138d..63a278c2ecc 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -45,7 +45,6 @@ ExecutionGroup::ExecutionGroup() { this->m_isOutput = false; this->m_complex = false; - this->m_chunkExecutionStates = nullptr; this->m_bTree = nullptr; this->m_height = 0; this->m_width = 0; @@ -121,18 +120,14 @@ NodeOperation *ExecutionGroup::getOutputOperation() const void ExecutionGroup::initExecution() { - if (this->m_chunkExecutionStates != nullptr) { - MEM_freeN(this->m_chunkExecutionStates); - } + m_chunk_execution_states.clear(); unsigned int index; determineNumberOfChunks(); - this->m_chunkExecutionStates = nullptr; if (this->m_numberOfChunks != 0) { - this->m_chunkExecutionStates = (eChunkExecutionState *)MEM_mallocN( - sizeof(eChunkExecutionState) * this->m_numberOfChunks, __func__); + m_chunk_execution_states.resize(this->m_numberOfChunks); for (index = 0; index < this->m_numberOfChunks; index++) { - this->m_chunkExecutionStates[index] = eChunkExecutionState::NOT_SCHEDULED; + m_chunk_execution_states[index] = eChunkExecutionState::NOT_SCHEDULED; } } @@ -152,10 +147,7 @@ void ExecutionGroup::initExecution() void ExecutionGroup::deinitExecution() { - if (this->m_chunkExecutionStates != nullptr) { - MEM_freeN(this->m_chunkExecutionStates); - this->m_chunkExecutionStates = nullptr; - } + m_chunk_execution_states.clear(); this->m_numberOfChunks = 0; this->m_numberOfXChunks = 0; this->m_numberOfYChunks = 0; @@ -338,25 +330,30 @@ void ExecutionGroup::execute(ExecutionSystem *graph) chunkNumber = chunkOrder[index]; int yChunk = chunkNumber / this->m_numberOfXChunks; int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks); - const eChunkExecutionState state = this->m_chunkExecutionStates[chunkNumber]; - if (state == eChunkExecutionState::NOT_SCHEDULED) { - scheduleChunkWhenPossible(graph, xChunk, yChunk); - finished = false; - startEvaluated = true; - numberEvaluated++; - - if (bTree->update_draw) { - bTree->update_draw(bTree->udh); + switch (m_chunk_execution_states[chunkNumber]) { + case eChunkExecutionState::NOT_SCHEDULED: { + scheduleChunkWhenPossible(graph, xChunk, yChunk); + finished = false; + startEvaluated = true; + numberEvaluated++; + + if (bTree->update_draw) { + bTree->update_draw(bTree->udh); + } + break; } - } - else if (state == eChunkExecutionState::SCHEDULED) { - finished = false; - startEvaluated = true; - numberEvaluated++; - } - else if (state == eChunkExecutionState::EXECUTED && !startEvaluated) { - startIndex = index + 1; - } + case eChunkExecutionState::SCHEDULED: { + finished = false; + startEvaluated = true; + numberEvaluated++; + break; + } + case eChunkExecutionState::EXECUTED: { + if (!startEvaluated) { + startIndex = index + 1; + } + } + }; } WorkScheduler::finish(); @@ -405,8 +402,8 @@ MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *mem void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers) { - if (this->m_chunkExecutionStates[chunkNumber] == eChunkExecutionState::SCHEDULED) { - this->m_chunkExecutionStates[chunkNumber] = eChunkExecutionState::EXECUTED; + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) { + this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::EXECUTED; } atomic_add_and_fetch_u(&this->m_chunksFinished, 1); @@ -517,8 +514,8 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber) { - if (this->m_chunkExecutionStates[chunkNumber] == eChunkExecutionState::NOT_SCHEDULED) { - this->m_chunkExecutionStates[chunkNumber] = eChunkExecutionState::SCHEDULED; + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::NOT_SCHEDULED) { + this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::SCHEDULED; WorkScheduler::schedule(this, chunkNumber); return true; } @@ -535,12 +532,12 @@ bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChun } int chunkNumber = yChunk * this->m_numberOfXChunks + xChunk; // chunk is already executed - if (this->m_chunkExecutionStates[chunkNumber] == eChunkExecutionState::EXECUTED) { + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::EXECUTED) { return true; } // chunk is scheduled, but not executed - if (this->m_chunkExecutionStates[chunkNumber] == eChunkExecutionState::SCHEDULED) { + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) { return false; } diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h index bfd745d8320..415505616bd 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.h +++ b/source/blender/compositor/intern/COM_ExecutionGroup.h @@ -23,6 +23,8 @@ #endif #include "BLI_rect.h" +#include "BLI_vector.hh" + #include "COM_CompositorContext.h" #include "COM_Device.h" #include "COM_MemoryProxy.h" @@ -149,12 +151,12 @@ class ExecutionGroup { unsigned int m_chunksFinished; /** - * \brief the chunkExecutionStates holds per chunk the execution state. this state can be + * \brief m_chunk_execution_states holds per chunk the execution state. this state can be * - eChunkExecutionState::NOT_SCHEDULED: not scheduled * - eChunkExecutionState::SCHEDULED: scheduled * - eChunkExecutionState::EXECUTED: executed */ - eChunkExecutionState *m_chunkExecutionStates; + blender::Vector m_chunk_execution_states; /** * \brief indicator when this ExecutionGroup has valid Operations in its vector for Execution -- cgit v1.2.3 From 87842d63883664125177e8361b5f06e2e5eba344 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 15:58:52 +0100 Subject: Cleanup: Use blender::Vector in ExecutionGroup. --- .../compositor/intern/COM_ExecutionGroup.cpp | 23 ++++++++-------------- .../blender/compositor/intern/COM_ExecutionGroup.h | 9 +++------ 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index 63a278c2ecc..2427d3c4bd5 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -107,7 +107,7 @@ bool ExecutionGroup::addOperation(NodeOperation *operation) m_initialized = true; } - m_operations.push_back(operation); + m_operations.append(operation); return true; } @@ -136,8 +136,8 @@ void ExecutionGroup::initExecution() for (index = 0; index < this->m_operations.size(); index++) { NodeOperation *operation = this->m_operations[index]; if (operation->isReadBufferOperation()) { - ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; - this->m_cachedReadOperations.push_back(readOperation); + ReadBufferOperation *readOperation = static_cast(operation); + this->m_read_operations.append(readOperation); maxNumber = MAX2(maxNumber, readOperation->getOffset()); } } @@ -151,7 +151,7 @@ void ExecutionGroup::deinitExecution() this->m_numberOfChunks = 0; this->m_numberOfXChunks = 0; this->m_numberOfYChunks = 0; - this->m_cachedReadOperations.clear(); + this->m_read_operations.clear(); this->m_bTree = nullptr; } void ExecutionGroup::determineResolution(unsigned int resolution[2]) @@ -372,16 +372,13 @@ MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber) { rcti rect; std::vector memoryproxies; - unsigned int index; determineChunkRect(&rect, chunkNumber); this->determineDependingMemoryProxies(&memoryproxies); MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN( sizeof(MemoryBuffer *) * this->m_cachedMaxReadBufferOffset, __func__); rcti output; - for (index = 0; index < this->m_cachedReadOperations.size(); index++) { - ReadBufferOperation *readOperation = - (ReadBufferOperation *)this->m_cachedReadOperations[index]; + for (ReadBufferOperation *readOperation : m_read_operations) { MemoryProxy *memoryProxy = readOperation->getMemoryProxy(); this->determineDependingAreaOfInterest(&rect, readOperation, &output); MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer( @@ -551,9 +548,8 @@ bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChun bool canBeExecuted = true; rcti area; - for (index = 0; index < this->m_cachedReadOperations.size(); index++) { - ReadBufferOperation *readOperation = - (ReadBufferOperation *)this->m_cachedReadOperations[index]; + for (index = 0; index < m_read_operations.size(); index++) { + ReadBufferOperation *readOperation = m_read_operations[index]; BLI_rcti_init(&area, 0, 0, 0, 0); MemoryProxy *memoryProxy = memoryProxies[index]; determineDependingAreaOfInterest(&rect, readOperation, &area); @@ -585,10 +581,7 @@ void ExecutionGroup::determineDependingAreaOfInterest(rcti *input, void ExecutionGroup::determineDependingMemoryProxies(std::vector *memoryProxies) { - unsigned int index; - for (index = 0; index < this->m_cachedReadOperations.size(); index++) { - ReadBufferOperation *readOperation = - (ReadBufferOperation *)this->m_cachedReadOperations[index]; + for (ReadBufferOperation *readOperation : m_read_operations) { memoryProxies->push_back(readOperation->getMemoryProxy()); } } diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h index 415505616bd..9a749e1a9ed 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.h +++ b/source/blender/compositor/intern/COM_ExecutionGroup.h @@ -63,16 +63,13 @@ enum class eChunkExecutionState { * \ingroup Execution */ class ExecutionGroup { - public: - typedef std::vector Operations; - private: // fields /** * \brief list of operations in this ExecutionGroup */ - Operations m_operations; + blender::Vector m_operations; /** * \brief is this ExecutionGroup an input ExecutionGroup @@ -134,9 +131,9 @@ class ExecutionGroup { unsigned int m_cachedMaxReadBufferOffset; /** - * \brief a cached vector of all read operations in the execution group. + * \brief All read operations of this execution group. */ - Operations m_cachedReadOperations; + blender::Vector m_read_operations; /** * \brief reference to the original bNodeTree, -- cgit v1.2.3 From 921138cf5f17f157243f860092a48a1c4081204e Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 16:03:15 +0100 Subject: Cleanup: rename private attribtue m_max_read_buffer_offset. --- .../blender/compositor/intern/COM_ExecutionGroup.cpp | 20 +++++++++----------- .../blender/compositor/intern/COM_ExecutionGroup.h | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index 2427d3c4bd5..1286a07c4d0 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -48,7 +48,7 @@ ExecutionGroup::ExecutionGroup() this->m_bTree = nullptr; this->m_height = 0; this->m_width = 0; - this->m_cachedMaxReadBufferOffset = 0; + this->m_max_read_buffer_offset = 0; this->m_numberOfXChunks = 0; this->m_numberOfYChunks = 0; this->m_numberOfChunks = 0; @@ -121,28 +121,26 @@ NodeOperation *ExecutionGroup::getOutputOperation() const void ExecutionGroup::initExecution() { m_chunk_execution_states.clear(); - unsigned int index; determineNumberOfChunks(); if (this->m_numberOfChunks != 0) { m_chunk_execution_states.resize(this->m_numberOfChunks); - for (index = 0; index < this->m_numberOfChunks; index++) { + for (int index = 0; index < this->m_numberOfChunks; index++) { m_chunk_execution_states[index] = eChunkExecutionState::NOT_SCHEDULED; } } - unsigned int maxNumber = 0; + unsigned int max_offset = 0; - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; + for (NodeOperation *operation : m_operations) { if (operation->isReadBufferOperation()) { ReadBufferOperation *readOperation = static_cast(operation); this->m_read_operations.append(readOperation); - maxNumber = MAX2(maxNumber, readOperation->getOffset()); + max_offset = MAX2(max_offset, readOperation->getOffset()); } } - maxNumber++; - this->m_cachedMaxReadBufferOffset = maxNumber; + max_offset++; + this->m_max_read_buffer_offset = max_offset; } void ExecutionGroup::deinitExecution() @@ -376,7 +374,7 @@ MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber) this->determineDependingMemoryProxies(&memoryproxies); MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN( - sizeof(MemoryBuffer *) * this->m_cachedMaxReadBufferOffset, __func__); + sizeof(MemoryBuffer *) * this->m_max_read_buffer_offset, __func__); rcti output; for (ReadBufferOperation *readOperation : m_read_operations) { MemoryProxy *memoryProxy = readOperation->getMemoryProxy(); @@ -405,7 +403,7 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo atomic_add_and_fetch_u(&this->m_chunksFinished, 1); if (memoryBuffers) { - for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) { + for (unsigned int index = 0; index < this->m_max_read_buffer_offset; index++) { MemoryBuffer *buffer = memoryBuffers[index]; if (buffer) { if (buffer->isTemporarily()) { diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h index 9a749e1a9ed..7ca886f6fc5 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.h +++ b/source/blender/compositor/intern/COM_ExecutionGroup.h @@ -128,7 +128,7 @@ class ExecutionGroup { * \brief what is the maximum number field of all ReadBufferOperation in this ExecutionGroup. * \note this is used to construct the MemoryBuffers that will be passed during execution. */ - unsigned int m_cachedMaxReadBufferOffset; + unsigned int m_max_read_buffer_offset; /** * \brief All read operations of this execution group. -- cgit v1.2.3 From 7bccbce512bd715c113350cccc11962987cadc07 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 16:16:41 +0100 Subject: Cleanup: use snake case. --- .../compositor/intern/COM_ExecutionGroup.cpp | 103 ++++++++++----------- .../blender/compositor/intern/COM_ExecutionGroup.h | 18 ++-- 2 files changed, 60 insertions(+), 61 deletions(-) diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index 1286a07c4d0..37623228183 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -43,19 +43,19 @@ ExecutionGroup::ExecutionGroup() { - this->m_isOutput = false; + this->m_is_output = false; this->m_complex = false; this->m_bTree = nullptr; this->m_height = 0; this->m_width = 0; this->m_max_read_buffer_offset = 0; - this->m_numberOfXChunks = 0; - this->m_numberOfYChunks = 0; - this->m_numberOfChunks = 0; + this->m_x_chunks_len = 0; + this->m_y_chunks_len = 0; + this->m_chunks_len = 0; this->m_initialized = false; this->m_openCL = false; this->m_singleThreaded = false; - this->m_chunksFinished = 0; + this->m_chunks_finished = 0; BLI_rcti_init(&this->m_viewerBorder, 0, 0, 0, 0); this->m_executionStartTime = 0; } @@ -123,9 +123,9 @@ void ExecutionGroup::initExecution() m_chunk_execution_states.clear(); determineNumberOfChunks(); - if (this->m_numberOfChunks != 0) { - m_chunk_execution_states.resize(this->m_numberOfChunks); - for (int index = 0; index < this->m_numberOfChunks; index++) { + if (this->m_chunks_len != 0) { + m_chunk_execution_states.resize(this->m_chunks_len); + for (int index = 0; index < this->m_chunks_len; index++) { m_chunk_execution_states[index] = eChunkExecutionState::NOT_SCHEDULED; } } @@ -146,9 +146,9 @@ void ExecutionGroup::initExecution() void ExecutionGroup::deinitExecution() { m_chunk_execution_states.clear(); - this->m_numberOfChunks = 0; - this->m_numberOfXChunks = 0; - this->m_numberOfYChunks = 0; + this->m_chunks_len = 0; + this->m_x_chunks_len = 0; + this->m_y_chunks_len = 0; this->m_read_operations.clear(); this->m_bTree = nullptr; } @@ -164,17 +164,17 @@ void ExecutionGroup::determineResolution(unsigned int resolution[2]) void ExecutionGroup::determineNumberOfChunks() { if (this->m_singleThreaded) { - this->m_numberOfXChunks = 1; - this->m_numberOfYChunks = 1; - this->m_numberOfChunks = 1; + this->m_x_chunks_len = 1; + this->m_y_chunks_len = 1; + this->m_chunks_len = 1; } else { const float chunkSizef = this->m_chunkSize; const int border_width = BLI_rcti_size_x(&this->m_viewerBorder); const int border_height = BLI_rcti_size_y(&this->m_viewerBorder); - this->m_numberOfXChunks = ceil(border_width / chunkSizef); - this->m_numberOfYChunks = ceil(border_height / chunkSizef); - this->m_numberOfChunks = this->m_numberOfXChunks * this->m_numberOfYChunks; + this->m_x_chunks_len = ceil(border_width / chunkSizef); + this->m_y_chunks_len = ceil(border_height / chunkSizef); + this->m_chunks_len = this->m_x_chunks_len * this->m_y_chunks_len; } } @@ -192,20 +192,20 @@ void ExecutionGroup::execute(ExecutionSystem *graph) if (bTree->test_break && bTree->test_break(bTree->tbh)) { return; } /** \note Early break out for blur and preview nodes. */ - if (this->m_numberOfChunks == 0) { + if (this->m_chunks_len == 0) { return; } /** \note Early break out. */ unsigned int chunkNumber; this->m_executionStartTime = PIL_check_seconds_timer(); - this->m_chunksFinished = 0; + this->m_chunks_finished = 0; this->m_bTree = bTree; unsigned int index; - unsigned int *chunkOrder = (unsigned int *)MEM_mallocN( - sizeof(unsigned int) * this->m_numberOfChunks, __func__); + unsigned int *chunkOrder = (unsigned int *)MEM_mallocN(sizeof(unsigned int) * this->m_chunks_len, + __func__); - for (chunkNumber = 0; chunkNumber < this->m_numberOfChunks; chunkNumber++) { + for (chunkNumber = 0; chunkNumber < this->m_chunks_len; chunkNumber++) { chunkOrder[chunkNumber] = chunkNumber; } NodeOperation *operation = this->getOutputOperation(); @@ -225,9 +225,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) switch (chunkorder) { case COM_TO_RANDOM: - for (index = 0; index < 2 * this->m_numberOfChunks; index++) { - int index1 = rand() % this->m_numberOfChunks; - int index2 = rand() % this->m_numberOfChunks; + for (index = 0; index < 2 * this->m_chunks_len; index++) { + int index1 = rand() % this->m_chunks_len; + int index2 = rand() % this->m_chunks_len; int s = chunkOrder[index1]; chunkOrder[index1] = chunkOrder[index2]; chunkOrder[index2] = s; @@ -237,9 +237,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) ChunkOrderHotspot *hotspots[1]; hotspots[0] = new ChunkOrderHotspot(border_width * centerX, border_height * centerY, 0.0f); rcti rect; - ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN( - sizeof(ChunkOrder) * this->m_numberOfChunks, __func__); - for (index = 0; index < this->m_numberOfChunks; index++) { + ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len, + __func__); + for (index = 0; index < this->m_chunks_len; index++) { determineChunkRect(&rect, index); chunkOrders[index].number = index; chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin; @@ -247,8 +247,8 @@ void ExecutionGroup::execute(ExecutionSystem *graph) chunkOrders[index].update_distance(hotspots, 1); } - std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks - 1]); - for (index = 0; index < this->m_numberOfChunks; index++) { + std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len - 1]); + for (index = 0; index < this->m_chunks_len; index++) { chunkOrder[index] = chunkOrders[index].number; } @@ -265,7 +265,7 @@ void ExecutionGroup::execute(ExecutionSystem *graph) unsigned int bx = mx + 2 * tx; unsigned int by = my + 2 * ty; - float addition = this->m_numberOfChunks / COM_RULE_OF_THIRDS_DIVIDER; + float addition = this->m_chunks_len / COM_RULE_OF_THIRDS_DIVIDER; hotspots[0] = new ChunkOrderHotspot(mx, my, addition * 0); hotspots[1] = new ChunkOrderHotspot(tx, my, addition * 1); hotspots[2] = new ChunkOrderHotspot(bx, my, addition * 2); @@ -276,9 +276,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) hotspots[7] = new ChunkOrderHotspot(mx, ty, addition * 7); hotspots[8] = new ChunkOrderHotspot(mx, by, addition * 8); rcti rect; - ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN( - sizeof(ChunkOrder) * this->m_numberOfChunks, __func__); - for (index = 0; index < this->m_numberOfChunks; index++) { + ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len, + __func__); + for (index = 0; index < this->m_chunks_len; index++) { determineChunkRect(&rect, index); chunkOrders[index].number = index; chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin; @@ -286,9 +286,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) chunkOrders[index].update_distance(hotspots, 9); } - std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks]); + std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len]); - for (index = 0; index < this->m_numberOfChunks; index++) { + for (index = 0; index < this->m_chunks_len; index++) { chunkOrder[index] = chunkOrders[index].number; } @@ -322,12 +322,11 @@ void ExecutionGroup::execute(ExecutionSystem *graph) finished = true; int numberEvaluated = 0; - for (index = startIndex; - index < this->m_numberOfChunks && numberEvaluated < maxNumberEvaluated; + for (index = startIndex; index < this->m_chunks_len && numberEvaluated < maxNumberEvaluated; index++) { chunkNumber = chunkOrder[index]; - int yChunk = chunkNumber / this->m_numberOfXChunks; - int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks); + int yChunk = chunkNumber / this->m_x_chunks_len; + int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len); switch (m_chunk_execution_states[chunkNumber]) { case eChunkExecutionState::NOT_SCHEDULED: { scheduleChunkWhenPossible(graph, xChunk, yChunk); @@ -401,7 +400,7 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::EXECUTED; } - atomic_add_and_fetch_u(&this->m_chunksFinished, 1); + atomic_add_and_fetch_u(&this->m_chunks_finished, 1); if (memoryBuffers) { for (unsigned int index = 0; index < this->m_max_read_buffer_offset; index++) { MemoryBuffer *buffer = memoryBuffers[index]; @@ -416,16 +415,16 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo } if (this->m_bTree) { // status report is only performed for top level Execution Groups. - float progress = this->m_chunksFinished; - progress /= this->m_numberOfChunks; + float progress = this->m_chunks_finished; + progress /= this->m_chunks_len; this->m_bTree->progress(this->m_bTree->prh, progress); char buf[128]; BLI_snprintf(buf, sizeof(buf), TIP_("Compositing | Tile %u-%u"), - this->m_chunksFinished, - this->m_numberOfChunks); + this->m_chunks_finished, + this->m_chunks_len); this->m_bTree->stats_draw(this->m_bTree->sdh, buf); } } @@ -456,8 +455,8 @@ inline void ExecutionGroup::determineChunkRect(rcti *rect, void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumber) const { - const unsigned int yChunk = chunkNumber / this->m_numberOfXChunks; - const unsigned int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks); + const unsigned int yChunk = chunkNumber / this->m_x_chunks_len; + const unsigned int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len); determineChunkRect(rect, xChunk, yChunk); } @@ -492,8 +491,8 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area int maxychunk = (maxy + (int)m_chunkSize - 1) / (int)m_chunkSize; minxchunk = max_ii(minxchunk, 0); minychunk = max_ii(minychunk, 0); - maxxchunk = min_ii(maxxchunk, (int)m_numberOfXChunks); - maxychunk = min_ii(maxychunk, (int)m_numberOfYChunks); + maxxchunk = min_ii(maxxchunk, (int)m_x_chunks_len); + maxychunk = min_ii(maxychunk, (int)m_y_chunks_len); bool result = true; for (indexx = minxchunk; indexx < maxxchunk; indexx++) { @@ -519,13 +518,13 @@ bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber) bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk) { - if (xChunk < 0 || xChunk >= (int)this->m_numberOfXChunks) { + if (xChunk < 0 || xChunk >= (int)this->m_x_chunks_len) { return true; } - if (yChunk < 0 || yChunk >= (int)this->m_numberOfYChunks) { + if (yChunk < 0 || yChunk >= (int)this->m_y_chunks_len) { return true; } - int chunkNumber = yChunk * this->m_numberOfXChunks + xChunk; + int chunkNumber = yChunk * this->m_x_chunks_len + xChunk; // chunk is already executed if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::EXECUTED) { return true; diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h index 7ca886f6fc5..f73f4473b5d 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.h +++ b/source/blender/compositor/intern/COM_ExecutionGroup.h @@ -76,7 +76,7 @@ class ExecutionGroup { * an input execution group is a group that is at the end of the calculation * (the output is important for the user). */ - int m_isOutput; + bool m_is_output; /** * \brief Width of the output @@ -97,17 +97,17 @@ class ExecutionGroup { /** * \brief number of chunks in the x-axis */ - unsigned int m_numberOfXChunks; + unsigned int m_x_chunks_len; /** * \brief number of chunks in the y-axis */ - unsigned int m_numberOfYChunks; + unsigned int m_y_chunks_len; /** * \brief total number of chunks */ - unsigned int m_numberOfChunks; + unsigned int m_chunks_len; /** * \brief contains this ExecutionGroup a complex NodeOperation. @@ -145,7 +145,7 @@ class ExecutionGroup { /** * \brief total number of chunks that have been calculated for this ExecutionGroup */ - unsigned int m_chunksFinished; + unsigned int m_chunks_finished; /** * \brief m_chunk_execution_states holds per chunk the execution state. this state can be @@ -269,18 +269,18 @@ class ExecutionGroup { * \note ViewerOperation, CompositeOperation, PreviewOperation. * \see NodeOperation.isOutputOperation */ - int isOutputExecutionGroup() const + bool isOutputExecutionGroup() const { - return this->m_isOutput; + return this->m_is_output; } /** * \brief set whether this ExecutionGroup is an output * \param isOutput: */ - void setOutputExecutionGroup(int isOutput) + void setOutputExecutionGroup(bool is_output) { - this->m_isOutput = isOutput; + this->m_is_output = is_output; } /** -- cgit v1.2.3 From 7c8ec99b9a8ac8fc36abb893755082bfb8dcdc3d Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 16:21:56 +0100 Subject: Cleanup: use blender::Vector. --- source/blender/compositor/intern/COM_ExecutionSystem.cpp | 3 ++- source/blender/compositor/intern/COM_ExecutionSystem.h | 6 +++--- source/blender/compositor/intern/COM_NodeOperationBuilder.cpp | 2 +- source/blender/compositor/intern/COM_NodeOperationBuilder.h | 3 +-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp index 9d6359e9cb3..21ffb7c045e 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp @@ -121,7 +121,8 @@ ExecutionSystem::~ExecutionSystem() this->m_groups.clear(); } -void ExecutionSystem::set_operations(const Operations &operations, const Groups &groups) +void ExecutionSystem::set_operations(const Operations &operations, + const blender::Vector &groups) { m_operations = operations; m_groups = groups; diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index dd68edd4793..0314c4cfbdd 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -115,7 +115,6 @@ class ExecutionGroup; class ExecutionSystem { public: typedef std::vector Operations; - typedef std::vector Groups; private: /** @@ -131,7 +130,7 @@ class ExecutionSystem { /** * \brief vector of groups */ - Groups m_groups; + blender::Vector m_groups; private: // methods /** @@ -162,7 +161,8 @@ class ExecutionSystem { */ ~ExecutionSystem(); - void set_operations(const Operations &operations, const Groups &groups); + void set_operations(const Operations &operations, + const blender::Vector &groups); /** * \brief execute this system diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp index 37d8d44ec72..d08290a2fb9 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp @@ -705,7 +705,7 @@ static void add_group_operations_recursive(Tags &visited, NodeOperation *op, Exe ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op) { ExecutionGroup *group = new ExecutionGroup(); - m_groups.push_back(group); + m_groups.append(group); Tags visited; add_group_operations_recursive(visited, op, group); diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h index 0d362af4512..6d9b5b67f11 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h @@ -64,7 +64,6 @@ class NodeOperationBuilder { typedef std::vector Operations; typedef std::vector Links; - typedef std::vector Groups; typedef std::map InputSocketMap; typedef std::map OutputSocketMap; @@ -78,7 +77,7 @@ class NodeOperationBuilder { Operations m_operations; Links m_links; - Groups m_groups; + blender::Vector m_groups; /** Maps operation inputs to node inputs */ InputSocketMap m_input_map; -- cgit v1.2.3 From d4c673d4c6dc3323327ec7bd5969551e410885a8 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 16:28:08 +0100 Subject: Cleanup: use blender::Vector. --- source/blender/compositor/intern/COM_NodeGraph.cpp | 2 +- source/blender/compositor/intern/COM_NodeGraph.h | 26 +++++++--------------- .../compositor/intern/COM_NodeOperationBuilder.cpp | 8 +++---- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/source/blender/compositor/intern/COM_NodeGraph.cpp b/source/blender/compositor/intern/COM_NodeGraph.cpp index dc5ae52ba8e..421a762d9b5 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.cpp +++ b/source/blender/compositor/intern/COM_NodeGraph.cpp @@ -90,7 +90,7 @@ void NodeGraph::add_node(Node *node, void NodeGraph::add_link(NodeOutput *fromSocket, NodeInput *toSocket) { - m_links.push_back(Link(fromSocket, toSocket)); + m_links.append(Link(fromSocket, toSocket)); /* register with the input */ toSocket->setLink(fromSocket); diff --git a/source/blender/compositor/intern/COM_NodeGraph.h b/source/blender/compositor/intern/COM_NodeGraph.h index 7252d546fce..990e3a30831 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.h +++ b/source/blender/compositor/intern/COM_NodeGraph.h @@ -18,6 +18,8 @@ #pragma once +#include "BLI_vector.hh" + #include #include #include @@ -39,33 +41,21 @@ class NodeOutput; */ class NodeGraph { public: - class Link { - private: - NodeOutput *m_from; - NodeInput *m_to; - - public: - Link(NodeOutput *from, NodeInput *to) : m_from(from), m_to(to) - { - } + struct Link { + NodeOutput *from; + NodeInput *to; - NodeOutput *getFromSocket() const - { - return m_from; - } - NodeInput *getToSocket() const + Link(NodeOutput *from, NodeInput *to) : from(from), to(to) { - return m_to; } }; typedef std::vector Nodes; typedef Nodes::iterator NodeIterator; - typedef std::vector Links; private: Nodes m_nodes; - Links m_links; + blender::Vector m_links; public: NodeGraph(); @@ -75,7 +65,7 @@ class NodeGraph { { return m_nodes; } - const Links &links() const + const blender::Vector &links() const { return m_links; } diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp index d08290a2fb9..507dfab2627 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp @@ -72,11 +72,9 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system) inverse_input_map[it->second].push_back(it->first); } - for (NodeGraph::Links::const_iterator it = m_graph.links().begin(); it != m_graph.links().end(); - ++it) { - const NodeGraph::Link &link = *it; - NodeOutput *from = link.getFromSocket(); - NodeInput *to = link.getToSocket(); + for (const NodeGraph::Link &link : m_graph.links()) { + NodeOutput *from = link.from; + NodeInput *to = link.to; NodeOperationOutput *op_from = find_operation_output(m_output_map, from); const OpInputs &op_to_list = find_operation_inputs(inverse_input_map, to); -- cgit v1.2.3 From 0729376a13a55a8e375045e8021b00cb4d9fd2e9 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 16:44:30 +0100 Subject: Fix: compilation OpenCL kernels Compositor. introduced during cleanup. --- .../compositor/operations/COM_OpenCLKernels.cl | 38 +++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/source/blender/compositor/operations/COM_OpenCLKernels.cl b/source/blender/compositor/operations/COM_OpenCLKernels.cl index b31153abd1e..ebe8a6d08ec 100644 --- a/source/blender/compositor/operations/COM_OpenCLKernels.cl +++ b/source/blender/compositor/operations/COM_OpenCLKernels.cl @@ -48,8 +48,8 @@ __kernel void bokehBlurKernel(__read_only image2d_t boundingBox, __read_only ima if (tempBoundingBox > 0.0f && radius > 0 ) { const int2 bokehImageDim = get_image_dim(bokehImage); const int2 bokehImageCenter = bokehImageDim/2; - const int2 minXY = MAX2(realCoordinate - radius, zero); - const int2 maxXY = MIN2(realCoordinate + radius, dimension); + const int2 minXY = max(realCoordinate - radius, zero); + const int2 maxXY = min(realCoordinate + radius, dimension); int nx, ny; float2 uv; @@ -97,10 +97,10 @@ __kernel void defocusKernel(__read_only image2d_t inputImage, __read_only image2 float4 multiplier_accum = {1.0f, 1.0f, 1.0f, 1.0f}; float4 color_accum; - int minx = MAX2(realCoordinate.s0 - maxBlurScalar, 0); - int miny = MAX2(realCoordinate.s1 - maxBlurScalar, 0); - int maxx = MIN2(realCoordinate.s0 + maxBlurScalar, dimension.s0); - int maxy = MIN2(realCoordinate.s1 + maxBlurScalar, dimension.s1); + int minx = max(realCoordinate.s0 - maxBlurScalar, 0); + int miny = max(realCoordinate.s1 - maxBlurScalar, 0); + int maxx = min(realCoordinate.s0 + maxBlurScalar, dimension.s0); + int maxy = min(realCoordinate.s1 + maxBlurScalar, dimension.s1); { int2 inputCoordinate = realCoordinate - offsetInput; @@ -116,7 +116,7 @@ __kernel void defocusKernel(__read_only image2d_t inputImage, __read_only image2 float dx = nx - realCoordinate.s0; if (dx != 0 || dy != 0) { inputCoordinate.s0 = nx - offsetInput.s0; - size = MIN2(read_imagef(inputSize, SAMPLER_NEAREST, inputCoordinate).s0 * scalar, size_center); + size = min(read_imagef(inputSize, SAMPLER_NEAREST, inputCoordinate).s0 * scalar, size_center); if (size > threshold) { if (size >= fabs(dx) && size >= fabs(dy)) { float2 uv = {256.0f + dx * 255.0f / size, @@ -157,8 +157,8 @@ __kernel void dilateKernel(__read_only image2d_t inputImage, __write_only image coords += offset; const int2 realCoordinate = coords + offsetOutput; - const int2 minXY = MAX2(realCoordinate - scope, zero); - const int2 maxXY = MIN2(realCoordinate + scope, dimension); + const int2 minXY = max(realCoordinate - scope, zero); + const int2 maxXY = min(realCoordinate + scope, dimension); float value = 0.0f; int nx, ny; @@ -170,7 +170,7 @@ __kernel void dilateKernel(__read_only image2d_t inputImage, __write_only image const float deltaX = (realCoordinate.x - nx); const float measuredDistance = deltaX * deltaX + deltaY * deltaY; if (measuredDistance <= distanceSquared) { - value = MAX2(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0); + value = max(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0); } } } @@ -188,8 +188,8 @@ __kernel void erodeKernel(__read_only image2d_t inputImage, __write_only image2 coords += offset; const int2 realCoordinate = coords + offsetOutput; - const int2 minXY = MAX2(realCoordinate - scope, zero); - const int2 maxXY = MIN2(realCoordinate + scope, dimension); + const int2 minXY = max(realCoordinate - scope, zero); + const int2 maxXY = min(realCoordinate + scope, dimension); float value = 1.0f; int nx, ny; @@ -201,7 +201,7 @@ __kernel void erodeKernel(__read_only image2d_t inputImage, __write_only image2 const float deltaY = (realCoordinate.y - ny); const float measuredDistance = deltaX * deltaX+deltaY * deltaY; if (measuredDistance <= distanceSquared) { - value = MIN2(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0); + value = min(value, read_imagef(inputImage, SAMPLER_NEAREST, inputXy).s0); } } } @@ -268,10 +268,10 @@ __kernel void gaussianXBlurOperationKernel(__read_only image2d_t inputImage, int2 inputCoordinate = realCoordinate - offsetInput; float weight = 0.0f; - int xmin = MAX2(realCoordinate.x - filter_size, 0) - offsetInput.x; - int xmax = MIN2(realCoordinate.x + filter_size + 1, dimension.x) - offsetInput.x; + int xmin = max(realCoordinate.x - filter_size, 0) - offsetInput.x; + int xmax = min(realCoordinate.x + filter_size + 1, dimension.x) - offsetInput.x; - for (int nx = xmin, i = MAX2(filter_size - realCoordinate.x, 0); nx < xmax; ++nx, ++i) { + for (int nx = xmin, i = max(filter_size - realCoordinate.x, 0); nx < xmax; ++nx, ++i) { float w = gausstab[i]; inputCoordinate.x = nx; color += read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate) * w; @@ -299,10 +299,10 @@ __kernel void gaussianYBlurOperationKernel(__read_only image2d_t inputImage, int2 inputCoordinate = realCoordinate - offsetInput; float weight = 0.0f; - int ymin = MAX2(realCoordinate.y - filter_size, 0) - offsetInput.y; - int ymax = MIN2(realCoordinate.y + filter_size + 1, dimension.y) - offsetInput.y; + int ymin = max(realCoordinate.y - filter_size, 0) - offsetInput.y; + int ymax = min(realCoordinate.y + filter_size + 1, dimension.y) - offsetInput.y; - for (int ny = ymin, i = MAX2(filter_size - realCoordinate.y, 0); ny < ymax; ++ny, ++i) { + for (int ny = ymin, i = max(filter_size - realCoordinate.y, 0); ny < ymax; ++ny, ++i) { float w = gausstab[i]; inputCoordinate.y = ny; color += read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate) * w; -- cgit v1.2.3 From ffd5b0d91e26a1b2018d503a42f309186f39fcdf Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 16:45:11 +0100 Subject: Cleanup: Use blender::Vector. --- .../compositor/intern/COM_ExecutionSystem.cpp | 7 +-- .../compositor/intern/COM_ExecutionSystem.h | 10 +++-- .../compositor/intern/COM_NodeOperationBuilder.cpp | 51 ++++++++-------------- .../compositor/intern/COM_NodeOperationBuilder.h | 3 +- 4 files changed, 28 insertions(+), 43 deletions(-) diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp index 21ffb7c045e..6691e5feb5f 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp @@ -121,7 +121,7 @@ ExecutionSystem::~ExecutionSystem() this->m_groups.clear(); } -void ExecutionSystem::set_operations(const Operations &operations, +void ExecutionSystem::set_operations(const blender::Vector &operations, const blender::Vector &groups) { m_operations = operations; @@ -136,10 +136,7 @@ void ExecutionSystem::execute() DebugInfo::execute_started(this); unsigned int order = 0; - for (std::vector::iterator iter = this->m_operations.begin(); - iter != this->m_operations.end(); - ++iter) { - NodeOperation *operation = *iter; + for (NodeOperation *operation : m_operations) { if (operation->isReadBufferOperation()) { ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; readOperation->setOffset(order); diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index 0314c4cfbdd..9a51baf55d7 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -21,12 +21,16 @@ class ExecutionGroup; #pragma once #include "BKE_text.h" + #include "COM_ExecutionGroup.h" #include "COM_Node.h" #include "COM_NodeOperation.h" + #include "DNA_color_types.h" #include "DNA_node_types.h" +#include "BLI_vector.hh" + /** * \page execution Execution model * In order to get to an efficient model for execution, several steps are being done. these steps @@ -113,8 +117,6 @@ class ExecutionGroup; * \brief the ExecutionSystem contains the whole compositor tree. */ class ExecutionSystem { - public: - typedef std::vector Operations; private: /** @@ -125,7 +127,7 @@ class ExecutionSystem { /** * \brief vector of operations */ - Operations m_operations; + blender::Vector m_operations; /** * \brief vector of groups @@ -161,7 +163,7 @@ class ExecutionSystem { */ ~ExecutionSystem(); - void set_operations(const Operations &operations, + void set_operations(const blender::Vector &operations, const blender::Vector &groups); /** diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp index 507dfab2627..688b693080f 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp @@ -123,7 +123,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system) void NodeOperationBuilder::addOperation(NodeOperation *operation) { - m_operations.push_back(operation); + m_operations.append(operation); } void NodeOperationBuilder::mapInputSocket(NodeInput *node_socket, @@ -304,8 +304,7 @@ void NodeOperationBuilder::add_operation_input_constants() */ using Inputs = std::vector; Inputs pending_inputs; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; + for (NodeOperation *op : m_operations) { for (int k = 0; k < op->getNumberOfInputSockets(); ++k) { NodeOperationInput *input = op->getInputSocket(k); if (!input->isConnected()) { @@ -406,9 +405,7 @@ void NodeOperationBuilder::resolve_proxies() void NodeOperationBuilder::determineResolutions() { /* determine all resolutions of the operations (Width/Height) */ - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { if (op->isOutputOperation(m_context->isRendering()) && !op->isPreviewOperation()) { unsigned int resolution[2] = {0, 0}; unsigned int preferredResolution[2] = {0, 0}; @@ -417,9 +414,7 @@ void NodeOperationBuilder::determineResolutions() } } - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { if (op->isOutputOperation(m_context->isRendering()) && op->isPreviewOperation()) { unsigned int resolution[2] = {0, 0}; unsigned int preferredResolution[2] = {0, 0}; @@ -573,16 +568,14 @@ void NodeOperationBuilder::add_complex_operation_buffers() /* note: complex ops and get cached here first, since adding operations * will invalidate iterators over the main m_operations */ - Operations complex_ops; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - if ((*it)->isComplex()) { - complex_ops.push_back(*it); + blender::Vector complex_ops; + for (NodeOperation *operation : m_operations) { + if (operation->isComplex()) { + complex_ops.append(operation); } } - for (Operations::const_iterator it = complex_ops.begin(); it != complex_ops.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : complex_ops) { DebugInfo::operation_read_write_buffer(op); for (int index = 0; index < op->getNumberOfInputSockets(); index++) { @@ -622,9 +615,7 @@ static void find_reachable_operations_recursive(Tags &reachable, NodeOperation * void NodeOperationBuilder::prune_operations() { Tags reachable; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { /* output operations are primary executed operations */ if (op->isOutputOperation(m_context->isRendering())) { find_reachable_operations_recursive(reachable, op); @@ -632,12 +623,10 @@ void NodeOperationBuilder::prune_operations() } /* delete unreachable operations */ - Operations reachable_ops; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + blender::Vector reachable_ops; + for (NodeOperation *op : m_operations) { if (reachable.find(op) != reachable.end()) { - reachable_ops.push_back(op); + reachable_ops.append(op); } else { delete op; @@ -648,7 +637,7 @@ void NodeOperationBuilder::prune_operations() } /* topological (depth-first) sorting of operations */ -static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted, +static void sort_operations_recursive(blender::Vector &sorted, Tags &visited, NodeOperation *op) { @@ -664,17 +653,17 @@ static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted, } } - sorted.push_back(op); + sorted.append(op); } void NodeOperationBuilder::sort_operations() { - Operations sorted; + blender::Vector sorted; sorted.reserve(m_operations.size()); Tags visited; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - sort_operations_recursive(sorted, visited, *it); + for (NodeOperation *operation : m_operations) { + sort_operations_recursive(sorted, visited, operation); } m_operations = sorted; @@ -713,9 +702,7 @@ ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op) void NodeOperationBuilder::group_operations() { - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { if (op->isOutputOperation(m_context->isRendering())) { ExecutionGroup *group = make_group(op); group->setOutputExecutionGroup(true); diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h index 6d9b5b67f11..b502a12d9b1 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h @@ -62,7 +62,6 @@ class NodeOperationBuilder { } }; - typedef std::vector Operations; typedef std::vector Links; typedef std::map InputSocketMap; @@ -75,7 +74,7 @@ class NodeOperationBuilder { const CompositorContext *m_context; NodeGraph m_graph; - Operations m_operations; + blender::Vector m_operations; Links m_links; blender::Vector m_groups; -- cgit v1.2.3 From d5c727c6ea5f52201ba92a2a7a4d92f1cb7a4138 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 5 Mar 2021 16:08:11 +0100 Subject: Fix windows compilation. --- source/blender/compositor/intern/COM_Device.h | 2 +- source/blender/compositor/intern/COM_WorkPackage.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/source/blender/compositor/intern/COM_Device.h b/source/blender/compositor/intern/COM_Device.h index bb95f1e953c..0b0f0f5c1c6 100644 --- a/source/blender/compositor/intern/COM_Device.h +++ b/source/blender/compositor/intern/COM_Device.h @@ -55,7 +55,7 @@ class Device { * \brief execute a WorkPackage * \param work: the WorkPackage to execute */ - virtual void execute(WorkPackage *work) = 0; + virtual void execute(struct WorkPackage *work) = 0; #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("COM:Device") diff --git a/source/blender/compositor/intern/COM_WorkPackage.h b/source/blender/compositor/intern/COM_WorkPackage.h index 81616e123b2..db5eb3d3072 100644 --- a/source/blender/compositor/intern/COM_WorkPackage.h +++ b/source/blender/compositor/intern/COM_WorkPackage.h @@ -16,8 +16,6 @@ * Copyright 2011, Blender Foundation. */ -class WorkPackage; - #pragma once class ExecutionGroup; -- cgit v1.2.3 From f882bee4311d22fef01f33d95a6386a6ee2bef02 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 5 Mar 2021 10:13:42 -0600 Subject: Fix crash with pinned geometry node tree with no active object The check for a null active object was after trying to retrieve the active modifier from the object. --- source/blender/blenkernel/intern/node_ui_storage.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/node_ui_storage.cc b/source/blender/blenkernel/intern/node_ui_storage.cc index 6e0253eca31..97f52dd3727 100644 --- a/source/blender/blenkernel/intern/node_ui_storage.cc +++ b/source/blender/blenkernel/intern/node_ui_storage.cc @@ -62,8 +62,12 @@ const NodeUIStorage *BKE_node_tree_ui_storage_get_from_context(const bContext *C } const Object *active_object = CTX_data_active_object(C); + if (active_object == nullptr) { + return nullptr; + } + const ModifierData *active_modifier = BKE_object_active_modifier(active_object); - if (active_object == nullptr || active_modifier == nullptr) { + if (active_modifier == nullptr) { return nullptr; } -- cgit v1.2.3 From ed84161529527274852d5665f93a7d8b7cd1be9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastia=CC=81n=20Barschkis?= Date: Fri, 5 Mar 2021 17:35:25 +0100 Subject: Cleanup: Rename func occurences to _fn Use _fn as a suffix for callbacks. --- source/blender/blenkernel/BKE_node.h | 16 +++---- source/blender/blenkernel/intern/node.cc | 16 +++---- source/blender/editors/space_file/filelist.c | 50 +++++++++++----------- source/blender/makesrna/RNA_define.h | 2 +- source/blender/makesrna/intern/makesrna.c | 6 +-- source/blender/makesrna/intern/rna_access.c | 20 ++++----- source/blender/makesrna/intern/rna_define.c | 12 +++--- .../blender/makesrna/intern/rna_internal_types.h | 4 +- source/blender/makesrna/intern/rna_rna.c | 4 +- source/blender/nodes/intern/node_exec.c | 14 +++--- source/blender/nodes/intern/node_exec.h | 2 +- source/blender/nodes/shader/node_shader_util.c | 4 +- .../shader/nodes/node_shader_tex_environment.c | 10 ++--- 13 files changed, 80 insertions(+), 80 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index d675df6d868..655c53455cc 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -301,11 +301,11 @@ typedef struct bNodeType { void (*free_self)(struct bNodeType *ntype); /* **** execution callbacks **** */ - NodeInitExecFunction initexecfunc; - NodeFreeExecFunction freeexecfunc; - NodeExecFunction execfunc; + NodeInitExecFunction init_exec_fn; + NodeFreeExecFunction free_exec_fn; + NodeExecFunction exec_fn; /* gpu */ - NodeGPUExecFunction gpufunc; + NodeGPUExecFunction gpu_fn; /* Expands the bNode into nodes in a multi-function network, which will be evaluated later on. */ NodeExpandInMFNetworkFunction expand_in_mf_network; @@ -829,10 +829,10 @@ void node_type_group_update(struct bNodeType *ntype, struct bNode *node)); void node_type_exec(struct bNodeType *ntype, - NodeInitExecFunction initexecfunc, - NodeFreeExecFunction freeexecfunc, - NodeExecFunction execfunc); -void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc); + NodeInitExecFunction init_exec_fn, + NodeFreeExecFunction free_exec_fn, + NodeExecFunction exec_fn); +void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn); void node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *)); diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 55cb0d5cce4..6b46ae3430b 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -4482,18 +4482,18 @@ void node_type_group_update(struct bNodeType *ntype, } void node_type_exec(struct bNodeType *ntype, - NodeInitExecFunction initexecfunc, - NodeFreeExecFunction freeexecfunc, - NodeExecFunction execfunc) + NodeInitExecFunction init_exec_fn, + NodeFreeExecFunction free_exec_fn, + NodeExecFunction exec_fn) { - ntype->initexecfunc = initexecfunc; - ntype->freeexecfunc = freeexecfunc; - ntype->execfunc = execfunc; + ntype->init_exec_fn = init_exec_fn; + ntype->free_exec_fn = free_exec_fn; + ntype->exec_fn = exec_fn; } -void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc) +void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn) { - ntype->gpufunc = gpufunc; + ntype->gpu_fn = gpu_fn; } void node_type_internal_links(bNodeType *ntype, diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 518fc777c67..757ec7c741f 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -410,14 +410,14 @@ typedef struct FileList { /* Set given path as root directory, * if last bool is true may change given string in place to a valid value. * Returns True if valid dir. */ - bool (*checkdirf)(struct FileList *, char *, const bool); + bool (*check_dir_fn)(struct FileList *, char *, const bool); /* Fill filelist (to be called by read job). */ - void (*read_jobf)( + void (*read_job_fn)( Main *, struct FileList *, const char *, short *, short *, float *, ThreadMutex *); /* Filter an entry of current filelist. */ - bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *); + bool (*filter_fn)(struct FileListInternEntry *, const char *, FileListFilter *); short tags; /* FileListTags */ } FileList; @@ -963,7 +963,7 @@ void filelist_filter(FileList *filelist) /* Filter remap & count how many files are left after filter in a single loop. */ for (file = filelist->filelist_intern.entries.first; file; file = file->next) { - if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) { + if (filelist->filter_fn(file, filelist->filelist.root, &filelist->filter_data)) { filtered_tmp[num_filtered++] = file; } } @@ -1742,25 +1742,25 @@ void filelist_settype(FileList *filelist, short type) filelist->tags = 0; switch (filelist->type) { case FILE_MAIN: - filelist->checkdirf = filelist_checkdir_main; - filelist->read_jobf = filelist_readjob_main; - filelist->filterf = is_filtered_main; + filelist->check_dir_fn = filelist_checkdir_main; + filelist->read_job_fn = filelist_readjob_main; + filelist->filter_fn = is_filtered_main; break; case FILE_LOADLIB: - filelist->checkdirf = filelist_checkdir_lib; - filelist->read_jobf = filelist_readjob_lib; - filelist->filterf = is_filtered_lib; + filelist->check_dir_fn = filelist_checkdir_lib; + filelist->read_job_fn = filelist_readjob_lib; + filelist->filter_fn = is_filtered_lib; break; case FILE_MAIN_ASSET: - filelist->checkdirf = filelist_checkdir_main_assets; - filelist->read_jobf = filelist_readjob_main_assets; - filelist->filterf = is_filtered_main_assets; + filelist->check_dir_fn = filelist_checkdir_main_assets; + filelist->read_job_fn = filelist_readjob_main_assets; + filelist->filter_fn = is_filtered_main_assets; filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA | FILELIST_TAGS_NO_THREADS; break; default: - filelist->checkdirf = filelist_checkdir_dir; - filelist->read_jobf = filelist_readjob_dir; - filelist->filterf = is_filtered_file; + filelist->check_dir_fn = filelist_checkdir_dir; + filelist->read_job_fn = filelist_readjob_dir; + filelist->filter_fn = is_filtered_file; break; } @@ -1867,7 +1867,7 @@ const char *filelist_dir(struct FileList *filelist) bool filelist_is_dir(struct FileList *filelist, const char *path) { - return filelist->checkdirf(filelist, (char *)path, false); + return filelist->check_dir_fn(filelist, (char *)path, false); } /** @@ -1879,7 +1879,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir) BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir); - const bool is_valid_path = filelist->checkdirf(filelist, r_dir, !allow_invalid); + const bool is_valid_path = filelist->check_dir_fn(filelist, r_dir, !allow_invalid); BLI_assert(is_valid_path || allow_invalid); UNUSED_VARS_NDEBUG(is_valid_path); @@ -3356,13 +3356,13 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update BLI_mutex_unlock(&flrj->lock); - flrj->tmp_filelist->read_jobf(flrj->current_main, - flrj->tmp_filelist, - flrj->main_name, - stop, - do_update, - progress, - &flrj->lock); + flrj->tmp_filelist->read_job_fn(flrj->current_main, + flrj->tmp_filelist, + flrj->main_name, + stop, + do_update, + progress, + &flrj->lock); } static void filelist_readjob_update(void *flrjv) diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index c12426ffcd0..c49a52ceed7 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -421,7 +421,7 @@ void RNA_def_property_string_funcs(PropertyRNA *prop, const char *length, const char *set); void RNA_def_property_pointer_funcs( - PropertyRNA *prop, const char *get, const char *set, const char *typef, const char *poll); + PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll); void RNA_def_property_collection_funcs(PropertyRNA *prop, const char *begin, const char *next, diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index bec3db10905..1f887c2eec3 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3671,7 +3671,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr } } else { - if (!defaultfound && !(eprop->itemf && eprop->item == DummyRNA_NULL_items)) { + if (!defaultfound && !(eprop->item_fn && eprop->item == DummyRNA_NULL_items)) { CLOG_ERROR(&LOG, "%s%s.%s, enum default is not in items.", srna->identifier, @@ -3992,7 +3992,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr "\t%s, %s, %s, %s, %s, NULL, ", rna_function_string(eprop->get), rna_function_string(eprop->set), - rna_function_string(eprop->itemf), + rna_function_string(eprop->item_fn), rna_function_string(eprop->get_ex), rna_function_string(eprop->set_ex)); if (eprop->item) { @@ -4010,7 +4010,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr "\t%s, %s, %s, %s,", rna_function_string(pprop->get), rna_function_string(pprop->set), - rna_function_string(pprop->typef), + rna_function_string(pprop->type_fn), rna_function_string(pprop->poll)); if (pprop->type) { fprintf(f, "&RNA_%s\n", (const char *)pprop->type); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index c5dd516d16e..8e5e70642cc 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1571,8 +1571,8 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop) if (prop->type == PROP_POINTER) { PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop; - if (pprop->typef) { - return pprop->typef(ptr); + if (pprop->type_fn) { + return pprop->type_fn(ptr); } if (pprop->type) { return pprop->type; @@ -1623,14 +1623,14 @@ void RNA_property_enum_items_ex(bContext *C, *r_free = false; - if (!use_static && eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { + if (!use_static && eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { const EnumPropertyItem *item; if (prop->flag & PROP_ENUM_NO_CONTEXT) { - item = eprop->itemf(NULL, ptr, prop, r_free); + item = eprop->item_fn(NULL, ptr, prop, r_free); } else { - item = eprop->itemf(C, ptr, prop, r_free); + item = eprop->item_fn(C, ptr, prop, r_free); } /* any callbacks returning NULL should be fixed */ @@ -1753,16 +1753,16 @@ void RNA_property_enum_items_gettexted_all(bContext *C, *r_totitem = eprop->totitem; } - if (eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { + if (eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { const EnumPropertyItem *item; int i; bool free = false; if (prop->flag & PROP_ENUM_NO_CONTEXT) { - item = eprop->itemf(NULL, ptr, prop, &free); + item = eprop->item_fn(NULL, ptr, prop, &free); } else { - item = eprop->itemf(C, ptr, prop, &free); + item = eprop->item_fn(C, ptr, prop, &free); } /* any callbacks returning NULL should be fixed */ @@ -3662,8 +3662,8 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop) } /* for groups, data is idprop itself */ - if (pprop->typef) { - return rna_pointer_inherit_refine(ptr, pprop->typef(ptr), idprop); + if (pprop->type_fn) { + return rna_pointer_inherit_refine(ptr, pprop->type_fn(ptr), idprop); } return rna_pointer_inherit_refine(ptr, pprop->type, idprop); } diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index df3bd0cca29..5e188285e39 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -3267,7 +3267,7 @@ void RNA_def_property_enum_funcs(PropertyRNA *prop, eprop->set = (PropEnumSetFunc)set; } if (item) { - eprop->itemf = (PropEnumItemFunc)item; + eprop->item_fn = (PropEnumItemFunc)item; } break; } @@ -3292,7 +3292,7 @@ void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop, eprop->set_ex = setfunc; } if (itemfunc) { - eprop->itemf = itemfunc; + eprop->item_fn = itemfunc; } if (getfunc || setfunc) { @@ -3373,7 +3373,7 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop, } void RNA_def_property_pointer_funcs( - PropertyRNA *prop, const char *get, const char *set, const char *typef, const char *poll) + PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll) { StructRNA *srna = DefRNA.laststruct; @@ -3392,8 +3392,8 @@ void RNA_def_property_pointer_funcs( if (set) { pprop->set = (PropPointerSetFunc)set; } - if (typef) { - pprop->typef = (PropPointerTypeFunc)typef; + if (type_fn) { + pprop->type_fn = (PropPointerTypeFunc)type_fn; } if (poll) { pprop->poll = (PropPointerPollFunc)poll; @@ -3821,7 +3821,7 @@ PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont_, void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc) { EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop; - eprop->itemf = itemfunc; + eprop->item_fn = itemfunc; } PropertyRNA *RNA_def_float(StructOrFunctionRNA *cont_, diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index e6ed0f69300..1dd08bb1074 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -453,7 +453,7 @@ typedef struct EnumPropertyRNA { PropEnumGetFunc get; PropEnumSetFunc set; - PropEnumItemFunc itemf; + PropEnumItemFunc item_fn; PropEnumGetFuncEx get_ex; PropEnumSetFuncEx set_ex; @@ -471,7 +471,7 @@ typedef struct PointerPropertyRNA { PropPointerGetFunc get; PropPointerSetFunc set; - PropPointerTypeFunc typef; + PropPointerTypeFunc type_fn; /** unlike operators, 'set' can still run if poll fails, used for filtering display. */ PropPointerPollFunc poll; diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index b0a942cd39e..d553ead1e45 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -910,14 +910,14 @@ static const EnumPropertyItem *rna_EnumProperty_default_itemf(bContext *C, return DummyRNA_NULL_items; } - if ((eprop->itemf == NULL) || (eprop->itemf == rna_EnumProperty_default_itemf) || + if ((eprop->item_fn == NULL) || (eprop->item_fn == rna_EnumProperty_default_itemf) || (ptr->type == &RNA_EnumProperty) || (C == NULL)) { if (eprop->item) { return eprop->item; } } - return eprop->itemf(C, ptr, prop, r_free); + return eprop->item_fn(C, ptr, prop, r_free); } /* XXX - not sure this is needed? */ diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c index 0d46119ab60..6207a1bf024 100644 --- a/source/blender/nodes/intern/node_exec.c +++ b/source/blender/nodes/intern/node_exec.c @@ -218,7 +218,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, /* prepare all nodes for execution */ for (n = 0, nodeexec = exec->nodeexec; n < totnodes; n++, nodeexec++) { node = nodeexec->node = nodelist[n]; - nodeexec->freeexecfunc = node->typeinfo->freeexecfunc; + nodeexec->free_exec_fn = node->typeinfo->free_exec_fn; /* tag inputs */ for (sock = node->inputs.first; sock; sock = sock->next) { @@ -242,8 +242,8 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, nodeexec->data.preview = context->previews ? BKE_node_instance_hash_lookup(context->previews, nodekey) : NULL; - if (node->typeinfo->initexecfunc) { - nodeexec->data.data = node->typeinfo->initexecfunc(context, node, nodekey); + if (node->typeinfo->init_exec_fn) { + nodeexec->data.data = node->typeinfo->init_exec_fn(context, node, nodekey); } } @@ -264,8 +264,8 @@ void ntree_exec_end(bNodeTreeExec *exec) } for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) { - if (nodeexec->freeexecfunc) { - nodeexec->freeexecfunc(nodeexec->data.data); + if (nodeexec->free_exec_fn) { + nodeexec->free_exec_fn(nodeexec->data.data); } } @@ -323,8 +323,8 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call * If the mute func is not set, assume the node should never be muted, * and hence execute it! */ - if (node->typeinfo->execfunc && !(node->flag & NODE_MUTED)) { - node->typeinfo->execfunc(callerdata, thread, node, &nodeexec->data, nsin, nsout); + if (node->typeinfo->exec_fn && !(node->flag & NODE_MUTED)) { + node->typeinfo->exec_fn(callerdata, thread, node, &nodeexec->data, nsin, nsout); } } } diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h index 806dd10d9bf..de7cbb8cedb 100644 --- a/source/blender/nodes/intern/node_exec.h +++ b/source/blender/nodes/intern/node_exec.h @@ -48,7 +48,7 @@ typedef struct bNodeExec { bNodeExecData data; /** Free function, stored in exec itself to avoid dangling node pointer access. */ - NodeFreeExecFunction freeexecfunc; + NodeFreeExecFunction free_exec_fn; } bNodeExec; /* Execution Data for each instance of node tree execution */ diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c index 25d6aef69e5..1a2405e021f 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.c @@ -257,11 +257,11 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node } if (do_it) { - if (node->typeinfo->gpufunc) { + if (node->typeinfo->gpu_fn) { node_get_stack(node, stack, nsin, nsout); gpu_stack_from_data_list(gpuin, &node->inputs, nsin); gpu_stack_from_data_list(gpuout, &node->outputs, nsout); - if (node->typeinfo->gpufunc(mat, node, &nodeexec->data, gpuin, gpuout)) { + if (node->typeinfo->gpu_fn(mat, node, &nodeexec->data, gpuin, gpuout)) { data_from_gpu_stack_list(&node->outputs, nsout, gpuout); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c index 41c978e75ba..26a1db1f3a6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -90,7 +90,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, sampler &= ~GPU_SAMPLER_REPEAT; } - const char *gpufunc; + const char *gpu_fn; static const char *names[] = { "node_tex_image_linear", "node_tex_image_cubic", @@ -98,19 +98,19 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, switch (tex->interpolation) { case SHD_INTERP_LINEAR: - gpufunc = names[0]; + gpu_fn = names[0]; break; case SHD_INTERP_CLOSEST: sampler &= ~(GPU_SAMPLER_FILTER | GPU_SAMPLER_MIPMAP); - gpufunc = names[0]; + gpu_fn = names[0]; break; default: - gpufunc = names[1]; + gpu_fn = names[1]; break; } /* Sample texture with correct interpolation. */ - GPU_link(mat, gpufunc, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha); + GPU_link(mat, gpu_fn, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha); if (out[0].hasoutput) { if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) || -- cgit v1.2.3 From b9e54566e3b1a49d9757680da64d8e19c136c706 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 5 Mar 2021 17:38:53 +0100 Subject: Cleanup: Add & use enum value for ID Outliner element type Code to check if the Outliner tree-element type was the general ID one would always check against "0" (explicity or even implicitly). For somebody unfamiliar with the code this is very confusing. Instead the value should be given a name, e.g. through an enum. Adds `TSE_SOME_ID` as the "default" ID tree-element type. Other types may still represent IDs, as I explained in a comment at the definition. There may also still be cases where the type is checked against "0". I noted in the comment that such cases should be cleaned up if found. --- .../blender/blenkernel/intern/outliner_treehash.c | 4 +- .../editors/space_outliner/outliner_collections.c | 10 ++--- .../editors/space_outliner/outliner_context.c | 2 +- .../editors/space_outliner/outliner_dragdrop.c | 8 ++-- .../blender/editors/space_outliner/outliner_draw.c | 35 +++++++-------- .../blender/editors/space_outliner/outliner_edit.c | 8 ++-- .../editors/space_outliner/outliner_select.c | 16 +++---- .../blender/editors/space_outliner/outliner_sync.c | 4 +- .../editors/space_outliner/outliner_tools.c | 9 ++-- .../blender/editors/space_outliner/outliner_tree.c | 51 ++++++++++++---------- .../editors/space_outliner/outliner_utils.c | 8 ++-- .../space_outliner/tree/tree_display_libraries.cc | 4 +- .../space_outliner/tree/tree_display_orphaned.cc | 3 +- .../space_outliner/tree/tree_display_scenes.cc | 3 +- .../space_outliner/tree/tree_display_view_layer.cc | 14 +++--- .../space_outliner/tree/tree_element_anim_data.cc | 3 +- source/blender/makesdna/DNA_outliner_types.h | 10 +++++ 17 files changed, 107 insertions(+), 85 deletions(-) diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c index 05873d20f7f..b9497d389e7 100644 --- a/source/blender/blenkernel/intern/outliner_treehash.c +++ b/source/blender/blenkernel/intern/outliner_treehash.c @@ -101,7 +101,7 @@ static unsigned int tse_hash(const void *ptr) unsigned int u_int; } hash; - BLI_assert(tse->type || !tse->nr); + BLI_assert((tse->type != TSE_SOME_ID) || !tse->nr); hash.h_pair[0] = tse->type; hash.h_pair[1] = tse->nr; @@ -193,7 +193,7 @@ static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short { TreeStoreElem tse_template; tse_template.type = type; - tse_template.nr = type ? nr : 0; /* we're picky! :) */ + tse_template.nr = (type == TSE_SOME_ID) ? 0 : nr; /* we're picky! :) */ tse_template.id = id; BLI_assert(th); diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index ef5733fe375..d54e35f659c 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -71,7 +71,7 @@ bool outliner_is_collection_tree_element(const TreeElement *te) TSE_VIEW_COLLECTION_BASE)) { return true; } - if (tselem->type == 0 && te->idcode == ID_GR) { + if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_GR) { return true; } @@ -94,7 +94,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) Scene *scene = (Scene *)tselem->id; return scene->master_collection; } - if (tselem->type == 0 && te->idcode == ID_GR) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_GR)) { return (Collection *)tselem->id; } @@ -111,7 +111,7 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu return TRAVERSE_CONTINUE; } - if (tselem->type || (tselem->id && GS(tselem->id->name) != ID_GR)) { + if ((tselem->type != TSE_SOME_ID) || (tselem->id && GS(tselem->id->name) != ID_GR)) { return TRAVERSE_SKIP_CHILDS; } @@ -127,7 +127,7 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom return TRAVERSE_CONTINUE; } - if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { return TRAVERSE_SKIP_CHILDS; } @@ -1458,7 +1458,7 @@ static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void BLI_gset_add(data->collections_to_edit, lc); } } - else if (tselem->type == 0 && te->idcode == ID_OB) { + else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; Base *base = BKE_view_layer_base_find(data->view_layer, ob); BLI_gset_add(data->bases_to_edit, base); diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.c index e2b3b79e027..4293d8da73e 100644 --- a/source/blender/editors/space_outliner/outliner_context.c +++ b/source/blender/editors/space_outliner/outliner_context.c @@ -34,7 +34,7 @@ static void outliner_context_selected_ids_recursive(const ListBase *subtree, { LISTBASE_FOREACH (const TreeElement *, te, subtree) { const TreeStoreElem *tse = TREESTORE(te); - if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, 0, TSE_LAYER_COLLECTION))) { + if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, TSE_SOME_ID, TSE_LAYER_COLLECTION))) { CTX_data_id_list_add(result, tse->id); } outliner_context_selected_ids_recursive(&te->subtree, result); diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index 3090cab75ae..01fb0fc6f78 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -124,7 +124,7 @@ static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode TreeElement *te = outliner_drop_find(C, event); TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL; - if (te && te->idcode == idcode && tselem->type == 0) { + if (te && (te->idcode == idcode) && (tselem->type == TSE_SOME_ID)) { return tselem->id; } return NULL; @@ -215,7 +215,7 @@ static bool is_collection_element(TreeElement *te) static bool is_object_element(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - return tselem->type == 0 && te->idcode == ID_OB; + return (tselem->type == TSE_SOME_ID) && te->idcode == ID_OB; } static bool is_pchan_element(TreeElement *te) @@ -281,7 +281,7 @@ static int outliner_get_insert_index(TreeElement *drag_te, static bool parent_drop_allowed(TreeElement *te, Object *potential_child) { TreeStoreElem *tselem = TREESTORE(te); - if (te->idcode != ID_OB || tselem->type != 0) { + if ((te->idcode != ID_OB) || (tselem->type != TSE_SOME_ID)) { return false; } @@ -421,7 +421,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) TreeElement *te = outliner_drop_find(C, event); TreeStoreElem *tselem = te ? TREESTORE(te) : NULL; - if (!(te && te->idcode == ID_OB && tselem->type == 0)) { + if (!(te && (te->idcode == ID_OB) && (tselem->type == TSE_SOME_ID))) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 008ae727947..690adb09570 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -675,7 +675,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) if (ts && tselem) { TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem); - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { BLI_libblock_ensure_unique_name(bmain, tselem->id->name); switch (GS(tselem->id->name)) { @@ -1100,11 +1100,11 @@ static void outliner_draw_restrictbuts(uiBlock *block, UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } } - else if ((tselem->type == 0 && te->idcode == ID_OB) && + else if (((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) && (te->flag & TE_CHILD_NOT_IN_COLLECTION)) { /* Don't show restrict columns for children that are not directly inside the collection. */ } - else if (tselem->type == 0 && te->idcode == ID_OB) { + else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { PointerRNA ptr; Object *ob = (Object *)tselem->id; RNA_id_pointer_create(&ob->id, &ptr); @@ -1699,7 +1699,7 @@ static void outliner_draw_userbuts(uiBlock *block, LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) { - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { uiBut *bt; ID *id = tselem->id; const char *tip = NULL; @@ -1949,7 +1949,7 @@ static void outliner_draw_mode_column_toggle(uiBlock *block, TreeStoreElem *tselem, const bool lock_object_modes) { - if (tselem->type != 0 || te->idcode != ID_OB) { + if ((tselem->type != TSE_SOME_ID) || (te->idcode != ID_OB)) { return; } @@ -2046,7 +2046,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) { TreeElementIcon data = {0}; - if (tselem->type) { + if (tselem->type != TSE_SOME_ID) { switch (tselem->type) { case TSE_ANIM_DATA: data.icon = ICON_ANIM_DATA; /* XXX */ @@ -2825,7 +2825,8 @@ int tree_element_id_type_to_index(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - const int id_index = tselem->type == 0 ? BKE_idtype_idcode_to_index(te->idcode) : INDEX_ID_GR; + const int id_index = (tselem->type == TSE_SOME_ID) ? BKE_idtype_idcode_to_index(te->idcode) : + INDEX_ID_GR; if (id_index < INDEX_ID_OB) { return id_index; } @@ -2862,9 +2863,9 @@ static void outliner_draw_iconrow(bContext *C, te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED); /* object hierarchy always, further constrained on level */ - if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) { + if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) { /* active blocks get white circle */ - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { if (te->idcode == ID_OB) { active = (tvc->obact == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE; } @@ -2879,7 +2880,7 @@ static void outliner_draw_iconrow(bContext *C, active = tree_element_type_active_state_get(C, tvc, te, tselem); } - if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) { + if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) { outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1); } else { @@ -2954,7 +2955,7 @@ static bool element_should_draw_faded(const TreeViewContext *tvc, const TreeElement *te, const TreeStoreElem *tselem) { - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { switch (te->idcode) { case ID_OB: { const Object *ob = (const Object *)tselem->id; @@ -3023,7 +3024,7 @@ static void outliner_draw_tree_element(bContext *C, GPU_blend(GPU_BLEND_ALPHA); /* Colors for active/selected data. */ - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { if (te->idcode == ID_OB) { Object *ob = (Object *)tselem->id; Base *base = (te->directdata) ? (Base *)te->directdata : @@ -3080,7 +3081,7 @@ static void outliner_draw_tree_element(bContext *C, if (tselem->type == TSE_VIEW_COLLECTION_BASE) { /* Scene collection in view layer can't expand/collapse. */ } - else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || + else if (te->subtree.first || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) || (te->flag & TE_LAZY_CLOSED)) { /* Open/close icon, only when sub-levels, except for scene. */ int icon_x = startx; @@ -3117,7 +3118,7 @@ static void outliner_draw_tree_element(bContext *C, offsx += 2 * ufac; } - if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) || + if (ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION) || ((tselem->type == TSE_RNA_STRUCT) && RNA_struct_is_ID(te->rnaptr.type))) { const BIFIconID lib_icon = UI_icon_from_library(tselem->id); if (lib_icon != ICON_NONE) { @@ -3143,7 +3144,7 @@ static void outliner_draw_tree_element(bContext *C, /* Closed item, we draw the icons, not when it's a scene, or master-server list though. */ if (!TSELEM_OPEN(tselem, space_outliner)) { if (te->subtree.first) { - if (tselem->type == 0 && te->idcode == ID_SCE) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) { /* Pass. */ } /* this tree element always has same amount of branches, so don't draw */ @@ -3210,7 +3211,7 @@ static bool subtree_contains_object(ListBase *lb) { LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { return true; } } @@ -3265,7 +3266,7 @@ static void outliner_draw_hierarchy_lines_recursive(uint pos, y = *starty; } - else if (tselem->type == 0 && te->idcode == ID_OB) { + else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { if (subtree_contains_object(&te->subtree)) { draw_hierarchy_line = true; is_object_line = true; diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 09aa268d856..c63209b6b60 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -638,7 +638,7 @@ static bool outliner_id_remap_find_tree_element(bContext *C, if (y > te->ys && y < te->ys + UI_UNIT_Y) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && tselem->id) { + if ((tselem->type == TSE_SOME_ID) && tselem->id) { printf("found id %s (%p)!\n", tselem->id->name, tselem->id); RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name)); @@ -763,7 +763,7 @@ static int outliner_id_copy_tag(SpaceOutliner *space_outliner, ListBase *tree) TreeStoreElem *tselem = TREESTORE(te); /* if item is selected and is an ID, tag it as needing to be copied. */ - if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { + if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) { ID *id = tselem->id; if (!(id->tag & LIB_TAG_DOIT)) { BKE_copybuffer_tag_ID(tselem->id); @@ -1640,7 +1640,7 @@ static int subtree_has_objects(ListBase *lb) { LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { return 1; } if (subtree_has_objects(&te->subtree)) { @@ -1658,7 +1658,7 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outli TreeStoreElem *tselem = TREESTORE(te); if (ELEM(tselem->type, - 0, + TSE_SOME_ID, TSE_SCENE_OBJECTS_BASE, TSE_VIEW_COLLECTION_BASE, TSE_LAYER_COLLECTION)) { diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index e31af48ab7e..d53a37fa60e 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -198,7 +198,7 @@ void outliner_item_mode_toggle(bContext *C, { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; Base *base = BKE_view_layer_base_find(tvc->view_layer, ob); @@ -301,7 +301,7 @@ static void tree_element_object_activate(bContext *C, Object *ob = NULL; /* if id is not object, we search back */ - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { ob = (Object *)tselem->id; } else { @@ -443,7 +443,7 @@ static void tree_element_world_activate(bContext *C, Scene *scene, TreeElement * TreeElement *tep = te->parent; if (tep) { TreeStoreElem *tselem = TREESTORE(tep); - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { sce = (Scene *)tselem->id; } } @@ -1165,7 +1165,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE int context = 0; /* ID Types */ - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { RNA_id_pointer_create(tselem->id, &ptr); switch (te->idcode) { @@ -1374,12 +1374,12 @@ static void do_outliner_item_activate_tree_element(bContext *C, tvc->scene, tvc->view_layer, te, - (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : - OL_SETSEL_NORMAL, - recursive && tselem->type == 0); + (extend && tselem->type == TSE_SOME_ID) ? OL_SETSEL_EXTEND : + OL_SETSEL_NORMAL, + recursive && tselem->type == TSE_SOME_ID); } - if (tselem->type == 0) { /* The lib blocks. */ + if (tselem->type == TSE_SOME_ID) { /* The lib blocks. */ if (do_activate_data == false) { /* Only select in outliner. */ } diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c index 8bd5e3a130a..6543a909a41 100644 --- a/source/blender/editors/space_outliner/outliner_sync.c +++ b/source/blender/editors/space_outliner/outliner_sync.c @@ -326,7 +326,7 @@ static void outliner_sync_selection_from_outliner(Scene *scene, LISTBASE_FOREACH (TreeElement *, te, tree) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { if (sync_types->object) { outliner_select_sync_to_object(view_layer, te, tselem, selected_items->objects); } @@ -503,7 +503,7 @@ static void outliner_sync_selection_to_outliner(ViewLayer *view_layer, LISTBASE_FOREACH (TreeElement *, te, tree) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) { if (sync_types->object) { outliner_select_sync_from_object(view_layer, active_data->object, te, tselem); } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index b735064cfef..9af2ba6a82b 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -106,7 +106,7 @@ static void get_element_operation_type( TreeStoreElem *tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { /* Layer collection points to collection ID. */ - if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { + if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) { if (*datalevel == 0) { *datalevel = tselem->type; } @@ -402,7 +402,8 @@ static void outliner_do_libdata_operation(bContext *C, LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { - if ((tselem->type == 0 && te->idcode != 0) || tselem->type == TSE_LAYER_COLLECTION) { + if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) || + tselem->type == TSE_LAYER_COLLECTION) { TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; operation_fn(C, reports, scene, te, tsep, tselem, user_data); } @@ -1044,7 +1045,7 @@ void outliner_do_object_operation_ex(bContext *C, TreeStoreElem *tselem = TREESTORE(te); bool select_handled = false; if (tselem->flag & TSE_SELECTED) { - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { /* When objects selected in other scenes... dunno if that should be allowed. */ Scene *scene_owner = (Scene *)outliner_search_back(te, ID_SCE); if (scene_owner && scene_act != scene_owner) { @@ -1601,7 +1602,7 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void return TRAVERSE_CONTINUE; } - if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { return TRAVERSE_SKIP_CHILDS; } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 0d82ba992c2..3696ef8dbce 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -307,7 +307,7 @@ static void outliner_add_line_styles(SpaceOutliner *space_outliner, continue; } linestyle->id.tag &= ~LIB_TAG_DOIT; - outliner_add_element(space_outliner, lb, linestyle, te, 0, 0); + outliner_add_element(space_outliner, lb, linestyle, te, TSE_SOME_ID, 0); } } } @@ -332,7 +332,7 @@ static void outliner_add_scene_contents(SpaceOutliner *space_outliner, } /* World */ - outliner_add_element(space_outliner, lb, sce->world, te, 0, 0); + outliner_add_element(space_outliner, lb, sce->world, te, TSE_SOME_ID, 0); /* Collections */ ten = outliner_add_element(space_outliner, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0); @@ -343,7 +343,7 @@ static void outliner_add_scene_contents(SpaceOutliner *space_outliner, ten = outliner_add_element(space_outliner, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0); ten->name = IFACE_("Objects"); FOREACH_SCENE_OBJECT_BEGIN (sce, ob) { - outliner_add_element(space_outliner, &ten->subtree, ob, ten, 0, 0); + outliner_add_element(space_outliner, &ten->subtree, ob, ten, TSE_SOME_ID, 0); } FOREACH_SCENE_OBJECT_END; outliner_make_object_parent_hierarchy(&ten->subtree); @@ -368,14 +368,14 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, &te->subtree, ob->poselib, te, - 0, + TSE_SOME_ID, 0); /* XXX FIXME.. add a special type for this. */ if (ob->proxy && !ID_IS_LINKED(ob)) { outliner_add_element(space_outliner, &te->subtree, ob->proxy, te, TSE_PROXY, 0); } - outliner_add_element(space_outliner, &te->subtree, ob->data, te, 0, 0); + outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0); if (ob->pose) { bArmature *arm = ob->data; @@ -458,7 +458,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } for (int a = 0; a < ob->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, TSE_SOME_ID, a); } if (!BLI_listbase_is_empty(&ob->constraints)) { @@ -624,7 +624,8 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, /* duplicated group */ if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) { - outliner_add_element(space_outliner, &te->subtree, ob->instance_collection, te, 0, 0); + outliner_add_element( + space_outliner, &te->subtree, ob->instance_collection, te, TSE_SOME_ID, 0); } } @@ -686,9 +687,9 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, outliner_add_element(space_outliner, &te->subtree, me, te, TSE_ANIM_DATA, 0); } - outliner_add_element(space_outliner, &te->subtree, me->key, te, 0, 0); + outliner_add_element(space_outliner, &te->subtree, me->key, te, TSE_SOME_ID, 0); for (int a = 0; a < me->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, TSE_SOME_ID, a); } /* could do tfaces with image links, but the images are not grouped nicely. * would require going over all tfaces, sort images in use. etc... */ @@ -702,7 +703,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, } for (int a = 0; a < cu->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, TSE_SOME_ID, a); } break; } @@ -714,7 +715,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, } for (int a = 0; a < mb->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, TSE_SOME_ID, a); } break; } @@ -730,7 +731,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, if (outliner_animdata_test(tex->adt)) { outliner_add_element(space_outliner, &te->subtree, tex, te, TSE_ANIM_DATA, 0); } - outliner_add_element(space_outliner, &te->subtree, tex->ima, te, 0, 0); + outliner_add_element(space_outliner, &te->subtree, tex->ima, te, TSE_SOME_ID, 0); break; } case ID_CA: { @@ -1008,7 +1009,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, if (te->type) { outliner_tree_element_type_expand(te->type, space_outliner); } - else if (type == 0) { + else if (type == TSE_SOME_ID) { TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL; /* ID data-block. */ @@ -1229,7 +1230,7 @@ BLI_INLINE void outliner_add_collection_objects(SpaceOutliner *space_outliner, TreeElement *parent) { LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - outliner_add_element(space_outliner, tree, cob->ob, parent, 0, 0); + outliner_add_element(space_outliner, tree, cob->ob, parent, TSE_SOME_ID, 0); } } @@ -1240,7 +1241,8 @@ static TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outli outliner_add_collection_init(ten, collection); LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - outliner_add_element(space_outliner, &ten->subtree, &child->collection->id, ten, 0, 0); + outliner_add_element( + space_outliner, &ten->subtree, &child->collection->id, ten, TSE_SOME_ID, 0); } if (space_outliner->outlinevis != SO_SCENES) { @@ -1265,7 +1267,7 @@ void outliner_make_object_parent_hierarchy(ListBase *lb) TreeElement *ten = te->next; TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) { Object *ob = (Object *)tselem->id; if (ob->parent && ob->parent->id.newid) { BLI_remlink(lb, te); @@ -1406,7 +1408,7 @@ static void outliner_sort(ListBase *lb) /* sorting rules; only object lists, ID lists, or deformgroups */ if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || - (tselem->type == 0 && te->idcode == ID_OB)) { + ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) { int totelem = BLI_listbase_count(lb); if (totelem > 1) { @@ -1420,7 +1422,7 @@ static void outliner_sort(ListBase *lb) tp->name = te->name; tp->idcode = te->idcode; - if (tselem->type && tselem->type != TSE_DEFGROUP) { + if ((tselem->type != TSE_SOME_ID) && tselem->type != TSE_DEFGROUP) { tp->idcode = 0; /* Don't sort this. */ } if (tselem->type == TSE_ID_BASE) { @@ -1471,7 +1473,7 @@ static void outliner_collections_children_sort(ListBase *lb) TreeStoreElem *tselem = TREESTORE(te); /* Sorting rules: only object lists. */ - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { int totelem = BLI_listbase_count(lb); if (totelem > 1) { @@ -1546,7 +1548,7 @@ static bool test_collection_callback(TreeElement *te) static bool test_object_callback(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - return ((tselem->type == 0) && (te->idcode == ID_OB)); + return ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)); } /** @@ -1707,7 +1709,7 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, } TreeStoreElem *tselem = TREESTORE(te); - if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { if ((exclude_filter & SO_FILTER_OB_TYPE) == SO_FILTER_OB_TYPE) { return false; } @@ -1790,14 +1792,15 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, return is_visible; } - if ((te->parent != NULL) && (TREESTORE(te->parent)->type == 0) && + if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) && (te->parent->idcode == ID_OB)) { if (exclude_filter & SO_FILTER_NO_CHILDREN) { return false; } } } - else if (te->parent != NULL && TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB) { + else if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) && + (te->parent->idcode == ID_OB)) { if (exclude_filter & SO_FILTER_NO_OB_CONTENT) { return false; } @@ -1821,7 +1824,7 @@ static bool outliner_element_is_collection_or_object(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { return true; } diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index 92178cfdfc9..562457c62e9 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -226,7 +226,7 @@ TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const { LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { if (tselem->id == id) { return te; } @@ -266,7 +266,7 @@ TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone) } TreeStoreElem *tselem = TREESTORE(te); - if (ELEM(tselem->type, 0, TSE_EBONE)) { + if (ELEM(tselem->type, TSE_SOME_ID, TSE_EBONE)) { TreeElement *tes = outliner_find_editbone(&te->subtree, ebone); if (tes) { return tes; @@ -283,7 +283,7 @@ TreeElement *outliner_search_back_te(TreeElement *te, short idcode) while (te) { tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == idcode) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == idcode)) { return te; } te = te->parent; @@ -510,7 +510,7 @@ Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2]) te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]); if (te) { TreeStoreElem *tselem = TREESTORE(te); - if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; base = (te->directdata) ? (Base *)te->directdata : BKE_view_layer_base_find(view_layer, ob); } diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc index a81ce11498a..91b690d35fa 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc @@ -144,7 +144,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, if (!tenlib) { /* Create library tree element on demand, depending if there are any data-blocks. */ if (lib) { - tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, 0, 0); + tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, TSE_SOME_ID, 0); } else { tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0); @@ -168,7 +168,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, for (ID *id : List(lbarray[a])) { if (library_id_filter_poll(lib, id)) { - outliner_add_element(&space_outliner_, &ten->subtree, id, ten, 0, 0); + outliner_add_element(&space_outliner_, &ten->subtree, id, ten, TSE_SOME_ID, 0); } } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc index 559cb289f3f..69ccf014642 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc @@ -76,7 +76,8 @@ ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data) /* Add the orphaned data-blocks - these will not be added with any subtrees attached. */ for (ID *id : List(lbarray[a])) { if (ID_REAL_USERS(id) <= 0) { - outliner_add_element(&space_outliner_, (te) ? &te->subtree : &tree, id, te, 0, 0); + outliner_add_element( + &space_outliner_, (te) ? &te->subtree : &tree, id, te, TSE_SOME_ID, 0); } } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc index f377512d81e..390f81cfcd1 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc @@ -46,7 +46,8 @@ ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data) for (ID *id : List(source_data.bmain->scenes)) { Scene *scene = reinterpret_cast(id); - TreeElement *te = outliner_add_element(&space_outliner_, &tree, scene, nullptr, 0, 0); + TreeElement *te = outliner_add_element( + &space_outliner_, &tree, scene, nullptr, TSE_SOME_ID, 0); TreeStoreElem *tselem = TREESTORE(te); /* New scene elements open by default */ diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc index a0ebac5f451..89c9960a24f 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc @@ -80,7 +80,7 @@ ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data) /* Show objects in the view layer. */ for (Base *base : List(view_layer_->object_bases)) { TreeElement *te_object = outliner_add_element( - &space_outliner_, &tree, base->object, nullptr, 0, 0); + &space_outliner_, &tree, base->object, nullptr, TSE_SOME_ID, 0); te_object->directdata = base; } @@ -158,7 +158,7 @@ void TreeDisplayViewLayer::add_layer_collection_objects(ListBase &tree, for (CollectionObject *cob : List(lc.collection->gobject)) { Base *base = BKE_view_layer_base_find(view_layer_, cob->ob); TreeElement *te_object = outliner_add_element( - &space_outliner_, &tree, base->object, &ten, 0, 0); + &space_outliner_, &tree, base->object, &ten, TSE_SOME_ID, 0); te_object->directdata = base; } } @@ -203,7 +203,7 @@ void ObjectsChildrenBuilder::object_tree_elements_lookup_create_recursive(TreeEl continue; } - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; /* Lookup children or add new, empty children vector. */ Vector &tree_elements = object_tree_elements_map_.lookup_or_add(ob, {}); @@ -261,8 +261,12 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections() if (!found) { /* We add the child in the tree even if it is not in the collection. * We deliberately clear its sub-tree though, to make it less prominent. */ - TreeElement *child_ob_tree_element = outliner_add_element( - &outliner_, &parent_ob_tree_element->subtree, child, parent_ob_tree_element, 0, 0); + TreeElement *child_ob_tree_element = outliner_add_element(&outliner_, + &parent_ob_tree_element->subtree, + child, + parent_ob_tree_element, + TSE_SOME_ID, + 0); outliner_free_tree(&child_ob_tree_element->subtree); child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION; child_ob_tree_elements.append(child_ob_tree_element); diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc index 13a25800800..5a9568ea906 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc @@ -44,7 +44,8 @@ TreeElementAnimData::TreeElementAnimData(TreeElement &legacy_te, ID &id) void TreeElementAnimData::expand(SpaceOutliner &space_outliner) const { /* Animation data-block itself. */ - outliner_add_element(&space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, 0, 0); + outliner_add_element( + &space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, TSE_SOME_ID, 0); expand_drivers(space_outliner); expand_NLA_tracks(space_outliner); diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index 16129768b60..7a39e0caef3 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -73,6 +73,16 @@ enum { /** #TreeStoreElem.types */ typedef enum eTreeStoreElemType { + /** + * If an element is of this type, `TreeStoreElem.id` points to a valid ID and the ID-type can be + * received through `TreeElement.idcode` (or `GS(TreeStoreElem.id->name)`). Note however that the + * types below may also have a valid ID pointer (see #TSE_IS_REAL_ID()). + * + * In cases where the type is still checked against "0" (even implicitly), please replace it with + * an explicit check against `TSE_SOME_ID`. + */ + TSE_SOME_ID = 0, + TSE_NLA = 1, /* NO ID */ TSE_NLA_ACTION = 2, TSE_DEFGROUP_BASE = 3, -- cgit v1.2.3 From ae005393dce4746c0ee97887ea1a81281a1f726f Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 5 Mar 2021 17:39:52 +0100 Subject: Fix incorrect assert in Outliner ID deletion Mistake in aa3a4973a30f. The expanded `ELEM()` check would include `0 && te->idcode != 0`, which always evaluates to `false`/`0`. That wouldn't cause the asset to fail, but the `te->idcode` part would never be checked. Fixed the error and cleaned up the check against "0" with a check against `TSE_SOME_ID`, see b9e54566e3b1a. --- source/blender/editors/space_outliner/outliner_edit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index c63209b6b60..18abe17d515 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -464,7 +464,8 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto ID *id = tselem->id; BLI_assert(id != NULL); - BLI_assert(ELEM(tselem->type, 0 && te->idcode != 0, TSE_LAYER_COLLECTION)); + BLI_assert(((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) || + (tselem->type == TSE_LAYER_COLLECTION)); UNUSED_VARS_NDEBUG(te); if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) { -- cgit v1.2.3 From 3a907e742507dde9b26eb5f531c18ad00b0e2ab6 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 5 Mar 2021 18:01:31 +0100 Subject: Outliner: Barebones to port IDs to new Outliner tree-element code design Continuation of work in 2e221de4ceee and 249e4df110e0 . This prepares things so we can start porting the individual ID types to the new code design. I already added some code for library IDs, because they need some special handling during construction, which I didn't want to break. The `AbstractTreeElement::isExpandValid()` check can be removed once types were ported and can be assumed to have a proper `expand()` implemenation. Also makes `TreeElementGPencilLayer` `final` which I forgot in e0442a955bad. --- .../blender/editors/space_outliner/CMakeLists.txt | 2 + .../blender/editors/space_outliner/outliner_tree.c | 7 +- .../editors/space_outliner/tree/tree_element.cc | 9 ++ .../editors/space_outliner/tree/tree_element.h | 1 + .../editors/space_outliner/tree/tree_element.hh | 9 ++ .../tree/tree_element_gpencil_layer.hh | 2 +- .../editors/space_outliner/tree/tree_element_id.cc | 100 +++++++++++++++++++++ .../editors/space_outliner/tree/tree_element_id.hh | 48 ++++++++++ 8 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 source/blender/editors/space_outliner/tree/tree_element_id.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_id.hh diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 040410c0bdd..7b9bc44f986 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -58,6 +58,7 @@ set(SRC tree/tree_element_anim_data.cc tree/tree_element_driver_base.cc tree/tree_element_gpencil_layer.cc + tree/tree_element_id.cc tree/tree_element_nla.cc outliner_intern.h @@ -68,6 +69,7 @@ set(SRC tree/tree_element_anim_data.hh tree/tree_element_driver_base.hh tree/tree_element_gpencil_layer.hh + tree/tree_element_id.hh tree/tree_element_nla.hh ) diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 3696ef8dbce..f109efbaa2b 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -992,6 +992,11 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, else if (type == TSE_ID_BASE) { /* pass */ } + else if (type == TSE_SOME_ID) { + if (!te->type) { + BLI_assert(!"Expected this ID type to be ported to new Outliner tree-element design"); + } + } else { /* Other cases must be caught above. */ BLI_assert(TSE_IS_REAL_ID(tselem)); @@ -1006,7 +1011,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, te->idcode = GS(id->name); } - if (te->type) { + if (te->type && outliner_tree_element_type_is_expand_valid(te->type)) { outliner_tree_element_type_expand(te->type, space_outliner); } else if (type == TSE_SOME_ID) { diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index a692aae37c3..79c2831475f 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -23,6 +23,7 @@ #include "tree_element_anim_data.hh" #include "tree_element_driver_base.hh" #include "tree_element_gpencil_layer.hh" +#include "tree_element_id.hh" #include "tree_element_nla.hh" #include "tree_element.h" @@ -37,6 +38,8 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te ID &id = *static_cast(idv); switch (type) { + case TSE_SOME_ID: + return TreeElementID::createFromID(legacy_te, id); case TSE_ANIM_DATA: return new TreeElementAnimData(legacy_te, id); case TSE_DRIVER_BASE: @@ -82,6 +85,12 @@ void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *spa outliner::tree_element_expand(reinterpret_cast(*type), *space_outliner); } +bool outliner_tree_element_type_is_expand_valid(TreeElementType *type) +{ + outliner::AbstractTreeElement &element = reinterpret_cast( + *type); + return element.isExpandValid(); +} void outliner_tree_element_type_free(TreeElementType **type) { diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h index d88c37180b3..c3dec1bf68a 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.h +++ b/source/blender/editors/space_outliner/tree/tree_element.h @@ -39,6 +39,7 @@ TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy void outliner_tree_element_type_free(TreeElementType **type); void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner); +bool outliner_tree_element_type_is_expand_valid(TreeElementType *type); #ifdef __cplusplus } diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh index 8a1ebb51eae..3e61dd25898 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.hh +++ b/source/blender/editors/space_outliner/tree/tree_element.hh @@ -48,6 +48,15 @@ class AbstractTreeElement { virtual void expand(SpaceOutliner &) const { } + + /** + * Just while transitioning to the new tree-element design: Some types are only partially ported, + * and the expanding isn't done yet. + */ + virtual bool isExpandValid() const + { + return true; + } }; } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh index dd18dd42344..da57ef63f1f 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh @@ -26,7 +26,7 @@ struct bGPDlayer; namespace blender::ed::outliner { -class TreeElementGPencilLayer : public AbstractTreeElement { +class TreeElementGPencilLayer final : public AbstractTreeElement { public: TreeElementGPencilLayer(TreeElement &legacy_te, bGPDlayer &gplayer); }; diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc new file mode 100644 index 00000000000..26787475635 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_ID.h" + +#include "BLI_utildefines.h" + +#include "../outliner_intern.h" + +#include "tree_element_id.hh" + +namespace blender::ed::outliner { + +TreeElementID::TreeElementID(TreeElement &legacy_te, const ID &id) : AbstractTreeElement(legacy_te) +{ + BLI_assert(legacy_te_.store_elem->type == TSE_SOME_ID); + BLI_assert(TSE_IS_REAL_ID(legacy_te_.store_elem)); + + /* Default, some specific types override this. */ + legacy_te_.name = id.name + 2; + legacy_te_.idcode = GS(id.name); +} + +TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, const ID &id) +{ + switch (ID_Type type = GS(id.name); type) { + case ID_LI: + return new TreeElementIDLibrary(legacy_te, id); + case ID_SCE: + case ID_OB: + case ID_ME: + case ID_CU: + case ID_MB: + case ID_MA: + case ID_TE: + case ID_LT: + case ID_LA: + case ID_CA: + case ID_KE: + case ID_SCR: + case ID_WO: + case ID_SPK: + case ID_GR: + case ID_NT: + case ID_BR: + case ID_PA: + case ID_MC: + case ID_MSK: + case ID_LS: + case ID_LP: + case ID_GD: + case ID_WS: + case ID_HA: + case ID_PT: + case ID_VO: + case ID_SIM: + case ID_WM: + case ID_IM: + case ID_VF: + case ID_TXT: + case ID_SO: + case ID_AR: + case ID_AC: + case ID_PAL: + case ID_PC: + case ID_CF: + return new TreeElementID(legacy_te, id); + /* Deprecated */ + case ID_IP: + BLI_assert(!"Outliner trying to build tree-element for deprecated ID type"); + return nullptr; + } + + return nullptr; +} + +TreeElementIDLibrary::TreeElementIDLibrary(TreeElement &legacy_te, const ID &id) + : TreeElementID(legacy_te, id) +{ + legacy_te.name = ((Library &)id).filepath; +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh new file mode 100644 index 00000000000..d1e672ed387 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh @@ -0,0 +1,48 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementID : public AbstractTreeElement { + public: + TreeElementID(TreeElement &legacy_te, const ID &id); + + static TreeElementID *createFromID(TreeElement &legacy_te, const ID &id); + + /** + * Expanding not implemented for all types yet. Once it is, this can be set to true or + * `AbstractTreeElement::expandValid()` can be removed alltogether. + */ + bool isExpandValid() const override + { + return false; + } +}; + +class TreeElementIDLibrary final : public TreeElementID { + public: + TreeElementIDLibrary(TreeElement &legacy_te, const ID &id); +}; + +} // namespace blender::ed::outliner -- cgit v1.2.3 From 4addcf1efcd6d6cc4d72a730bd88f4b89d2f1a8d Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 5 Mar 2021 18:14:56 +0100 Subject: Cleanup: Remove redundant special handling after previous commit Not needed anymore since 3a907e742507. --- source/blender/editors/space_outliner/outliner_tree.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index f109efbaa2b..6ca986660c1 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1001,13 +1001,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, /* Other cases must be caught above. */ BLI_assert(TSE_IS_REAL_ID(tselem)); - /* do here too, for blend file viewer, own ID_LI then shows file name */ - if (GS(id->name) == ID_LI) { - te->name = ((Library *)id)->filepath; - } - else { - te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */ - } + te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */ te->idcode = GS(id->name); } -- cgit v1.2.3 From becc36cce5248417fe4f626dedb50804c0e0eb1d Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 5 Mar 2021 14:45:09 -0600 Subject: Geometry Nodes: Sort attribute search items when menu opens Because the search didn't run when the menu first opens, the attributes appeared in a different order than after you typed anything into the search field. This commit instead runs the search when the menu is first opened, but it only sorts items without filtering. --- .../editors/space_node/node_geometry_attribute_search.cc | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index 982c57eb3ec..b03346577a8 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -75,15 +75,9 @@ static void attribute_search_update_fn( UI_search_item_add(items, str, (void *)str, ICON_X, 0, 0); } - /* Skip the filter when the menu is first opened, so all of the items are visible. */ - if (is_first) { - for (const std::string &attribute_name : attribute_name_hints) { - /* Just use the pointer to the name string as the search data, - * since it's not used anyway but we need a pointer. */ - UI_search_item_add(items, attribute_name.c_str(), (void *)&attribute_name, ICON_NONE, 0, 0); - } - return; - } + /* Don't filter when the menu is first opened, but still run the search + * so the items are in the same order they will appear in while searching. */ + const char *string = is_first ? "" : str; StringSearch *search = BLI_string_search_new(); for (const std::string &attribute_name : attribute_name_hints) { @@ -91,7 +85,7 @@ static void attribute_search_update_fn( } std::string **filtered_items; - const int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items); + const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items); for (const int i : IndexRange(filtered_amount)) { std::string *item = filtered_items[i]; -- cgit v1.2.3 From f117ea26246355f423fd78785a3b00a2490bd9a4 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 5 Mar 2021 15:16:25 -0600 Subject: Geometry Nodes: Expose vertex normals as an attribute This attribute exposes mesh vertex normals as a `vertex_normal` attribute for use with nodes. Since the normal vector stored in vertices is only a cache of data computable from the surrounding faces, the attribute is read-only. A proper error message for attempting to write this attribute is part of T85749. A write-only normal attribute will likely come later, most likely called `corner_normal`. The normals are recomputed before reading if they are marked dirty. This involves const write-access to the mesh, protected by the mutex stored in `Mesh_Runtime`. This is essential for correct behavior after nodes like "Edge Split" or nodes that adjust the position attribute. Ref T84297, T85880, T86206 Differential Revision: https://developer.blender.org/D10541 --- .../blender/blenkernel/intern/attribute_access.cc | 66 +++++++++++++++++++++- .../blenkernel/intern/geometry_set_instances.cc | 3 +- .../nodes/geometry/nodes/node_geo_join_geometry.cc | 5 +- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index aeb7fba47e8..8348851741f 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -31,6 +31,7 @@ #include "BLI_color.hh" #include "BLI_float2.hh" #include "BLI_span.hh" +#include "BLI_threads.h" #include "CLG_log.h" @@ -712,11 +713,13 @@ struct CustomDataAccessInfo { class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); + using UpdateOnRead = void (*)(const GeometryComponent &component); using UpdateOnWrite = void (*)(GeometryComponent &component); const CustomDataType stored_type_; const CustomDataAccessInfo custom_data_access_; const AsReadAttribute as_read_attribute_; const AsWriteAttribute as_write_attribute_; + const UpdateOnRead update_on_read_; const UpdateOnWrite update_on_write_; public: @@ -730,6 +733,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { const CustomDataAccessInfo custom_data_access, const AsReadAttribute as_read_attribute, const AsWriteAttribute as_write_attribute, + const UpdateOnRead update_on_read, const UpdateOnWrite update_on_write) : BuiltinAttributeProvider( std::move(attribute_name), domain, attribute_type, creatable, writable, deletable), @@ -737,6 +741,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { custom_data_access_(custom_data_access), as_read_attribute_(as_read_attribute), as_write_attribute_(as_write_attribute), + update_on_read_(update_on_read), update_on_write_(update_on_write) { } @@ -747,6 +752,11 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { if (custom_data == nullptr) { return {}; } + + if (update_on_read_ != nullptr) { + update_on_read_(component); + } + const int domain_size = component.attribute_domain_size(domain_); const void *data = CustomData_get_layer(custom_data, stored_type_); if (data == nullptr) { @@ -1350,6 +1360,43 @@ static WriteAttributePtr make_material_index_write_attribute(void *data, const i ATTR_DOMAIN_POLYGON, MutableSpan((MPoly *)data, domain_size)); } +static float3 get_vertex_normal(const MVert &vert) +{ + float3 result; + normal_short_to_float_v3(result, vert.no); + return result; +} + +static ReadAttributePtr make_vertex_normal_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique>( + ATTR_DOMAIN_POINT, Span((const MVert *)data, domain_size)); +} + +static void update_vertex_normals_when_dirty(const GeometryComponent &component) +{ + const Mesh *mesh = get_mesh_from_component_for_read(component); + if (mesh == nullptr) { + return; + } + + /* Since normals are derived data, const write access to them is okay. However, ensure that + * two threads don't use write normals to a mesh at the same time. Note that this relies on + * the idempotence of the operation; calculating the normals just fills the MVert struct + * rather than allocating new memory. */ + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex; + BLI_mutex_lock(mesh_eval_mutex); + + /* Check again to avoid a second thread needlessly recalculating the same normals. */ + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + BKE_mesh_calc_normals(const_cast(mesh)); + } + + BLI_mutex_unlock(mesh_eval_mutex); + } +} + static float2 get_loop_uv(const MLoopUV &uv) { return float2(uv.uv); @@ -1459,6 +1506,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() point_access, make_vertex_position_read_attribute, make_vertex_position_write_attribute, + nullptr, tag_normals_dirty_when_writing_position); static BuiltinCustomDataLayerProvider material_index("material_index", @@ -1471,8 +1519,22 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() polygon_access, make_material_index_read_attribute, make_material_index_write_attribute, + nullptr, nullptr); + static BuiltinCustomDataLayerProvider vertex_normal("vertex_normal", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_MVERT, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Readonly, + BuiltinAttributeProvider::NonDeletable, + point_access, + make_vertex_normal_read_attribute, + nullptr, + update_vertex_normals_when_dirty, + nullptr); + static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, CD_MLOOPUV, @@ -1493,7 +1555,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access); - return ComponentAttributeProviders({&position, &material_index}, + return ComponentAttributeProviders({&position, &material_index, &vertex_normal}, {&uvs, &vertex_colors, &corner_custom_data, @@ -1541,6 +1603,7 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud() point_access, make_array_read_attribute, make_array_write_attribute, + nullptr, nullptr); static BuiltinCustomDataLayerProvider radius( "radius", @@ -1553,6 +1616,7 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud() point_access, make_array_read_attribute, make_array_write_attribute, + nullptr, nullptr); static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); return ComponentAttributeProviders({&position, &radius}, {&point_custom_data}); diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 1a260c5d48e..6c4c3231667 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -378,7 +378,8 @@ static void join_instance_groups_mesh(Span set_groups, /* Don't copy attributes that are stored directly in the mesh data structs. */ Map attributes; - gather_attribute_info(attributes, component_types, set_groups, {"position", "material_index"}); + gather_attribute_info( + attributes, component_types, set_groups, {"position", "material_index", "vertex_normal"}); join_attributes( set_groups, component_types, attributes, static_cast(dst_component)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 4e15f232934..9dce52c072d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -222,8 +222,9 @@ static void join_components(Span src_components, Geometry dst_component.replace(new_mesh); /* Don't copy attributes that are stored directly in the mesh data structs. */ - join_attributes( - to_base_components(src_components), dst_component, {"position", "material_index"}); + join_attributes(to_base_components(src_components), + dst_component, + {"position", "material_index", "vertex_normal"}); } static void join_components(Span src_components, GeometrySet &result) -- cgit v1.2.3 From 3bc406274b17c6232c0ba5f86d9be7f3449aa804 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Mar 2021 13:03:30 +1100 Subject: Cleanup: comments --- source/blender/blenkernel/intern/attribute_access.cc | 4 ++-- source/blender/blenloader/intern/versioning_280.c | 2 +- source/blender/editors/space_outliner/tree/tree_element_id.hh | 2 +- source/blender/python/intern/bpy_rna.c | 7 +++---- source/blender/windowmanager/intern/wm_platform_support.c | 10 ++++++---- source/creator/creator_args.c | 2 +- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 8348851741f..61dc0903cc8 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -1380,9 +1380,9 @@ static void update_vertex_normals_when_dirty(const GeometryComponent &component) return; } - /* Since normals are derived data, const write access to them is okay. However, ensure that + /* Since normals are derived data, `const` write access to them is okay. However, ensure that * two threads don't use write normals to a mesh at the same time. Note that this relies on - * the idempotence of the operation; calculating the normals just fills the MVert struct + * the idempotence of the operation; calculating the normals just fills the #MVert struct * rather than allocating new memory. */ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex; diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index ef2e196094e..1ecaee10e6a 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -3684,7 +3684,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) if (!MAIN_VERSION_ATLEAST(bmain, 280, 48)) { for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { /* Those are not currently used, but are accessible through RNA API and were not - * properly initialized previously. This is mere copy of BKE_init_scene() code. */ + * properly initialized previously. This is mere copy of #scene_init_data code. */ if (scene->r.im_format.view_settings.look[0] == '\0') { BKE_color_managed_display_settings_init(&scene->r.im_format.display_settings); BKE_color_managed_view_settings_init_render( diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh index d1e672ed387..612c1cd4a6f 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh @@ -32,7 +32,7 @@ class TreeElementID : public AbstractTreeElement { /** * Expanding not implemented for all types yet. Once it is, this can be set to true or - * `AbstractTreeElement::expandValid()` can be removed alltogether. + * `AbstractTreeElement::expandValid()` can be removed altogether. */ bool isExpandValid() const override { diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index cdf121a6864..ecaa5791e38 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -4598,13 +4598,12 @@ static PyObject *pyrna_prop_collection_getattro(BPy_PropertyRNA *self, PyObject #else { /* Could just do this except for 1 awkward case. - * PyObject_GenericGetAttr((PyObject *)self, pyname); - * so as to support 'bpy.data.library.load()' - * note, this _only_ supports static methods */ + * `PyObject_GenericGetAttr((PyObject *)self, pyname);` + * so as to support `bpy.data.library.load()` */ PyObject *ret = PyObject_GenericGetAttr((PyObject *)self, pyname); - if (ret == NULL && name[0] != '_') { /* Avoid inheriting __call__ and similar. */ + if (ret == NULL && name[0] != '_') { /* Avoid inheriting `__call__` and similar. */ /* Since this is least common case, handle it last. */ PointerRNA r_ptr; if (RNA_property_collection_type_get(&self->ptr, self->prop, &r_ptr)) { diff --git a/source/blender/windowmanager/intern/wm_platform_support.c b/source/blender/windowmanager/intern/wm_platform_support.c index 65e1cd45e02..45618e9d6d3 100644 --- a/source/blender/windowmanager/intern/wm_platform_support.c +++ b/source/blender/windowmanager/intern/wm_platform_support.c @@ -43,7 +43,9 @@ #define WM_PLATFORM_SUPPORT_TEXT_SIZE 1024 -/* Check if user has already approved the given platform_support_key. */ +/** + * Check if user has already approved the given `platform_support_key`. + */ static bool wm_platform_support_check_approval(const char *platform_support_key, bool update) { const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); @@ -120,11 +122,11 @@ bool WM_platform_support_perform_checks() eGPUSupportLevel support_level = GPU_platform_support_level(); const char *platform_key = GPU_platform_support_level_key(); - /* check if previous check matches the current check. Don't update the approval when running in - * `background`. this could have been triggered by installing addons via installers. */ + /* Check if previous check matches the current check. Don't update the approval when running in + * `background`. this could have been triggered by installing add-ons via installers. */ if (support_level != GPU_SUPPORT_LEVEL_UNSUPPORTED && !G.factory_startup && wm_platform_support_check_approval(platform_key, !G.background)) { - /* if it matches the user has confirmed and whishes to use it */ + /* If it matches the user has confirmed and wishes to use it. */ return result; } diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index e35fce3160f..0e0d66d40a9 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -1149,7 +1149,7 @@ static const char arg_handle_env_system_set_doc_python[] = static int arg_handle_env_system_set(int argc, const char **argv, void *UNUSED(data)) { - /* "--env-system-scripts" --> "BLENDER_SYSTEM_SCRIPTS" */ + /* `--env-system-scripts` -> `BLENDER_SYSTEM_SCRIPTS` */ char env[64] = "BLENDER"; char *ch_dst = env + 7; /* skip BLENDER */ -- cgit v1.2.3 From b22b0372295a1a9ee23154e0c8589be75777ad66 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Mar 2021 13:22:32 +1100 Subject: Cleanup: rename wm_get_cursor_position Match naming of other wm_cursor_position_* functions. --- source/blender/windowmanager/intern/wm_cursors.c | 2 +- source/blender/windowmanager/intern/wm_draw.c | 2 +- source/blender/windowmanager/intern/wm_event_system.c | 2 +- source/blender/windowmanager/intern/wm_window.c | 12 ++++++------ source/blender/windowmanager/wm_window.h | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index e32552063af..d6e4a93f6a6 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -303,7 +303,7 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y) { /* note: don't use wmEvent coords because of continuous grab T36409. */ int cx, cy; - wm_get_cursor_position(win, &cx, &cy); + wm_cursor_position_get(win, &cx, &cy); WM_cursor_warp(win, cx + x, cy + y); } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 85611a0be93..071bce822a5 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -117,7 +117,7 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region) if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) { int x = 0, y = 0; - wm_get_cursor_position(win, &x, &y); + wm_cursor_position_get(win, &x, &y); pc->draw(C, x, y, pc->customdata); } else { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 18ec8402482..4c4523c80bc 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2343,7 +2343,7 @@ static int wm_handler_fileselect_do(bContext *C, wm_window_make_drawable(wm, ctx_win); /* Ensure correct cursor position, otherwise, popups may close immediately after * opening (UI_BLOCK_MOVEMOUSE_QUIT). */ - wm_get_cursor_position(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y); + wm_cursor_position_get(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y); wm->winactive = ctx_win; /* Reports use this... */ if (handler->context.win == win) { handler->context.win = NULL; diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index f09a9aecb1d..2fc941c3d6b 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -520,7 +520,7 @@ void WM_window_set_dpi(const wmWindow *win) static void wm_window_update_eventstate(wmWindow *win) { /* Update mouse position when a window is activated. */ - wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y); + wm_cursor_position_get(win, &win->eventstate->x, &win->eventstate->y); } static void wm_window_ensure_eventstate(wmWindow *win) @@ -983,15 +983,15 @@ void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y) GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y); } -void wm_get_cursor_position(wmWindow *win, int *x, int *y) +void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y) { if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) { - *x = win->eventstate->x; - *y = win->eventstate->y; + *r_x = win->eventstate->x; + *r_y = win->eventstate->y; return; } - GHOST_GetCursorPosition(g_system, x, y); - wm_cursor_position_from_ghost(win, x, y); + GHOST_GetCursorPosition(g_system, r_x, r_y); + wm_cursor_position_from_ghost(win, r_x, r_y); } typedef enum { diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 0ac67b987d7..f205f923ec8 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -69,8 +69,8 @@ void wm_window_swap_buffers(wmWindow *win); void wm_window_set_swap_interval(wmWindow *win, int interval); bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut); -void wm_get_cursor_position(wmWindow *win, int *x, int *y); -void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y); +void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y); +void wm_cursor_position_from_ghost(wmWindow *win, int *r_x, int *r_y); void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y); #ifdef WITH_INPUT_IME -- cgit v1.2.3 From 753f1cf0adf7bca5bf3c10ffb533552af19498ef Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Mar 2021 13:52:10 +1100 Subject: Cleanup: redundant pose bone assignment --- release/scripts/startup/bl_ui/properties_data_bone.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py index 170d7910339..f3e116ca321 100644 --- a/release/scripts/startup/bl_ui/properties_data_bone.py +++ b/release/scripts/startup/bl_ui/properties_data_bone.py @@ -255,17 +255,11 @@ class BONE_PT_display(BoneButtonsPanel, Panel): layout = self.layout layout.use_property_split = True - ob = context.object bone = context.bone - pchan = None - - if ob and bone: - pchan = ob.pose.bones[bone.name] - elif bone is None: + if bone is None: bone = context.edit_bone if bone: - col = layout.column() col.prop(bone, "hide", text="Hide", toggle=False) -- cgit v1.2.3 From bd7969159997b8802d54e79a002350a7fb97944d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Mar 2021 18:16:39 +1100 Subject: Cleanup: unused variables --- release/scripts/modules/bl_i18n_utils/utils_rtl.py | 2 +- .../scripts/modules/bl_previews_utils/bl_previews_render.py | 3 ++- release/scripts/modules/bpy_extras/object_utils.py | 1 - release/scripts/modules/rna_info.py | 4 ++-- release/scripts/startup/bl_ui/properties_data_gpencil.py | 1 - .../scripts/startup/bl_ui/properties_grease_pencil_common.py | 3 --- release/scripts/startup/bl_ui/properties_paint_common.py | 2 -- release/scripts/startup/bl_ui/properties_view_layer.py | 4 ---- release/scripts/startup/bl_ui/space_outliner.py | 1 - release/scripts/startup/bl_ui/space_sequencer.py | 10 +++++----- release/scripts/startup/bl_ui/space_toolsystem_toolbar.py | 2 +- release/scripts/startup/bl_ui/space_userpref.py | 2 +- release/scripts/startup/bl_ui/space_view3d.py | 5 ++--- release/scripts/startup/bl_ui/space_view3d_toolbar.py | 10 +++------- 14 files changed, 17 insertions(+), 33 deletions(-) diff --git a/release/scripts/modules/bl_i18n_utils/utils_rtl.py b/release/scripts/modules/bl_i18n_utils/utils_rtl.py index 2b6a56c5deb..041dd477406 100755 --- a/release/scripts/modules/bl_i18n_utils/utils_rtl.py +++ b/release/scripts/modules/bl_i18n_utils/utils_rtl.py @@ -89,7 +89,7 @@ def protect_format_seq(msg): PDF = "\u202C" LRO = "\u202D" RLO = "\u202E" - uctrl = {LRE, RLE, PDF, LRO, RLO} + # uctrl = {LRE, RLE, PDF, LRO, RLO} # Most likely incomplete, but seems to cover current needs. format_codes = set("tslfd") digits = set(".0123456789") diff --git a/release/scripts/modules/bl_previews_utils/bl_previews_render.py b/release/scripts/modules/bl_previews_utils/bl_previews_render.py index 6e3d04e7fa2..979b47f7a14 100644 --- a/release/scripts/modules/bl_previews_utils/bl_previews_render.py +++ b/release/scripts/modules/bl_previews_utils/bl_previews_render.py @@ -283,7 +283,8 @@ def do_previews(do_objects, do_collections, do_scenes, do_data_intern): return cos def preview_render_do(render_context, item_container, item_name, objects, offset_matrix=None): - scene = bpy.data.scenes[render_context.scene, None] + # Unused. + # scene = bpy.data.scenes[render_context.scene, None] if objects is not None: camera = bpy.data.objects[render_context.camera, None] light = bpy.data.objects[render_context.light, None] if render_context.light is not None else None diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index 8afb09882fd..b20800c4207 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -113,7 +113,6 @@ def object_data_add(context, obdata, operator=None, name=None): :return: the newly created object in the scene. :rtype: :class:`bpy.types.Object` """ - scene = context.scene layer = context.view_layer layer_collection = context.layer_collection or layer.active_layer_collection scene_collection = layer_collection.collection diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py index 964eff0e572..3bcc709ab72 100644 --- a/release/scripts/modules/rna_info.py +++ b/release/scripts/modules/rna_info.py @@ -622,8 +622,8 @@ def BuildRNAInfo(): yield (rna_sub_type_name, rna_sub_struct) i += 1 - for (rna_type_name, rna_struct) in _bpy_types_iterator(): - # if not rna_type_name.startswith('__'): + for (_rna_type_name, rna_struct) in _bpy_types_iterator(): + # if not _rna_type_name.startswith('__'): identifier = rna_struct.identifier diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py index 9db6eedb04c..69720a6c54b 100644 --- a/release/scripts/startup/bl_ui/properties_data_gpencil.py +++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py @@ -392,7 +392,6 @@ class DATA_PT_gpencil_display(DataButtonsPanel, Panel): layout.use_property_decorate = False gpd = context.gpencil - gpl = gpd.layers.active layout.prop(gpd, "edit_line_color", text="Edit Line Color") diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 0eb5d60457c..c23cc838e51 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -37,8 +37,6 @@ class AnnotationDrawingToolsPanel: tool_settings = context.tool_settings - is_clip_editor = context.space_data.type == 'CLIP_EDITOR' - col = layout.column(align=True) col.label(text="Draw:") @@ -337,7 +335,6 @@ class GPENCIL_MT_material_active(Menu): layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' ob = context.active_object - mat_active = ob.active_material for slot in ob.material_slots: mat = slot.material diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index dfdc6ab79f4..1f1d407bd10 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -614,7 +614,6 @@ def brush_settings(layout, context, brush, popover=False): # use_persistent, set_persistent_base if capabilities.has_persistence: - ob = context.sculpt_object layout.separator() layout.prop(brush, "use_persistent") layout.operator("sculpt.set_persistent_base") @@ -1318,7 +1317,6 @@ def brush_basic_gpencil_sculpt_settings(layout, context, brush, *, compact=False def brush_basic_gpencil_weight_settings(layout, _context, brush, *, compact=False): - gp_settings = brush.gpencil_settings layout.prop(brush, "size", slider=True) row = layout.row(align=True) diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py index 8c39684583f..ae6cc56b730 100644 --- a/release/scripts/startup/bl_ui/properties_view_layer.py +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -77,8 +77,6 @@ class VIEWLAYER_PT_eevee_layer_passes_data(ViewLayerButtonsPanel, Panel): layout.use_property_split = True layout.use_property_decorate = False - scene = context.scene - rd = scene.render view_layer = context.view_layer col = layout.column() @@ -101,8 +99,6 @@ class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel): view_layer = context.view_layer view_layer_eevee = view_layer.eevee - scene = context.scene - scene_eevee = scene.eevee col = layout.column(heading="Diffuse", align=True) col.prop(view_layer, "use_pass_diffuse_direct", text="Light") diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 43a5e17e50e..012ab038569 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -278,7 +278,6 @@ class OUTLINER_MT_object(Menu): layout = self.layout space = context.space_data - obj = context.active_object layout.operator("outliner.id_copy", text="Copy", icon='COPYDOWN') layout.operator("outliner.id_paste", text="Paste", icon='PASTEDOWN') diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index e10f3383bc8..fa7082e139a 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -113,6 +113,10 @@ class SEQUENCER_HT_tool_header(Header): # TODO: options popover. def draw_tool_settings(self, context): + pass + + # Currently unused. + ''' layout = self.layout # Active Tool @@ -120,6 +124,7 @@ class SEQUENCER_HT_tool_header(Header): from bl_ui.space_toolsystem_common import ToolSelectPanelHelper tool = ToolSelectPanelHelper.draw_active_tool_header(context, layout) tool_mode = context.mode if tool is None else tool.mode + ''' class SEQUENCER_HT_header(Header): @@ -129,8 +134,6 @@ class SEQUENCER_HT_header(Header): layout = self.layout st = context.space_data - scene = context.scene - sequencer_tool_settings = context.tool_settings.sequencer_tool_settings show_region_tool_header = st.show_region_tool_header @@ -336,8 +339,6 @@ class SEQUENCER_MT_view(Menu): st = context.space_data is_preview = st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'} is_sequencer_view = st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'} - scene = context.scene - ed = scene.sequence_editor if st.view_type == 'PREVIEW': # Specifying the REGION_PREVIEW context is needed in preview-only @@ -1904,7 +1905,6 @@ class SEQUENCER_PT_strip_proxy(SequencerButtonsPanel, Panel): if strip.proxy: proxy = strip.proxy - flow = layout.column_flow() if ed.proxy_storage == 'PER_STRIP': col = layout.column(heading="Custom Proxy") col.prop(proxy, "use_proxy_custom_directory", text="Directory") diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 8e99c3af4c3..913fa7ea48a 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -2412,7 +2412,7 @@ class _defs_sequencer_generic: @ToolDef.from_fn def sample(): def draw_settings(_context, layout, tool): - props = tool.operator_properties("sequencer.sample") + tool.operator_properties("sequencer.sample") return dict( idname="builtin.sample", label="Sample", diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 94a1e2bec4d..b61daf0e472 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -642,7 +642,7 @@ class USERPREF_PT_system_video_sequencer(SystemPanel, CenterAlignMixIn, Panel): def draw_centered(self, context, layout): prefs = context.preferences system = prefs.system - edit = prefs.edit + # edit = prefs.edit layout.prop(system, "memory_cache_limit") diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 41a1831f46a..08d128b6023 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -7009,10 +7009,9 @@ class VIEW3D_PT_gpencil_curve_edit(Panel): bl_label = "Curve Editing" def draw(self, context): - gpd = context.gpencil_data - settings = context.tool_settings.gpencil_sculpt - layout = self.layout + + gpd = context.gpencil_data col = layout.column(align=True) col.prop(gpd, "edit_curve_resolution") col.prop(gpd, "curve_edit_threshold") diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index a469973c28f..725075fb143 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -199,8 +199,6 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): ob = context.active_object mesh = ob.data - split = layout.split() - row = layout.row(align=True, heading="Transform") row.prop(tool_settings, "use_transform_correct_face_attributes") @@ -1352,8 +1350,6 @@ class VIEW3D_PT_tools_grease_pencil_brush_select(Panel, View3DPanel, GreasePenci if context.mode == 'PAINT_GPENCIL': brush = tool_settings.gpencil_paint.brush if brush is not None: - gp_settings = brush.gpencil_settings - col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="") if brush.use_custom_icon: @@ -1493,7 +1489,8 @@ class VIEW3D_PT_tools_grease_pencil_brush_stroke(Panel, View3DPanel): return brush is not None and brush.gpencil_tool == 'DRAW' def draw(self, context): - layout = self.layout + # layout = self.layout + pass class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(Panel, View3DPanel): @@ -1850,7 +1847,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_weight_falloff(GreasePencilBrushFallof ts = context.tool_settings settings = ts.gpencil_weight_paint brush = settings.brush - return (settings and settings.brush and settings.brush.curve) + return (brush and brush.curve) # Grease Pencil vertex painting tools @@ -1942,7 +1939,6 @@ class VIEW3D_PT_tools_grease_pencil_brush_vertex_color(View3DPanel, Panel): ts = context.tool_settings settings = ts.gpencil_vertex_paint brush = settings.brush - gp_settings = brush.gpencil_settings col = layout.column() -- cgit v1.2.3 From 9dc0c44aa102b5a7dae1fe92fd9105231ab1798c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Mar 2021 18:21:17 +1100 Subject: Cleanup: unused arguments --- release/scripts/startup/bl_operators/geometry_nodes.py | 4 ++-- release/scripts/startup/bl_operators/view3d.py | 2 +- release/scripts/startup/bl_ui/properties_constraint.py | 10 +++++----- release/scripts/startup/bl_ui/properties_data_hair.py | 2 +- .../scripts/startup/bl_ui/properties_data_modifier.py | 4 ++-- .../startup/bl_ui/properties_data_pointcloud.py | 2 +- .../scripts/startup/bl_ui/properties_data_shaderfx.py | 2 +- .../scripts/startup/bl_ui/properties_data_volume.py | 2 +- .../scripts/startup/bl_ui/properties_mask_common.py | 2 +- .../scripts/startup/bl_ui/properties_paint_common.py | 2 +- release/scripts/startup/bl_ui/properties_view_layer.py | 2 +- release/scripts/startup/bl_ui/space_image.py | 2 +- release/scripts/startup/bl_ui/space_outliner.py | 2 +- .../scripts/startup/bl_ui/space_toolsystem_common.py | 2 +- .../scripts/startup/bl_ui/space_toolsystem_toolbar.py | 18 +++++++++--------- release/scripts/startup/bl_ui/space_topbar.py | 4 ++-- release/scripts/startup/bl_ui/space_userpref.py | 10 +++++----- release/scripts/startup/bl_ui/space_view3d.py | 8 ++++---- release/scripts/startup/bl_ui/space_view3d_toolbar.py | 5 +++-- 19 files changed, 43 insertions(+), 42 deletions(-) diff --git a/release/scripts/startup/bl_operators/geometry_nodes.py b/release/scripts/startup/bl_operators/geometry_nodes.py index 9652f23aadb..c66f0ada955 100644 --- a/release/scripts/startup/bl_operators/geometry_nodes.py +++ b/release/scripts/startup/bl_operators/geometry_nodes.py @@ -19,7 +19,7 @@ import bpy -def geometry_node_group_empty_new(context): +def geometry_node_group_empty_new(): group = bpy.data.node_groups.new("Geometry Nodes", 'GeometryNodeTree') group.inputs.new('NodeSocketGeometry', "Geometry") group.outputs.new('NodeSocketGeometry', "Geometry") @@ -85,7 +85,7 @@ class NewGeometryNodeTreeAssign(bpy.types.Operator): if not modifier: return {'CANCELLED'} - group = geometry_node_group_empty_new(context) + group = geometry_node_group_empty_new() modifier.node_group = group return {'FINISHED'} diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py index 3442e189d14..ff5bcdb034f 100644 --- a/release/scripts/startup/bl_operators/view3d.py +++ b/release/scripts/startup/bl_operators/view3d.py @@ -169,7 +169,7 @@ class VIEW3D_OT_edit_mesh_extrude_manifold_normal(Operator): obj = context.active_object return (obj is not None and obj.mode == 'EDIT') - def execute(self, context): + def execute(self, _context): bpy.ops.mesh.extrude_manifold( 'INVOKE_REGION_WIN', MESH_OT_extrude_region={ diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index e8c62368239..e835e577953 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -42,7 +42,7 @@ class OBJECT_PT_constraints(ObjectConstraintPanel, Panel): bl_label = "Object Constraints" bl_options = {'HIDE_HEADER'} - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint") @@ -56,7 +56,7 @@ class BONE_PT_constraints(BoneConstraintPanel, Panel): bl_label = "Bone Constraints" bl_options = {'HIDE_HEADER'} - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint") @@ -122,7 +122,7 @@ class ConstraintButtonsPanel: elif con.target.type in {'MESH', 'LATTICE'}: col.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group") - def get_constraint(self, context): + def get_constraint(self, _context): con = self.custom_data self.layout.context_pointer_set("constraint", con) return con @@ -844,7 +844,7 @@ class ConstraintButtonsPanel: self.draw_influence(layout, con) - def draw_python_constraint(self, context): + def draw_python_constraint(self, _context): layout = self.layout layout.label(text="Blender 2.6 doesn't support python constraints yet") @@ -976,7 +976,7 @@ class ConstraintButtonsSubPanel: bl_label = "" bl_options = {'DRAW_BOX'} - def get_constraint(self, context): + def get_constraint(self, _context): con = self.custom_data self.layout.context_pointer_set("constraint", con) return con diff --git a/release/scripts/startup/bl_ui/properties_data_hair.py b/release/scripts/startup/bl_ui/properties_data_hair.py index 4964316ad0f..7f95fad9a9e 100644 --- a/release/scripts/startup/bl_ui/properties_data_hair.py +++ b/release/scripts/startup/bl_ui/properties_data_hair.py @@ -81,7 +81,7 @@ class HAIR_MT_add_attribute(Menu): class HAIR_UL_attributes(UIList): - def draw_item(self, context, layout, data, attribute, icon, active_data, active_propname, index): + def draw_item(self, _context, layout, _data, attribute, _icon, _active_data, _active_propname, _index): data_type = attribute.bl_rna.properties['data_type'].enum_items[attribute.data_type] domain = attribute.bl_rna.properties['domain'].enum_items[attribute.domain] diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index d464a3ffc6b..833cd94d2ea 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -37,7 +37,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): ob = context.object return ob and ob.type != 'GPENCIL' - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator_menu_enum("object.modifier_add", "type") layout.template_modifiers() @@ -51,7 +51,7 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel): ob = context.object return ob and ob.type == 'GPENCIL' - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator_menu_enum("object.gpencil_modifier_add", "type") layout.template_grease_pencil_modifiers() diff --git a/release/scripts/startup/bl_ui/properties_data_pointcloud.py b/release/scripts/startup/bl_ui/properties_data_pointcloud.py index eca59ea4aaf..f0584c81c0c 100644 --- a/release/scripts/startup/bl_ui/properties_data_pointcloud.py +++ b/release/scripts/startup/bl_ui/properties_data_pointcloud.py @@ -83,7 +83,7 @@ class POINTCLOUD_MT_add_attribute(Menu): class POINTCLOUD_UL_attributes(UIList): - def draw_item(self, context, layout, data, attribute, icon, active_data, active_propname, index): + def draw_item(self, _context, layout, _data, attribute, _icon, _active_data, _active_propname, _index): data_type = attribute.bl_rna.properties['data_type'].enum_items[attribute.data_type] split = layout.split(factor=0.75) diff --git a/release/scripts/startup/bl_ui/properties_data_shaderfx.py b/release/scripts/startup/bl_ui/properties_data_shaderfx.py index a96fef018c7..576910697ad 100644 --- a/release/scripts/startup/bl_ui/properties_data_shaderfx.py +++ b/release/scripts/startup/bl_ui/properties_data_shaderfx.py @@ -37,7 +37,7 @@ class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel): # ob = context.object # return ob and ob.type == 'GPENCIL' - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator_menu_enum("object.shaderfx_add", "type") layout.template_shaderfx() diff --git a/release/scripts/startup/bl_ui/properties_data_volume.py b/release/scripts/startup/bl_ui/properties_data_volume.py index e7bf9adb876..70056b1d27c 100644 --- a/release/scripts/startup/bl_ui/properties_data_volume.py +++ b/release/scripts/startup/bl_ui/properties_data_volume.py @@ -84,7 +84,7 @@ class DATA_PT_volume_file(DataButtonsPanel, Panel): class VOLUME_UL_grids(UIList): - def draw_item(self, context, layout, data, grid, icon, active_data, active_propname, index): + def draw_item(self, _context, layout, _data, grid, _icon, _active_data, _active_propname, _index): name = grid.name data_type = grid.bl_rna.properties['data_type'].enum_items[grid.data_type] diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py index 4d25b8ca309..09a1f40d3a9 100644 --- a/release/scripts/startup/bl_ui/properties_mask_common.py +++ b/release/scripts/startup/bl_ui/properties_mask_common.py @@ -26,7 +26,7 @@ from bpy.app.translations import contexts as i18n_contexts # Use by both image & clip context menus. -def draw_mask_context_menu(layout, context): +def draw_mask_context_menu(layout, _context): layout.operator_menu_enum("mask.handle_type_set", "type") layout.operator("mask.switch_direction") layout.operator("mask.cyclic_toggle") diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 1f1d407bd10..9620666858f 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -1282,7 +1282,7 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False) layout.template_curve_mapping(settings, "thickness_primitive_curve", brush=True) -def brush_basic_gpencil_sculpt_settings(layout, context, brush, *, compact=False): +def brush_basic_gpencil_sculpt_settings(layout, _context, brush, *, compact=False): gp_settings = brush.gpencil_settings tool = brush.gpencil_sculpt_tool diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py index ae6cc56b730..ad7d6008238 100644 --- a/release/scripts/startup/bl_ui/properties_view_layer.py +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -21,7 +21,7 @@ from bpy.types import Panel, UIList class VIEWLAYER_UL_aov(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname): row = layout.row() split = row.split(factor=0.65) icon = 'NONE' if item.is_valid else 'ERROR' diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 73cc674858c..9b5942cbaa9 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -375,7 +375,7 @@ class IMAGE_MT_uvs_split(Menu): class IMAGE_MT_uvs_unwrap(Menu): bl_label = "Unwrap" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator("uv.unwrap") diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 012ab038569..2805e2147cb 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -257,7 +257,7 @@ class OUTLINER_MT_collection_new(Menu): bl_label = "Collection" @staticmethod - def draw_without_context_menu(context, layout): + def draw_without_context_menu(_context, layout): layout.operator("outliner.collection_new", text="New Collection").nested = True layout.operator("outliner.id_paste", text="Paste Data-Blocks", icon='PASTEDOWN') diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py index 12ec863327c..25f2a740f7c 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_common.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py @@ -1022,7 +1022,7 @@ def activate_by_id(context, space_type, idname, *, as_fallback=False): return True -def activate_by_id_or_cycle(context, space_type, idname, *, offset=1, as_fallback=False): +def activate_by_id_or_cycle(context, space_type, idname, *, offset=1, _as_fallback=False): # Only cycle when the active tool is activated again. cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 913fa7ea48a..46c2c24cb6f 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1096,7 +1096,7 @@ class _defs_edit_curve: @ToolDef.from_fn def draw(): - def draw_settings(context, layout, tool, *, extra=False): + def draw_settings(context, layout, _tool, *, extra=False): # Tool settings initialize operator options. tool_settings = context.tool_settings cps = tool_settings.curve_paint_settings @@ -1589,7 +1589,7 @@ class _defs_weight_paint: @ToolDef.from_fn def sample_weight(): - def draw_settings(context, layout, tool): + def draw_settings(context, layout, _tool): if context.tool_settings.unified_paint_settings.use_unified_weight: weight = context.tool_settings.unified_paint_settings.weight elif context.tool_settings.weight_paint.brush: @@ -1869,7 +1869,7 @@ class _defs_image_uv_sculpt: class _defs_gpencil_paint: @staticmethod - def gpencil_primitive_toolbar(context, layout, tool, props): + def gpencil_primitive_toolbar(context, layout, _tool, props): paint = context.tool_settings.gpencil_paint brush = paint.brush @@ -1907,7 +1907,7 @@ class _defs_gpencil_paint: @ToolDef.from_fn def cutter(): - def draw_settings(context, layout, tool): + def draw_settings(_context, layout, tool): props = tool.operator_properties("gpencil.stroke_cutter") row = layout.row() row.use_property_split = False @@ -2020,7 +2020,7 @@ class _defs_gpencil_paint: @ToolDef.from_fn def eyedropper(): - def draw_settings(context, layout, tool): + def draw_settings(_context, layout, tool): props = tool.operator_properties("ui.eyedropper_gpencil_color") row = layout.row() row.use_property_split = False @@ -2037,7 +2037,7 @@ class _defs_gpencil_paint: @ToolDef.from_fn def interpolate(): - def draw_settings(context, layout, tool): + def draw_settings(_context, layout, tool): props = tool.operator_properties("gpencil.interpolate") layout.prop(props, "layers") layout.prop(props, "flip") @@ -2201,7 +2201,7 @@ class _defs_gpencil_edit: @ToolDef.from_fn def transform_fill(): - def draw_settings(context, layout, tool): + def draw_settings(_context, layout, tool): props = tool.operator_properties("gpencil.transform_fill") row = layout.row() row.use_property_split = False @@ -2219,7 +2219,7 @@ class _defs_gpencil_edit: @ToolDef.from_fn def interpolate(): - def draw_settings(context, layout, tool): + def draw_settings(_context, layout, tool): props = tool.operator_properties("gpencil.interpolate") layout.prop(props, "layers") layout.prop(props, "interpolate_selected_only") @@ -2412,7 +2412,7 @@ class _defs_sequencer_generic: @ToolDef.from_fn def sample(): def draw_settings(_context, layout, tool): - tool.operator_properties("sequencer.sample") + props = tool.operator_properties("sequencer.sample") return dict( idname="builtin.sample", label="Sample", diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 45460a1a5de..7219922c379 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -244,7 +244,7 @@ class TOPBAR_MT_app(Menu): class TOPBAR_MT_file_cleanup(Menu): bl_label = "Clean Up" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.separator() @@ -475,7 +475,7 @@ class TOPBAR_MT_file_export(Menu): bl_label = "Export" bl_owner_use_filter = False - def draw(self, context): + def draw(self, _context): if bpy.app.build_options.collada: self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)") diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index b61daf0e472..b214dc0c245 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -96,7 +96,7 @@ class USERPREF_MT_editor_menus(Menu): class USERPREF_MT_view(Menu): bl_label = "View" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.menu("INFO_MT_area") @@ -241,7 +241,7 @@ class USERPREF_PT_interface_translation(InterfacePanel, CenterAlignMixIn, Panel) bl_translation_context = i18n_contexts.id_windowmanager @classmethod - def poll(cls, context): + def poll(cls, _context): return bpy.app.build_options.international def draw_centered(self, context, layout): @@ -581,7 +581,7 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel): bl_label = "Cycles Render Devices" @classmethod - def poll(cls, context): + def poll(cls, _context): # No GPU rendering on macOS currently. import sys return bpy.app.build_options.cycles and sys.platform != "darwin" @@ -2185,7 +2185,7 @@ class ExperimentalPanel: url_prefix = "https://developer.blender.org/" @classmethod - def poll(cls, context): + def poll(cls, _context): return bpy.app.version_cycle == 'alpha' def _draw_items(self, context, items): @@ -2260,7 +2260,7 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel): bl_label = "Debugging" @classmethod - def poll(cls, context): + def poll(cls, _context): # Unlike the other experimental panels, the debugging one is always visible # even in beta or release. return True diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 08d128b6023..26e0c128f7c 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1068,7 +1068,7 @@ class VIEW3D_MT_snap(Menu): class VIEW3D_MT_uv_map(Menu): bl_label = "UV Mapping" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator("uv.unwrap") @@ -1822,7 +1822,7 @@ class VIEW3D_MT_select_edit_armature(Menu): class VIEW3D_MT_paint_gpencil(Menu): bl_label = "Paint" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator("gpencil.vertex_color_set", text="Set Vertex Colors") @@ -2238,7 +2238,7 @@ class VIEW3D_MT_object(Menu): bl_context = "objectmode" bl_label = "Object" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.menu("VIEW3D_MT_transform_object") @@ -2717,7 +2717,7 @@ class VIEW3D_MT_object_constraints(Menu): class VIEW3D_MT_object_quick_effects(Menu): bl_label = "Quick Effects" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator("object.quick_fur") diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 725075fb143..83ab5bf3100 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1488,7 +1488,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_stroke(Panel, View3DPanel): brush = context.tool_settings.gpencil_paint.brush return brush is not None and brush.gpencil_tool == 'DRAW' - def draw(self, context): + def draw(self, _context): # layout = self.layout pass @@ -1847,7 +1847,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_weight_falloff(GreasePencilBrushFallof ts = context.tool_settings settings = ts.gpencil_weight_paint brush = settings.brush - return (brush and brush.curve) + return (settings and settings.brush and settings.brush.curve) # Grease Pencil vertex painting tools @@ -1939,6 +1939,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_vertex_color(View3DPanel, Panel): ts = context.tool_settings settings = ts.gpencil_vertex_paint brush = settings.brush + gp_settings = brush.gpencil_settings col = layout.column() -- cgit v1.2.3 From 37793b90be12307c368bea9bb44f13e133eff706 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Mar 2021 19:24:07 +1100 Subject: Cleanup: unused imports --- release/scripts/modules/bl_i18n_utils/bl_extract_messages.py | 2 -- release/scripts/modules/bl_i18n_utils/utils.py | 3 --- release/scripts/modules/bl_i18n_utils/utils_rtl.py | 1 - release/scripts/modules/bpy_extras/object_utils.py | 3 +-- release/scripts/modules/bpy_types.py | 1 - .../scripts/startup/bl_app_templates_system/Video_Editing/__init__.py | 1 - release/scripts/startup/bl_operators/object_align.py | 1 - release/scripts/startup/bl_operators/object_quick_effects.py | 1 - release/scripts/startup/bl_operators/uvcalc_follow_active.py | 1 - release/scripts/startup/bl_ui/properties_data_modifier.py | 2 -- release/scripts/startup/bl_ui/properties_physics_fluid.py | 2 +- release/scripts/startup/bl_ui/space_outliner.py | 4 ---- 12 files changed, 2 insertions(+), 20 deletions(-) diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index 180f9f0a01c..3355e9075a0 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -22,8 +22,6 @@ # XXX: This script is meant to be used from inside Blender! # You should not directly use this script, rather use update_msg.py! -import collections -import copy import datetime import os import re diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py index fd4488ecd73..b17c9eeebc5 100644 --- a/release/scripts/modules/bl_i18n_utils/utils.py +++ b/release/scripts/modules/bl_i18n_utils/utils.py @@ -21,12 +21,9 @@ # Some misc utilities... import collections -import copy -import hashlib import os import re import struct -import sys import tempfile #import time diff --git a/release/scripts/modules/bl_i18n_utils/utils_rtl.py b/release/scripts/modules/bl_i18n_utils/utils_rtl.py index 041dd477406..8da1417c468 100755 --- a/release/scripts/modules/bl_i18n_utils/utils_rtl.py +++ b/release/scripts/modules/bl_i18n_utils/utils_rtl.py @@ -32,7 +32,6 @@ # \", %s, %x12, %.4f, etc.), protecting them from ugly (evil) fribidi, # which seems completely unaware of such things (as unicode is...). -import sys import ctypes import re diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index b20800c4207..ddfd3d66e90 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -32,7 +32,6 @@ __all__ = ( import bpy from bpy.props import ( - BoolProperty, FloatVectorProperty, EnumProperty, ) @@ -50,7 +49,7 @@ def add_object_align_init(context, operator): :rtype: :class:`mathutils.Matrix` """ - from mathutils import Matrix, Vector, Euler + from mathutils import Matrix, Vector properties = operator.properties if operator is not None else None space_data = context.space_data diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index e90739debf8..ee9115b6643 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -19,7 +19,6 @@ # from _bpy import types as bpy_types -import _bpy StructRNA = bpy_types.bpy_struct StructMetaPropGroup = bpy_types.bpy_struct_meta_idprop diff --git a/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py b/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py index bfad66ec6cd..c97c3466085 100644 --- a/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py +++ b/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py @@ -22,7 +22,6 @@ from bpy.app.handlers import persistent @persistent def load_handler(dummy): - import os from bpy import context screen = context.screen for area in screen.areas: diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index 70b80f7198f..4a7700b03bb 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -19,7 +19,6 @@ # -import bpy from bpy.types import Operator from mathutils import Vector diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index 48312f958ef..a34ed019148 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -25,7 +25,6 @@ from bpy.props import ( BoolProperty, EnumProperty, FloatProperty, - FloatVectorProperty, IntProperty, ) diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py index 4343717f264..1b801f77e07 100644 --- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py +++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py @@ -18,7 +18,6 @@ # -import bpy from bpy.types import Operator from bpy.props import ( diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 833cd94d2ea..39250559741 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -17,9 +17,7 @@ # ##### END GPL LICENSE BLOCK ##### # -import bpy from bpy.types import Panel -from bpy.app.translations import pgettext_iface as iface_ class ModifierButtonsPanel: diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py index 5d3417fad0f..d168d9ab6dd 100644 --- a/release/scripts/startup/bl_ui/properties_physics_fluid.py +++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py @@ -19,7 +19,7 @@ # import bpy -from bpy.types import Menu, Panel +from bpy.types import Panel from bl_ui.utils import PresetPanel from .properties_physics_common import ( effector_weights_ui, diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 2805e2147cb..5c5a78f3942 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -19,10 +19,6 @@ # import bpy from bpy.types import Header, Menu, Panel -from bpy.app.translations import ( - contexts as i18n_contexts, - pgettext_iface as iface_, -) class OUTLINER_HT_header(Header): -- cgit v1.2.3 From 995bb0860a540e2f0240dc34a1f2628dcf87e09a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Mar 2021 19:24:31 +1100 Subject: Cleanup: remove redundant draw callback --- release/scripts/startup/bl_ui/space_toolsystem_toolbar.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 46c2c24cb6f..1e52142c85c 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -2411,8 +2411,6 @@ class _defs_sequencer_generic: @ToolDef.from_fn def sample(): - def draw_settings(_context, layout, tool): - props = tool.operator_properties("sequencer.sample") return dict( idname="builtin.sample", label="Sample", @@ -2421,7 +2419,6 @@ class _defs_sequencer_generic: ), icon="ops.paint.weight_sample", # XXX, needs own icon. keymap="Sequencer Tool: Sample", - draw_settings=draw_settings, ) -- cgit v1.2.3 From 11efc9087b27099b9d3f31ae45e622ede831a965 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Mar 2021 19:29:03 +1100 Subject: Cleanup: remove workaround for Python 3.7x crashing with libedit This removes workaround for T43491. It's no longer needed as Python 3.9x supports libedit as an alternative to readline on all platforms. --- release/scripts/modules/console_python.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/release/scripts/modules/console_python.py b/release/scripts/modules/console_python.py index 5106010b555..9e1b921774d 100644 --- a/release/scripts/modules/console_python.py +++ b/release/scripts/modules/console_python.py @@ -229,8 +229,6 @@ execute.hooks = [] def autocomplete(context): - _readline_bypass() - from console import intellisense sc = context.space_data @@ -358,14 +356,3 @@ def banner(context): sc.prompt = PROMPT return {'FINISHED'} - - -# workaround for readline crashing, see: T43491 -def _readline_bypass(): - if "rlcompleter" in sys.modules or "readline" in sys.modules: - return - - # prevent 'rlcompleter' from loading the real 'readline' module. - sys.modules["readline"] = None - import rlcompleter - del sys.modules["readline"] -- cgit v1.2.3 From cfd766cebdf6f65e3184229277985b95128f9ad2 Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Sat, 6 Mar 2021 09:05:55 -0500 Subject: Fix T86308 Crash in Exact Boolean when have custom normal layer. Custom Normal layers can't be interpolated, so needed a check for non-interpolatable layers before trying to interpolate. --- source/blender/blenkernel/intern/mesh_boolean_convert.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index d9564f91a04..a179d39a9d2 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -611,6 +611,9 @@ static void copy_or_interp_loop_attributes(Mesh *dest_mesh, * A non bmesh version could have the benefit of not copying data into src_blocks_ofs - * using the contiguous data instead. TODO: add to the custom data API. */ int target_layer_type_index = CustomData_get_named_layer(target_cd, ty, name); + if (!CustomData_layer_has_interp(source_cd, source_layer_i)) { + continue; + } int source_layer_type_index = source_layer_i - source_cd->typemap[ty]; BLI_assert(target_layer_type_index != -1 && source_layer_type_index >= 0); for (int j = 0; j < orig_mp->totloop; ++j) { -- cgit v1.2.3 From d2869943d2c02f1535270f0e206a67aab78c8ebb Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sat, 6 Mar 2021 16:51:06 +0100 Subject: Nodes: refactor derived node tree This is a complete rewrite of the derived node tree data structure. It is a much thinner abstraction about `NodeTreeRef` than before. This gives the user of the derived node tree more control and allows for greater introspection capabilities (e.g. before muted nodes were completely abstracted away; this was convenient, but came with limitations). Another nice benefit of the new structure is that it is much cheaper to build, because it does not inline all nodes and sockets in nested node groups. Differential Revision: https://developer.blender.org/D10620 --- source/blender/modifiers/intern/MOD_nodes.cc | 261 +++++---- source/blender/nodes/NOD_derived_node_tree.hh | 558 ++++++------------ source/blender/nodes/NOD_geometry_exec.hh | 6 +- .../blender/nodes/NOD_node_tree_multi_function.hh | 107 ++-- .../function/nodes/node_fn_group_instance_id.cc | 7 +- .../nodes/function/nodes/node_fn_random_float.cc | 11 +- source/blender/nodes/intern/derived_node_tree.cc | 634 ++++++--------------- source/blender/nodes/intern/node_geometry_exec.cc | 15 +- .../nodes/intern/node_tree_multi_function.cc | 263 ++++----- .../blender/nodes/shader/nodes/node_shader_math.cc | 8 +- .../nodes/shader/nodes/node_shader_value.cc | 2 +- 11 files changed, 703 insertions(+), 1169 deletions(-) diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index b47f5806c9c..4d1823b8951 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -77,6 +77,7 @@ #include "NOD_type_callbacks.hh" using blender::float3; +using blender::FunctionRef; using blender::IndexRange; using blender::Map; using blender::Set; @@ -90,8 +91,8 @@ using blender::bke::PersistentObjectHandle; using blender::fn::GMutablePointer; using blender::fn::GValueMap; using blender::nodes::GeoNodeExecParams; -using namespace blender::nodes::derived_node_tree_types; using namespace blender::fn::multi_function_types; +using namespace blender::nodes::derived_node_tree_types; static void initData(ModifierData *md) { @@ -254,8 +255,8 @@ static bool isDisabled(const struct Scene *UNUSED(scene), class GeometryNodesEvaluator { private: blender::LinearAllocator<> allocator_; - Map, GMutablePointer> value_by_input_; - Vector group_outputs_; + Map, GMutablePointer> value_by_input_; + Vector group_outputs_; blender::nodes::MultiFunctionByNode &mf_by_node_; const blender::nodes::DataTypeConversions &conversions_; const PersistentDataHandleMap &handle_map_; @@ -264,8 +265,8 @@ class GeometryNodesEvaluator { Depsgraph *depsgraph_; public: - GeometryNodesEvaluator(const Map &group_input_data, - Vector group_outputs, + GeometryNodesEvaluator(const Map &group_input_data, + Vector group_outputs, blender::nodes::MultiFunctionByNode &mf_by_node, const PersistentDataHandleMap &handle_map, const Object *self_object, @@ -280,15 +281,15 @@ class GeometryNodesEvaluator { depsgraph_(depsgraph) { for (auto item : group_input_data.items()) { - this->forward_to_inputs(*item.key, item.value); + this->forward_to_inputs(item.key, item.value); } } Vector execute() { Vector results; - for (const DInputSocket *group_output : group_outputs_) { - Vector result = this->get_input_values(*group_output); + for (const DInputSocket &group_output : group_outputs_) { + Vector result = this->get_input_values(group_output); results.append(result[0]); } for (GMutablePointer value : value_by_input_.values()) { @@ -298,62 +299,63 @@ class GeometryNodesEvaluator { } private: - Vector get_input_values(const DInputSocket &socket_to_compute) + Vector get_input_values(const DInputSocket socket_to_compute) { + Vector from_sockets; + socket_to_compute.foreach_origin_socket([&](DSocket socket) { from_sockets.append(socket); }); - Span from_sockets = socket_to_compute.linked_sockets(); - Span from_group_inputs = socket_to_compute.linked_group_inputs(); - const int total_inputs = from_sockets.size() + from_group_inputs.size(); + /* Multi-input sockets contain a vector of inputs. */ + if (socket_to_compute->is_multi_input_socket()) { + Vector values; + for (const DSocket from_socket : from_sockets) { + GMutablePointer value = get_input_from_incoming_link(socket_to_compute, from_socket); + values.append(value); + } + return values; + } - if (total_inputs == 0) { + if (from_sockets.is_empty()) { /* The input is not connected, use the value from the socket itself. */ - return {get_unlinked_input_value(socket_to_compute)}; + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo()); + return {get_unlinked_input_value(socket_to_compute, type)}; } - if (from_group_inputs.size() == 1) { - return {get_unlinked_input_value(socket_to_compute)}; - } + const DSocket from_socket = from_sockets[0]; + GMutablePointer value = this->get_input_from_incoming_link(socket_to_compute, from_socket); + return {value}; + } - /* Multi-input sockets contain a vector of inputs. */ - if (socket_to_compute.is_multi_input_socket()) { - Vector values; - for (const DOutputSocket *from_socket : from_sockets) { - const std::pair key = std::make_pair( - &socket_to_compute, from_socket); - std::optional value = value_by_input_.pop_try(key); - if (value.has_value()) { - values.append(*value); - } - else { - this->compute_output_and_forward(*from_socket); - GMutablePointer value = value_by_input_.pop(key); - values.append(value); - } + GMutablePointer get_input_from_incoming_link(const DInputSocket socket_to_compute, + const DSocket from_socket) + { + if (from_socket->is_output()) { + const DOutputSocket from_output_socket{from_socket}; + const std::pair key = std::make_pair(socket_to_compute, + from_output_socket); + std::optional value = value_by_input_.pop_try(key); + if (value.has_value()) { + /* This input has been computed before, return it directly. */ + return {*value}; } - return values; - } - const DOutputSocket &from_socket = *from_sockets[0]; - const std::pair key = std::make_pair( - &socket_to_compute, &from_socket); - std::optional value = value_by_input_.pop_try(key); - if (value.has_value()) { - /* This input has been computed before, return it directly. */ - return {*value}; + /* Compute the socket now. */ + this->compute_output_and_forward(from_output_socket); + return {value_by_input_.pop(key)}; } - /* Compute the socket now. */ - this->compute_output_and_forward(from_socket); - return {value_by_input_.pop(key)}; + /* Get value from an unlinked input socket. */ + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo()); + const DInputSocket from_input_socket{from_socket}; + return {get_unlinked_input_value(from_input_socket, type)}; } - void compute_output_and_forward(const DOutputSocket &socket_to_compute) + void compute_output_and_forward(const DOutputSocket socket_to_compute) { - const DNode &node = socket_to_compute.node(); + const DNode node{socket_to_compute.context(), &socket_to_compute->node()}; - if (!socket_to_compute.is_available()) { + if (!socket_to_compute->is_available()) { /* If the output is not available, use a default value. */ - const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute.typeinfo()); + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo()); void *buffer = allocator_.allocate(type.size(), type.alignment()); type.copy_to_uninitialized(type.default_value(), buffer); this->forward_to_inputs(socket_to_compute, {type, buffer}); @@ -362,9 +364,9 @@ class GeometryNodesEvaluator { /* Prepare inputs required to execute the node. */ GValueMap node_inputs_map{allocator_}; - for (const DInputSocket *input_socket : node.inputs()) { + for (const InputSocketRef *input_socket : node->inputs()) { if (input_socket->is_available()) { - Vector values = this->get_input_values(*input_socket); + Vector values = this->get_input_values({node.context(), input_socket}); for (int i = 0; i < values.size(); ++i) { /* Values from Multi Input Sockets are stored in input map with the format * []. */ @@ -382,15 +384,15 @@ class GeometryNodesEvaluator { this->execute_node(node, params); /* Forward computed outputs to linked input sockets. */ - for (const DOutputSocket *output_socket : node.outputs()) { + for (const OutputSocketRef *output_socket : node->outputs()) { if (output_socket->is_available()) { GMutablePointer value = node_outputs_map.extract(output_socket->identifier()); - this->forward_to_inputs(*output_socket, value); + this->forward_to_inputs({node.context(), output_socket}, value); } } } - void execute_node(const DNode &node, GeoNodeExecParams params) + void execute_node(const DNode node, GeoNodeExecParams params) { const bNode &bnode = params.node(); @@ -403,7 +405,7 @@ class GeometryNodesEvaluator { } /* Use the multi-function implementation if it exists. */ - const MultiFunction *multi_function = mf_by_node_.lookup_default(&node, nullptr); + const MultiFunction *multi_function = mf_by_node_.lookup_default(node, nullptr); if (multi_function != nullptr) { this->execute_multi_function_node(node, params, *multi_function); return; @@ -413,51 +415,52 @@ class GeometryNodesEvaluator { this->execute_unknown_node(node, params); } - void store_ui_hints(const DNode &node, GeoNodeExecParams params) const + void store_ui_hints(const DNode node, GeoNodeExecParams params) const { - for (const DInputSocket *dsocket : node.inputs()) { - if (!dsocket->is_available()) { + for (const InputSocketRef *socket_ref : node->inputs()) { + if (!socket_ref->is_available()) { continue; } - if (dsocket->bsocket()->type != SOCK_GEOMETRY) { + if (socket_ref->bsocket()->type != SOCK_GEOMETRY) { continue; } - bNodeTree *btree_cow = node.node_ref().tree().btree(); + bNodeTree *btree_cow = node->btree(); bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow); const NodeTreeEvaluationContext context(*self_object_, *modifier_); - const GeometrySet &geometry_set = params.get_input(dsocket->identifier()); + const GeometrySet &geometry_set = params.get_input(socket_ref->identifier()); const Vector components = geometry_set.get_components_for_read(); for (const GeometryComponent *component : components) { - component->attribute_foreach([&](StringRefNull attribute_name, - const AttributeMetaData &UNUSED(meta_data)) { - BKE_nodetree_attribute_hint_add(*btree_original, context, *node.bnode(), attribute_name); - return true; - }); + component->attribute_foreach( + [&](StringRefNull attribute_name, const AttributeMetaData &UNUSED(meta_data)) { + BKE_nodetree_attribute_hint_add( + *btree_original, context, *node->bnode(), attribute_name); + return true; + }); } } } - void execute_multi_function_node(const DNode &node, + void execute_multi_function_node(const DNode node, GeoNodeExecParams params, const MultiFunction &fn) { MFContextBuilder fn_context; MFParamsBuilder fn_params{fn, 1}; Vector input_data; - for (const DInputSocket *dsocket : node.inputs()) { - if (dsocket->is_available()) { - GMutablePointer data = params.extract_input(dsocket->identifier()); + for (const InputSocketRef *socket_ref : node->inputs()) { + if (socket_ref->is_available()) { + GMutablePointer data = params.extract_input(socket_ref->identifier()); fn_params.add_readonly_single_input(GSpan(*data.type(), data.get(), 1)); input_data.append(data); } } Vector output_data; - for (const DOutputSocket *dsocket : node.outputs()) { - if (dsocket->is_available()) { - const CPPType &type = *blender::nodes::socket_cpp_type_get(*dsocket->typeinfo()); + for (const OutputSocketRef *socket_ref : node->outputs()) { + if (socket_ref->is_available()) { + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_ref->typeinfo()); void *buffer = allocator_.allocate(type.size(), type.alignment()); fn_params.add_uninitialized_single_output(GMutableSpan(type, buffer, 1)); output_data.append(GMutablePointer(type, buffer)); @@ -468,19 +471,19 @@ class GeometryNodesEvaluator { value.destruct(); } int output_index = 0; - for (const int i : node.outputs().index_range()) { - if (node.output(i).is_available()) { + for (const int i : node->outputs().index_range()) { + if (node->output(i).is_available()) { GMutablePointer value = output_data[output_index]; - params.set_output_by_move(node.output(i).identifier(), value); + params.set_output_by_move(node->output(i).identifier(), value); value.destruct(); output_index++; } } } - void execute_unknown_node(const DNode &node, GeoNodeExecParams params) + void execute_unknown_node(const DNode node, GeoNodeExecParams params) { - for (const DOutputSocket *socket : node.outputs()) { + for (const OutputSocketRef *socket : node->outputs()) { if (socket->is_available()) { const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); params.set_output_by_copy(socket->identifier(), {type, type.default_value()}); @@ -488,17 +491,18 @@ class GeometryNodesEvaluator { } } - void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward) + void forward_to_inputs(const DOutputSocket from_socket, GMutablePointer value_to_forward) { /* For all sockets that are linked with the from_socket push the value to their node. */ - Span to_sockets_all = from_socket.linked_sockets(); + Vector to_sockets_all; + from_socket.foreach_target_socket( + [&](DInputSocket to_socket) { to_sockets_all.append(to_socket); }); const CPPType &from_type = *value_to_forward.type(); - Vector to_sockets_same_type; - for (const DInputSocket *to_socket : to_sockets_all) { + Vector to_sockets_same_type; + for (const DInputSocket &to_socket : to_sockets_all) { const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo()); - const std::pair key = std::make_pair( - to_socket, &from_socket); + const std::pair key = std::make_pair(to_socket, from_socket); if (from_type == to_type) { to_sockets_same_type.append(to_socket); } @@ -520,23 +524,21 @@ class GeometryNodesEvaluator { } else if (to_sockets_same_type.size() == 1) { /* This value is only used on one input socket, no need to copy it. */ - const DInputSocket *to_socket = to_sockets_same_type[0]; - const std::pair key = std::make_pair( - to_socket, &from_socket); + const DInputSocket to_socket = to_sockets_same_type[0]; + const std::pair key = std::make_pair(to_socket, from_socket); add_value_to_input_socket(key, value_to_forward); } else { /* Multiple inputs use the value, make a copy for every input except for one. */ - const DInputSocket *first_to_socket = to_sockets_same_type[0]; - Span other_to_sockets = to_sockets_same_type.as_span().drop_front(1); + const DInputSocket first_to_socket = to_sockets_same_type[0]; + Span other_to_sockets = to_sockets_same_type.as_span().drop_front(1); const CPPType &type = *value_to_forward.type(); - const std::pair first_key = std::make_pair( - first_to_socket, &from_socket); + const std::pair first_key = std::make_pair(first_to_socket, + from_socket); add_value_to_input_socket(first_key, value_to_forward); - for (const DInputSocket *to_socket : other_to_sockets) { - const std::pair key = std::make_pair( - to_socket, &from_socket); + for (const DInputSocket &to_socket : other_to_sockets) { + const std::pair key = std::make_pair(to_socket, from_socket); void *buffer = allocator_.allocate(type.size(), type.alignment()); type.copy_to_uninitialized(value_to_forward.get(), buffer); add_value_to_input_socket(key, GMutablePointer{type, buffer}); @@ -544,22 +546,17 @@ class GeometryNodesEvaluator { } } - void add_value_to_input_socket(const std::pair key, + void add_value_to_input_socket(const std::pair key, GMutablePointer value) { value_by_input_.add_new(key, value); } - GMutablePointer get_unlinked_input_value(const DInputSocket &socket) + GMutablePointer get_unlinked_input_value(const DInputSocket &socket, + const CPPType &required_type) { - bNodeSocket *bsocket; - if (socket.linked_group_inputs().size() == 0) { - bsocket = socket.bsocket(); - } - else { - bsocket = socket.linked_group_inputs()[0]->bsocket(); - } - const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket.typeinfo()); + bNodeSocket *bsocket = socket->bsocket(); + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); void *buffer = allocator_.allocate(type.size(), type.alignment()); if (bsocket->type == SOCK_OBJECT) { @@ -576,7 +573,19 @@ class GeometryNodesEvaluator { blender::nodes::socket_cpp_value_get(*bsocket, buffer); } - return {type, buffer}; + if (type == required_type) { + return {type, buffer}; + } + if (conversions_.is_convertible(type, required_type)) { + void *converted_buffer = allocator_.allocate(required_type.size(), + required_type.alignment()); + conversions_.convert(type, required_type, buffer, converted_buffer); + type.destruct(buffer); + return {required_type, converted_buffer}; + } + void *default_buffer = allocator_.allocate(required_type.size(), required_type.alignment()); + type.copy_to_uninitialized(type.default_value(), default_buffer); + return {required_type, default_buffer}; } }; @@ -985,7 +994,7 @@ static void fill_data_handle_map(const NodesModifierSettings &settings, { Set used_ids; find_used_ids_from_settings(settings, used_ids); - find_used_ids_from_nodes(*tree.btree(), used_ids); + find_used_ids_from_nodes(*tree.root_context().tree().btree(), used_ids); int current_handle = 0; for (ID *id : used_ids) { @@ -1013,8 +1022,8 @@ static void reset_tree_ui_storage(Span tree * often than necessary. It's going to be replaced soon. */ static GeometrySet compute_geometry(const DerivedNodeTree &tree, - Span group_input_sockets, - const DInputSocket &socket_to_compute, + Span group_input_sockets, + const InputSocketRef &socket_to_compute, GeometrySet input_geometry_set, NodesModifierData *nmd, const ModifierEvalContext *ctx) @@ -1026,32 +1035,33 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, PersistentDataHandleMap handle_map; fill_data_handle_map(nmd->settings, tree, handle_map); - Map group_inputs; + Map group_inputs; + const DTreeContext *root_context = &tree.root_context(); if (group_input_sockets.size() > 0) { - Span remaining_input_sockets = group_input_sockets; + Span remaining_input_sockets = group_input_sockets; /* If the group expects a geometry as first input, use the geometry that has been passed to * modifier. */ - const DOutputSocket *first_input_socket = group_input_sockets[0]; + const OutputSocketRef *first_input_socket = group_input_sockets[0]; if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) { GeometrySet *geometry_set_in = allocator.construct( std::move(input_geometry_set)); - group_inputs.add_new(first_input_socket, geometry_set_in); + group_inputs.add_new({root_context, first_input_socket}, geometry_set_in); remaining_input_sockets = remaining_input_sockets.drop_front(1); } /* Initialize remaining group inputs. */ - for (const DOutputSocket *socket : remaining_input_sockets) { + for (const OutputSocketRef *socket : remaining_input_sockets) { const CPPType &cpp_type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment()); initialize_group_input(*nmd, handle_map, *socket->bsocket(), cpp_type, value_in); - group_inputs.add_new(socket, {cpp_type, value_in}); + group_inputs.add_new({root_context, socket}, {cpp_type, value_in}); } } - Vector group_outputs; - group_outputs.append(&socket_to_compute); + Vector group_outputs; + group_outputs.append({root_context, &socket_to_compute}); GeometryNodesEvaluator evaluator{group_inputs, group_outputs, @@ -1126,16 +1136,17 @@ static void modifyGeometry(ModifierData *md, check_property_socket_sync(ctx->object, md); - blender::nodes::NodeTreeRefMap tree_refs; - DerivedNodeTree tree{nmd->node_group, tree_refs}; + NodeTreeRefMap tree_refs; + DerivedNodeTree tree{*nmd->node_group, tree_refs}; if (tree.has_link_cycles()) { BKE_modifier_set_error(ctx->object, md, "Node group has cycles"); return; } - Span input_nodes = tree.nodes_by_type("NodeGroupInput"); - Span output_nodes = tree.nodes_by_type("NodeGroupOutput"); + const NodeTreeRef &root_tree_ref = tree.root_context().tree(); + Span input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput"); + Span output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput"); if (input_nodes.size() > 1) { return; @@ -1144,16 +1155,18 @@ static void modifyGeometry(ModifierData *md, return; } - Span group_inputs = (input_nodes.size() == 1) ? - input_nodes[0]->outputs().drop_back(1) : - Span{}; - Span group_outputs = output_nodes[0]->inputs().drop_back(1); + Span group_inputs; + if (input_nodes.size() == 1) { + group_inputs = input_nodes[0]->outputs().drop_back(1); + } + + Span group_outputs = output_nodes[0]->inputs().drop_back(1); if (group_outputs.size() == 0) { return; } - const DInputSocket *group_output = group_outputs[0]; + const InputSocketRef *group_output = group_outputs[0]; if (group_output->idname() != "NodeSocketGeometry") { return; } diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index ea67f23eade..a254f908bfd 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -19,544 +19,360 @@ /** \file * \ingroup nodes * - * DerivedNodeTree provides a flattened view on a bNodeTree, i.e. node groups are inlined. It - * builds on top of NodeTreeRef and supports similar queries efficiently. - * - * Every inlined node remembers its path to the parent ("call stack"). - * - * Unlinked group node inputs are handled separately from other sockets. - * - * There is a dot graph exporter for debugging purposes. + * DerivedNodeTree builds on top of NodeTreeRef and makes working with (nested) node groups more + * convenient and safe. It does so by pairing nodes and sockets with a context. The context + * contains information about the current "instance" of the node or socket. A node might be + * "instanced" multiple times when it is in a node group that is used multiple times. */ -#include "NOD_node_tree_ref.hh" - +#include "BLI_function_ref.hh" #include "BLI_vector_set.hh" +#include "NOD_node_tree_ref.hh" + namespace blender::nodes { -class DSocket; -class DInputSocket; -class DOutputSocket; -class DNode; -class DParentNode; -class DGroupInput; +class DTreeContext; class DerivedNodeTree; -class DSocket : NonCopyable, NonMovable { - protected: - DNode *node_; - const SocketRef *socket_ref_; - int id_; - - friend DerivedNodeTree; - - public: - const DNode &node() const; - - int id() const; - int index() const; - - bool is_input() const; - bool is_output() const; - - const DSocket &as_base() const; - const DInputSocket &as_input() const; - const DOutputSocket &as_output() const; - - PointerRNA *rna() const; - StringRefNull idname() const; - StringRefNull name() const; - StringRefNull identifier() const; - bNodeSocketType *typeinfo() const; - - const SocketRef &socket_ref() const; - bNodeSocket *bsocket() const; - - bool is_available() const; -}; +struct DNode; +struct DSocket; +struct DInputSocket; +struct DOutputSocket; -class DInputSocket : public DSocket { +/** + * The context attached to every node or socket in a derived node tree. It can be used to determine + * the place of a node in a hierarchy of node groups. + * + * Contexts are organized in a tree data structure to avoid having to store the entire path to the + * root node group for every node/socket. + */ +class DTreeContext { private: - Vector linked_sockets_; - Vector linked_group_inputs_; - bool is_multi_input_socket_; + /* Null when this context is for the root node group. Otherwise it points to the context one + * level up. */ + DTreeContext *parent_context_; + /* Null when this context is for the root node group. Otherwise it points to the group node in + * the parent node group that contains this context. */ + const NodeRef *parent_node_; + /* The current node tree. */ + const NodeTreeRef *tree_; + /* All the children contexts of this context. */ + Map children_; friend DerivedNodeTree; public: - const InputSocketRef &socket_ref() const; - - Span linked_sockets() const; - Span linked_group_inputs() const; - - bool is_linked() const; - bool is_multi_input_socket() const; + const NodeTreeRef &tree() const; + const DTreeContext *parent_context() const; + const NodeRef *parent_node() const; + const DTreeContext *child_context(const NodeRef &node) const; + bool is_root() const; }; -class DOutputSocket : public DSocket { +/* A (nullable) reference to a node and the context it is in. It is unique within an entire nested + * node group hierarchy. This type is small and can be passed around by value. */ +class DNode { private: - Vector linked_sockets_; - - friend DerivedNodeTree; + const DTreeContext *context_ = nullptr; + const NodeRef *node_ref_ = nullptr; public: - const OutputSocketRef &socket_ref() const; - Span linked_sockets() const; -}; + DNode() = default; + DNode(const DTreeContext *context, const NodeRef *node); -class DGroupInput : NonCopyable, NonMovable { - private: - const InputSocketRef *socket_ref_; - DParentNode *parent_; - Vector linked_sockets_; - int id_; + const DTreeContext *context() const; + const NodeRef *node_ref() const; + const NodeRef *operator->() const; - friend DerivedNodeTree; + friend bool operator==(const DNode &a, const DNode &b); + friend bool operator!=(const DNode &a, const DNode &b); + operator bool() const; - public: - const InputSocketRef &socket_ref() const; - bNodeSocket *bsocket() const; - const DParentNode *parent() const; - Span linked_sockets() const; - int id() const; - StringRefNull name() const; + uint64_t hash() const; }; -class DNode : NonCopyable, NonMovable { - private: - const NodeRef *node_ref_; - DParentNode *parent_; - - Span inputs_; - Span outputs_; - - int id_; - - friend DerivedNodeTree; +/* A (nullable) reference to a socket and the context it is in. It is unique within an entire + * nested node group hierarchy. This type is small and can be passed around by value. + * + * A #DSocket can represent an input or an output socket. If the type of a socket is known at + * compile time is is preferable to use #DInputSocket or #DOutputSocket instead. */ +class DSocket { + protected: + const DTreeContext *context_ = nullptr; + const SocketRef *socket_ref_ = nullptr; public: - const NodeRef &node_ref() const; - const DParentNode *parent() const; + DSocket() = default; + DSocket(const DTreeContext *context, const SocketRef *socket); + DSocket(const DInputSocket &input_socket); + DSocket(const DOutputSocket &output_socket); - Span inputs() const; - Span outputs() const; + const DTreeContext *context() const; + const SocketRef *socket_ref() const; + const SocketRef *operator->() const; - const DInputSocket &input(int index) const; - const DOutputSocket &output(int index) const; + friend bool operator==(const DSocket &a, const DSocket &b); + friend bool operator!=(const DSocket &a, const DSocket &b); + operator bool() const; - const DInputSocket &input(int index, StringRef expected_name) const; - const DOutputSocket &output(int index, StringRef expected_name) const; + uint64_t hash() const; +}; - int id() const; +/* A (nullable) reference to an input socket and the context it is in. */ +class DInputSocket : public DSocket { + public: + DInputSocket() = default; + DInputSocket(const DTreeContext *context, const InputSocketRef *socket); + explicit DInputSocket(const DSocket &base_socket); - PointerRNA *rna() const; - StringRefNull idname() const; - StringRefNull name() const; - bNode *bnode() const; - bNodeType *typeinfo() const; + const InputSocketRef *socket_ref() const; + const InputSocketRef *operator->() const; - private: - void destruct_with_sockets(); + DOutputSocket get_corresponding_group_node_output() const; + Vector get_corresponding_group_input_sockets() const; + + void foreach_origin_socket(FunctionRef callback) const; }; -class DParentNode : NonCopyable, NonMovable { - private: - const NodeRef *node_ref_; - DParentNode *parent_; - int id_; +/* A (nullable) reference to an output socket and the context it is in. */ +class DOutputSocket : public DSocket { + public: + DOutputSocket() = default; + DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket); + explicit DOutputSocket(const DSocket &base_socket); - friend DerivedNodeTree; + const OutputSocketRef *socket_ref() const; + const OutputSocketRef *operator->() const; - public: - const DParentNode *parent() const; - const NodeRef &node_ref() const; - int id() const; + DInputSocket get_corresponding_group_node_input() const; + DInputSocket get_active_corresponding_group_output_socket() const; + + void foreach_target_socket(FunctionRef callback) const; }; -class DerivedNodeTree : NonCopyable, NonMovable { +class DerivedNodeTree { private: LinearAllocator<> allocator_; - Vector nodes_by_id_; - Vector group_inputs_; - Vector parent_nodes_; - - Vector sockets_by_id_; - Vector input_sockets_; - Vector output_sockets_; - - MultiValueMap nodes_by_type_; + DTreeContext *root_context_; VectorSet used_node_tree_refs_; - bNodeTree *btree_; public: - DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs); + DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs); ~DerivedNodeTree(); - bNodeTree *btree() const; - - Span nodes() const; - Span nodes_by_type(StringRefNull idname) const; - Span nodes_by_type(const bNodeType *nodetype) const; - - Span sockets() const; - Span input_sockets() const; - Span output_sockets() const; - - Span group_inputs() const; - + const DTreeContext &root_context() const; Span used_node_tree_refs() const; bool has_link_cycles() const; - - std::string to_dot() const; + void foreach_node(FunctionRef callback) const; private: - /* Utility functions used during construction. */ - void insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref, - DParentNode *parent, - Vector &all_nodes); - DNode &create_node(const NodeRef &node_ref, - DParentNode *parent, - MutableSpan r_sockets_map); - void expand_groups(Vector &all_nodes, - Vector &all_group_inputs, - Vector &all_parent_nodes, - NodeTreeRefMap &node_tree_refs); - void expand_group_node(DNode &group_node, - Vector &all_nodes, - Vector &all_group_inputs, - Vector &all_parent_nodes, - NodeTreeRefMap &node_tree_refs); - void create_group_inputs_for_unlinked_inputs(DNode &node, - Vector &all_group_inputs); - void relink_group_inputs(const NodeTreeRef &group_ref, - Span nodes_by_id, - DNode &group_node); - void relink_group_outputs(const NodeTreeRef &group_ref, - Span nodes_by_id, - DNode &group_node); - void remove_expanded_group_interfaces(Vector &all_nodes); - void remove_unused_group_inputs(Vector &all_group_inputs); - void relink_and_remove_muted_nodes(Vector &all_nodes); - void relink_muted_node(DNode &muted_node); - void store_in_this_and_init_ids(Vector &&all_nodes, - Vector &&all_group_inputs, - Vector &&all_parent_nodes); + DTreeContext &construct_context_recursively(DTreeContext *parent_context, + const NodeRef *parent_node, + bNodeTree &btree, + NodeTreeRefMap &node_tree_refs); + void destruct_context_recursively(DTreeContext *context); + + void foreach_node_in_context_recursive(const DTreeContext &context, + FunctionRef callback) const; }; namespace derived_node_tree_types { +using namespace node_tree_ref_types; using nodes::DerivedNodeTree; -using nodes::DGroupInput; using nodes::DInputSocket; using nodes::DNode; using nodes::DOutputSocket; -using nodes::DParentNode; -}; // namespace derived_node_tree_types +using nodes::DSocket; +using nodes::DTreeContext; +} // namespace derived_node_tree_types /* -------------------------------------------------------------------- - * DSocket inline methods. + * DTreeContext inline methods. */ -inline const DNode &DSocket::node() const -{ - return *node_; -} - -inline int DSocket::id() const -{ - return id_; -} - -inline int DSocket::index() const +inline const NodeTreeRef &DTreeContext::tree() const { - return socket_ref_->index(); + return *tree_; } -inline bool DSocket::is_input() const +inline const DTreeContext *DTreeContext::parent_context() const { - return socket_ref_->is_input(); + return parent_context_; } -inline bool DSocket::is_output() const +inline const NodeRef *DTreeContext::parent_node() const { - return socket_ref_->is_output(); + return parent_node_; } -inline const DSocket &DSocket::as_base() const +inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) const { - return *this; + return children_.lookup_default(&node, nullptr); } -inline const DInputSocket &DSocket::as_input() const +inline bool DTreeContext::is_root() const { - return static_cast(*this); + return parent_context_ == nullptr; } -inline const DOutputSocket &DSocket::as_output() const -{ - return static_cast(*this); -} +/* -------------------------------------------------------------------- + * DNode inline methods. + */ -inline PointerRNA *DSocket::rna() const +inline DNode::DNode(const DTreeContext *context, const NodeRef *node_ref) + : context_(context), node_ref_(node_ref) { - return socket_ref_->rna(); + BLI_assert(node_ref == nullptr || &node_ref->tree() == &context->tree()); } -inline StringRefNull DSocket::idname() const +inline const DTreeContext *DNode::context() const { - return socket_ref_->idname(); + return context_; } -inline StringRefNull DSocket::name() const +inline const NodeRef *DNode::node_ref() const { - return socket_ref_->name(); + return node_ref_; } -inline StringRefNull DSocket::identifier() const +inline bool operator==(const DNode &a, const DNode &b) { - return socket_ref_->identifier(); + return a.context_ == b.context_ && a.node_ref_ == b.node_ref_; } -inline bNodeSocketType *DSocket::typeinfo() const +inline bool operator!=(const DNode &a, const DNode &b) { - return socket_ref_->bsocket()->typeinfo; + return !(a == b); } -inline const SocketRef &DSocket::socket_ref() const +inline DNode::operator bool() const { - return *socket_ref_; + return node_ref_ != nullptr; } -inline bNodeSocket *DSocket::bsocket() const +inline const NodeRef *DNode::operator->() const { - return socket_ref_->bsocket(); + return node_ref_; } -inline bool DSocket::is_available() const +inline uint64_t DNode::hash() const { - return (socket_ref_->bsocket()->flag & SOCK_UNAVAIL) == 0; + return DefaultHash{}(context_) ^ DefaultHash{}(node_ref_); } /* -------------------------------------------------------------------- - * DInputSocket inline methods. + * DSocket inline methods. */ -inline const InputSocketRef &DInputSocket::socket_ref() const +inline DSocket::DSocket(const DTreeContext *context, const SocketRef *socket_ref) + : context_(context), socket_ref_(socket_ref) { - return socket_ref_->as_input(); + BLI_assert(socket_ref == nullptr || &socket_ref->tree() == &context->tree()); } -inline Span DInputSocket::linked_sockets() const +inline DSocket::DSocket(const DInputSocket &input_socket) + : DSocket(input_socket.context_, input_socket.socket_ref_) { - return linked_sockets_; } -inline Span DInputSocket::linked_group_inputs() const +inline DSocket::DSocket(const DOutputSocket &output_socket) + : DSocket(output_socket.context_, output_socket.socket_ref_) { - return linked_group_inputs_; } -inline bool DInputSocket::is_linked() const +inline const DTreeContext *DSocket::context() const { - return linked_sockets_.size() > 0 || linked_group_inputs_.size() > 0; + return context_; } -inline bool DInputSocket::is_multi_input_socket() const +inline const SocketRef *DSocket::socket_ref() const { - return is_multi_input_socket_; + return socket_ref_; } -/* -------------------------------------------------------------------- - * DOutputSocket inline methods. - */ - -inline const OutputSocketRef &DOutputSocket::socket_ref() const -{ - return socket_ref_->as_output(); -} - -inline Span DOutputSocket::linked_sockets() const -{ - return linked_sockets_; -} - -/* -------------------------------------------------------------------- - * DGroupInput inline methods. - */ - -inline const InputSocketRef &DGroupInput::socket_ref() const +inline bool operator==(const DSocket &a, const DSocket &b) { - return *socket_ref_; + return a.context_ == b.context_ && a.socket_ref_ == b.socket_ref_; } -inline bNodeSocket *DGroupInput::bsocket() const +inline bool operator!=(const DSocket &a, const DSocket &b) { - return socket_ref_->bsocket(); + return !(a == b); } -inline const DParentNode *DGroupInput::parent() const +inline DSocket::operator bool() const { - return parent_; + return socket_ref_ != nullptr; } -inline Span DGroupInput::linked_sockets() const +inline const SocketRef *DSocket::operator->() const { - return linked_sockets_; + return socket_ref_; } -inline int DGroupInput::id() const +inline uint64_t DSocket::hash() const { - return id_; -} - -inline StringRefNull DGroupInput::name() const -{ - return socket_ref_->name(); + return DefaultHash{}(context_) ^ + DefaultHash{}(socket_ref_); } /* -------------------------------------------------------------------- - * DNode inline methods. + * DInputSocket inline methods. */ -inline const NodeRef &DNode::node_ref() const -{ - return *node_ref_; -} - -inline const DParentNode *DNode::parent() const -{ - return parent_; -} - -inline Span DNode::inputs() const -{ - return inputs_; -} - -inline Span DNode::outputs() const -{ - return outputs_; -} - -inline const DInputSocket &DNode::input(int index) const -{ - return *inputs_[index]; -} - -inline const DOutputSocket &DNode::output(int index) const -{ - return *outputs_[index]; -} - -inline const DInputSocket &DNode::input(int index, StringRef expected_name) const +inline DInputSocket::DInputSocket(const DTreeContext *context, const InputSocketRef *socket_ref) + : DSocket(context, socket_ref) { - const DInputSocket &socket = *inputs_[index]; - BLI_assert(socket.name() == expected_name); - UNUSED_VARS_NDEBUG(expected_name); - return socket; } -inline const DOutputSocket &DNode::output(int index, StringRef expected_name) const +inline DInputSocket::DInputSocket(const DSocket &base_socket) : DSocket(base_socket) { - const DOutputSocket &socket = *outputs_[index]; - BLI_assert(socket.name() == expected_name); - UNUSED_VARS_NDEBUG(expected_name); - return socket; + BLI_assert(base_socket->is_input()); } -inline int DNode::id() const +inline const InputSocketRef *DInputSocket::socket_ref() const { - return id_; + return (const InputSocketRef *)socket_ref_; } -inline PointerRNA *DNode::rna() const +inline const InputSocketRef *DInputSocket::operator->() const { - return node_ref_->rna(); + return (const InputSocketRef *)socket_ref_; } -inline StringRefNull DNode::idname() const -{ - return node_ref_->idname(); -} - -inline StringRefNull DNode::name() const -{ - return node_ref_->name(); -} - -inline bNode *DNode::bnode() const -{ - return node_ref_->bnode(); -} +/* -------------------------------------------------------------------- + * DOutputSocket inline methods. + */ -inline bNodeType *DNode::typeinfo() const +inline DOutputSocket::DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket_ref) + : DSocket(context, socket_ref) { - return node_ref_->bnode()->typeinfo; } -/* -------------------------------------------------------------------- - * DParentNode inline methods. - */ - -inline const DParentNode *DParentNode::parent() const +inline DOutputSocket::DOutputSocket(const DSocket &base_socket) : DSocket(base_socket) { - return parent_; + BLI_assert(base_socket->is_output()); } -inline const NodeRef &DParentNode::node_ref() const +inline const OutputSocketRef *DOutputSocket::socket_ref() const { - return *node_ref_; + return (const OutputSocketRef *)socket_ref_; } -inline int DParentNode::id() const +inline const OutputSocketRef *DOutputSocket::operator->() const { - return id_; + return (const OutputSocketRef *)socket_ref_; } /* -------------------------------------------------------------------- * DerivedNodeTree inline methods. */ -inline bNodeTree *DerivedNodeTree::btree() const -{ - return btree_; -} - -inline Span DerivedNodeTree::nodes() const -{ - return nodes_by_id_; -} - -inline Span DerivedNodeTree::nodes_by_type(StringRefNull idname) const -{ - const bNodeType *nodetype = nodeTypeFind(idname.c_str()); - return this->nodes_by_type(nodetype); -} - -inline Span DerivedNodeTree::nodes_by_type(const bNodeType *nodetype) const -{ - return nodes_by_type_.lookup(nodetype); -} - -inline Span DerivedNodeTree::sockets() const -{ - return sockets_by_id_; -} - -inline Span DerivedNodeTree::input_sockets() const -{ - return input_sockets_; -} - -inline Span DerivedNodeTree::output_sockets() const -{ - return output_sockets_; -} - -inline Span DerivedNodeTree::group_inputs() const +inline const DTreeContext &DerivedNodeTree::root_context() const { - return group_inputs_; + return *root_context_; } inline Span DerivedNodeTree::used_node_tree_refs() const diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index e648d77337b..1772f92c4b6 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -59,7 +59,7 @@ using fn::GValueMap; class GeoNodeExecParams { private: - const DNode &node_; + const DNode node_; GValueMap &input_values_; GValueMap &output_values_; const PersistentDataHandleMap &handle_map_; @@ -68,7 +68,7 @@ class GeoNodeExecParams { Depsgraph *depsgraph_; public: - GeoNodeExecParams(const DNode &node, + GeoNodeExecParams(const DNode node, GValueMap &input_values, GValueMap &output_values, const PersistentDataHandleMap &handle_map, @@ -182,7 +182,7 @@ class GeoNodeExecParams { */ const bNode &node() const { - return *node_.bnode(); + return *node_->bnode(); } const PersistentDataHandleMap &handle_map() const diff --git a/source/blender/nodes/NOD_node_tree_multi_function.hh b/source/blender/nodes/NOD_node_tree_multi_function.hh index 552ef5509fa..df31ee18369 100644 --- a/source/blender/nodes/NOD_node_tree_multi_function.hh +++ b/source/blender/nodes/NOD_node_tree_multi_function.hh @@ -28,14 +28,15 @@ #include "NOD_derived_node_tree.hh" #include "NOD_type_callbacks.hh" +#include "BLI_multi_value_map.hh" #include "BLI_resource_collector.hh" namespace blender::nodes { /** - * A MFNetworkTreeMap maps various components of a DerivedNodeTree to components of a - * fn::MFNetwork. This is necessary for further processing of a multi-function network that has - * been generated from a node tree. + * A MFNetworkTreeMap maps various components of a node tree to components of a fn::MFNetwork. This + * is necessary for further processing of a multi-function network that has been generated from a + * node tree. */ class MFNetworkTreeMap { private: @@ -47,15 +48,11 @@ class MFNetworkTreeMap { */ const DerivedNodeTree &tree_; fn::MFNetwork &network_; - Array> sockets_by_dsocket_id_; - Array socket_by_group_input_id_; + MultiValueMap sockets_by_dsocket_; public: MFNetworkTreeMap(const DerivedNodeTree &tree, fn::MFNetwork &network) - : tree_(tree), - network_(network), - sockets_by_dsocket_id_(tree.sockets().size()), - socket_by_group_input_id_(tree.group_inputs().size(), nullptr) + : tree_(tree), network_(network) { } @@ -76,96 +73,95 @@ class MFNetworkTreeMap { void add(const DSocket &dsocket, fn::MFSocket &socket) { - BLI_assert(dsocket.is_input() == socket.is_input()); - BLI_assert(dsocket.is_input() || sockets_by_dsocket_id_[dsocket.id()].size() == 0); - sockets_by_dsocket_id_[dsocket.id()].append(&socket); + BLI_assert(dsocket->is_input() == socket.is_input()); + BLI_assert(dsocket->is_input() || sockets_by_dsocket_.lookup(dsocket).is_empty()); + sockets_by_dsocket_.add(dsocket, &socket); } void add(const DInputSocket &dsocket, fn::MFInputSocket &socket) { - sockets_by_dsocket_id_[dsocket.id()].append(&socket); + sockets_by_dsocket_.add(dsocket, &socket); } void add(const DOutputSocket &dsocket, fn::MFOutputSocket &socket) { /* There can be at most one matching output socket. */ - BLI_assert(sockets_by_dsocket_id_[dsocket.id()].size() == 0); - sockets_by_dsocket_id_[dsocket.id()].append(&socket); + BLI_assert(sockets_by_dsocket_.lookup(dsocket).is_empty()); + sockets_by_dsocket_.add(dsocket, &socket); } - void add(Span dsockets, Span sockets) + void add(const DTreeContext &context, + Span dsockets, + Span sockets) { assert_same_size(dsockets, sockets); for (int i : dsockets.index_range()) { - this->add(*dsockets[i], *sockets[i]); + this->add(DInputSocket(&context, dsockets[i]), *sockets[i]); } } - void add(Span dsockets, Span sockets) + void add(const DTreeContext &context, + Span dsockets, + Span sockets) { assert_same_size(dsockets, sockets); for (int i : dsockets.index_range()) { - this->add(*dsockets[i], *sockets[i]); + this->add(DOutputSocket(&context, dsockets[i]), *sockets[i]); } } - void add(const DGroupInput &group_input, fn::MFOutputSocket &socket) - { - BLI_assert(socket_by_group_input_id_[group_input.id()] == nullptr); - socket_by_group_input_id_[group_input.id()] = &socket; - } - void add_try_match(const DNode &dnode, fn::MFNode &node) { - this->add_try_match(dnode.inputs().cast(), + this->add_try_match(*dnode.context(), + dnode->inputs().cast(), node.inputs().cast()); - this->add_try_match(dnode.outputs().cast(), + this->add_try_match(*dnode.context(), + dnode->outputs().cast(), node.outputs().cast()); } - void add_try_match(Span dsockets, Span sockets) + void add_try_match(const DTreeContext &context, + Span dsockets, + Span sockets) { - this->add_try_match(dsockets.cast(), sockets.cast()); + this->add_try_match( + context, dsockets.cast(), sockets.cast()); } - void add_try_match(Span dsockets, Span sockets) + void add_try_match(const DTreeContext &context, + Span dsockets, + Span sockets) { - this->add_try_match(dsockets.cast(), sockets.cast()); + this->add_try_match( + context, dsockets.cast(), sockets.cast()); } - void add_try_match(Span dsockets, Span sockets) + void add_try_match(const DTreeContext &context, + Span dsockets, + Span sockets) { int used_sockets = 0; - for (const DSocket *dsocket : dsockets) { + for (const SocketRef *dsocket : dsockets) { if (!dsocket->is_available()) { continue; } - if (!socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) { + if (!socket_is_mf_data_socket(*dsocket->typeinfo())) { continue; } fn::MFSocket *socket = sockets[used_sockets]; - this->add(*dsocket, *socket); + this->add(DSocket(&context, dsocket), *socket); used_sockets++; } } - fn::MFOutputSocket &lookup(const DGroupInput &group_input) - { - fn::MFOutputSocket *socket = socket_by_group_input_id_[group_input.id()]; - BLI_assert(socket != nullptr); - return *socket; - } - fn::MFOutputSocket &lookup(const DOutputSocket &dsocket) { - auto &sockets = sockets_by_dsocket_id_[dsocket.id()]; - BLI_assert(sockets.size() == 1); - return sockets[0]->as_output(); + return sockets_by_dsocket_.lookup(dsocket)[0]->as_output(); } Span lookup(const DInputSocket &dsocket) { - return sockets_by_dsocket_id_[dsocket.id()].as_span().cast(); + return sockets_by_dsocket_.lookup(dsocket).cast(); } fn::MFInputSocket &lookup_dummy(const DInputSocket &dsocket) @@ -186,7 +182,7 @@ class MFNetworkTreeMap { bool is_mapped(const DSocket &dsocket) const { - return sockets_by_dsocket_id_[dsocket.id()].size() >= 1; + return !sockets_by_dsocket_.lookup(dsocket).is_empty(); } }; @@ -258,12 +254,7 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase { public: SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DSocket &dsocket) - : MFNetworkBuilderBase(common), bsocket_(dsocket.bsocket()) - { - } - - SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DGroupInput &group_input) - : MFNetworkBuilderBase(common), bsocket_(group_input.bsocket()) + : MFNetworkBuilderBase(common), bsocket_(dsocket->bsocket()) { } @@ -331,10 +322,10 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase { */ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { private: - const DNode &dnode_; + DNode dnode_; public: - NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DNode &dnode) + NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, DNode dnode) : MFNetworkBuilderBase(common), dnode_(dnode) { } @@ -352,7 +343,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { const fn::MultiFunction &get_not_implemented_fn() { - return this->get_default_fn("Not Implemented (" + dnode_.name() + ")"); + return this->get_default_fn("Not Implemented (" + dnode_->name() + ")"); } const fn::MultiFunction &get_default_fn(StringRef name); @@ -377,7 +368,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { */ bNode &bnode() { - return *dnode_.node_ref().bnode(); + return *dnode_->bnode(); } /** @@ -393,7 +384,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network, const DerivedNodeTree &tree, ResourceCollector &resources); -using MultiFunctionByNode = Map; +using MultiFunctionByNode = Map; MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, ResourceCollector &resources); diff --git a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc index 1e22cde721d..3d0ea201239 100644 --- a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc +++ b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc @@ -26,9 +26,10 @@ static void fn_node_group_instance_id_expand_in_mf_network( { const blender::nodes::DNode &node = builder.dnode(); std::string id = "/"; - for (const blender::nodes::DParentNode *parent = node.parent(); parent; - parent = parent->parent()) { - id = "/" + parent->node_ref().name() + id; + for (const blender::nodes::DTreeContext *context = node.context(); + context->parent_node() != nullptr; + context = context->parent_context()) { + id = "/" + context->parent_node()->name() + id; } builder.construct_and_set_matching_fn>( std::move(id)); diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/node_fn_random_float.cc index f3401a2c00d..d0ecb5592da 100644 --- a/source/blender/nodes/function/nodes/node_fn_random_float.cc +++ b/source/blender/nodes/function/nodes/node_fn_random_float.cc @@ -67,12 +67,13 @@ static void fn_node_random_float_expand_in_mf_network( blender::nodes::NodeMFNetworkBuilder &builder) { uint32_t function_seed = 1746872341u; - const blender::nodes::DNode &node = builder.dnode(); + blender::nodes::DNode node = builder.dnode(); const blender::DefaultHash hasher; - function_seed = 33 * function_seed + hasher(node.name()); - for (const blender::nodes::DParentNode *parent = node.parent(); parent != nullptr; - parent = parent->parent()) { - function_seed = 33 * function_seed + hasher(parent->node_ref().name()); + function_seed = 33 * function_seed + hasher(node->name()); + for (const blender::nodes::DTreeContext *context = node.context(); + context->parent_node() != nullptr; + context = context->parent_context()) { + function_seed = 33 * function_seed + hasher(context->parent_node()->name()); } builder.construct_and_set_matching_fn(function_seed); diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index a65641bca2a..c20d6fa943e 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -16,518 +16,256 @@ #include "NOD_derived_node_tree.hh" -#include "BLI_dot_export.hh" - -#define UNINITIALIZED_ID UINT32_MAX - namespace blender::nodes { -DerivedNodeTree::DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs) : btree_(btree) +/* Construct a new derived node tree for a given root node tree. The generated derived node tree + * does not own the used node tree refs (so that those can be used by others as well). The caller + * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the + * derived node tree. */ +DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs) { - BLI_assert(btree != nullptr); - - const NodeTreeRef &main_tree_ref = get_tree_ref_from_map(node_tree_refs, *btree); - used_node_tree_refs_.add_new(&main_tree_ref); - - Vector all_nodes; - Vector all_group_inputs; - Vector all_parent_nodes; - - this->insert_nodes_and_links_in_id_order(main_tree_ref, nullptr, all_nodes); - this->expand_groups(all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs); - this->relink_and_remove_muted_nodes(all_nodes); - this->remove_expanded_group_interfaces(all_nodes); - this->remove_unused_group_inputs(all_group_inputs); - this->store_in_this_and_init_ids( - std::move(all_nodes), std::move(all_group_inputs), std::move(all_parent_nodes)); + /* Construct all possible contexts immediately. This is significantly cheaper than inlining all + * node groups. If it still becomes a performance issue in the future, contexts could be + * constructed lazily when they are needed. */ + root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs); } -BLI_NOINLINE void DerivedNodeTree::insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref, - DParentNode *parent, - Vector &all_nodes) +DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context, + const NodeRef *parent_node, + bNodeTree &btree, + NodeTreeRefMap &node_tree_refs) { - Array sockets_map(tree_ref.sockets().size()); - - /* Insert nodes. */ - for (const NodeRef *node_ref : tree_ref.nodes()) { - DNode &node = this->create_node(*node_ref, parent, sockets_map); - all_nodes.append(&node); - } - - /* Insert links. */ - for (const NodeRef *node_ref : tree_ref.nodes()) { - for (const InputSocketRef *to_socket_ref : node_ref->inputs()) { - DInputSocket *to_socket = static_cast(sockets_map[to_socket_ref->id()]); - for (const OutputSocketRef *from_socket_ref : to_socket_ref->linked_sockets()) { - DOutputSocket *from_socket = static_cast( - sockets_map[from_socket_ref->id()]); - to_socket->linked_sockets_.append(from_socket); - from_socket->linked_sockets_.append(to_socket); + DTreeContext &context = *allocator_.construct(); + context.parent_context_ = parent_context; + context.parent_node_ = parent_node; + context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree); + used_node_tree_refs_.add(context.tree_); + + for (const NodeRef *node : context.tree_->nodes()) { + if (node->is_group_node()) { + bNode *bnode = node->bnode(); + bNodeTree *child_btree = reinterpret_cast(bnode->id); + if (child_btree != nullptr) { + DTreeContext &child = this->construct_context_recursively( + &context, node, *child_btree, node_tree_refs); + context.children_.add_new(node, &child); } } } + + return context; } -DNode &DerivedNodeTree::create_node(const NodeRef &node_ref, - DParentNode *parent, - MutableSpan r_sockets_map) +DerivedNodeTree::~DerivedNodeTree() { - DNode &node = *allocator_.construct(); - node.node_ref_ = &node_ref; - node.parent_ = parent; - node.id_ = UNINITIALIZED_ID; - - node.inputs_ = allocator_.construct_elements_and_pointer_array( - node_ref.inputs().size()); - node.outputs_ = allocator_.construct_elements_and_pointer_array( - node_ref.outputs().size()); - - for (int i : node.inputs_.index_range()) { - const InputSocketRef &socket_ref = node_ref.input(i); - DInputSocket &socket = *node.inputs_[i]; - socket.is_multi_input_socket_ = socket_ref.bsocket()->flag & SOCK_MULTI_INPUT; - socket.id_ = UNINITIALIZED_ID; - socket.node_ = &node; - socket.socket_ref_ = &socket_ref; - - r_sockets_map[socket_ref.id()] = &socket; - } - - for (int i : node.outputs_.index_range()) { - const OutputSocketRef &socket_ref = node_ref.output(i); - DOutputSocket &socket = *node.outputs_[i]; - - socket.id_ = UNINITIALIZED_ID; - socket.node_ = &node; - socket.socket_ref_ = &socket_ref; - - r_sockets_map[socket_ref.id()] = &socket; - } - - return node; + /* Has to be destructed manually, because the context info is allocated in a linear allocator. */ + this->destruct_context_recursively(root_context_); } -BLI_NOINLINE void DerivedNodeTree::expand_groups(Vector &all_nodes, - Vector &all_group_inputs, - Vector &all_parent_nodes, - NodeTreeRefMap &node_tree_refs) +void DerivedNodeTree::destruct_context_recursively(DTreeContext *context) { - for (int i = 0; i < all_nodes.size(); i++) { - DNode &node = *all_nodes[i]; - if (node.node_ref_->is_group_node()) { - /* Muted nodes are relinked in a separate step. */ - if (!node.node_ref_->is_muted()) { - this->expand_group_node( - node, all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs); - } - } + for (DTreeContext *child : context->children_.values()) { + this->destruct_context_recursively(child); } + context->~DTreeContext(); } -BLI_NOINLINE void DerivedNodeTree::expand_group_node(DNode &group_node, - Vector &all_nodes, - Vector &all_group_inputs, - Vector &all_parent_nodes, - NodeTreeRefMap &node_tree_refs) +/* Returns true if there are any cycles in the node tree. */ +bool DerivedNodeTree::has_link_cycles() const { - const NodeRef &group_node_ref = *group_node.node_ref_; - BLI_assert(group_node_ref.is_group_node()); - - bNodeTree *btree = reinterpret_cast(group_node_ref.bnode()->id); - if (btree == nullptr) { - return; + for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { + if (tree_ref->has_link_cycles()) { + return true; + } } - - const NodeTreeRef &group_ref = get_tree_ref_from_map(node_tree_refs, *btree); - used_node_tree_refs_.add(&group_ref); - - DParentNode &parent = *allocator_.construct(); - parent.id_ = all_parent_nodes.append_and_get_index(&parent); - parent.parent_ = group_node.parent_; - parent.node_ref_ = &group_node_ref; - - this->insert_nodes_and_links_in_id_order(group_ref, &parent, all_nodes); - Span new_nodes_by_id = all_nodes.as_span().take_back(group_ref.nodes().size()); - - this->create_group_inputs_for_unlinked_inputs(group_node, all_group_inputs); - this->relink_group_inputs(group_ref, new_nodes_by_id, group_node); - this->relink_group_outputs(group_ref, new_nodes_by_id, group_node); + return false; } -BLI_NOINLINE void DerivedNodeTree::create_group_inputs_for_unlinked_inputs( - DNode &node, Vector &all_group_inputs) +/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */ +void DerivedNodeTree::foreach_node(FunctionRef callback) const { - for (DInputSocket *input_socket : node.inputs_) { - if (input_socket->is_linked()) { - continue; - } - - DGroupInput &group_input = *allocator_.construct(); - group_input.id_ = UNINITIALIZED_ID; - group_input.socket_ref_ = &input_socket->socket_ref(); - group_input.parent_ = node.parent_; - - group_input.linked_sockets_.append(input_socket); - input_socket->linked_group_inputs_.append(&group_input); - all_group_inputs.append(&group_input); - } + this->foreach_node_in_context_recursive(*root_context_, callback); } -BLI_NOINLINE void DerivedNodeTree::relink_group_inputs(const NodeTreeRef &group_ref, - Span nodes_by_id, - DNode &group_node) +void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context, + FunctionRef callback) const { - Span node_refs = group_ref.nodes_by_type("NodeGroupInput"); - if (node_refs.size() == 0) { - return; + for (const NodeRef *node_ref : context.tree_->nodes()) { + callback(DNode(&context, node_ref)); } - - int input_amount = group_node.inputs().size(); - - for (int input_index : IndexRange(input_amount)) { - DInputSocket *outside_group = group_node.inputs_[input_index]; - - for (DOutputSocket *outside_connected : outside_group->linked_sockets_) { - outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group); - } - - for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) { - outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group); - } - - for (const NodeRef *input_node_ref : node_refs) { - DNode &input_node = *nodes_by_id[input_node_ref->id()]; - DOutputSocket *inside_group = input_node.outputs_[input_index]; - - for (DInputSocket *inside_connected : inside_group->linked_sockets_) { - inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group); - - for (DOutputSocket *outside_connected : outside_group->linked_sockets_) { - inside_connected->linked_sockets_.append(outside_connected); - outside_connected->linked_sockets_.append(inside_connected); - } - - for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) { - inside_connected->linked_group_inputs_.append(outside_connected); - outside_connected->linked_sockets_.append(inside_connected); - } - } - - inside_group->linked_sockets_.clear(); - } - - outside_group->linked_sockets_.clear(); - outside_group->linked_group_inputs_.clear(); + for (const DTreeContext *child_context : context.children_.values()) { + this->foreach_node_in_context_recursive(*child_context, callback); } } -BLI_NOINLINE void DerivedNodeTree::relink_group_outputs(const NodeTreeRef &group_ref, - Span nodes_by_id, - DNode &group_node) +DOutputSocket DInputSocket::get_corresponding_group_node_output() const { - Span node_refs = group_ref.nodes_by_type("NodeGroupOutput"); - if (node_refs.size() == 0) { - return; - } - /* TODO: Pick correct group output node if there are more than one. */ - const NodeRef &output_node_ref = *node_refs[0]; - DNode &output_node = *nodes_by_id[output_node_ref.id()]; - - int output_amount = group_node.outputs().size(); - BLI_assert(output_amount == output_node_ref.inputs().size() - 1); + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_output_node()); + BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1); - for (int output_index : IndexRange(output_amount)) { - DOutputSocket *outside_group = group_node.outputs_[output_index]; - DInputSocket *inside_group = output_node.inputs_[output_index]; + const DTreeContext *parent_context = context_->parent_context(); + const NodeRef *parent_node = context_->parent_node(); + BLI_assert(parent_context != nullptr); + BLI_assert(parent_node != nullptr); - for (DInputSocket *outside_connected : outside_group->linked_sockets_) { - outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group); - } - - for (DOutputSocket *inside_connected : inside_group->linked_sockets_) { - inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group); - - for (DInputSocket *outside_connected : outside_group->linked_sockets_) { - inside_connected->linked_sockets_.append(outside_connected); - outside_connected->linked_sockets_.append(inside_connected); - } - } - - for (DGroupInput *inside_connected : inside_group->linked_group_inputs_) { - inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group); - - for (DInputSocket *outside_connected : outside_group->linked_sockets_) { - inside_connected->linked_sockets_.append(outside_connected); - outside_connected->linked_group_inputs_.append(inside_connected); - } - } - - outside_group->linked_sockets_.clear(); - inside_group->linked_sockets_.clear(); - } + const int socket_index = socket_ref_->index(); + return {parent_context, &parent_node->output(socket_index)}; } -BLI_NOINLINE void DerivedNodeTree::remove_expanded_group_interfaces(Vector &all_nodes) +Vector DInputSocket::get_corresponding_group_input_sockets() const { - int index = 0; - while (index < all_nodes.size()) { - DNode &node = *all_nodes[index]; - const NodeRef &node_ref = *node.node_ref_; - if (node_ref.is_group_node() || - (node.parent_ != nullptr && - (node_ref.is_group_input_node() || node_ref.is_group_output_node()))) { - all_nodes.remove_and_reorder(index); - node.destruct_with_sockets(); - } - else { - index++; - } + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_node()); + + const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + BLI_assert(child_context != nullptr); + + const NodeTreeRef &child_tree = child_context->tree(); + Span group_input_nodes = child_tree.nodes_by_type("NodeGroupInput"); + const int socket_index = socket_ref_->index(); + Vector sockets; + for (const NodeRef *group_input_node : group_input_nodes) { + sockets.append(DOutputSocket(child_context, &group_input_node->output(socket_index))); } + return sockets; } -BLI_NOINLINE void DerivedNodeTree::remove_unused_group_inputs( - Vector &all_group_inputs) +DInputSocket DOutputSocket::get_corresponding_group_node_input() const { - int index = 0; - while (index < all_group_inputs.size()) { - DGroupInput &group_input = *all_group_inputs[index]; - if (group_input.linked_sockets_.is_empty()) { - all_group_inputs.remove_and_reorder(index); - group_input.~DGroupInput(); - } - else { - index++; - } - } + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_input_node()); + BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1); + + const DTreeContext *parent_context = context_->parent_context(); + const NodeRef *parent_node = context_->parent_node(); + BLI_assert(parent_context != nullptr); + BLI_assert(parent_node != nullptr); + + const int socket_index = socket_ref_->index(); + return {parent_context, &parent_node->input(socket_index)}; } -BLI_NOINLINE void DerivedNodeTree::relink_and_remove_muted_nodes(Vector &all_nodes) +DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const { - int index = 0; - while (index < all_nodes.size()) { - DNode &node = *all_nodes[index]; - const NodeRef &node_ref = *node.node_ref_; - if (node_ref.is_muted()) { - this->relink_muted_node(node); - all_nodes.remove_and_reorder(index); - node.destruct_with_sockets(); - } - else { - index++; + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_node()); + + const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + BLI_assert(child_context != nullptr); + + const NodeTreeRef &child_tree = child_context->tree(); + Span group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput"); + const int socket_index = socket_ref_->index(); + for (const NodeRef *group_output_node : group_output_nodes) { + if (group_output_node->bnode()->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) { + return {child_context, &group_output_node->input(socket_index)}; } } + return {}; } -BLI_NOINLINE void DerivedNodeTree::relink_muted_node(DNode &node) +/* Call the given callback for every "real" origin socket. "Real" means that reroutes, muted nodes + * and node groups are handled by this function. Origin sockets are ones where a node gets its + * inputs from. */ +void DInputSocket::foreach_origin_socket(FunctionRef callback) const { - const bNode &bnode = *node.bnode(); - LISTBASE_FOREACH (const bNodeLink *, internal_link, &bnode.internal_links) { - BLI_assert(internal_link->fromnode == &bnode); - BLI_assert(internal_link->tonode == &bnode); - bNodeSocket *input_bsocket = internal_link->fromsock; - bNodeSocket *output_bsocket = internal_link->tosock; - - /* Find internally linked sockets. */ - DInputSocket *input_socket = nullptr; - DOutputSocket *output_socket = nullptr; - for (DInputSocket *socket : node.inputs_) { - if (socket->bsocket() == input_bsocket) { - input_socket = socket; - break; - } - } - for (DOutputSocket *socket : node.outputs_) { - if (socket->bsocket() == output_bsocket) { - output_socket = socket; - break; + BLI_assert(*this); + for (const OutputSocketRef *linked_socket : socket_ref_->as_input().linked_sockets()) { + const NodeRef &linked_node = linked_socket->node(); + DOutputSocket linked_dsocket{context_, linked_socket}; + + if (linked_node.is_muted()) { + /* If the node is muted, follow the internal links of the node. */ + for (const InternalLinkRef *internal_link : linked_node.internal_links()) { + if (&internal_link->to() == linked_socket) { + DInputSocket input_of_muted_node{context_, &internal_link->from()}; + input_of_muted_node.foreach_origin_socket(callback); + } } } - BLI_assert(input_socket != nullptr); - BLI_assert(output_socket != nullptr); - - /* Link sockets connected to the input to sockets that are connected to the internally linked - * output. */ - for (DInputSocket *to_socket : output_socket->linked_sockets_) { - for (DOutputSocket *from_socket : input_socket->linked_sockets_) { - from_socket->linked_sockets_.append_non_duplicates(to_socket); - to_socket->linked_sockets_.append_non_duplicates(from_socket); + else if (linked_node.is_group_input_node()) { + if (context_->is_root()) { + /* This is a group input in the root node group. */ + callback(linked_dsocket); } - for (DGroupInput *group_input : input_socket->linked_group_inputs_) { - group_input->linked_sockets_.append_non_duplicates(to_socket); - to_socket->linked_group_inputs_.append_non_duplicates(group_input); + else { + DInputSocket socket_in_parent_group = linked_dsocket.get_corresponding_group_node_input(); + if (socket_in_parent_group->is_linked()) { + /* Follow the links coming into the corresponding socket on the parent group node. */ + socket_in_parent_group.foreach_origin_socket(callback); + } + else { + /* The corresponding input on the parent group node is not connected. Therefore, we use + * the value of that input socket directly. */ + callback(socket_in_parent_group); + } } } - } - - /* Remove remaining links from muted node. */ - for (DInputSocket *to_socket : node.inputs_) { - for (DOutputSocket *from_socket : to_socket->linked_sockets_) { - from_socket->linked_sockets_.remove_first_occurrence_and_reorder(to_socket); - } - for (DGroupInput *from_group_input : to_socket->linked_group_inputs_) { - from_group_input->linked_sockets_.remove_first_occurrence_and_reorder(to_socket); - } - to_socket->linked_sockets_.clear(); - to_socket->linked_group_inputs_.clear(); - } - for (DOutputSocket *from_socket : node.outputs_) { - for (DInputSocket *to_socket : from_socket->linked_sockets_) { - to_socket->linked_sockets_.remove_first_occurrence_and_reorder(from_socket); - } - from_socket->linked_sockets_.clear(); - } -} - -void DNode::destruct_with_sockets() -{ - for (DInputSocket *socket : inputs_) { - socket->~DInputSocket(); - } - for (DOutputSocket *socket : outputs_) { - socket->~DOutputSocket(); - } - this->~DNode(); -} - -BLI_NOINLINE void DerivedNodeTree::store_in_this_and_init_ids( - Vector &&all_nodes, - Vector &&all_group_inputs, - Vector &&all_parent_nodes) -{ - nodes_by_id_ = std::move(all_nodes); - group_inputs_ = std::move(all_group_inputs); - parent_nodes_ = std::move(all_parent_nodes); - - for (int node_index : nodes_by_id_.index_range()) { - DNode *node = nodes_by_id_[node_index]; - node->id_ = node_index; - - const bNodeType *nodetype = node->node_ref_->bnode()->typeinfo; - nodes_by_type_.add(nodetype, node); - - for (DInputSocket *socket : node->inputs_) { - socket->id_ = sockets_by_id_.append_and_get_index(socket); - input_sockets_.append(socket); - } - for (DOutputSocket *socket : node->outputs_) { - socket->id_ = sockets_by_id_.append_and_get_index(socket); - output_sockets_.append(socket); + else if (linked_node.is_group_node()) { + DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket(); + if (socket_in_group) { + if (socket_in_group->is_linked()) { + /* Follow the links coming into the group output node of the child node group. */ + socket_in_group.foreach_origin_socket(callback); + } + else { + /* The output of the child node group is not connected, so we have to get the value from + * that socket. */ + callback(socket_in_group); + } + } } - } - - for (int i : group_inputs_.index_range()) { - group_inputs_[i]->id_ = i; - } -} - -DerivedNodeTree::~DerivedNodeTree() -{ - for (DInputSocket *socket : input_sockets_) { - socket->~DInputSocket(); - } - for (DOutputSocket *socket : output_sockets_) { - socket->~DOutputSocket(); - } - for (DNode *node : nodes_by_id_) { - node->~DNode(); - } - for (DGroupInput *group_input : group_inputs_) { - group_input->~DGroupInput(); - } - for (DParentNode *parent : parent_nodes_) { - parent->~DParentNode(); - } -} - -bool DerivedNodeTree::has_link_cycles() const -{ - for (const NodeTreeRef *tree : used_node_tree_refs_) { - if (tree->has_link_cycles()) { - return true; + else { + /* The normal case: just use the value of a linked output socket. */ + callback(linked_dsocket); } } - return false; -} - -static dot::Cluster *get_cluster_for_parent(dot::DirectedGraph &graph, - Map &clusters, - const DParentNode *parent) -{ - if (parent == nullptr) { - return nullptr; - } - return clusters.lookup_or_add_cb(parent, [&]() { - dot::Cluster *parent_cluster = get_cluster_for_parent(graph, clusters, parent->parent()); - bNodeTree *btree = reinterpret_cast(parent->node_ref().bnode()->id); - dot::Cluster *new_cluster = &graph.new_cluster(parent->node_ref().name() + " / " + - StringRef(btree->id.name + 2)); - new_cluster->set_parent_cluster(parent_cluster); - return new_cluster; - }); } -std::string DerivedNodeTree::to_dot() const +/* Calls the given callback for every "real" target socket. "Real" means that reroutes, muted nodes + * and node groups are handled by this function. Target sockets are on the nodes that use the value + * from this socket. */ +void DOutputSocket::foreach_target_socket(FunctionRef callback) const { - dot::DirectedGraph digraph; - digraph.set_rankdir(dot::Attr_rankdir::LeftToRight); - - Map dot_nodes; - Map dot_group_inputs; - Map dot_clusters; - - for (const DNode *node : nodes_by_id_) { - dot::Node &dot_node = digraph.new_node(""); - dot_node.set_background_color("white"); - - Vector input_names; - for (const DInputSocket *socket : node->inputs()) { - input_names.append(socket->name()); - } - Vector output_names; - for (const DOutputSocket *socket : node->outputs()) { - output_names.append(socket->name()); + for (const InputSocketRef *linked_socket : socket_ref_->as_output().linked_sockets()) { + const NodeRef &linked_node = linked_socket->node(); + DInputSocket linked_dsocket{context_, linked_socket}; + + if (linked_node.is_muted()) { + /* If the target node is muted, follow its internal links. */ + for (const InternalLinkRef *internal_link : linked_node.internal_links()) { + if (&internal_link->from() == linked_socket) { + DOutputSocket output_of_muted_node{context_, &internal_link->to()}; + output_of_muted_node.foreach_target_socket(callback); + } + } } - - dot_nodes.add_new(node, - dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names)); - - dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, node->parent()); - dot_node.set_parent_cluster(cluster); - } - - for (const DGroupInput *group_input : group_inputs_) { - dot::Node &dot_node = digraph.new_node(""); - dot_node.set_background_color("white"); - - std::string group_input_name = group_input->name(); - dot_group_inputs.add_new( - group_input, dot::NodeWithSocketsRef(dot_node, "Group Input", {}, {group_input_name})); - - dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, group_input->parent()); - dot_node.set_parent_cluster(cluster); - } - - for (const DNode *to_node : nodes_by_id_) { - dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(to_node); - - for (const DInputSocket *to_socket : to_node->inputs()) { - for (const DOutputSocket *from_socket : to_socket->linked_sockets()) { - const DNode *from_node = &from_socket->node(); - dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(from_node); - - digraph.new_edge(from_dot_node.output(from_socket->index()), - to_dot_node.input(to_socket->index())); + else if (linked_node.is_group_output_node()) { + if (context_->is_root()) { + /* This is a group output in the root node group. */ + callback(linked_dsocket); } - for (const DGroupInput *group_input : to_socket->linked_group_inputs()) { - dot::NodeWithSocketsRef &from_dot_node = dot_group_inputs.lookup(group_input); - - digraph.new_edge(from_dot_node.output(0), to_dot_node.input(to_socket->index())); + else { + /* Follow the links going out of the group node in the parent node group. */ + DOutputSocket socket_in_parent_group = + linked_dsocket.get_corresponding_group_node_output(); + socket_in_parent_group.foreach_target_socket(callback); } } + else if (linked_node.is_group_node()) { + /* Follow the links within the nested node group. */ + Vector sockets_in_group = + linked_dsocket.get_corresponding_group_input_sockets(); + for (DOutputSocket socket_in_group : sockets_in_group) { + socket_in_group.foreach_target_socket(callback); + } + } + else { + /* The normal case: just use the linked input socket as target. */ + callback(linked_dsocket); + } } - - digraph.set_random_cluster_bgcolors(); - return digraph.to_dot_string(); } } // namespace blender::nodes diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index 9e62b7d7312..a4fb99a988e 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -20,7 +20,6 @@ #include "DEG_depsgraph_query.h" -#include "NOD_derived_node_tree.hh" #include "NOD_geometry_exec.hh" #include "NOD_type_callbacks.hh" @@ -30,7 +29,7 @@ namespace blender::nodes { void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const { - bNodeTree *btree_cow = node_.node_ref().tree().btree(); + bNodeTree *btree_cow = node_->btree(); BLI_assert(btree_cow != nullptr); if (btree_cow == nullptr) { return; @@ -40,12 +39,12 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin const NodeTreeEvaluationContext context(*self_object_, *modifier_); BKE_nodetree_error_message_add( - *btree_original, context, *node_.bnode(), type, std::move(message)); + *btree_original, context, *node_->bnode(), type, std::move(message)); } const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const { - for (const DSocket *socket : node_.inputs()) { + for (const InputSocketRef *socket : node_->inputs()) { if (socket->is_available() && socket->name() == name) { return socket->bsocket(); } @@ -176,7 +175,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier, const CPPType *requested_type) const { bNodeSocket *found_socket = nullptr; - for (const DSocket *socket : node_.inputs()) { + for (const InputSocketRef *socket : node_->inputs()) { if (socket->identifier() == identifier) { found_socket = socket->bsocket(); break; @@ -186,7 +185,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier, if (found_socket == nullptr) { std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const DSocket *socket : node_.inputs()) { + for (const InputSocketRef *socket : node_->inputs()) { if (socket->is_available()) { std::cout << "'" << socket->identifier() << "', "; } @@ -218,7 +217,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier, void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &value_type) const { bNodeSocket *found_socket = nullptr; - for (const DSocket *socket : node_.outputs()) { + for (const OutputSocketRef *socket : node_->outputs()) { if (socket->identifier() == identifier) { found_socket = socket->bsocket(); break; @@ -228,7 +227,7 @@ void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &va if (found_socket == nullptr) { std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const DSocket *socket : node_.outputs()) { + for (const OutputSocketRef *socket : node_->outputs()) { if (socket->is_available()) { std::cout << "'" << socket->identifier() << "', "; } diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc index c2391667e86..bb1367573f8 100644 --- a/source/blender/nodes/intern/node_tree_multi_function.cc +++ b/source/blender/nodes/intern/node_tree_multi_function.cc @@ -29,17 +29,17 @@ const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name) Vector input_types; Vector output_types; - for (const DInputSocket *dsocket : dnode_.inputs()) { + for (const InputSocketRef *dsocket : dnode_->inputs()) { if (dsocket->is_available()) { - std::optional data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); + std::optional data_type = socket_mf_type_get(*dsocket->typeinfo()); if (data_type.has_value()) { input_types.append(*data_type); } } } - for (const DOutputSocket *dsocket : dnode_.outputs()) { + for (const OutputSocketRef *dsocket : dnode_->outputs()) { if (dsocket->is_available()) { - std::optional data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); + std::optional data_type = socket_mf_type_get(*dsocket->typeinfo()); if (data_type.has_value()) { output_types.append(*data_type); } @@ -57,9 +57,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d Vector input_types; Vector input_names; - Vector input_dsockets; + Vector input_dsockets; - for (const DInputSocket *dsocket : dnode.inputs()) { + for (const InputSocketRef *dsocket : dnode->inputs()) { if (dsocket->is_available()) { std::optional data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); if (data_type.has_value()) { @@ -72,9 +72,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d Vector output_types; Vector output_names; - Vector output_dsockets; + Vector output_dsockets; - for (const DOutputSocket *dsocket : dnode.outputs()) { + for (const OutputSocketRef *dsocket : dnode->outputs()) { if (dsocket->is_available()) { std::optional data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); if (data_type.has_value()) { @@ -86,20 +86,20 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d } fn::MFDummyNode &dummy_node = common.network.add_dummy( - dnode.name(), input_types, output_types, input_names, output_names); + dnode->name(), input_types, output_types, input_names, output_names); - common.network_map.add(input_dsockets, dummy_node.inputs()); - common.network_map.add(output_dsockets, dummy_node.outputs()); + common.network_map.add(*dnode.context(), input_dsockets, dummy_node.inputs()); + common.network_map.add(*dnode.context(), output_dsockets, dummy_node.outputs()); } static bool has_data_sockets(const DNode &dnode) { - for (const DInputSocket *socket : dnode.inputs()) { + for (const InputSocketRef *socket : dnode->inputs()) { if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) { return true; } } - for (const DOutputSocket *socket : dnode.outputs()) { + for (const OutputSocketRef *socket : dnode->outputs()) { if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) { return true; } @@ -107,70 +107,39 @@ static bool has_data_sockets(const DNode &dnode) return false; } +static void foreach_node_to_insert(CommonMFNetworkBuilderData &common, + FunctionRef callback) +{ + common.tree.foreach_node([&](const DNode dnode) { + if (dnode->is_group_node()) { + return; + } + /* Don't insert non-root group input/output nodes, because they will be inlined. */ + if (!dnode.context()->is_root()) { + if (dnode->is_group_input_node() || dnode->is_group_output_node()) { + return; + } + } + callback(dnode); + }); +} + /** * Expands all function nodes in the multi-function network. Nodes that don't have an expand * function, but do have data sockets, will get corresponding dummy nodes. */ static void insert_nodes(CommonMFNetworkBuilderData &common) { - for (const DNode *dnode : common.tree.nodes()) { - const bNodeType *node_type = dnode->node_ref().bnode()->typeinfo; + foreach_node_to_insert(common, [&](const DNode dnode) { + const bNodeType *node_type = dnode->typeinfo(); if (node_type->expand_in_mf_network != nullptr) { - NodeMFNetworkBuilder builder{common, *dnode}; + NodeMFNetworkBuilder builder{common, dnode}; node_type->expand_in_mf_network(builder); } - else if (has_data_sockets(*dnode)) { - insert_dummy_node(common, *dnode); - } - } -} - -static void insert_group_inputs(CommonMFNetworkBuilderData &common) -{ - for (const DGroupInput *group_input : common.tree.group_inputs()) { - bNodeSocket *bsocket = group_input->bsocket(); - if (socket_is_mf_data_socket(*bsocket->typeinfo)) { - bNodeSocketType *socktype = bsocket->typeinfo; - BLI_assert(socktype->expand_in_mf_network != nullptr); - - SocketMFNetworkBuilder builder{common, *group_input}; - socktype->expand_in_mf_network(builder); - - fn::MFOutputSocket *from_socket = builder.built_socket(); - BLI_assert(from_socket != nullptr); - common.network_map.add(*group_input, *from_socket); - } - } -} - -static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common, - const DInputSocket &to_dsocket) -{ - Span from_dsockets = to_dsocket.linked_sockets(); - Span from_group_inputs = to_dsocket.linked_group_inputs(); - int total_linked_amount = from_dsockets.size() + from_group_inputs.size(); - BLI_assert(total_linked_amount <= 1); - - if (total_linked_amount == 0) { - return nullptr; - } - - if (from_dsockets.size() == 1) { - const DOutputSocket &from_dsocket = *from_dsockets[0]; - if (!from_dsocket.is_available()) { - return nullptr; - } - if (socket_is_mf_data_socket(*from_dsocket.bsocket()->typeinfo)) { - return &common.network_map.lookup(from_dsocket); + else if (has_data_sockets(dnode)) { + insert_dummy_node(common, dnode); } - return nullptr; - } - - const DGroupInput &from_group_input = *from_group_inputs[0]; - if (socket_is_mf_data_socket(*from_group_input.bsocket()->typeinfo)) { - return &common.network_map.lookup(from_group_input); - } - return nullptr; + }); } template @@ -286,78 +255,82 @@ static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderD return node.output(0); } -static void insert_links(CommonMFNetworkBuilderData &common) +static fn::MFOutputSocket *insert_unlinked_input(CommonMFNetworkBuilderData &common, + const DInputSocket &dsocket) { - for (const DInputSocket *to_dsocket : common.tree.input_sockets()) { - if (!to_dsocket->is_available()) { - continue; - } - if (!to_dsocket->is_linked()) { - continue; - } - if (!socket_is_mf_data_socket(*to_dsocket->bsocket()->typeinfo)) { - continue; - } - - Span to_sockets = common.network_map.lookup(*to_dsocket); - BLI_assert(to_sockets.size() >= 1); - fn::MFDataType to_type = to_sockets[0]->data_type(); + BLI_assert(socket_is_mf_data_socket(*dsocket->typeinfo())); - fn::MFOutputSocket *from_socket = try_find_origin(common, *to_dsocket); - if (from_socket == nullptr) { - from_socket = &insert_default_value_for_type(common, to_type); - } - - fn::MFDataType from_type = from_socket->data_type(); - - if (from_type != to_type) { - const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion( - from_type, to_type); - if (conversion_fn != nullptr) { - fn::MFNode &node = common.network.add_function(*conversion_fn); - common.network.add_link(*from_socket, node.input(0)); - from_socket = &node.output(0); - } - else { - from_socket = &insert_default_value_for_type(common, to_type); - } - } + SocketMFNetworkBuilder builder{common, dsocket}; + socket_expand_in_mf_network(builder); - for (fn::MFInputSocket *to_socket : to_sockets) { - common.network.add_link(*from_socket, *to_socket); - } - } + fn::MFOutputSocket *built_socket = builder.built_socket(); + BLI_assert(built_socket != nullptr); + return built_socket; } -static void insert_unlinked_input(CommonMFNetworkBuilderData &common, const DInputSocket &dsocket) +static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common) { - bNodeSocket *bsocket = dsocket.bsocket(); - bNodeSocketType *socktype = bsocket->typeinfo; - BLI_assert(socktype->expand_in_mf_network != nullptr); - - SocketMFNetworkBuilder builder{common, dsocket}; - socktype->expand_in_mf_network(builder); - - fn::MFOutputSocket *from_socket = builder.built_socket(); - BLI_assert(from_socket != nullptr); + foreach_node_to_insert(common, [&](const DNode dnode) { + for (const InputSocketRef *socket_ref : dnode->inputs()) { + const DInputSocket to_dsocket{dnode.context(), socket_ref}; + if (!to_dsocket->is_available()) { + continue; + } + if (!socket_is_mf_data_socket(*to_dsocket->typeinfo())) { + continue; + } - for (fn::MFInputSocket *to_socket : common.network_map.lookup(dsocket)) { - common.network.add_link(*from_socket, *to_socket); - } -} + Span to_sockets = common.network_map.lookup(to_dsocket); + BLI_assert(to_sockets.size() >= 1); + const fn::MFDataType to_type = to_sockets[0]->data_type(); -static void insert_unlinked_inputs(CommonMFNetworkBuilderData &common) -{ - Vector unlinked_data_inputs; - for (const DInputSocket *dsocket : common.tree.input_sockets()) { - if (dsocket->is_available()) { - if (socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) { - if (!dsocket->is_linked()) { - insert_unlinked_input(common, *dsocket); + Vector from_dsockets; + to_dsocket.foreach_origin_socket([&](DSocket socket) { from_dsockets.append(socket); }); + if (from_dsockets.size() > 1) { + fn::MFOutputSocket &from_socket = insert_default_value_for_type(common, to_type); + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(from_socket, *to_socket); + } + continue; + } + if (from_dsockets.is_empty()) { + /* The socket is not linked. Need to use the value of the socket itself. */ + fn::MFOutputSocket *built_socket = insert_unlinked_input(common, to_dsocket); + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(*built_socket, *to_socket); } + continue; + } + if (from_dsockets[0]->is_input()) { + DInputSocket from_dsocket{from_dsockets[0]}; + fn::MFOutputSocket *built_socket = insert_unlinked_input(common, from_dsocket); + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(*built_socket, *to_socket); + } + continue; + } + DOutputSocket from_dsocket{from_dsockets[0]}; + fn::MFOutputSocket *from_socket = &common.network_map.lookup(from_dsocket); + const fn::MFDataType from_type = from_socket->data_type(); + + if (from_type != to_type) { + const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion( + from_type, to_type); + if (conversion_fn != nullptr) { + fn::MFNode &node = common.network.add_function(*conversion_fn); + common.network.add_link(*from_socket, node.input(0)); + from_socket = &node.output(0); + } + else { + from_socket = &insert_default_value_for_type(common, to_type); + } + } + + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(*from_socket, *to_socket); } } - } + }); } /** @@ -376,9 +349,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network, CommonMFNetworkBuilderData common{resources, network, network_map, tree}; insert_nodes(common); - insert_group_inputs(common); - insert_links(common); - insert_unlinked_inputs(common); + insert_links_and_unlinked_inputs(common); return network_map; } @@ -420,16 +391,17 @@ static NodeExpandType get_node_expand_type(MFNetworkTreeMap &network_map, } }; - for (const DInputSocket *dsocket : dnode.inputs()) { + for (const InputSocketRef *dsocket : dnode->inputs()) { if (dsocket->is_available()) { - for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) { + for (fn::MFInputSocket *mf_input : + network_map.lookup(DInputSocket(dnode.context(), dsocket))) { check_mf_node(mf_input->node()); } } } - for (const DOutputSocket *dsocket : dnode.outputs()) { + for (const OutputSocketRef *dsocket : dnode->outputs()) { if (dsocket->is_available()) { - fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket); + fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket)); check_mf_node(mf_output.node()); } } @@ -451,20 +423,21 @@ static const fn::MultiFunction &create_function_for_node_that_expands_into_multi ResourceCollector &resources) { Vector dummy_fn_inputs; - for (const DInputSocket *dsocket : dnode.inputs()) { + for (const InputSocketRef *dsocket : dnode->inputs()) { if (dsocket->is_available()) { MFDataType data_type = *socket_mf_type_get(*dsocket->typeinfo()); fn::MFOutputSocket &fn_input = network.add_input(data_type.to_string(), data_type); - for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) { + for (fn::MFInputSocket *mf_input : + network_map.lookup(DInputSocket(dnode.context(), dsocket))) { network.add_link(fn_input, *mf_input); dummy_fn_inputs.append(&fn_input); } } } Vector dummy_fn_outputs; - for (const DOutputSocket *dsocket : dnode.outputs()) { + for (const OutputSocketRef *dsocket : dnode->outputs()) { if (dsocket->is_available()) { - fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket); + fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket)); MFDataType data_type = mf_output.data_type(); fn::MFInputSocket &fn_output = network.add_output(data_type.to_string(), data_type); network.add_link(mf_output, fn_output); @@ -492,18 +465,18 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, CommonMFNetworkBuilderData common{resources, network, network_map, tree}; - for (const DNode *dnode : tree.nodes()) { + tree.foreach_node([&](DNode dnode) { const bNodeType *node_type = dnode->typeinfo(); if (node_type->expand_in_mf_network == nullptr) { /* This node does not have a multi-function implementation. */ - continue; + return; } - NodeMFNetworkBuilder builder{common, *dnode}; + NodeMFNetworkBuilder builder{common, dnode}; node_type->expand_in_mf_network(builder); const fn::MultiFunction *single_function = nullptr; - const NodeExpandType expand_type = get_node_expand_type(network_map, *dnode, &single_function); + const NodeExpandType expand_type = get_node_expand_type(network_map, dnode, &single_function); switch (expand_type) { case NodeExpandType::HasDummyNodes: { @@ -519,12 +492,12 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, /* If a node expanded into multiple functions, a new function has to be created that * combines those. */ const fn::MultiFunction &fn = create_function_for_node_that_expands_into_multiple( - *dnode, network, network_map, resources); + dnode, network, network_map, resources); functions_by_node.add_new(dnode, &fn); break; } } - } + }); return functions_by_node; } diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index f54914ceba9..7a846031456 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -116,7 +116,7 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild blender::fn::MFNetwork &network = builder.network(); blender::fn::MFFunctionNode &base_node = network.add_function(base_function); - builder.network_map().add_try_match(dnode.inputs(), base_node.inputs()); + builder.network_map().add_try_match(*dnode.context(), dnode->inputs(), base_node.inputs()); const bool clamp_output = builder.bnode().custom2 != 0; if (clamp_output) { @@ -126,10 +126,12 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild }}; blender::fn::MFFunctionNode &clamp_node = network.add_function(clamp_fn); network.add_link(base_node.output(0), clamp_node.input(0)); - builder.network_map().add(dnode.output(0), clamp_node.output(0)); + builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)), + clamp_node.output(0)); } else { - builder.network_map().add(dnode.output(0), base_node.output(0)); + builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)), + base_node.output(0)); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc index 5a8a1b847cc..495c8d12824 100644 --- a/source/blender/nodes/shader/nodes/node_shader_value.cc +++ b/source/blender/nodes/shader/nodes/node_shader_value.cc @@ -41,7 +41,7 @@ static int gpu_shader_value(GPUMaterial *mat, static void sh_node_value_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { - const bNodeSocket *bsocket = builder.dnode().output(0).bsocket(); + const bNodeSocket *bsocket = builder.dnode()->output(0).bsocket(); const bNodeSocketValueFloat *value = (const bNodeSocketValueFloat *)bsocket->default_value; builder.construct_and_set_matching_fn>(value->value); } -- cgit v1.2.3 From 9828882b8e7450e712865b067d64a793e18a3383 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sat, 6 Mar 2021 16:54:09 +0100 Subject: Cleanup: clang tidy --- source/blender/blenkernel/intern/armature_pose.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/armature_pose.cc b/source/blender/blenkernel/intern/armature_pose.cc index a9613da2335..bb371b16c42 100644 --- a/source/blender/blenkernel/intern/armature_pose.cc +++ b/source/blender/blenkernel/intern/armature_pose.cc @@ -50,7 +50,7 @@ void BKE_pose_apply_action(struct Object *ob, struct AnimationEvalContext *anim_eval_context) { bPose *pose = ob->pose; - if (pose == NULL) { + if (pose == nullptr) { return; } -- cgit v1.2.3 From 8618c4159c7b0c9bddf6b86522dee383de7207cf Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sat, 6 Mar 2021 17:54:28 +0100 Subject: Cleanup: use class instead of struct in forward declaration --- source/blender/nodes/NOD_derived_node_tree.hh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index a254f908bfd..f1dbb2caf29 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -35,10 +35,10 @@ namespace blender::nodes { class DTreeContext; class DerivedNodeTree; -struct DNode; -struct DSocket; -struct DInputSocket; -struct DOutputSocket; +class DNode; +class DSocket; +class DInputSocket; +class DOutputSocket; /** * The context attached to every node or socket in a derived node tree. It can be used to determine -- cgit v1.2.3 From 84da76a96c5c2b59aeb67fa905398f656af25649 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 7 Mar 2021 19:27:11 +1100 Subject: Cleanup: use POINTER_OFFSET macro --- source/blender/blenlib/intern/string_utils.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index dbeb75570fb..dbe5c96260b 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -333,11 +333,6 @@ bool BLI_uniquename_cb(UniquenameCheckCallback unique_check, return false; } -/* little helper macro for BLI_uniquename */ -#ifndef GIVE_STRADDR -# define GIVE_STRADDR(data, offset) (((char *)data) + offset) -#endif - /** * Generic function to set a unique name. It is only designed to be used in situations * where the name is part of the struct. @@ -353,7 +348,7 @@ static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, for (link = list->first; link; link = link->next) { if (link != vlink) { - if (STREQ(GIVE_STRADDR(link, name_offs), name)) { + if (STREQ(POINTER_OFFSET((const char *)link, name_offs), name)) { return true; } } @@ -403,7 +398,7 @@ bool BLI_uniquename( } return BLI_uniquename_cb( - uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len); + uniquename_unique_check, &data, defname, delim, POINTER_OFFSET(vlink, name_offs), name_len); } /* ------------------------------------------------------------------------- */ -- cgit v1.2.3 From 456d3cc85e9f408341b12eb0d4f2c3a925855e8c Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sun, 7 Mar 2021 14:15:20 +0100 Subject: BLI: reduce wasted memory in linear allocator The main change is that large allocations are done separately now. Also, buffers that small allocations are packed into, have a maximum size now. Using larger buffers does not really provider performance benefits, but increases wasted memory. --- source/blender/blenlib/BLI_linear_allocator.hh | 41 +++++++++++++++------- .../blenlib/tests/BLI_linear_allocator_test.cc | 21 +++++++++++ 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh index a616ec5cf28..11022a03d69 100644 --- a/source/blender/blenlib/BLI_linear_allocator.hh +++ b/source/blender/blenlib/BLI_linear_allocator.hh @@ -38,18 +38,20 @@ template class LinearAllocator : NonCopya uintptr_t current_begin_; uintptr_t current_end_; - int64_t next_min_alloc_size_; #ifdef DEBUG int64_t debug_allocated_amount_ = 0; #endif + /* Buffers larger than that are not packed together with smaller allocations to avoid wasting + * memory. */ + constexpr static inline int64_t large_buffer_threshold = 4096; + public: LinearAllocator() { current_begin_ = 0; current_end_ = 0; - next_min_alloc_size_ = 64; } ~LinearAllocator() @@ -71,23 +73,23 @@ template class LinearAllocator : NonCopya BLI_assert(alignment >= 1); BLI_assert(is_power_of_2_i(alignment)); -#ifdef DEBUG - debug_allocated_amount_ += size; -#endif - const uintptr_t alignment_mask = alignment - 1; const uintptr_t potential_allocation_begin = (current_begin_ + alignment_mask) & ~alignment_mask; const uintptr_t potential_allocation_end = potential_allocation_begin + size; if (potential_allocation_end <= current_end_) { +#ifdef DEBUG + debug_allocated_amount_ += size; +#endif current_begin_ = potential_allocation_end; return reinterpret_cast(potential_allocation_begin); } - else { - this->allocate_new_buffer(size + alignment); + if (size <= large_buffer_threshold) { + this->allocate_new_buffer(size + alignment, alignment); return this->allocate(size, alignment); } + return this->allocator_large_buffer(size, alignment); }; /** @@ -195,7 +197,7 @@ template class LinearAllocator : NonCopya } private: - void allocate_new_buffer(int64_t min_allocation_size) + void allocate_new_buffer(int64_t min_allocation_size, int64_t min_alignment) { for (int64_t i : unused_borrowed_buffers_.index_range()) { Span buffer = unused_borrowed_buffers_[i]; @@ -207,15 +209,28 @@ template class LinearAllocator : NonCopya } } - const int64_t size_in_bytes = power_of_2_min_u( - std::max(min_allocation_size, next_min_alloc_size_)); - next_min_alloc_size_ = size_in_bytes * 2; + /* Possibly allocate more bytes than necessary for the current allocation. This way more small + * allocations can be packed together. Large buffers are allocated exactly to avoid wasting too + * much memory. */ + int64_t size_in_bytes = min_allocation_size; + if (size_in_bytes <= large_buffer_threshold) { + /* Gradually grow buffer size with each allocation, up to a maximum. */ + const int64_t grow_size = 1 << std::min(owned_buffers_.size() + 6, 20); + size_in_bytes = std::min(large_buffer_threshold, std::max(size_in_bytes, grow_size)); + } - void *buffer = allocator_.allocate(size_in_bytes, 8, AT); + void *buffer = allocator_.allocate(size_in_bytes, min_alignment, __func__); owned_buffers_.append(buffer); current_begin_ = (uintptr_t)buffer; current_end_ = current_begin_ + size_in_bytes; } + + void *allocator_large_buffer(const int64_t size, const int64_t alignment) + { + void *buffer = allocator_.allocate(size, alignment, __func__); + owned_buffers_.append(buffer); + return buffer; + } }; } // namespace blender diff --git a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc index a35fbf70711..95156ae5c0c 100644 --- a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc +++ b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc @@ -1,6 +1,7 @@ /* Apache License, Version 2.0 */ #include "BLI_linear_allocator.hh" +#include "BLI_rand.hh" #include "BLI_strict_flags.h" #include "testing/testing.h" @@ -115,4 +116,24 @@ TEST(linear_allocator, ConstructArrayCopy) EXPECT_EQ(span2[2], 3); } +TEST(linear_allocator, AllocateLarge) +{ + LinearAllocator<> allocator; + void *buffer1 = allocator.allocate(1024 * 1024, 8); + void *buffer2 = allocator.allocate(1024 * 1024, 8); + EXPECT_NE(buffer1, buffer2); +} + +TEST(linear_allocator, ManyAllocations) +{ + LinearAllocator<> allocator; + RandomNumberGenerator rng; + for (int i = 0; i < 1000; i++) { + int size = rng.get_int32(10000); + int alignment = 1 << (rng.get_int32(7)); + void *buffer = allocator.allocate(size, alignment); + EXPECT_NE(buffer, nullptr); + } +} + } // namespace blender::tests -- cgit v1.2.3 From 649916f0983e4c59201672e6e28dcc7ae1f655b2 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sun, 7 Mar 2021 14:24:52 +0100 Subject: BLI: make it harder to forget to destruct a value Instead of returning a raw pointer, `LinearAllocator.construct(...)` now returns a `destruct_ptr`, which is similar to `unique_ptr`, but does not deallocate the memory and only calls the destructor instead. --- source/blender/blenlib/BLI_linear_allocator.hh | 8 ++--- source/blender/blenlib/BLI_resource_collector.hh | 7 +++-- .../blenlib/tests/BLI_linear_allocator_test.cc | 2 +- .../intern/multi_function_network_evaluation.cc | 36 ++++++++++++---------- source/blender/modifiers/intern/MOD_nodes.cc | 4 +-- 5 files changed, 31 insertions(+), 26 deletions(-) diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh index 11022a03d69..0bf4ad194e1 100644 --- a/source/blender/blenlib/BLI_linear_allocator.hh +++ b/source/blender/blenlib/BLI_linear_allocator.hh @@ -118,14 +118,14 @@ template class LinearAllocator : NonCopya * * Arguments passed to this method will be forwarded to the constructor of T. * - * You must not call `delete` on the returned pointer. - * Instead, the destruct has to be called explicitly. + * You must not call `delete` on the returned value. + * Instead, only the destructor has to be called. */ - template T *construct(Args &&... args) + template destruct_ptr construct(Args &&... args) { void *buffer = this->allocate(sizeof(T), alignof(T)); T *value = new (buffer) T(std::forward(args)...); - return value; + return destruct_ptr(value); } /** diff --git a/source/blender/blenlib/BLI_resource_collector.hh b/source/blender/blenlib/BLI_resource_collector.hh index ecae9b8c682..70804ceb1f1 100644 --- a/source/blender/blenlib/BLI_resource_collector.hh +++ b/source/blender/blenlib/BLI_resource_collector.hh @@ -130,9 +130,10 @@ class ResourceCollector : NonCopyable, NonMovable { */ template T &construct(const char *name, Args &&... args) { - T *value = m_allocator.construct(std::forward(args)...); - this->add(destruct_ptr(value), name); - return *value; + destruct_ptr value_ptr = m_allocator.construct(std::forward(args)...); + T &value_ref = *value_ptr; + this->add(std::move(value_ptr), name); + return value_ref; } /** diff --git a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc index 95156ae5c0c..977e5dba497 100644 --- a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc +++ b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc @@ -79,7 +79,7 @@ TEST(linear_allocator, Construct) LinearAllocator<> allocator; std::array values = {1, 2, 3, 4, 5}; - Vector *vector = allocator.construct>(values); + Vector *vector = allocator.construct>(values).release(); EXPECT_EQ(vector->size(), 5); EXPECT_EQ((*vector)[3], 4); vector->~Vector(); diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc index c543d86ad34..5a37a45908f 100644 --- a/source/blender/functions/intern/multi_function_network_evaluation.cc +++ b/source/blender/functions/intern/multi_function_network_evaluation.cc @@ -663,7 +663,7 @@ void MFNetworkEvaluationStorage::add_single_input_from_caller(const MFOutputSock BLI_assert(value_per_output_id_[socket.id()] == nullptr); BLI_assert(virtual_span.size() >= min_array_size_); - auto *value = allocator_.construct(virtual_span); + auto *value = allocator_.construct(virtual_span).release(); value_per_output_id_[socket.id()] = value; } @@ -673,7 +673,7 @@ void MFNetworkEvaluationStorage::add_vector_input_from_caller(const MFOutputSock BLI_assert(value_per_output_id_[socket.id()] == nullptr); BLI_assert(virtual_array_span.size() >= min_array_size_); - auto *value = allocator_.construct(virtual_array_span); + auto *value = allocator_.construct(virtual_array_span).release(); value_per_output_id_[socket.id()] = value; } @@ -683,7 +683,7 @@ void MFNetworkEvaluationStorage::add_single_output_from_caller(const MFOutputSoc BLI_assert(value_per_output_id_[socket.id()] == nullptr); BLI_assert(span.size() >= min_array_size_); - auto *value = allocator_.construct(span); + auto *value = allocator_.construct(span).release(); value_per_output_id_[socket.id()] = value; } @@ -693,7 +693,7 @@ void MFNetworkEvaluationStorage::add_vector_output_from_caller(const MFOutputSoc BLI_assert(value_per_output_id_[socket.id()] == nullptr); BLI_assert(vector_array.size() >= min_array_size_); - auto *value = allocator_.construct(vector_array); + auto *value = allocator_.construct(vector_array).release(); value_per_output_id_[socket.id()] = value; } @@ -705,7 +705,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_single_output__full(const MFOutputS void *buffer = MEM_mallocN_aligned(min_array_size_ * type.size(), type.alignment(), AT); GMutableSpan span(type, buffer, min_array_size_); - auto *value = allocator_.construct(span, socket.targets().size(), false); + auto *value = + allocator_.construct(span, socket.targets().size(), false).release(); value_per_output_id_[socket.id()] = value; return span; @@ -723,7 +724,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_single_output__single(const MFOutpu void *buffer = allocator_.allocate(type.size(), type.alignment()); GMutableSpan span(type, buffer, 1); - auto *value = allocator_.construct(span, socket.targets().size(), true); + auto *value = + allocator_.construct(span, socket.targets().size(), true).release(); value_per_output_id_[socket.id()] = value; return value->span; @@ -742,7 +744,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_vector_output__full(const MFOutput const CPPType &type = socket.data_type().vector_base_type(); GVectorArray *vector_array = new GVectorArray(type, min_array_size_); - auto *value = allocator_.construct(*vector_array, socket.targets().size()); + auto *value = + allocator_.construct(*vector_array, socket.targets().size()).release(); value_per_output_id_[socket.id()] = value; return *value->vector_array; @@ -759,7 +762,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_vector_output__single(const MFOutp const CPPType &type = socket.data_type().vector_base_type(); GVectorArray *vector_array = new GVectorArray(type, 1); - auto *value = allocator_.construct(*vector_array, socket.targets().size()); + auto *value = + allocator_.construct(*vector_array, socket.targets().size()).release(); value_per_output_id_[socket.id()] = value; return *value->vector_array; @@ -806,8 +810,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputS GMutableSpan new_array_ref(type, new_buffer, min_array_size_); virtual_span.materialize_to_uninitialized(mask_, new_array_ref.data()); - OwnSingleValue *new_value = allocator_.construct( - new_array_ref, to.targets().size(), false); + OwnSingleValue *new_value = + allocator_.construct(new_array_ref, to.targets().size(), false).release(); value_per_output_id_[to.id()] = new_value; return new_array_ref; } @@ -850,8 +854,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__single(const MFInpu type.copy_to_uninitialized(virtual_span.as_single_element(), new_buffer); GMutableSpan new_array_ref(type, new_buffer, 1); - OwnSingleValue *new_value = allocator_.construct( - new_array_ref, to.targets().size(), true); + OwnSingleValue *new_value = + allocator_.construct(new_array_ref, to.targets().size(), true).release(); value_per_output_id_[to.id()] = new_value; return new_array_ref; } @@ -891,8 +895,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__full(const MFInput GVectorArray *new_vector_array = new GVectorArray(base_type, min_array_size_); new_vector_array->extend(mask_, virtual_array_span); - OwnVectorValue *new_value = allocator_.construct(*new_vector_array, - to.targets().size()); + OwnVectorValue *new_value = + allocator_.construct(*new_vector_array, to.targets().size()).release(); value_per_output_id_[to.id()] = new_value; return *new_vector_array; @@ -934,8 +938,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__single(const MFInp GVectorArray *new_vector_array = new GVectorArray(base_type, 1); new_vector_array->extend(0, virtual_array_span[0]); - OwnVectorValue *new_value = allocator_.construct(*new_vector_array, - to.targets().size()); + OwnVectorValue *new_value = + allocator_.construct(*new_vector_array, to.targets().size()).release(); value_per_output_id_[to.id()] = new_value; return *new_vector_array; } diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 4d1823b8951..50c07578173 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -1045,8 +1045,8 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, * modifier. */ const OutputSocketRef *first_input_socket = group_input_sockets[0]; if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) { - GeometrySet *geometry_set_in = allocator.construct( - std::move(input_geometry_set)); + GeometrySet *geometry_set_in = + allocator.construct(std::move(input_geometry_set)).release(); group_inputs.add_new({root_context, first_input_socket}, geometry_set_in); remaining_input_sockets = remaining_input_sockets.drop_front(1); } -- cgit v1.2.3 From c14770370f0f5906c479bb444f70a26733efade9 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sun, 7 Mar 2021 14:27:08 +0100 Subject: Cleanup: fix implicit conversion warning --- source/blender/blenlib/BLI_linear_allocator.hh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh index 0bf4ad194e1..47705b1d40b 100644 --- a/source/blender/blenlib/BLI_linear_allocator.hh +++ b/source/blender/blenlib/BLI_linear_allocator.hh @@ -215,8 +215,9 @@ template class LinearAllocator : NonCopya int64_t size_in_bytes = min_allocation_size; if (size_in_bytes <= large_buffer_threshold) { /* Gradually grow buffer size with each allocation, up to a maximum. */ - const int64_t grow_size = 1 << std::min(owned_buffers_.size() + 6, 20); - size_in_bytes = std::min(large_buffer_threshold, std::max(size_in_bytes, grow_size)); + const int grow_size = 1 << std::min(owned_buffers_.size() + 6, 20); + size_in_bytes = std::min(large_buffer_threshold, + std::max(size_in_bytes, grow_size)); } void *buffer = allocator_.allocate(size_in_bytes, min_alignment, __func__); -- cgit v1.2.3 From e72dc1e6c69ef22dbec8c6c17d7a4e309d362e9e Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sun, 7 Mar 2021 14:46:48 +0100 Subject: Cleanup: compiler warnings --- source/blender/functions/intern/multi_function_network.cc | 4 ++-- source/blender/modifiers/intern/MOD_nodes.cc | 2 +- source/blender/nodes/intern/node_tree_ref.cc | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/functions/intern/multi_function_network.cc b/source/blender/functions/intern/multi_function_network.cc index 77c8ba6373f..b5c2c09a35a 100644 --- a/source/blender/functions/intern/multi_function_network.cc +++ b/source/blender/functions/intern/multi_function_network.cc @@ -70,7 +70,7 @@ MFFunctionNode &MFNetwork::add_function(const MultiFunction &function) } } - MFFunctionNode &node = *allocator_.construct(); + MFFunctionNode &node = *allocator_.construct().release(); function_nodes_.add_new(&node); node.network_ = this; @@ -129,7 +129,7 @@ MFDummyNode &MFNetwork::add_dummy(StringRef name, assert_same_size(input_types, input_names); assert_same_size(output_types, output_names); - MFDummyNode &node = *allocator_.construct(); + MFDummyNode &node = *allocator_.construct().release(); dummy_nodes_.add_new(&node); node.network_ = this; diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 50c07578173..c0c7897413b 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -307,7 +307,7 @@ class GeometryNodesEvaluator { /* Multi-input sockets contain a vector of inputs. */ if (socket_to_compute->is_multi_input_socket()) { Vector values; - for (const DSocket from_socket : from_sockets) { + for (const DSocket &from_socket : from_sockets) { GMutablePointer value = get_input_from_incoming_link(socket_to_compute, from_socket); values.append(value); } diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index 7fe21ec8582..0ea2538d6f1 100644 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -25,7 +25,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) Map node_mapping; LISTBASE_FOREACH (bNode *, bnode, &btree->nodes) { - NodeRef &node = *allocator_.construct(); + NodeRef &node = *allocator_.construct().release(); node.tree_ = this; node.bnode_ = bnode; @@ -33,7 +33,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) RNA_pointer_create(&btree->id, &RNA_Node, bnode, &node.rna_); LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->inputs) { - InputSocketRef &socket = *allocator_.construct(); + InputSocketRef &socket = *allocator_.construct().release(); socket.node_ = &node; socket.index_ = node.inputs_.append_and_get_index(&socket); socket.is_input_ = true; @@ -43,7 +43,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) } LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->outputs) { - OutputSocketRef &socket = *allocator_.construct(); + OutputSocketRef &socket = *allocator_.construct().release(); socket.node_ = &node; socket.index_ = node.outputs_.append_and_get_index(&socket); socket.is_input_ = false; @@ -53,7 +53,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) } LISTBASE_FOREACH (bNodeLink *, blink, &bnode->internal_links) { - InternalLinkRef &internal_link = *allocator_.construct(); + InternalLinkRef &internal_link = *allocator_.construct().release(); internal_link.blink_ = blink; for (InputSocketRef *socket_ref : node.inputs_) { if (socket_ref->bsocket_ == blink->fromsock) { @@ -82,7 +82,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) InputSocketRef &to_socket = this->find_input_socket( node_mapping, blink->tonode, blink->tosock); - LinkRef &link = *allocator_.construct(); + LinkRef &link = *allocator_.construct().release(); link.from_ = &from_socket; link.to_ = &to_socket; link.blink_ = blink; -- cgit v1.2.3 From b30f89918ee16ae3473faa2cfaa5c843b012d878 Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Sun, 7 Mar 2021 08:54:21 -0500 Subject: Fix T85632 Improve Exact boolean in cell fracture of Suzanne. The Exact boolean used in the cell fracture addon incorrectly kept some outside faces: due to some raycasts going into open eye socket then out of the head, leading to one ray direction (out of 8) saying the face was inside the head. The current code allowed 1 of 8 rays only as "inside" to accommodate the case of a plane used in boolean to bisect. But this cell fracture case needs more confidence of being inside. So changed the test for intersection to require at least 3 of 8 rays to be inside. Maybe the number of rays to indicate insideness should be exposed as an option, to allow user tuning according to the degree of "non-volumeness" of the arguments, but will try at least for now to magically guess the right value of the rays-inside threshold. Note: all of this only for the case where the arguments are not all PWN (approx: manifold). The all-PWN case doesn't use raycast. --- source/blender/blenlib/intern/mesh_boolean.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc index fcf5c5bfad3..68d7ddec7ef 100644 --- a/source/blender/blenlib/intern/mesh_boolean.cc +++ b/source/blender/blenlib/intern/mesh_boolean.cc @@ -2542,11 +2542,12 @@ static IMesh raycast_boolean(const IMesh &tm, * operation, we want to be pretty sure that the point is inside other_shape. * E.g., T75827. */ - bool need_high_confidence = (op == BoolOpType::Difference) && (shape != 0); + bool need_high_confidence = (op == BoolOpType::Difference && shape != 0) || + op == BoolOpType::Intersect; bool inside = in_shape[other_shape] >= (need_high_confidence ? 0.5f : 0.1f); if (dbg_level > 0) { std::cout << "test point is " << (inside ? "inside" : "outside") << " other_shape " - << other_shape << "\n"; + << other_shape << " val = " << in_shape[other_shape] << "\n"; } winding[other_shape] = inside; } -- cgit v1.2.3 From a9fc9ce0aec0ab5ea1dc1cee9a5a77cb2ef9052d Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sun, 7 Mar 2021 16:08:45 +0100 Subject: Cleanup: remove dead code --- source/blender/nodes/CMakeLists.txt | 2 - source/blender/nodes/NOD_node_tree_dependencies.hh | 76 ---------------------- .../blender/nodes/intern/node_tree_dependencies.cc | 57 ---------------- 3 files changed, 135 deletions(-) delete mode 100644 source/blender/nodes/NOD_node_tree_dependencies.hh delete mode 100644 source/blender/nodes/intern/node_tree_dependencies.cc diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index e21959d839c..9386f686c73 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -302,7 +302,6 @@ set(SRC intern/node_exec.c intern/node_geometry_exec.cc intern/node_socket.cc - intern/node_tree_dependencies.cc intern/node_tree_multi_function.cc intern/node_tree_ref.cc intern/node_util.c @@ -321,7 +320,6 @@ set(SRC NOD_geometry.h NOD_geometry_exec.hh NOD_math_functions.hh - NOD_node_tree_dependencies.hh NOD_node_tree_multi_function.hh NOD_node_tree_ref.hh NOD_shader.h diff --git a/source/blender/nodes/NOD_node_tree_dependencies.hh b/source/blender/nodes/NOD_node_tree_dependencies.hh deleted file mode 100644 index 13bb2bde2f3..00000000000 --- a/source/blender/nodes/NOD_node_tree_dependencies.hh +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include "BLI_vector_set.hh" - -#include "DNA_ID.h" -#include "DNA_object_types.h" - -struct bNodeTree; - -namespace blender::nodes { - -class NodeTreeDependencies { - private: - VectorSet transform_deps_; - VectorSet geometry_deps_; - VectorSet id_deps_; - - public: - void add_transform_dependency(Object *object) - { - if (object == nullptr) { - return; - } - transform_deps_.add(object); - id_deps_.add(&object->id); - } - - void add_geometry_dependency(Object *object) - { - if (object == nullptr) { - return; - } - geometry_deps_.add(object); - id_deps_.add(&object->id); - } - - bool depends_on(ID *id) const - { - return id_deps_.contains(id); - } - - Span transform_dependencies() - { - return transform_deps_; - } - - Span geometry_dependencies() - { - return geometry_deps_; - } - - Span id_dependencies() - { - return id_deps_; - } -}; - -NodeTreeDependencies find_node_tree_dependencies(bNodeTree &ntree); - -} // namespace blender::nodes diff --git a/source/blender/nodes/intern/node_tree_dependencies.cc b/source/blender/nodes/intern/node_tree_dependencies.cc deleted file mode 100644 index 9d279dd4d75..00000000000 --- a/source/blender/nodes/intern/node_tree_dependencies.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. - */ - -#include "NOD_node_tree_dependencies.hh" - -#include "DNA_node_types.h" - -#include "BKE_node.h" - -namespace blender::nodes { - -static void add_dependencies_of_node_tree(bNodeTree &ntree, NodeTreeDependencies &r_dependencies) -{ - /* TODO: Do a bit more sophisticated parsing to see which dependencies are really required. */ - LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { - LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { - if (socket->type == SOCK_OBJECT) { - Object *object = reinterpret_cast(socket->default_value)->value; - if (object != nullptr) { - r_dependencies.add_transform_dependency(object); - if (object->type == OB_MESH) { - r_dependencies.add_geometry_dependency(object); - } - } - } - } - - if (node->type == NODE_GROUP) { - bNodeTree *group = reinterpret_cast(node->id); - if (group != nullptr) { - add_dependencies_of_node_tree(*group, r_dependencies); - } - } - } -} - -NodeTreeDependencies find_node_tree_dependencies(bNodeTree &ntree) -{ - NodeTreeDependencies dependencies; - add_dependencies_of_node_tree(ntree, dependencies); - return dependencies; -} - -} // namespace blender::nodes -- cgit v1.2.3 From 111a77e81827705119fb82f8191a41dd8752a888 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sun, 7 Mar 2021 17:03:20 +0100 Subject: Cleanup: remove dead code --- source/blender/blenkernel/intern/simulation.cc | 1 - source/blender/functions/CMakeLists.txt | 3 - source/blender/functions/FN_attributes_ref.hh | 341 --------------------- source/blender/functions/intern/attributes_ref.cc | 78 ----- .../functions/tests/FN_attributes_ref_test.cc | 97 ------ 5 files changed, 520 deletions(-) delete mode 100644 source/blender/functions/FN_attributes_ref.hh delete mode 100644 source/blender/functions/intern/attributes_ref.cc delete mode 100644 source/blender/functions/tests/FN_attributes_ref_test.cc diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 6b46804c251..216563b860d 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -54,7 +54,6 @@ #include "BLI_map.hh" #include "BLT_translation.h" -#include "FN_attributes_ref.hh" #include "FN_multi_function_network_evaluation.hh" #include "FN_multi_function_network_optimization.hh" diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt index 429959f9c33..e4a0b154a07 100644 --- a/source/blender/functions/CMakeLists.txt +++ b/source/blender/functions/CMakeLists.txt @@ -27,7 +27,6 @@ set(INC_SYS ) set(SRC - intern/attributes_ref.cc intern/cpp_types.cc intern/multi_function.cc intern/multi_function_builder.cc @@ -36,7 +35,6 @@ set(SRC intern/multi_function_network_optimization.cc FN_array_spans.hh - FN_attributes_ref.hh FN_cpp_type.hh FN_generic_pointer.hh FN_generic_value_map.hh @@ -63,7 +61,6 @@ blender_add_lib(bf_functions "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(WITH_GTESTS) set(TEST_SRC tests/FN_array_spans_test.cc - tests/FN_attributes_ref_test.cc tests/FN_cpp_type_test.cc tests/FN_generic_vector_array_test.cc tests/FN_multi_function_network_test.cc diff --git a/source/blender/functions/FN_attributes_ref.hh b/source/blender/functions/FN_attributes_ref.hh deleted file mode 100644 index a9236f73549..00000000000 --- a/source/blender/functions/FN_attributes_ref.hh +++ /dev/null @@ -1,341 +0,0 @@ -/* - * 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. - */ - -#pragma once - -/** \file - * \ingroup fn - * - * An AttributesRef references multiple arrays of equal length. Each array has a corresponding name - * and index. - */ - -#include - -#include "FN_spans.hh" - -#include "BLI_linear_allocator.hh" -#include "BLI_map.hh" -#include "BLI_utility_mixins.hh" -#include "BLI_vector_set.hh" - -namespace blender::fn { - -class AttributesInfo; - -class AttributesInfoBuilder : NonCopyable, NonMovable { - private: - LinearAllocator<> allocator_; - VectorSet names_; - Vector types_; - Vector defaults_; - - friend AttributesInfo; - - public: - AttributesInfoBuilder() = default; - ~AttributesInfoBuilder(); - - template bool add(StringRef name, const T &default_value) - { - return this->add(name, CPPType::get(), static_cast(&default_value)); - } - - bool add(StringRef name, const CPPType &type, const void *default_value = nullptr); -}; - -/** - * Stores which attributes are in an AttributesRef. Every attribute has a unique index, a unique - * name, a type and a default value. - */ -class AttributesInfo : NonCopyable, NonMovable { - private: - LinearAllocator<> allocator_; - Map index_by_name_; - Vector name_by_index_; - Vector type_by_index_; - Vector defaults_; - - public: - AttributesInfo() = default; - AttributesInfo(const AttributesInfoBuilder &builder); - ~AttributesInfo(); - - int size() const - { - return name_by_index_.size(); - } - - IndexRange index_range() const - { - return name_by_index_.index_range(); - } - - StringRefNull name_of(int index) const - { - return name_by_index_[index]; - } - - int index_of(StringRef name) const - { - return index_by_name_.lookup_as(name); - } - - const void *default_of(int index) const - { - return defaults_[index]; - } - - const void *default_of(StringRef name) const - { - return this->default_of(this->index_of(name)); - } - - template const T &default_of(int index) const - { - BLI_assert(type_by_index_[index]->is()); - return *static_cast(defaults_[index]); - } - - template const T &default_of(StringRef name) const - { - return this->default_of(this->index_of(name)); - } - - const CPPType &type_of(int index) const - { - return *type_by_index_[index]; - } - - const CPPType &type_of(StringRef name) const - { - return this->type_of(this->index_of(name)); - } - - bool has_attribute(StringRef name, const CPPType &type) const - { - return this->try_index_of(name, type) >= 0; - } - - int try_index_of(StringRef name) const - { - return index_by_name_.lookup_default_as(name, -1); - } - - int try_index_of(StringRef name, const CPPType &type) const - { - int index = this->try_index_of(name); - if (index == -1) { - return -1; - } - else if (this->type_of(index) == type) { - return index; - } - else { - return -1; - } - } -}; - -/** - * References multiple arrays that match the description of an AttributesInfo instance. This class - * is supposed to be relatively cheap to copy. It does not own any of the arrays itself. - */ -class MutableAttributesRef { - private: - const AttributesInfo *info_; - Span buffers_; - IndexRange range_; - - friend class AttributesRef; - - public: - MutableAttributesRef(const AttributesInfo &info, Span buffers, int64_t size) - : MutableAttributesRef(info, buffers, IndexRange(size)) - { - } - - MutableAttributesRef(const AttributesInfo &info, Span buffers, IndexRange range) - : info_(&info), buffers_(buffers), range_(range) - { - } - - int64_t size() const - { - return range_.size(); - } - - IndexRange index_range() const - { - return IndexRange(this->size()); - } - - const AttributesInfo &info() const - { - return *info_; - } - - GMutableSpan get(int index) const - { - const CPPType &type = info_->type_of(index); - void *ptr = POINTER_OFFSET(buffers_[index], type.size() * range_.start()); - return GMutableSpan(type, ptr, range_.size()); - } - - GMutableSpan get(StringRef name) const - { - return this->get(info_->index_of(name)); - } - - template MutableSpan get(int index) const - { - BLI_assert(info_->type_of(index).is()); - return MutableSpan(static_cast(buffers_[index]) + range_.start(), range_.size()); - } - - template MutableSpan get(StringRef name) const - { - return this->get(info_->index_of(name)); - } - - std::optional try_get(StringRef name, const CPPType &type) const - { - int index = info_->try_index_of(name, type); - if (index == -1) { - return {}; - } - else { - return this->get(index); - } - } - - template std::optional> try_get(StringRef name) const - { - int index = info_->try_index_of(name); - if (index == -1) { - return {}; - } - else if (info_->type_of(index).is()) { - return this->get(index); - } - else { - return {}; - } - } - - MutableAttributesRef slice(IndexRange range) const - { - return this->slice(range.start(), range.size()); - } - - MutableAttributesRef slice(int64_t start, int64_t size) const - { - return MutableAttributesRef(*info_, buffers_, range_.slice(start, size)); - } -}; - -class AttributesRef { - private: - const AttributesInfo *info_; - Span buffers_; - IndexRange range_; - - public: - AttributesRef(const AttributesInfo &info, Span buffers, int64_t size) - : AttributesRef(info, buffers, IndexRange(size)) - { - } - - AttributesRef(const AttributesInfo &info, Span buffers, IndexRange range) - : info_(&info), buffers_(buffers), range_(range) - { - } - - AttributesRef(MutableAttributesRef attributes) - : info_(attributes.info_), buffers_(attributes.buffers_), range_(attributes.range_) - { - } - - int64_t size() const - { - return range_.size(); - } - - const AttributesInfo &info() const - { - return *info_; - } - - GSpan get(int index) const - { - const CPPType &type = info_->type_of(index); - const void *ptr = POINTER_OFFSET(buffers_[index], type.size() * range_.start()); - return GSpan(type, ptr, range_.size()); - } - - GSpan get(StringRef name) const - { - return this->get(info_->index_of(name)); - } - - template Span get(int index) const - { - BLI_assert(info_->type_of(index).is()); - return Span(static_cast(buffers_[index]) + range_.start(), range_.size()); - } - - template Span get(StringRef name) const - { - return this->get(info_->index_of(name)); - } - - std::optional try_get(StringRef name, const CPPType &type) const - { - int64_t index = info_->try_index_of(name, type); - if (index == -1) { - return {}; - } - else { - return this->get(index); - } - } - - template std::optional> try_get(StringRef name) const - { - int index = info_->try_index_of(name); - if (index == -1) { - return {}; - } - else if (info_->type_of(index).is()) { - return this->get(index); - } - else { - return {}; - } - } - - AttributesRef slice(IndexRange range) const - { - return this->slice(range.start(), range.size()); - } - - AttributesRef slice(int64_t start, int64_t size) const - { - return AttributesRef(*info_, buffers_, range_.slice(start, size)); - } -}; - -} // namespace blender::fn diff --git a/source/blender/functions/intern/attributes_ref.cc b/source/blender/functions/intern/attributes_ref.cc deleted file mode 100644 index 9f1e7fa65e5..00000000000 --- a/source/blender/functions/intern/attributes_ref.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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. - */ - -#include "FN_attributes_ref.hh" - -namespace blender::fn { - -AttributesInfoBuilder::~AttributesInfoBuilder() -{ - for (int i : defaults_.index_range()) { - types_[i]->destruct(defaults_[i]); - } -} - -bool AttributesInfoBuilder::add(StringRef name, const CPPType &type, const void *default_value) -{ - if (name.size() == 0) { - std::cout << "Warning: Tried to add an attribute with empty name.\n"; - return false; - } - if (names_.add_as(name)) { - types_.append(&type); - - if (default_value == nullptr) { - default_value = type.default_value(); - } - void *dst = allocator_.allocate(type.size(), type.alignment()); - type.copy_to_uninitialized(default_value, dst); - defaults_.append(dst); - return true; - } - - const CPPType &stored_type = *types_[names_.index_of_as(name)]; - if (stored_type != type) { - std::cout << "Warning: Tried to add an attribute twice with different types (" << name << ": " - << stored_type.name() << ", " << type.name() << ").\n"; - } - return false; -} - -AttributesInfo::AttributesInfo(const AttributesInfoBuilder &builder) -{ - for (int i : builder.types_.index_range()) { - StringRefNull name = allocator_.copy_string(builder.names_[i]); - const CPPType &type = *builder.types_[i]; - const void *default_value = builder.defaults_[i]; - - index_by_name_.add_new(name, i); - name_by_index_.append(name); - type_by_index_.append(&type); - - void *dst = allocator_.allocate(type.size(), type.alignment()); - type.copy_to_uninitialized(default_value, dst); - defaults_.append(dst); - } -} - -AttributesInfo::~AttributesInfo() -{ - for (int i : defaults_.index_range()) { - type_by_index_[i]->destruct(defaults_[i]); - } -} - -} // namespace blender::fn diff --git a/source/blender/functions/tests/FN_attributes_ref_test.cc b/source/blender/functions/tests/FN_attributes_ref_test.cc deleted file mode 100644 index 3a5e4743c1e..00000000000 --- a/source/blender/functions/tests/FN_attributes_ref_test.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* Apache License, Version 2.0 */ - -#include "BLI_float3.hh" -#include "FN_attributes_ref.hh" - -#include "testing/testing.h" - -namespace blender::fn::tests { - -TEST(attributes_info, BuildEmpty) -{ - AttributesInfoBuilder info_builder; - AttributesInfo info{info_builder}; - - EXPECT_EQ(info.size(), 0); -} - -TEST(attributes_info, AddSameNameTwice) -{ - AttributesInfoBuilder info_builder; - info_builder.add("A", 4); - info_builder.add("A", 5); - AttributesInfo info{info_builder}; - EXPECT_EQ(info.size(), 1); - EXPECT_TRUE(info.has_attribute("A", CPPType::get())); - EXPECT_FALSE(info.has_attribute("B", CPPType::get())); - EXPECT_FALSE(info.has_attribute("A", CPPType::get())); - EXPECT_EQ(info.default_of("A"), 4); - EXPECT_EQ(info.name_of(0), "A"); - EXPECT_EQ(info.index_range().start(), 0); - EXPECT_EQ(info.index_range().one_after_last(), 1); -} - -TEST(attributes_info, BuildWithDefaultString) -{ - AttributesInfoBuilder info_builder; - info_builder.add("A", CPPType::get()); - AttributesInfo info{info_builder}; - EXPECT_EQ(info.default_of("A"), ""); -} - -TEST(attributes_info, BuildWithGivenDefault) -{ - AttributesInfoBuilder info_builder; - info_builder.add("A", "hello world"); - AttributesInfo info{info_builder}; - const void *default_value = info.default_of("A"); - EXPECT_EQ(*(const std::string *)default_value, "hello world"); - EXPECT_EQ(info.type_of("A"), CPPType::get()); -} - -TEST(mutable_attributes_ref, ComplexTest) -{ - AttributesInfoBuilder info_builder; - info_builder.add("Position", {0, 0, 10}); - info_builder.add("ID", 0); - info_builder.add("Size", 0.5f); - info_builder.add("Name", ""); - AttributesInfo info{info_builder}; - - int amount = 5; - Array positions(amount); - Array ids(amount, 0); - Array sizes(amount); - Array names(amount); - - Array buffers = {positions.data(), ids.data(), sizes.data(), names.data()}; - MutableAttributesRef attributes{info, buffers, IndexRange(1, 3)}; - EXPECT_EQ(attributes.size(), 3); - EXPECT_EQ(attributes.info().size(), 4); - EXPECT_EQ(attributes.get("Position").data(), positions.data() + 1); - EXPECT_EQ(attributes.get("ID").data(), ids.data() + 1); - EXPECT_EQ(attributes.get("Size").data(), sizes.data() + 1); - EXPECT_EQ(attributes.get("Name").data(), names.data() + 1); - - EXPECT_EQ(attributes.get("ID").size(), 3); - EXPECT_EQ(attributes.get("ID").size(), 3); - - EXPECT_EQ(ids[2], 0); - MutableSpan ids_span = attributes.get("ID"); - ids_span[1] = 42; - EXPECT_EQ(ids[2], 42); - - EXPECT_FALSE(attributes.try_get("not existant").has_value()); - EXPECT_FALSE(attributes.try_get("Position").has_value()); - EXPECT_TRUE(attributes.try_get("Position").has_value()); - EXPECT_FALSE(attributes.try_get("not existant", CPPType::get()).has_value()); - EXPECT_FALSE(attributes.try_get("Position", CPPType::get()).has_value()); - EXPECT_TRUE(attributes.try_get("Position", CPPType::get()).has_value()); - - MutableAttributesRef sliced = attributes.slice(IndexRange(1, 2)); - EXPECT_EQ(sliced.size(), 2); - sliced.get("ID")[0] = 100; - EXPECT_EQ(ids[2], 100); -} - -} // namespace blender::fn::tests -- cgit v1.2.3 From ac4d45dbf156f538d2591b5323a042b4a59692e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Sun, 7 Mar 2021 15:39:01 +0100 Subject: Alembic procedural: fix infinite update loop when modifying Object level properties --- intern/cycles/render/alembic.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index 627ffe2318a..60e24e7b375 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -1358,11 +1358,16 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress) } bool need_shader_updates = false; + bool need_data_updates = false; - /* Check for changes in shaders (newly requested attributes). */ foreach (Node *object_node, objects) { AlembicObject *object = static_cast(object_node); + if (object->is_modified()) { + need_data_updates = true; + } + + /* Check for changes in shaders (e.g. newly requested attributes). */ foreach (Node *shader_node, object->get_used_shaders()) { Shader *shader = static_cast(shader_node); @@ -1373,7 +1378,7 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress) } } - if (!is_modified() && !need_shader_updates) { + if (!is_modified() && !need_shader_updates && !need_data_updates) { return; } -- cgit v1.2.3 From 00f218602d52defee624e9853b03431d732649fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Sun, 7 Mar 2021 16:17:59 +0100 Subject: Alembic procedural: fix missing update when only the transforms change The missing update has two sources: The TimeSampling used for looking up transformations in the cache was uninitialized. To fix this, simply use the TimeSampling from the last transformation in the hierarchy (that is the object's parent), which should also contain the time information for all of its parents. The objects are not tagged for update when their trasformations change. --- intern/cycles/render/alembic.cpp | 47 +++++++++++++++++++++++++++++----------- intern/cycles/render/alembic.h | 8 ++++++- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index 60e24e7b375..9c73fb05405 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -1017,6 +1017,10 @@ void AlembicObject::setup_transform_cache(float scale) cached_data.transforms.clear(); cached_data.transforms.invalidate_last_loaded_time(); + if (xform_time_sampling) { + cached_data.transforms.set_time_sampling(*xform_time_sampling); + } + if (xform_samples.size() == 0) { Transform tfm = transform_scale(make_float3(scale)); cached_data.transforms.add_data(tfm, 0.0); @@ -1476,7 +1480,7 @@ void AlembicProcedural::load_objects(Progress &progress) IObject root = archive.getTop(); for (size_t i = 0; i < root.getNumChildren(); ++i) { - walk_hierarchy(root, root.getChildHeader(i), nullptr, object_map, progress); + walk_hierarchy(root, root.getChildHeader(i), {}, object_map, progress); } /* Create nodes in the scene. */ @@ -1541,6 +1545,10 @@ void AlembicProcedural::read_mesh(Scene *scene, Object *object = abc_object->get_object(); cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket()); + if (object->is_modified()) { + object->tag_update(scene_); + } + cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket()); cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_shader_socket()); @@ -1636,6 +1644,10 @@ void AlembicProcedural::read_subd(Scene *scene, Object *object = abc_object->get_object(); cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket()); + if (object->is_modified()) { + object->tag_update(scene_); + } + cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket()); /* cached_data.shader is also used for subd_shader */ @@ -1716,6 +1728,10 @@ void AlembicProcedural::read_curves(Scene *scene, Object *object = abc_object->get_object(); cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket()); + if (object->is_modified()) { + object->tag_update(scene_); + } + cached_data.curve_keys.copy_to_socket(frame_time, hair, hair->get_curve_keys_socket()); cached_data.curve_radius.copy_to_socket(frame_time, hair, hair->get_curve_radius_socket()); @@ -1746,7 +1762,7 @@ void AlembicProcedural::read_curves(Scene *scene, void AlembicProcedural::walk_hierarchy( IObject parent, const ObjectHeader &header, - MatrixSampleMap *xform_samples, + MatrixSamplesData matrix_samples_data, const unordered_map &object_map, Progress &progress) { @@ -1768,7 +1784,7 @@ void AlembicProcedural::walk_hierarchy( MatrixSampleMap local_xform_samples; MatrixSampleMap *temp_xform_samples = nullptr; - if (xform_samples == nullptr) { + if (matrix_samples_data.samples == nullptr) { /* If there is no parent transforms, fill the map directly. */ temp_xform_samples = &concatenated_xform_samples; } @@ -1783,11 +1799,13 @@ void AlembicProcedural::walk_hierarchy( temp_xform_samples->insert({sample_time, sample.getMatrix()}); } - if (xform_samples != nullptr) { - concatenate_xform_samples(*xform_samples, local_xform_samples, concatenated_xform_samples); + if (matrix_samples_data.samples != nullptr) { + concatenate_xform_samples( + *matrix_samples_data.samples, local_xform_samples, concatenated_xform_samples); } - xform_samples = &concatenated_xform_samples; + matrix_samples_data.samples = &concatenated_xform_samples; + matrix_samples_data.time_sampling = ts; } next_object = xform; @@ -1803,8 +1821,9 @@ void AlembicProcedural::walk_hierarchy( abc_object->iobject = subd; abc_object->schema_type = AlembicObject::SUBD; - if (xform_samples) { - abc_object->xform_samples = *xform_samples; + if (matrix_samples_data.samples) { + abc_object->xform_samples = *matrix_samples_data.samples; + abc_object->xform_time_sampling = matrix_samples_data.time_sampling; } } @@ -1821,8 +1840,9 @@ void AlembicProcedural::walk_hierarchy( abc_object->iobject = mesh; abc_object->schema_type = AlembicObject::POLY_MESH; - if (xform_samples) { - abc_object->xform_samples = *xform_samples; + if (matrix_samples_data.samples) { + abc_object->xform_samples = *matrix_samples_data.samples; + abc_object->xform_time_sampling = matrix_samples_data.time_sampling; } } @@ -1839,8 +1859,9 @@ void AlembicProcedural::walk_hierarchy( abc_object->iobject = curves; abc_object->schema_type = AlembicObject::CURVES; - if (xform_samples) { - abc_object->xform_samples = *xform_samples; + if (matrix_samples_data.samples) { + abc_object->xform_samples = *matrix_samples_data.samples; + abc_object->xform_time_sampling = matrix_samples_data.time_sampling; } } @@ -1857,7 +1878,7 @@ void AlembicProcedural::walk_hierarchy( if (next_object.valid()) { for (size_t i = 0; i < next_object.getNumChildren(); ++i) { walk_hierarchy( - next_object, next_object.getChildHeader(i), xform_samples, object_map, progress); + next_object, next_object.getChildHeader(i), matrix_samples_data, object_map, progress); } } } diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index b986f46bc8a..a00343c5225 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -38,6 +38,11 @@ class Shader; using MatrixSampleMap = std::map; +struct MatrixSamplesData { + MatrixSampleMap *samples = nullptr; + Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling; +}; + /* Helpers to detect if some type is a ccl::array. */ template struct is_array : public std::false_type { }; @@ -274,6 +279,7 @@ class AlembicObject : public Node { bool need_shader_update = true; + Alembic::AbcCoreAbstract::TimeSamplingPtr xform_time_sampling; MatrixSampleMap xform_samples; Alembic::AbcGeom::IObject iobject; @@ -384,7 +390,7 @@ class AlembicProcedural : public Procedural { * way for each IObject. */ void walk_hierarchy(Alembic::AbcGeom::IObject parent, const Alembic::AbcGeom::ObjectHeader &ohead, - MatrixSampleMap *xform_samples, + MatrixSamplesData matrix_samples_data, const unordered_map &object_map, Progress &progress); -- cgit v1.2.3 From 9c8382e6186b519429e4dee8870265351810bc99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Sun, 7 Mar 2021 17:22:00 +0100 Subject: Cleanup: do not pass class member to class methods --- intern/cycles/render/alembic.cpp | 27 ++++++++++++--------------- intern/cycles/render/alembic.h | 9 +++------ 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index 9c73fb05405..468ebf7140f 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -1420,13 +1420,13 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress) } if (object->schema_type == AlembicObject::POLY_MESH) { - read_mesh(scene, object, frame_time, progress); + read_mesh(object, frame_time, progress); } else if (object->schema_type == AlembicObject::CURVES) { - read_curves(scene, object, frame_time, progress); + read_curves(object, frame_time, progress); } else if (object->schema_type == AlembicObject::SUBD) { - read_subd(scene, object, frame_time, progress); + read_subd(object, frame_time, progress); } object->clear_modified(); @@ -1515,8 +1515,7 @@ void AlembicProcedural::load_objects(Progress &progress) } } -void AlembicProcedural::read_mesh(Scene *scene, - AlembicObject *abc_object, +void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame_time, Progress &progress) { @@ -1579,7 +1578,7 @@ void AlembicProcedural::read_mesh(Scene *scene, /* we don't yet support arbitrary attributes, for now add vertex * coordinates as generated coordinates if requested */ - if (mesh->need_attribute(scene, ATTR_STD_GENERATED)) { + if (mesh->need_attribute(scene_, ATTR_STD_GENERATED)) { Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); memcpy( attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size()); @@ -1587,12 +1586,11 @@ void AlembicProcedural::read_mesh(Scene *scene, if (mesh->is_modified()) { bool need_rebuild = mesh->triangles_is_modified(); - mesh->tag_update(scene, need_rebuild); + mesh->tag_update(scene_, need_rebuild); } } -void AlembicProcedural::read_subd(Scene *scene, - AlembicObject *abc_object, +void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame_time, Progress &progress) { @@ -1683,7 +1681,7 @@ void AlembicProcedural::read_subd(Scene *scene, /* we don't yet support arbitrary attributes, for now add vertex * coordinates as generated coordinates if requested */ - if (mesh->need_attribute(scene, ATTR_STD_GENERATED)) { + if (mesh->need_attribute(scene_, ATTR_STD_GENERATED)) { Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); memcpy( attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size()); @@ -1697,12 +1695,11 @@ void AlembicProcedural::read_subd(Scene *scene, (mesh->subd_start_corner_is_modified()) || (mesh->subd_face_corners_is_modified()); - mesh->tag_update(scene, need_rebuild); + mesh->tag_update(scene_, need_rebuild); } } -void AlembicProcedural::read_curves(Scene *scene, - AlembicObject *abc_object, +void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t frame_time, Progress &progress) { @@ -1746,7 +1743,7 @@ void AlembicProcedural::read_curves(Scene *scene, /* we don't yet support arbitrary attributes, for now add first keys as generated coordinates if * requested */ - if (hair->need_attribute(scene, ATTR_STD_GENERATED)) { + if (hair->need_attribute(scene_, ATTR_STD_GENERATED)) { Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED); float3 *generated = attr_generated->data_float3(); @@ -1756,7 +1753,7 @@ void AlembicProcedural::read_curves(Scene *scene, } const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified()); - hair->tag_update(scene, rebuild); + hair->tag_update(scene_, rebuild); } void AlembicProcedural::walk_hierarchy( diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index a00343c5225..587843201ce 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -396,22 +396,19 @@ class AlembicProcedural : public Procedural { /* Read the data for an IPolyMesh at the specified frame_time. Creates corresponding Geometry and * Object Nodes in the Cycles scene if none exist yet. */ - void read_mesh(Scene *scene, - AlembicObject *abc_object, + void read_mesh(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time, Progress &progress); /* Read the data for an ICurves at the specified frame_time. Creates corresponding Geometry and * Object Nodes in the Cycles scene if none exist yet. */ - void read_curves(Scene *scene, - AlembicObject *abc_object, + void read_curves(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time, Progress &progress); /* Read the data for an ISubD at the specified frame_time. Creates corresponding Geometry and * Object Nodes in the Cycles scene if none exist yet. */ - void read_subd(Scene *scene, - AlembicObject *abc_object, + void read_subd(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time, Progress &progress); }; -- cgit v1.2.3 From 74979459cbbe4ec5bf7014a511775b5274b20060 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sun, 7 Mar 2021 17:51:56 +0100 Subject: Geometry Nodes: simplify allocating dynamically sized buffer on stack --- .../blender/blenkernel/intern/attribute_access.cc | 13 ++----- source/blender/blenlib/BLI_memory_utils.hh | 45 ++++++++++++++++++++++ source/blender/functions/FN_cpp_type.hh | 6 +++ 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 61dc0903cc8..b04af5327ca 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -438,9 +438,6 @@ class ConvertedReadAttribute final : public ReadAttribute { ReadAttributePtr base_attribute_; const nodes::DataTypeConversions &conversions_; - static constexpr int MaxValueSize = 64; - static constexpr int MaxValueAlignment = 64; - public: ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type) : ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()), @@ -449,17 +446,13 @@ class ConvertedReadAttribute final : public ReadAttribute { base_attribute_(std::move(base_attribute)), conversions_(nodes::get_implicit_type_conversions()) { - if (from_type_.size() > MaxValueSize || from_type_.alignment() > MaxValueAlignment) { - throw std::runtime_error( - "type is larger than expected, the buffer size has to be increased"); - } } void get_internal(const int64_t index, void *r_value) const override { - AlignedBuffer buffer; - base_attribute_->get(index, buffer.ptr()); - conversions_.convert(from_type_, to_type_, buffer.ptr(), r_value); + BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); + base_attribute_->get(index, buffer); + conversions_.convert(from_type_, to_type_, buffer, r_value); } }; diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index b3b6855089e..bdbbda9f0c7 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -28,6 +28,7 @@ #include #include "BLI_utildefines.h" +#include "MEM_guardedalloc.h" namespace blender { @@ -402,6 +403,50 @@ template class TypedBuffer { } }; +/* A dynamic stack buffer can be used instead of #alloca when wants to allocate a dynamic amount of + * memory on the stack. Using this class has some advantages: + * - It falls back to heap allocation, when the size is too large. + * - It can be used in loops safely. + * - If the buffer is heap allocated, it is free automatically in the destructor. + */ +template +class alignas(ReservedAlignment) DynamicStackBuffer { + private: + /* Don't create an empty array. This causes problems with some compilers. */ + char reserved_buffer_[(ReservedSize > 0) ? ReservedSize : 1]; + void *buffer_; + + public: + DynamicStackBuffer(const int64_t size, const int64_t alignment) + { + BLI_assert(size >= 0); + BLI_assert(alignment >= 0); + if (size <= ReservedSize && alignment <= ReservedAlignment) { + buffer_ = reserved_buffer_; + } + else { + buffer_ = MEM_mallocN_aligned(size, alignment, __func__); + } + } + ~DynamicStackBuffer() + { + if (buffer_ != reserved_buffer_) { + MEM_freeN(buffer_); + } + } + + /* Don't allow any copying or moving of this type. */ + DynamicStackBuffer(const DynamicStackBuffer &other) = delete; + DynamicStackBuffer(DynamicStackBuffer &&other) = delete; + DynamicStackBuffer &operator=(const DynamicStackBuffer &other) = delete; + DynamicStackBuffer &operator=(DynamicStackBuffer &&other) = delete; + + void *buffer() const + { + return buffer_; + } +}; + /** * This can be used by container constructors. A parameter of this type should be used to indicate * that the constructor does not construct the elements. diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh index a854e63288d..b8ac97d6dbd 100644 --- a/source/blender/functions/FN_cpp_type.hh +++ b/source/blender/functions/FN_cpp_type.hh @@ -935,3 +935,9 @@ inline std::unique_ptr create_cpp_type(StringRef name, const T &d { \ return blender::fn::CPPType::get(); \ } + +/* Utility for allocating an uninitialized buffer for a single value of the given #CPPType. */ +#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name) \ + blender::DynamicStackBuffer<64, 64> stack_buffer_for_##variable_name(type.size(), \ + type.alignment()); \ + void *variable_name = stack_buffer_for_##variable_name.buffer(); -- cgit v1.2.3 From 239a7d93ae04a7b9adb802dc81e5636c5735f53d Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Sun, 7 Mar 2021 18:05:25 +0100 Subject: Cleanup: fix compiler warning --- source/blender/nodes/intern/derived_node_tree.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index c20d6fa943e..c5f267470fd 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -35,7 +35,7 @@ DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *paren bNodeTree &btree, NodeTreeRefMap &node_tree_refs) { - DTreeContext &context = *allocator_.construct(); + DTreeContext &context = *allocator_.construct().release(); context.parent_context_ = parent_context; context.parent_node_ = parent_node; context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree); -- cgit v1.2.3 From 7a34bd7c2886dfc812345c0b1649d63a9ee4666f Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Sun, 7 Mar 2021 17:03:24 -0500 Subject: Fix modernize-raw-string-literal complaints from clang-tidy. --- .../blender/blenkernel/intern/cryptomatte_test.cc | 30 ++++++++++------------ .../blender/blenlib/tests/BLI_delaunay_2d_test.cc | 28 ++++++++++---------- source/blender/blenlib/tests/BLI_string_test.cc | 16 ++++++------ .../blender/blenlib/tests/BLI_string_utf8_test.cc | 4 +-- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/source/blender/blenkernel/intern/cryptomatte_test.cc b/source/blender/blenkernel/intern/cryptomatte_test.cc index 5481b97913c..22abd1a4d56 100644 --- a/source/blender/blenkernel/intern/cryptomatte_test.cc +++ b/source/blender/blenkernel/intern/cryptomatte_test.cc @@ -55,17 +55,17 @@ TEST(cryptomatte, layer) ASSERT_EQ("{}", layer.manifest()); layer.add_hash("Object", 123); - ASSERT_EQ("{\"Object\":\"0000007b\"}", layer.manifest()); + ASSERT_EQ(R"({"Object":"0000007b"})", layer.manifest()); layer.add_hash("Object2", 123245678); - ASSERT_EQ("{\"Object\":\"0000007b\",\"Object2\":\"0758946e\"}", layer.manifest()); + ASSERT_EQ(R"({"Object":"0000007b","Object2":"0758946e"})", layer.manifest()); } TEST(cryptomatte, layer_quoted) { blender::bke::cryptomatte::CryptomatteLayer layer; - layer.add_hash("\"Object\"", 123); - ASSERT_EQ("{\"\\\"Object\\\"\":\"0000007b\"}", layer.manifest()); + layer.add_hash(R"("Object")", 123); + ASSERT_EQ(R"({"\"Object\"":"0000007b"})", layer.manifest()); } static void test_cryptomatte_manifest(std::string expected, std::string manifest) @@ -77,17 +77,15 @@ static void test_cryptomatte_manifest(std::string expected, std::string manifest TEST(cryptomatte, layer_from_manifest) { test_cryptomatte_manifest("{}", "{}"); - test_cryptomatte_manifest("{\"Object\":\"12345678\"}", "{\"Object\": \"12345678\"}"); - test_cryptomatte_manifest("{\"Object\":\"12345678\",\"Object2\":\"87654321\"}", - "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}"); + test_cryptomatte_manifest(R"({"Object":"12345678"})", R"({"Object": "12345678"})"); + test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321"})", + R"({"Object":"12345678","Object2":"87654321"})"); + test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321"})", + R"( { "Object" : "12345678" , "Object2" : "87654321" } )"); + test_cryptomatte_manifest(R"({"Object\"01\"":"12345678"})", R"({"Object\"01\"": "12345678"})"); test_cryptomatte_manifest( - "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}", - " { \"Object\" : \"12345678\" , \"Object2\" : \"87654321\" } "); - test_cryptomatte_manifest("{\"Object\\\"01\\\"\":\"12345678\"}", - "{\"Object\\\"01\\\"\": \"12345678\"}"); - test_cryptomatte_manifest( - "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\",\"Object2\":\"87654321\"}", - "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\", \"Object2\":\"87654321\"}"); + R"({"Object\"01\"":"12345678","Object":"12345678","Object2":"87654321"})", + R"({"Object\"01\"":"12345678","Object":"12345678", "Object2":"87654321"})"); } TEST(cryptomatte, extract_layer_hash_from_metadata_key) @@ -155,10 +153,10 @@ TEST(cryptomatte, session_from_stamp_data) MEM_callocN(sizeof(RenderResult), __func__)); BKE_render_result_stamp_data(render_result, "cryptomatte/qwerty/name", "layer1"); BKE_render_result_stamp_data( - render_result, "cryptomatte/qwerty/manifest", "{\"Object\":\"12345678\"}"); + render_result, "cryptomatte/qwerty/manifest", R"({"Object":"12345678"})"); BKE_render_result_stamp_data(render_result, "cryptomatte/uiop/name", "layer2"); BKE_render_result_stamp_data( - render_result, "cryptomatte/uiop/manifest", "{\"Object2\":\"87654321\"}"); + render_result, "cryptomatte/uiop/manifest", R"({"Object2":"87654321"})"); CryptomatteSession *session = BKE_cryptomatte_init_from_render_result(render_result); EXPECT_NE(session, nullptr); RE_FreeRenderResult(render_result); diff --git a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc index d00e8bf55fd..aa3e183a382 100644 --- a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc +++ b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc @@ -333,37 +333,37 @@ void graph_draw(const std::string &label, } f << "
" << label << "
\n
\n" - << "n"; + << R"(n)"; for (const std::pair &e : edges) { const vec2 &uco = verts[e.first]; const vec2 &vco = verts[e.second]; int strokew = thin_line; - f << "\n"; + f << R"(\n)"; f << " [" << e.first << "][" << e.second << "]\n"; f << "\n"; if (draw_edge_labels) { - f << ""; + f << R"()"; f << "[" << e.first << "][" << e.second << "]\n"; } } int i = 0; for (const vec2 &vco : verts) { - f << "\n"; + f << R"(\n)"; f << " [" << i << "]" << vco << "\n"; f << "\n"; if (draw_vert_labels) { - f << "[" << i << "]\n"; + f << R"([)" << i << "]\n"; } ++i; } diff --git a/source/blender/blenlib/tests/BLI_string_test.cc b/source/blender/blenlib/tests/BLI_string_test.cc index 88cecaa5fee..3f7db261ac0 100644 --- a/source/blender/blenlib/tests/BLI_string_test.cc +++ b/source/blender/blenlib/tests/BLI_string_test.cc @@ -845,12 +845,12 @@ TEST_F(StringEscape, Simple) {"\\A", "\\\\A"}, {"A\\B", "A\\\\B"}, {"?", "?"}, - {"\"\\", "\\\"\\\\"}, - {"\\\"", "\\\\\\\""}, - {"\"\\\"", "\\\"\\\\\\\""}, + {R"("\)", R"(\"\\)"}, + {R"(\")", R"(\\\")"}, + {R"("\")", R"(\"\\\")"}, - {"\"\"\"", "\\\"\\\"\\\""}, - {"\\\\\\", "\\\\\\\\\\\\"}, + {R"(""")", R"(\"\"\")"}, + {R"(\\\)", R"(\\\\\\)"}, }; testEscapeWords(equal); @@ -868,9 +868,9 @@ TEST_F(StringEscape, Control) {"\f", "\\f"}, {"A\n", "A\\n"}, {"\nA", "\\nA"}, - {"\n\r\t\a\b\f", "\\n\\r\\t\\a\\b\\f"}, - {"\n_\r_\t_\a_\b_\f", "\\n_\\r_\\t_\\a_\\b_\\f"}, - {"\n\\\r\\\t\\\a\\\b\\\f", "\\n\\\\\\r\\\\\\t\\\\\\a\\\\\\b\\\\\\f"}, + {"\n\r\t\a\b\f", R"(\n\r\t\a\b\f)"}, + {"\n_\r_\t_\a_\b_\f", R"(\n_\r_\t_\a_\b_\f)"}, + {"\n\\\r\\\t\\\a\\\b\\\f", R"(\n\\\r\\\t\\\a\\\b\\\f)"}, }; testEscapeWords(escaped); diff --git a/source/blender/blenlib/tests/BLI_string_utf8_test.cc b/source/blender/blenlib/tests/BLI_string_utf8_test.cc index 1833945b3fd..e93835ba1b6 100644 --- a/source/blender/blenlib/tests/BLI_string_utf8_test.cc +++ b/source/blender/blenlib/tests/BLI_string_utf8_test.cc @@ -92,12 +92,12 @@ const char *utf8_invalid_tests[][3] = { "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\" |", - "3.1.9 \"\" |", "\x40"}, + "3.1.9 \"\" |", R"(@)"}, /* 3.2 Lonely start characters * 3.2.1 All 32 first bytes of 2-byte sequences (0xc0-0xdf), each followed by a space character: */ {"3.2.1 \"\xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc \xcd \xce \xcf " "\xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc \xdd \xde \xdf \" |", - "3.2.1 \" \" |", "\x20"}, + "3.2.1 \" \" |", R"( )"}, /* 3.2.2 All 16 first bytes of 3-byte sequences (0xe0-0xef), each followed by a space character: */ {"3.2.2 \"\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef \" |", "3.2.2 \" \" |", "\x10"}, -- cgit v1.2.3 From 1ba15f1f7f94616d52e8bbd80e22c9e34e45a81e Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Sun, 7 Mar 2021 18:13:19 -0500 Subject: Speedup for usual non-manifold exact boolean case. The commit rB6f63417b500d that made exact boolean work on meshes with holes (like Suzanne) unfortunately dramatically slowed things down on other non-manifold meshes that don't have holes and didn't need the per-triangle insideness test. This adds a hole_tolerant parameter, false by default, that the user can enable to get good results on non-manifold meshes with holes. Using false for this parameter speeds up the time from 90 seconds to 10 seconds on an example with 1.2M triangles. --- release/scripts/addons | 2 +- .../blender/blenkernel/BKE_mesh_boolean_convert.h | 1 + .../blenkernel/intern/mesh_boolean_convert.cc | 7 +- source/blender/blenlib/BLI_mesh_boolean.hh | 2 + source/blender/blenlib/intern/mesh_boolean.cc | 203 ++++++++++++++++----- .../blender/blenlib/tests/BLI_mesh_boolean_test.cc | 79 ++++++-- source/blender/bmesh/tools/bmesh_boolean.cc | 9 +- source/blender/bmesh/tools/bmesh_boolean.h | 2 + source/blender/editors/mesh/editmesh_intersect.c | 13 +- source/blender/editors/sculpt_paint/paint_mask.c | 3 +- source/blender/makesdna/DNA_modifier_types.h | 1 + source/blender/makesrna/intern/rna_modifier.c | 5 + source/blender/modifiers/intern/MOD_boolean.c | 46 +++-- .../nodes/geometry/nodes/node_geo_boolean.cc | 2 +- source/tools | 2 +- 15 files changed, 291 insertions(+), 86 deletions(-) diff --git a/release/scripts/addons b/release/scripts/addons index 24e756c0da8..117faa96af3 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit 24e756c0da89bdbf88dc22163ae3b7ef4f1fbb73 +Subproject commit 117faa96af35685d72e5e01f9a386d163d874133 diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.h b/source/blender/blenkernel/BKE_mesh_boolean_convert.h index be5cbb305fa..a87f2609e46 100644 --- a/source/blender/blenkernel/BKE_mesh_boolean_convert.h +++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.h @@ -31,6 +31,7 @@ Mesh *BKE_mesh_boolean(const Mesh **meshes, const float (*obmats[])[4][4], const int meshes_len, const bool use_self, + const bool hole_tolerant, const int boolean_mode); #ifdef __cplusplus diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index a179d39a9d2..61c9f74531d 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -762,6 +762,7 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim) static Mesh *direct_mesh_boolean(Span meshes, Span obmats, const bool use_self, + const bool hole_tolerant, const BoolOpType boolean_mode) { const int dbg_level = 0; @@ -784,7 +785,8 @@ static Mesh *direct_mesh_boolean(Span meshes, } return static_cast(mim.mesh_poly_offset.size()) - 1; }; - IMesh m_out = boolean_mesh(m_in, boolean_mode, meshes_len, shape_fn, use_self, nullptr, &arena); + IMesh m_out = boolean_mesh( + m_in, boolean_mode, meshes_len, shape_fn, use_self, hole_tolerant, nullptr, &arena); if (dbg_level > 1) { std::cout << m_out; write_obj_mesh(m_out, "m_out"); @@ -808,6 +810,7 @@ Mesh *BKE_mesh_boolean(const Mesh **meshes, const float (*obmats[])[4][4], const int meshes_len, const bool use_self, + const bool hole_tolerant, const int boolean_mode) { const blender::float4x4 **transforms = (const blender::float4x4 **)obmats; @@ -815,6 +818,7 @@ Mesh *BKE_mesh_boolean(const Mesh **meshes, blender::Span(meshes, meshes_len), blender::Span(transforms, meshes_len), use_self, + hole_tolerant, static_cast(boolean_mode)); } @@ -823,6 +827,7 @@ Mesh *BKE_mesh_boolean(const Mesh **UNUSED(meshes), const float (*obmats[])[4][4], const int UNUSED(meshes_len), const bool UNUSED(use_self), + const bool UNUSED(hole_tolerant), const int UNUSED(boolean_mode)) { UNUSED_VARS(obmats); diff --git a/source/blender/blenlib/BLI_mesh_boolean.hh b/source/blender/blenlib/BLI_mesh_boolean.hh index 94b2694893b..a55b2175527 100644 --- a/source/blender/blenlib/BLI_mesh_boolean.hh +++ b/source/blender/blenlib/BLI_mesh_boolean.hh @@ -59,6 +59,7 @@ IMesh boolean_mesh(IMesh &imesh, int nshapes, std::function shape_fn, bool use_self, + bool hole_tolerant, IMesh *imesh_triangulated, IMeshArena *arena); @@ -72,6 +73,7 @@ IMesh boolean_trimesh(IMesh &tm_in, int nshapes, std::function shape_fn, bool use_self, + bool hole_tolerant, IMeshArena *arena); } // namespace blender::meshintersect diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc index 68d7ddec7ef..cd7d0a812e4 100644 --- a/source/blender/blenlib/intern/mesh_boolean.cc +++ b/source/blender/blenlib/intern/mesh_boolean.cc @@ -2484,29 +2484,14 @@ static void test_tri_inside_shapes(const IMesh &tm, } /** - * Use the RayCast method for deciding if a triangle of the - * mesh is supposed to be included or excluded in the boolean result, - * and return the mesh that is the boolean result. - * The reason this is done on a triangle-by-triangle basis is that - * when the input is not PWN, some patches can be both inside and outside - * some shapes (e.g., a plane cutting through Suzanne's open eyes). + * Return a BVH Tree that contains all of the triangles of \a tm. + * The caller must free it. + * (We could possible reuse the BVH tree(s) built in TriOverlaps, + * in the mesh intersect function. A future TODO.) */ -static IMesh raycast_boolean(const IMesh &tm, - BoolOpType op, - int nshapes, - std::function shape_fn, - IMeshArena *arena) +static BVHTree *raycast_tree(const IMesh &tm) { - constexpr int dbg_level = 0; - if (dbg_level > 0) { - std::cout << "RAYCAST_BOOLEAN\n"; - } - IMesh ans; - - /* Build a BVH tree of tm's triangles. - * We could possibly reuse the BVH tree(s) build in TriOverlaps in - * the mesh intersect function. A future TODO. */ - BVHTree *tree = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 8, 8); + BVHTree *tree = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 4, 6); for (int i : tm.face_index_range()) { const Face *f = tm.face(i); float t_cos[9]; @@ -2519,7 +2504,70 @@ static IMesh raycast_boolean(const IMesh &tm, BLI_bvhtree_insert(tree, i, t_cos, 3); } BLI_bvhtree_balance(tree); + return tree; +} + +/** + * Should a face with given shape and given winding array be removed for given boolean op? + * Also return true in *r_do_flip if it retained by normals need to be flipped. + */ +static bool raycast_test_remove(BoolOpType op, Array &winding, int shape, bool *r_do_flip) +{ + constexpr int dbg_level = 0; + /* Find out the "in the output volume" flag for each of the cases of winding[shape] == 0 + * and winding[shape] == 1. If the flags are different, this patch should be in the output. + * Also, if this is a Difference and the shape isn't the first one, need to flip the normals. + */ + winding[shape] = 0; + bool in_output_volume_0 = apply_bool_op(op, winding); + winding[shape] = 1; + bool in_output_volume_1 = apply_bool_op(op, winding); + bool do_remove = in_output_volume_0 == in_output_volume_1; + bool do_flip = !do_remove && op == BoolOpType::Difference && shape != 0; + if (dbg_level > 0) { + std::cout << "winding = "; + for (int i = 0; i < winding.size(); ++i) { + std::cout << winding[i] << " "; + } + std::cout << "\niv0=" << in_output_volume_0 << ", iv1=" << in_output_volume_1 << "\n"; + std::cout << " remove=" << do_remove << ", flip=" << do_flip << "\n"; + } + *r_do_flip = do_flip; + return do_remove; +} +/** Add triangle a flipped version of tri to out_faces. */ +static void raycast_add_flipped(Vector &out_faces, Face &tri, IMeshArena *arena) +{ + + Array flipped_vs = {tri[0], tri[2], tri[1]}; + Array flipped_e_origs = {tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]}; + Array flipped_is_intersect = { + tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]}; + Face *flipped_f = arena->add_face(flipped_vs, tri.orig, flipped_e_origs, flipped_is_intersect); + out_faces.append(flipped_f); +} + +/** + * Use the RayCast method for deciding if a triangle of the + * mesh is supposed to be included or excluded in the boolean result, + * and return the mesh that is the boolean result. + * The reason this is done on a triangle-by-triangle basis is that + * when the input is not PWN, some patches can be both inside and outside + * some shapes (e.g., a plane cutting through Suzanne's open eyes). + */ +static IMesh raycast_tris_boolean(const IMesh &tm, + BoolOpType op, + int nshapes, + std::function shape_fn, + IMeshArena *arena) +{ + constexpr int dbg_level = 0; + if (dbg_level > 0) { + std::cout << "RAYCAST_TRIS_BOOLEAN\n"; + } + IMesh ans; + BVHTree *tree = raycast_tree(tm); Vector out_faces; out_faces.reserve(tm.face_size()); Array in_shape(nshapes, 0); @@ -2541,6 +2589,7 @@ static IMesh raycast_boolean(const IMesh &tm, * gives good results, but when shape is a cutter in a Difference * operation, we want to be pretty sure that the point is inside other_shape. * E.g., T75827. + * Also, when the operation is intersection, we also want high confidence. */ bool need_high_confidence = (op == BoolOpType::Difference && shape != 0) || op == BoolOpType::Intersect; @@ -2551,38 +2600,84 @@ static IMesh raycast_boolean(const IMesh &tm, } winding[other_shape] = inside; } - /* Find out the "in the output volume" flag for each of the cases of winding[shape] == 0 - * and winding[shape] == 1. If the flags are different, this patch should be in the output. - * Also, if this is a Difference and the shape isn't the first one, need to flip the normals. - */ - winding[shape] = 0; - bool in_output_volume_0 = apply_bool_op(op, winding); - winding[shape] = 1; - bool in_output_volume_1 = apply_bool_op(op, winding); - bool do_remove = in_output_volume_0 == in_output_volume_1; - bool do_flip = !do_remove && op == BoolOpType::Difference && shape != 0; - if (dbg_level > 0) { - std::cout << "winding = "; - for (int i = 0; i < nshapes; ++i) { - std::cout << winding[i] << " "; - } - std::cout << "\niv0=" << in_output_volume_0 << ", iv1=" << in_output_volume_1 << "\n"; - std::cout << "result for tri " << t << ": remove=" << do_remove << ", flip=" << do_flip - << "\n"; - } + bool do_flip; + bool do_remove = raycast_test_remove(op, winding, shape, &do_flip); if (!do_remove) { if (!do_flip) { out_faces.append(&tri); } else { - /* We need flipped version of tri. */ - Array flipped_vs = {tri[0], tri[2], tri[1]}; - Array flipped_e_origs = {tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]}; - Array flipped_is_intersect = { - tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]}; - Face *flipped_f = arena->add_face( - flipped_vs, tri.orig, flipped_e_origs, flipped_is_intersect); - out_faces.append(flipped_f); + raycast_add_flipped(out_faces, tri, arena); + } + } + } + BLI_bvhtree_free(tree); + ans.set_faces(out_faces); + return ans; +} + +/* This is (sometimes much faster) version of raycast boolean + * that does it per patch rather than per triangle. + * It may fail in cases where raycast_tri_boolean will succeed, + * but the latter can be very slow on huge meshes. */ +static IMesh raycast_patches_boolean(const IMesh &tm, + BoolOpType op, + int nshapes, + std::function shape_fn, + const PatchesInfo &pinfo, + IMeshArena *arena) +{ + constexpr int dbg_level = 0; + if (dbg_level > 0) { + std::cout << "RAYCAST_PATCHES_BOOLEAN\n"; + } + IMesh ans; + BVHTree *tree = raycast_tree(tm); + Vector out_faces; + out_faces.reserve(tm.face_size()); + Array in_shape(nshapes, 0); + Array winding(nshapes, 0); + for (int p : pinfo.index_range()) { + const Patch &patch = pinfo.patch(p); + /* For test triangle, choose one in the middle of patch list + * as the ones near the beginning may be very near other patches. */ + int test_t_index = patch.tri(patch.tot_tri() / 2); + Face &tri_test = *tm.face(test_t_index); + /* Assume all triangles in a patch are in the same shape. */ + int shape = shape_fn(tri_test.orig); + if (dbg_level > 0) { + std::cout << "process patch " << p << " = " << patch << "\n"; + std::cout << "test tri = " << test_t_index << " = " << &tri_test << "\n"; + std::cout << "shape = " << shape << "\n"; + } + if (shape == -1) { + continue; + } + test_tri_inside_shapes(tm, shape_fn, nshapes, test_t_index, tree, in_shape); + for (int other_shape = 0; other_shape < nshapes; ++other_shape) { + if (other_shape == shape) { + continue; + } + bool need_high_confidence = (op == BoolOpType::Difference && shape != 0) || + op == BoolOpType::Intersect; + bool inside = in_shape[other_shape] >= (need_high_confidence ? 0.5f : 0.1f); + if (dbg_level > 0) { + std::cout << "test point is " << (inside ? "inside" : "outside") << " other_shape " + << other_shape << " val = " << in_shape[other_shape] << "\n"; + } + winding[other_shape] = inside; + } + bool do_flip; + bool do_remove = raycast_test_remove(op, winding, shape, &do_flip); + if (!do_remove) { + for (int t : patch.tris()) { + Face *f = tm.face(t); + if (!do_flip) { + out_faces.append(f); + } + else { + raycast_add_flipped(out_faces, *f, arena); + } } } } @@ -3342,6 +3437,7 @@ IMesh boolean_trimesh(IMesh &tm_in, int nshapes, std::function shape_fn, bool use_self, + bool hole_tolerant, IMeshArena *arena) { constexpr int dbg_level = 0; @@ -3392,7 +3488,13 @@ IMesh boolean_trimesh(IMesh &tm_in, if (dbg_level > 0) { std::cout << "Input is not PWN, using raycast method\n"; } - tm_out = raycast_boolean(tm_si, op, nshapes, shape_fn, arena); + if (hole_tolerant) { + tm_out = raycast_tris_boolean(tm_si, op, nshapes, shape_fn, arena); + } + else { + PatchesInfo pinfo = find_patches(tm_si, tm_si_topo); + tm_out = raycast_patches_boolean(tm_si, op, nshapes, shape_fn, pinfo, arena); + } # ifdef PERFDEBUG double raycast_time = PIL_check_seconds_timer(); std::cout << " raycast_boolean done, time = " << raycast_time - pwn_time << "\n"; @@ -3487,6 +3589,7 @@ IMesh boolean_mesh(IMesh &imesh, int nshapes, std::function shape_fn, bool use_self, + bool hole_tolerant, IMesh *imesh_triangulated, IMeshArena *arena) { @@ -3520,7 +3623,7 @@ IMesh boolean_mesh(IMesh &imesh, if (dbg_level > 1) { write_obj_mesh(*tm_in, "boolean_tm_in"); } - IMesh tm_out = boolean_trimesh(*tm_in, op, nshapes, shape_fn, use_self, arena); + IMesh tm_out = boolean_trimesh(*tm_in, op, nshapes, shape_fn, use_self, hole_tolerant, arena); # ifdef PERFDEBUG double bool_tri_time = PIL_check_seconds_timer(); std::cout << "boolean_trimesh done, time = " << bool_tri_time - tri_time << "\n"; diff --git a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc index e503ef8f264..d759f0c3be4 100644 --- a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc +++ b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc @@ -113,7 +113,7 @@ TEST(boolean_trimesh, Empty) { IMeshArena arena; IMesh in; - IMesh out = boolean_trimesh(in, BoolOpType::None, 1, all_shape_zero, true, &arena); + IMesh out = boolean_trimesh(in, BoolOpType::None, 1, all_shape_zero, true, false, &arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 0); EXPECT_EQ(out.face_size(), 0); @@ -141,7 +141,8 @@ TEST(boolean_trimesh, TetTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::None, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::None, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 11); EXPECT_EQ(out.face_size(), 20); @@ -150,7 +151,8 @@ TEST(boolean_trimesh, TetTetTrimesh) } IMeshBuilder mb2(spec); - IMesh out2 = boolean_trimesh(mb2.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb2.arena); + IMesh out2 = boolean_trimesh( + mb2.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb2.arena); out2.populate_vert(); EXPECT_EQ(out2.vert_size(), 10); EXPECT_EQ(out2.face_size(), 16); @@ -160,7 +162,13 @@ TEST(boolean_trimesh, TetTetTrimesh) IMeshBuilder mb3(spec); IMesh out3 = boolean_trimesh( - mb3.imesh, BoolOpType::Union, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb3.arena); + mb3.imesh, + BoolOpType::Union, + 2, + [](int t) { return t < 4 ? 0 : 1; }, + false, + false, + &mb3.arena); out3.populate_vert(); EXPECT_EQ(out3.vert_size(), 10); EXPECT_EQ(out3.face_size(), 16); @@ -170,7 +178,13 @@ TEST(boolean_trimesh, TetTetTrimesh) IMeshBuilder mb4(spec); IMesh out4 = boolean_trimesh( - mb4.imesh, BoolOpType::Union, 2, [](int t) { return t < 4 ? 0 : 1; }, true, &mb4.arena); + mb4.imesh, + BoolOpType::Union, + 2, + [](int t) { return t < 4 ? 0 : 1; }, + true, + false, + &mb4.arena); out4.populate_vert(); EXPECT_EQ(out4.vert_size(), 10); EXPECT_EQ(out4.face_size(), 16); @@ -180,7 +194,13 @@ TEST(boolean_trimesh, TetTetTrimesh) IMeshBuilder mb5(spec); IMesh out5 = boolean_trimesh( - mb5.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb5.arena); + mb5.imesh, + BoolOpType::Intersect, + 2, + [](int t) { return t < 4 ? 0 : 1; }, + false, + false, + &mb5.arena); out5.populate_vert(); EXPECT_EQ(out5.vert_size(), 4); EXPECT_EQ(out5.face_size(), 4); @@ -195,6 +215,7 @@ TEST(boolean_trimesh, TetTetTrimesh) 2, [](int t) { return t < 4 ? 0 : 1; }, false, + false, &mb6.arena); out6.populate_vert(); EXPECT_EQ(out6.vert_size(), 6); @@ -210,6 +231,7 @@ TEST(boolean_trimesh, TetTetTrimesh) 2, [](int t) { return t < 4 ? 1 : 0; }, false, + false, &mb7.arena); out7.populate_vert(); EXPECT_EQ(out7.vert_size(), 8); @@ -241,7 +263,8 @@ TEST(boolean_trimesh, TetTet2Trimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 10); EXPECT_EQ(out.face_size(), 16); @@ -284,7 +307,8 @@ TEST(boolean_trimesh, CubeTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 14); EXPECT_EQ(out.face_size(), 24); @@ -316,7 +340,13 @@ TEST(boolean_trimesh, BinaryTetTetTrimesh) IMeshBuilder mb(spec); IMesh out = boolean_trimesh( - mb.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb.arena); + mb.imesh, + BoolOpType::Intersect, + 2, + [](int t) { return t < 4 ? 0 : 1; }, + false, + false, + &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 4); EXPECT_EQ(out.face_size(), 4); @@ -347,7 +377,8 @@ TEST(boolean_trimesh, TetTetCoplanarTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 5); EXPECT_EQ(out.face_size(), 6); @@ -378,7 +409,8 @@ TEST(boolean_trimesh, TetInsideTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 4); EXPECT_EQ(out.face_size(), 4); @@ -409,7 +441,8 @@ TEST(boolean_trimesh, TetBesideTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 8); EXPECT_EQ(out.face_size(), 8); @@ -445,7 +478,13 @@ TEST(boolean_trimesh, DegenerateTris) IMeshBuilder mb(spec); IMesh out = boolean_trimesh( - mb.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 5 ? 0 : 1; }, false, &mb.arena); + mb.imesh, + BoolOpType::Intersect, + 2, + [](int t) { return t < 5 ? 0 : 1; }, + false, + false, + &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 4); EXPECT_EQ(out.face_size(), 4); @@ -477,7 +516,7 @@ TEST(boolean_polymesh, TetTet) IMeshBuilder mb(spec); IMesh out = boolean_mesh( - mb.imesh, BoolOpType::None, 1, all_shape_zero, true, nullptr, &mb.arena); + mb.imesh, BoolOpType::None, 1, all_shape_zero, true, false, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 11); EXPECT_EQ(out.face_size(), 13); @@ -492,6 +531,7 @@ TEST(boolean_polymesh, TetTet) 2, [](int t) { return t < 4 ? 0 : 1; }, false, + false, nullptr, &mb2.arena); out2.populate_vert(); @@ -540,7 +580,7 @@ TEST(boolean_polymesh, CubeCube) write_obj_mesh(mb.imesh, "cube_cube_in"); } IMesh out = boolean_mesh( - mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, nullptr, &mb.arena); + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 20); EXPECT_EQ(out.face_size(), 12); @@ -555,6 +595,7 @@ TEST(boolean_polymesh, CubeCube) 2, [](int t) { return t < 6 ? 0 : 1; }, false, + false, nullptr, &mb2.arena); out2.populate_vert(); @@ -597,7 +638,7 @@ TEST(boolean_polymesh, CubeCone) IMeshBuilder mb(spec); IMesh out = boolean_mesh( - mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, nullptr, &mb.arena); + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 14); EXPECT_EQ(out.face_size(), 12); @@ -646,6 +687,7 @@ TEST(boolean_polymesh, CubeCubeCoplanar) 2, [](int t) { return t < 6 ? 0 : 1; }, false, + false, nullptr, &mb.arena); out.populate_vert(); @@ -684,6 +726,7 @@ TEST(boolean_polymesh, TetTeTCoplanarDiff) 2, [](int t) { return t < 4 ? 0 : 1; }, false, + false, nullptr, &mb.arena); out.populate_vert(); @@ -734,6 +777,7 @@ TEST(boolean_polymesh, CubeCubeStep) 2, [](int t) { return t < 6 ? 0 : 1; }, false, + false, nullptr, &mb.arena); out.populate_vert(); @@ -784,6 +828,7 @@ TEST(boolean_polymesh, CubeCyl4) 2, [](int t) { return t < 6 ? 1 : 0; }, false, + false, nullptr, &mb.arena); out.populate_vert(); @@ -855,6 +900,7 @@ TEST(boolean_polymesh, CubeCubesubdivDiff) 2, [](int t) { return t < 16 ? 1 : 0; }, false, + false, nullptr, &mb.arena); out.populate_vert(); @@ -896,6 +942,7 @@ TEST(boolean_polymesh, CubePlane) 2, [](int t) { return t >= 1 ? 0 : 1; }, false, + false, nullptr, &mb.arena); out.populate_vert(); diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc index ea5d66e195c..fec33a04e6f 100644 --- a/source/blender/bmesh/tools/bmesh_boolean.cc +++ b/source/blender/bmesh/tools/bmesh_boolean.cc @@ -354,6 +354,7 @@ static bool bmesh_boolean(BMesh *bm, const bool use_self, const bool use_separate_all, const bool keep_hidden, + const bool hole_tolerant, const BoolOpType boolean_mode) { IMeshArena arena; @@ -389,7 +390,7 @@ static bool bmesh_boolean(BMesh *bm, }; } IMesh m_out = boolean_mesh( - m_in, boolean_mode, nshapes, shape_fn, use_self, &m_triangulated, &arena); + m_in, boolean_mode, nshapes, shape_fn, use_self, hole_tolerant, &m_triangulated, &arena); # ifdef PERF_DEBUG double boolean_time = PIL_check_seconds_timer(); std::cout << "boolean done, time = " << boolean_time - mesh_time << "\n"; @@ -437,6 +438,7 @@ bool BM_mesh_boolean(BMesh *bm, const int nshapes, const bool use_self, const bool keep_hidden, + const bool hole_tolerant, const int boolean_mode) { return blender::meshintersect::bmesh_boolean( @@ -449,6 +451,7 @@ bool BM_mesh_boolean(BMesh *bm, use_self, false, keep_hidden, + hole_tolerant, static_cast(boolean_mode)); } @@ -468,6 +471,7 @@ bool BM_mesh_boolean_knife(BMesh *bm, const int nshapes, const bool use_self, const bool use_separate_all, + const bool hole_tolerant, const bool keep_hidden) { return blender::meshintersect::bmesh_boolean(bm, @@ -479,6 +483,7 @@ bool BM_mesh_boolean_knife(BMesh *bm, use_self, use_separate_all, keep_hidden, + hole_tolerant, blender::meshintersect::BoolOpType::None); } #else @@ -490,6 +495,7 @@ bool BM_mesh_boolean(BMesh *UNUSED(bm), const int UNUSED(nshapes), const bool UNUSED(use_self), const bool UNUSED(keep_hidden), + const bool UNUSED(hole_tolerant), const int UNUSED(boolean_mode)) { UNUSED_VARS(looptris, test_fn); @@ -512,6 +518,7 @@ bool BM_mesh_boolean_knife(BMesh *UNUSED(bm), const int UNUSED(nshapes), const bool UNUSED(use_self), const bool UNUSED(use_separate_all), + const bool UNUSED(hole_tolerant), const bool UNUSED(keep_hidden)) { UNUSED_VARS(looptris, test_fn); diff --git a/source/blender/bmesh/tools/bmesh_boolean.h b/source/blender/bmesh/tools/bmesh_boolean.h index 2cc32e143fc..ed77242e14c 100644 --- a/source/blender/bmesh/tools/bmesh_boolean.h +++ b/source/blender/bmesh/tools/bmesh_boolean.h @@ -32,6 +32,7 @@ bool BM_mesh_boolean(BMesh *bm, const int nshapes, const bool use_self, const bool keep_hidden, + const bool hole_tolerant, const int boolean_mode); bool BM_mesh_boolean_knife(BMesh *bm, @@ -42,6 +43,7 @@ bool BM_mesh_boolean_knife(BMesh *bm, const int nshapes, const bool use_self, const bool use_separate_all, + const bool hole_tolerant, const bool keep_hidden); #ifdef __cplusplus diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index b269a4f0514..0e3cc22d358 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -212,6 +212,7 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op) nshapes, use_self, use_separate_all, + false, true); } else { @@ -375,8 +376,16 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op) } if (use_exact) { - has_isect = BM_mesh_boolean( - em->bm, em->looptris, em->tottri, test_fn, NULL, 2, use_self, true, boolean_operation); + has_isect = BM_mesh_boolean(em->bm, + em->looptris, + em->tottri, + test_fn, + NULL, + 2, + use_self, + true, + false, + boolean_operation); } else { has_isect = BM_mesh_intersect(em->bm, diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 26e2bcc42cf..966f2ace931 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -1292,7 +1292,8 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext) BLI_assert(false); break; } - BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, 2, true, true, boolean_mode); + BM_mesh_boolean( + bm, looptris, tottri, bm_face_isect_pair, NULL, 2, true, true, false, boolean_mode); } MEM_freeN(looptris); diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index dbcb6ce45ea..368b1f93e4a 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -904,6 +904,7 @@ enum { eBooleanModifierFlag_Self = (1 << 0), eBooleanModifierFlag_Object = (1 << 1), eBooleanModifierFlag_Collection = (1 << 2), + eBooleanModifierFlag_HoleTolerant = (1 << 3), }; /* bm_flag only used when G_DEBUG. */ diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 5008240ea33..55d81bd3155 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -2789,6 +2789,11 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Self", "Allow self-intersection in operands"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "hole_tolerant", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", eBooleanModifierFlag_HoleTolerant); + RNA_def_property_ui_text(prop, "Hole tolerant", "Better results when there are holes (slower)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + /* BMesh debugging options, only used when G_DEBUG is set */ /* BMesh intersection options */ diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 070ba3a1bcf..0bfd0e54304 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -21,7 +21,7 @@ * \ingroup modifiers */ -// #ifdef DEBUG_TIME +// #define DEBUG_TIME #include @@ -422,7 +422,7 @@ static void BMD_mesh_intersection(BMesh *bm, if (use_exact) { BM_mesh_boolean( - bm, looptris, tottri, bm_face_isect_pair, NULL, 2, use_self, false, bmd->operation); + bm, looptris, tottri, bm_face_isect_pair, NULL, 2, use_self, false, false, bmd->operation); } else { BM_mesh_intersect(bm, @@ -587,8 +587,16 @@ static Mesh *collection_boolean_exact(BooleanModifierData *bmd, } BM_mesh_elem_index_ensure(bm, BM_FACE); - BM_mesh_boolean( - bm, looptris, tottri, bm_face_isect_nary, shape, num_shapes, true, false, bmd->operation); + BM_mesh_boolean(bm, + looptris, + tottri, + bm_face_isect_nary, + shape, + num_shapes, + true, + false, + false, + bmd->operation); result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); BM_mesh_free(bm); @@ -651,10 +659,12 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, } const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0; + const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0; result = BKE_mesh_boolean((const Mesh **)meshes, (const float(**)[4][4])obmats, BLI_array_len(meshes), use_self, + hole_tolerant, bmd->operation); BLI_array_free(meshes); @@ -846,31 +856,43 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(layout, ptr, "collection", 0, NULL, ICON_NONE); } - const bool use_exact = RNA_enum_get(ptr, "solver") == eBooleanModifierSolver_Exact; - uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + modifier_panel_end(layout, ptr); +} + +static void solver_options_panel_draw(const bContext *UNUSED(C), Panel *panel) +{ + uiLayout *layout = panel->layout; + uiLayout *col = uiLayoutColumn(layout, true); + + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + + const bool use_exact = RNA_enum_get(ptr, "solver") == eBooleanModifierSolver_Exact; + const bool operand_object = RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object; + if (use_exact) { /* When operand is collection, we always use_self. */ if (operand_object) { - uiItemR(layout, ptr, "use_self", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_self", 0, NULL, ICON_NONE); } + uiItemR(col, ptr, "hole_tolerant", 0, NULL, ICON_NONE); } else { - uiItemR(layout, ptr, "double_threshold", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "double_threshold", 0, NULL, ICON_NONE); } if (G.debug) { - uiLayout *col = uiLayoutColumn(layout, true); + col = uiLayoutColumn(layout, true); uiItemR(col, ptr, "debug_options", 0, NULL, ICON_NONE); } - - modifier_panel_end(layout, ptr); } static void panelRegister(ARegionType *region_type) { - modifier_panel_register(region_type, eModifierType_Boolean, panel_draw); + PanelType *panel = modifier_panel_register(region_type, eModifierType_Boolean, panel_draw); + modifier_subpanel_register( + region_type, "solver_options", "Solver Options", NULL, solver_options_panel_draw, panel); } ModifierTypeInfo modifierType_Boolean = { diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc index 38215b54640..9f331190420 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc @@ -100,7 +100,7 @@ static Mesh *mesh_boolean_calc(const Mesh *mesh_a, const Mesh *mesh_b, int boole } BM_mesh_boolean( - bm, looptris, tottri, bm_face_isect_pair, nullptr, 2, false, false, boolean_mode); + bm, looptris, tottri, bm_face_isect_pair, nullptr, 2, false, false, false, boolean_mode); Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh_a); BM_mesh_free(bm); diff --git a/source/tools b/source/tools index dc4ccc3bfb6..c37d8bd28dd 160000 --- a/source/tools +++ b/source/tools @@ -1 +1 @@ -Subproject commit dc4ccc3bfb646ef2a558bd3565f84080e99b0e8b +Subproject commit c37d8bd28ddddb8f1b0dff5739d75f8004e8034f -- cgit v1.2.3 From c950e08cbb0bb1b53802768a52382c4e6611d9f2 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 8 Mar 2021 14:39:00 +1100 Subject: Cleanup: add use prefix for boolean --- source/blender/makesrna/intern/rna_modifier.c | 2 +- source/blender/modifiers/intern/MOD_boolean.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 55d81bd3155..4f53a1e6c2b 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -2789,7 +2789,7 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Self", "Allow self-intersection in operands"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); - prop = RNA_def_property(srna, "hole_tolerant", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "use_hole_tolerant", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", eBooleanModifierFlag_HoleTolerant); RNA_def_property_ui_text(prop, "Hole tolerant", "Better results when there are holes (slower)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 0bfd0e54304..74a0687e64b 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -876,7 +876,7 @@ static void solver_options_panel_draw(const bContext *UNUSED(C), Panel *panel) if (operand_object) { uiItemR(col, ptr, "use_self", 0, NULL, ICON_NONE); } - uiItemR(col, ptr, "hole_tolerant", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_hole_tolerant", 0, NULL, ICON_NONE); } else { uiItemR(col, ptr, "double_threshold", 0, NULL, ICON_NONE); -- cgit v1.2.3 From 242a278b56114d15b91ad4fa0d370a0c44e87ec3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 8 Mar 2021 14:40:57 +1100 Subject: Cleanup: rename offs to offscreen --- source/blender/python/gpu/gpu_py_offscreen.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index dff4b169f9a..4a2b359bf39 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -96,20 +96,20 @@ static int pygpu_offscreen_valid_check(BPyGPUOffScreen *py_ofs) typedef struct { PyObject_HEAD /* required python macro */ - BPyGPUOffScreen *py_offs; + BPyGPUOffScreen *py_offscreen; int level; bool is_explicitly_bound; /* Bound by "bind" method. */ } OffScreenStackContext; static void pygpu_offscreen_stack_context__tp_dealloc(OffScreenStackContext *self) { - Py_DECREF(self->py_offs); + Py_DECREF(self->py_offscreen); PyObject_DEL(self); } static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self) { - BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs); + BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen); if (!self->is_explicitly_bound) { if (self->level != -1) { @@ -117,7 +117,7 @@ static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self return NULL; } - GPU_offscreen_bind(self->py_offs->ofs, true); + GPU_offscreen_bind(self->py_offscreen->ofs, true); self->level = GPU_framebuffer_stack_level_get(); } @@ -127,7 +127,7 @@ static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self static PyObject *pygpu_offscreen_stack_context_exit(OffScreenStackContext *self, PyObject *UNUSED(args)) { - BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs); + BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen); if (self->level == -1) { PyErr_SetString(PyExc_RuntimeError, "Not yet in use\n"); @@ -140,7 +140,7 @@ static PyObject *pygpu_offscreen_stack_context_exit(OffScreenStackContext *self, PyExc_RuntimeError, "Level of bind mismatch, expected %d, got %d\n", self->level, level); } - GPU_offscreen_unbind(self->py_offs->ofs, true); + GPU_offscreen_unbind(self->py_offscreen->ofs, true); Py_RETURN_NONE; } @@ -166,7 +166,7 @@ static PyObject *pygpu_offscreen_bind(BPyGPUOffScreen *self) { OffScreenStackContext *ret = PyObject_New(OffScreenStackContext, &PyGPUOffscreenStackContext_Type); - ret->py_offs = self; + ret->py_offscreen = self; ret->level = -1; ret->is_explicitly_bound = false; Py_INCREF(self); -- cgit v1.2.3 From b4f5128b21f1e1348defc68a96f4d4c2b1053fbe Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 8 Mar 2021 14:44:57 +1100 Subject: Cleanup: rename offs to offset --- source/blender/blenlib/BLI_string_utils.h | 2 +- source/blender/blenlib/intern/string_utils.c | 28 ++++++++++++++++------------ source/blender/blenloader/intern/readfile.c | 12 ++++++------ source/blender/blenloader/intern/readfile.h | 4 ++-- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h index 46fb096599f..1057e71a6b2 100644 --- a/source/blender/blenlib/BLI_string_utils.h +++ b/source/blender/blenlib/BLI_string_utils.h @@ -90,7 +90,7 @@ bool BLI_uniquename(struct ListBase *list, void *vlink, const char *defname, char delim, - int name_offs, + int name_offset, size_t len); #ifdef __cplusplus diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index dbe5c96260b..c847f7e1921 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -339,16 +339,16 @@ bool BLI_uniquename_cb(UniquenameCheckCallback unique_check, * * For places where this is used, see constraint.c for example... * - * \param name_offs: should be calculated using offsetof(structname, membername) - * macro from stddef.h + * \param name_offset: should be calculated using `offsetof(structname, membername)` + * macro from `stddef.h` */ -static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs) +static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offset) { Link *link; for (link = list->first; link; link = link->next) { if (link != vlink) { - if (STREQ(POINTER_OFFSET((const char *)link, name_offs), name)) { + if (STREQ(POINTER_OFFSET((const char *)link, name_offset), name)) { return true; } } @@ -362,9 +362,9 @@ static bool uniquename_unique_check(void *arg, const char *name) struct { ListBase *lb; void *vlink; - int name_offs; + int name_offset; } *data = arg; - return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs); + return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offset); } /** @@ -375,20 +375,20 @@ static bool uniquename_unique_check(void *arg, const char *name) * \param vlink: The block to check the name for * \param defname: To initialize block name if latter is empty * \param delim: Delimits numeric suffix in name - * \param name_offs: Offset of name within block structure + * \param name_offset: Offset of name within block structure * \param name_len: Maximum length of name area */ bool BLI_uniquename( - ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t name_len) + ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_len) { struct { ListBase *lb; void *vlink; - int name_offs; + int name_offset; } data; data.lb = list; data.vlink = vlink; - data.name_offs = name_offs; + data.name_offset = name_offset; BLI_assert(name_len > 1); @@ -397,8 +397,12 @@ bool BLI_uniquename( return false; } - return BLI_uniquename_cb( - uniquename_unique_check, &data, defname, delim, POINTER_OFFSET(vlink, name_offs), name_len); + return BLI_uniquename_cb(uniquename_unique_check, + &data, + defname, + delim, + POINTER_OFFSET(vlink, name_offset), + name_len); } /* ------------------------------------------------------------------------- */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 2200f7c291b..2eba9af233c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -967,15 +967,15 @@ static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock) /* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */ const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead) { - return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs); + return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offset); } /* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */ AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead) { BLI_assert(BKE_idtype_idcode_is_valid(bhead->code)); - return (fd->id_asset_data_offs >= 0) ? - *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offs) : + return (fd->id_asset_data_offset >= 0) ? + *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offset) : NULL; } @@ -1054,9 +1054,9 @@ static bool read_file_dna(FileData *fd, const char **r_error_message) fd->reconstruct_info = DNA_reconstruct_info_create( fd->filesdna, fd->memsdna, fd->compflags); /* used to retrieve ID names from (bhead+1) */ - fd->id_name_offs = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]"); - BLI_assert(fd->id_name_offs != -1); - fd->id_asset_data_offs = DNA_elem_offset( + fd->id_name_offset = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]"); + BLI_assert(fd->id_name_offset != -1); + fd->id_asset_data_offset = DNA_elem_offset( fd->filesdna, "ID", "AssetMetaData", "*asset_data"); return true; diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index b81d8bd9a2b..7c14c7a19bf 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -110,10 +110,10 @@ typedef struct FileData { int fileversion; /** Used to retrieve ID names from (bhead+1). */ - int id_name_offs; + int id_name_offset; /** Used to retrieve asset data from (bhead+1). NOTE: This may not be available in old files, * will be -1 then! */ - int id_asset_data_offs; + int id_asset_data_offset; /** For do_versions patching. */ int globalf, fileflags; -- cgit v1.2.3 From a1bc7729f20b8a8250f938d768ab2d104c41af54 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 8 Mar 2021 14:48:45 +1100 Subject: Cleanup: use ofs instead of offs as an abbreviation for offset Used for local structs/variables, since `ofs` is by far the most widely used abbreviation. --- source/blender/blenkernel/intern/displist.c | 12 +++---- .../blenkernel/intern/particle_distribute.c | 10 +++--- source/blender/editors/animation/anim_markers.c | 22 ++++++------ source/blender/editors/armature/armature_select.c | 17 ++++----- source/blender/editors/armature/pose_slide.c | 6 ++-- .../blender/editors/gpencil/gpencil_interpolate.c | 6 ++-- source/blender/editors/gpencil/gpencil_primitive.c | 6 ++-- .../blender/editors/interface/interface_handlers.c | 4 +-- .../blender/editors/interface/interface_widgets.c | 24 ++++++------- .../blender/editors/space_graph/graph_slider_ops.c | 6 ++-- .../editors/space_sequencer/sequencer_draw.c | 28 +++++++-------- .../blender/editors/space_view3d/view3d_select.c | 22 ++++++------ source/blender/gpu/intern/gpu_matrix.cc | 8 ++--- source/blender/render/intern/multires_bake.c | 16 ++++----- source/blender/render/intern/texture_procedural.c | 40 +++++++++++----------- 15 files changed, 111 insertions(+), 116 deletions(-) diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index c860e57520d..708b1971bd5 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -875,9 +875,9 @@ static float (*displist_vert_coords_alloc(ListBase *dispbase, int *r_vert_len))[ allverts = MEM_mallocN(sizeof(float[3]) * (*r_vert_len), "displist_vert_coords_alloc allverts"); fp = (float *)allverts; LISTBASE_FOREACH (DispList *, dl, dispbase) { - int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr); - memcpy(fp, dl->verts, sizeof(float) * offs); - fp += offs; + int ofs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr); + memcpy(fp, dl->verts, sizeof(float) * ofs); + fp += ofs; } return allverts; @@ -889,9 +889,9 @@ static void displist_vert_coords_apply(ListBase *dispbase, float (*allverts)[3]) fp = (float *)allverts; LISTBASE_FOREACH (DispList *, dl, dispbase) { - int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr); - memcpy(dl->verts, fp, sizeof(float) * offs); - fp += offs; + int ofs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr); + memcpy(dl->verts, fp, sizeof(float) * ofs); + fp += ofs; } } diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index c3cc9136057..ad617b4198b 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -338,18 +338,18 @@ static void hammersley_create(float *out, int n, int seed, float amount) { RNG *rng; - double offs[2], t; + double ofs[2], t; rng = BLI_rng_new(31415926 + n + seed); - offs[0] = BLI_rng_get_double(rng) + (double)amount; - offs[1] = BLI_rng_get_double(rng) + (double)amount; + ofs[0] = BLI_rng_get_double(rng) + (double)amount; + ofs[1] = BLI_rng_get_double(rng) + (double)amount; BLI_rng_free(rng); for (int k = 0; k < n; k++) { BLI_hammersley_1d(k, &t); - out[2 * k + 0] = fmod((double)k / (double)n + offs[0], 1.0); - out[2 * k + 1] = fmod(t + offs[1], 1.0); + out[2 * k + 0] = fmod((double)k / (double)n + ofs[0], 1.0); + out[2 * k + 1] = fmod(t + ofs[1], 1.0); } } diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 2ab809c3633..7adddf8f4ae 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -762,9 +762,9 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); MarkerMove *mm = op->customdata; TimeMarker *marker, *selmarker = NULL; - const int offs = RNA_int_get(op->ptr, "frames"); + const int ofs = RNA_int_get(op->ptr, "frames"); char str[UI_MAX_DRAW_STR]; - char str_offs[NUM_STR_REP_LEN]; + char str_ofs[NUM_STR_REP_LEN]; int totmark; const bool use_time = ed_marker_move_use_time(mm); @@ -776,27 +776,27 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op) } if (hasNumInput(&mm->num)) { - outputNumInput(&mm->num, str_offs, &scene->unit); + outputNumInput(&mm->num, str_ofs, &scene->unit); } else if (use_time) { - BLI_snprintf(str_offs, sizeof(str_offs), "%.2f", FRA2TIME(offs)); + BLI_snprintf(str_ofs, sizeof(str_ofs), "%.2f", FRA2TIME(ofs)); } else { - BLI_snprintf(str_offs, sizeof(str_offs), "%d", offs); + BLI_snprintf(str_ofs, sizeof(str_ofs), "%d", ofs); } if (totmark == 1 && selmarker) { /* we print current marker value */ if (use_time) { BLI_snprintf( - str, sizeof(str), TIP_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_offs); + str, sizeof(str), TIP_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_ofs); } else { - BLI_snprintf(str, sizeof(str), TIP_("Marker %d offset %s"), selmarker->frame, str_offs); + BLI_snprintf(str, sizeof(str), TIP_("Marker %d offset %s"), selmarker->frame, str_ofs); } } else { - BLI_snprintf(str, sizeof(str), TIP_("Marker offset %s"), str_offs); + BLI_snprintf(str, sizeof(str), TIP_("Marker offset %s"), str_ofs); } ED_area_status_text(CTX_wm_area(C), str); @@ -907,12 +907,12 @@ static void ed_marker_move_apply(bContext *C, wmOperator *op) #endif MarkerMove *mm = op->customdata; TimeMarker *marker; - int a, offs; + int a, ofs; - offs = RNA_int_get(op->ptr, "frames"); + ofs = RNA_int_get(op->ptr, "frames"); for (a = 0, marker = mm->markers->first; marker; marker = marker->next) { if (marker->flag & SELECT) { - marker->frame = mm->oldframe[a] + offs; + marker->frame = mm->oldframe[a] + ofs; a++; } } diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 60fe8ee7dee..226253cc063 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -644,8 +644,8 @@ static int selectbuffer_ret_hits_12(uint *UNUSED(buffer), const int hits12) static int selectbuffer_ret_hits_5(uint *buffer, const int hits12, const int hits5) { - const int offs = 4 * hits12; - memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint)); + const int ofs = 4 * hits12; + memcpy(buffer, buffer + ofs, 4 * hits5 * sizeof(uint)); return hits5; } @@ -704,17 +704,12 @@ static EditBone *get_nearest_editbonepoint( goto cache_end; } else if (hits12 > 0) { - int offs; + int ofs; - offs = 4 * hits12; + ofs = 4 * hits12; BLI_rcti_init_pt_radius(&rect, vc->mval, 5); - const int hits5 = view3d_opengl_select_with_id_filter(vc, - buffer + offs, - MAXPICKBUF - offs, - &rect, - select_mode, - select_filter, - select_id_ignore); + const int hits5 = view3d_opengl_select_with_id_filter( + vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter, select_id_ignore); if (hits5 == 1) { hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index d636f0d68af..93d36abe792 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -873,12 +873,12 @@ static void pose_slide_draw_status(tPoseSlideOp *pso) if (hasNumInput(&pso->num)) { Scene *scene = pso->scene; - char str_offs[NUM_STR_REP_LEN]; + char str_ofs[NUM_STR_REP_LEN]; - outputNumInput(&pso->num, str_offs, &scene->unit); + outputNumInput(&pso->num, str_ofs, &scene->unit); BLI_snprintf( - status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str); + status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_ofs, limits_str); } else { BLI_snprintf(status_str, diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 7c541f61d75..3b7c80cee07 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -599,10 +599,10 @@ static void gpencil_interpolate_status_indicators(bContext *C, tGPDinterpolate * BLI_strncpy(msg_str, TIP_("GPencil Interpolation: "), UI_MAX_DRAW_STR); if (hasNumInput(&p->num)) { - char str_offs[NUM_STR_REP_LEN]; + char str_ofs[NUM_STR_REP_LEN]; - outputNumInput(&p->num, str_offs, &scene->unit); - BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_offs); + outputNumInput(&p->num, str_ofs, &scene->unit); + BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_ofs); } else { BLI_snprintf(status_str, diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index b29ef2e7ee2..dfff0ce639e 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -466,10 +466,10 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi GP_STROKE_BOX, GP_STROKE_POLYLINE)) { if (hasNumInput(&tgpi->num)) { - char str_offs[NUM_STR_REP_LEN]; + char str_ofs[NUM_STR_REP_LEN]; - outputNumInput(&tgpi->num, str_offs, &scene->unit); - BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs); + outputNumInput(&tgpi->num, str_ofs, &scene->unit); + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_ofs); } else { if (tgpi->flag == IN_PROGRESS) { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 042f10ddded..834be49b2b3 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -5246,8 +5246,8 @@ static bool ui_numedit_but_SLI(uiBut *but, (but->softmax - but->softmin + but->a1); } else { - const float offs = (BLI_rctf_size_y(&but->rect) / 2.0f); - cursor_x_range = (BLI_rctf_size_x(&but->rect) - offs); + const float ofs = (BLI_rctf_size_y(&but->rect) / 2.0f); + cursor_x_range = (BLI_rctf_size_x(&but->rect) - ofs); } f = (mx_fl - data->dragstartx) / cursor_x_range + data->dragfstart; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 06b87dd857f..1d7d10b6d0c 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -3667,16 +3667,16 @@ static void widget_progressbar( /* round corners */ const float value = but_progressbar->progress; - const float offs = wcol->roundness * BLI_rcti_size_y(&rect_prog); + const float ofs = wcol->roundness * BLI_rcti_size_y(&rect_prog); float w = value * BLI_rcti_size_x(&rect_prog); /* Ensure minimum size. */ - w = MAX2(w, offs); + w = MAX2(w, ofs); rect_bar.xmax = rect_bar.xmin + w; - round_box_edges(&wtb, roundboxalign, &rect_prog, offs); - round_box_edges(&wtb_bar, roundboxalign, &rect_bar, offs); + round_box_edges(&wtb, roundboxalign, &rect_prog, ofs); + round_box_edges(&wtb_bar, roundboxalign, &rect_bar, ofs); wtb.draw_outline = true; widgetbase_draw(&wtb, wcol); @@ -3733,9 +3733,9 @@ static void widget_numslider( widget_init(&wtb1); /* Backdrop first. */ - const float offs = wcol->roundness * BLI_rcti_size_y(rect); - const float toffs = offs * 0.75f; - round_box_edges(&wtb, roundboxalign, rect, offs); + const float ofs = wcol->roundness * BLI_rcti_size_y(rect); + const float toffs = ofs * 0.75f; + round_box_edges(&wtb, roundboxalign, rect, ofs); wtb.draw_outline = false; widgetbase_draw(&wtb, wcol); @@ -3768,13 +3768,13 @@ static void widget_numslider( const float width = (float)BLI_rcti_size_x(rect); factor_ui = factor * width; - if (factor_ui <= offs) { + if (factor_ui <= ofs) { /* Left part only. */ roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT); - rect1.xmax = rect1.xmin + offs; - factor_discard = factor_ui / offs; + rect1.xmax = rect1.xmin + ofs; + factor_discard = factor_ui / ofs; } - else if (factor_ui <= width - offs) { + else if (factor_ui <= width - ofs) { /* Left part + middle part. */ roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT); rect1.xmax = rect1.xmin + factor_ui; @@ -3784,7 +3784,7 @@ static void widget_numslider( factor_discard = factor; } - round_box_edges(&wtb1, roundboxalign_slider, &rect1, offs); + round_box_edges(&wtb1, roundboxalign_slider, &rect1, ofs); wtb1.draw_outline = false; widgetbase_set_uniform_discard_factor(&wtb1, factor_discard); widgetbase_draw(&wtb1, wcol); diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c index 3e52dc7377b..4174e1c63ae 100644 --- a/source/blender/editors/space_graph/graph_slider_ops.c +++ b/source/blender/editors/space_graph/graph_slider_ops.c @@ -187,11 +187,11 @@ static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo) strcpy(mode_str, TIP_("Decimate Keyframes")); if (hasNumInput(&dgo->num)) { - char str_offs[NUM_STR_REP_LEN]; + char str_ofs[NUM_STR_REP_LEN]; - outputNumInput(&dgo->num, str_offs, &dgo->scene->unit); + outputNumInput(&dgo->num, str_ofs, &dgo->scene->unit); - BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs); + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs); } else { float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 9828368ccf7..31d3d0bc1bc 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -2112,7 +2112,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d) typedef struct CacheDrawData { struct View2D *v2d; - float stripe_offs; + float stripe_ofs_y; float stripe_ht; int cache_flag; GPUVertBuf *raw_vbo; @@ -2151,7 +2151,7 @@ static bool draw_cache_view_iter_fn(void *userdata, { CacheDrawData *drawdata = userdata; struct View2D *v2d = drawdata->v2d; - float stripe_bot, stripe_top, stripe_offs, stripe_ht; + float stripe_bot, stripe_top, stripe_ofs_y, stripe_ht; GPUVertBuf *vbo; size_t *vert_count; @@ -2164,27 +2164,27 @@ static bool draw_cache_view_iter_fn(void *userdata, vert_count = &drawdata->final_out_vert_count; } else if ((cache_type & SEQ_CACHE_STORE_RAW) && (drawdata->cache_flag & SEQ_CACHE_VIEW_RAW)) { - stripe_offs = drawdata->stripe_offs; + stripe_ofs_y = drawdata->stripe_ofs_y; stripe_ht = drawdata->stripe_ht; - stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs; + stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_ofs_y; stripe_top = stripe_bot + stripe_ht; vbo = drawdata->raw_vbo; vert_count = &drawdata->raw_vert_count; } else if ((cache_type & SEQ_CACHE_STORE_PREPROCESSED) && (drawdata->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED)) { - stripe_offs = drawdata->stripe_offs; + stripe_ofs_y = drawdata->stripe_ofs_y; stripe_ht = drawdata->stripe_ht; - stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + (stripe_offs + stripe_ht) + stripe_offs; + stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + (stripe_ofs_y + stripe_ht) + stripe_ofs_y; stripe_top = stripe_bot + stripe_ht; vbo = drawdata->preprocessed_vbo; vert_count = &drawdata->preprocessed_vert_count; } else if ((cache_type & SEQ_CACHE_STORE_COMPOSITE) && (drawdata->cache_flag & SEQ_CACHE_VIEW_COMPOSITE)) { - stripe_offs = drawdata->stripe_offs; + stripe_ofs_y = drawdata->stripe_ofs_y; stripe_ht = drawdata->stripe_ht; - stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_offs; + stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y; stripe_bot = stripe_top - stripe_ht; vbo = drawdata->composite_vbo; vert_count = &drawdata->composite_vert_count; @@ -2237,12 +2237,12 @@ static void draw_cache_view(const bContext *C) immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); float stripe_bot, stripe_top; - float stripe_offs = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin; + float stripe_ofs_y = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin; float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) - v2d->cur.ymin; CLAMP_MAX(stripe_ht, 0.2f); - CLAMP_MIN(stripe_offs, stripe_ht / 2); + CLAMP_MIN(stripe_ofs_y, stripe_ht / 2); if (scene->ed->cache_flag & SEQ_CACHE_VIEW_FINAL_OUT) { stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HANDLE_HEIGHT); @@ -2262,7 +2262,7 @@ static void draw_cache_view(const bContext *C) continue; } - stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs; + stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_ofs_y; stripe_top = stripe_bot + stripe_ht; if (scene->ed->cache_flag & SEQ_CACHE_VIEW_RAW) { @@ -2271,7 +2271,7 @@ static void draw_cache_view(const bContext *C) immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top); } - stripe_bot += stripe_ht + stripe_offs; + stripe_bot += stripe_ht + stripe_ofs_y; stripe_top = stripe_bot + stripe_ht; if (scene->ed->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED) { @@ -2280,7 +2280,7 @@ static void draw_cache_view(const bContext *C) immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top); } - stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_offs; + stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y; stripe_bot = stripe_top - stripe_ht; if (scene->ed->cache_flag & SEQ_CACHE_VIEW_COMPOSITE) { @@ -2297,7 +2297,7 @@ static void draw_cache_view(const bContext *C) CacheDrawData userdata; userdata.v2d = v2d; - userdata.stripe_offs = stripe_offs; + userdata.stripe_ofs_y = stripe_ofs_y; userdata.stripe_ht = stripe_ht; userdata.cache_flag = scene->ed->cache_flag; userdata.raw_vert_count = 0; diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 0605ea30806..7dc4a72e510 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1673,8 +1673,8 @@ static int selectbuffer_ret_hits_15(uint *UNUSED(buffer), const int hits15) static int selectbuffer_ret_hits_9(uint *buffer, const int hits15, const int hits9) { - const int offs = 4 * hits15; - memcpy(buffer, buffer + offs, 4 * hits9 * sizeof(uint)); + const int ofs = 4 * hits15; + memcpy(buffer, buffer + ofs, 4 * hits9 * sizeof(uint)); return hits9; } @@ -1683,8 +1683,8 @@ static int selectbuffer_ret_hits_5(uint *buffer, const int hits9, const int hits5) { - const int offs = 4 * hits15 + 4 * hits9; - memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint)); + const int ofs = 4 * hits15 + 4 * hits9; + memcpy(buffer, buffer + ofs, 4 * hits5 * sizeof(uint)); return hits5; } @@ -1726,30 +1726,30 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc, goto finally; } else if (hits15 > 0) { - int offs; + int ofs; has_bones15 = selectbuffer_has_bones(buffer, hits15); - offs = 4 * hits15; + ofs = 4 * hits15; BLI_rcti_init_pt_radius(&rect, mval, 9); hits9 = view3d_opengl_select( - vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter); + vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter); if (hits9 == 1) { hits = selectbuffer_ret_hits_9(buffer, hits15, hits9); goto finally; } else if (hits9 > 0) { - has_bones9 = selectbuffer_has_bones(buffer + offs, hits9); + has_bones9 = selectbuffer_has_bones(buffer + ofs, hits9); - offs += 4 * hits9; + ofs += 4 * hits9; BLI_rcti_init_pt_radius(&rect, mval, 5); hits5 = view3d_opengl_select( - vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter); + vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter); if (hits5 == 1) { hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); goto finally; } else if (hits5 > 0) { - has_bones5 = selectbuffer_has_bones(buffer + offs, hits5); + has_bones5 = selectbuffer_has_bones(buffer + ofs, hits5); } } diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc index 24cdea74347..2ae50d913da 100644 --- a/source/blender/gpu/intern/gpu_matrix.cc +++ b/source/blender/gpu/intern/gpu_matrix.cc @@ -736,7 +736,7 @@ float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float di int depthbits = 24; depth_fac = 1.0f / (float)((1 << depthbits) - 1); } - offs = (-1.0 / winmat[2][2]) * dist * depth_fac; + ofs = (-1.0 / winmat[2][2]) * dist * depth_fac; UNUSED_VARS(viewdist); #endif @@ -765,10 +765,10 @@ void GPU_polygon_offset(float viewdist, float dist) /* dist is from camera to center point */ - float offs = GPU_polygon_offset_calc(winmat, viewdist, dist); + float ofs = GPU_polygon_offset_calc(winmat, viewdist, dist); - winmat[3][2] -= offs; - offset += offs; + winmat[3][2] -= ofs; + offset += ofs; } else { winmat[3][2] += offset; diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c index 1859886f563..cba4628b63a 100644 --- a/source/blender/render/intern/multires_bake.c +++ b/source/blender/render/intern/multires_bake.c @@ -658,10 +658,10 @@ static void get_ccgdm_data(DerivedMesh *lodm, /* get the original cage face index */ int cage_face_index = index_mp_to_orig ? index_mp_to_orig[poly_index] : poly_index; /* local offset in total cage face grids - * (1 << (2 * lvl)) is number of all polys for one cage face */ - int loc_cage_poly_offs = poly_index % (1 << (2 * lvl)); + * `(1 << (2 * lvl))` is number of all polys for one cage face */ + int loc_cage_poly_ofs = poly_index % (1 << (2 * lvl)); /* local offset in the vertex grid itself */ - int cell_index = loc_cage_poly_offs % (polys_per_grid_side * polys_per_grid_side); + int cell_index = loc_cage_poly_ofs % (polys_per_grid_side * polys_per_grid_side); int cell_side = (grid_size - 1) / polys_per_grid_side; /* row and column based on grid side */ int row = cell_index / polys_per_grid_side; @@ -1193,7 +1193,7 @@ static void apply_ao_callback(DerivedMesh *lores_dm, MLoopUV *mloopuv = lores_dm->getLoopDataArray(lores_dm, CD_MLOOPUV); MAOBakeData *ao_data = (MAOBakeData *)bake_data; - int i, k, perm_offs; + int i, k, perm_ofs; float pos[3], nrm[3]; float cen[3]; float axisX[3], axisY[3], axisZ[3]; @@ -1236,7 +1236,7 @@ static void apply_ao_callback(DerivedMesh *lores_dm, build_coordinate_frame(axisX, axisY, axisZ); /* static noise */ - perm_offs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1); + perm_ofs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1); /* importance sample shadow rays (cosine weighted) */ for (i = 0; i < ao_data->number_of_rays; i++) { @@ -1246,12 +1246,12 @@ static void apply_ao_callback(DerivedMesh *lores_dm, * a multi-dimensional domain (2D) */ const unsigned short I = - ao_data->permutation_table_1[(i + perm_offs) % ao_data->number_of_rays]; + ao_data->permutation_table_1[(i + perm_ofs) % ao_data->number_of_rays]; const unsigned short J = ao_data->permutation_table_2[i]; - const float JitPh = (get_ao_random2(I + perm_offs) & (MAX_NUMBER_OF_AO_RAYS - 1)) / + const float JitPh = (get_ao_random2(I + perm_ofs) & (MAX_NUMBER_OF_AO_RAYS - 1)) / ((float)MAX_NUMBER_OF_AO_RAYS); - const float JitTh = (get_ao_random1(J + perm_offs) & (MAX_NUMBER_OF_AO_RAYS - 1)) / + const float JitTh = (get_ao_random1(J + perm_ofs) & (MAX_NUMBER_OF_AO_RAYS - 1)) / ((float)MAX_NUMBER_OF_AO_RAYS); const float SiSqPhi = (I + JitPh) / ao_data->number_of_rays; const float Theta = (float)(2 * M_PI) * ((J + JitTh) / ao_data->number_of_rays); diff --git a/source/blender/render/intern/texture_procedural.c b/source/blender/render/intern/texture_procedural.c index b0ab20de10d..bea9dfbb0ed 100644 --- a/source/blender/render/intern/texture_procedural.c +++ b/source/blender/render/intern/texture_procedural.c @@ -555,10 +555,10 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult tex->noisebasis); if (texres->nor != NULL) { - float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */ + float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ /* calculate bumpnormal */ - texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + offs, + texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs, texvec[1], texvec[2], tex->mg_H, @@ -566,7 +566,7 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult tex->mg_octaves, tex->noisebasis); texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0], - texvec[1] + offs, + texvec[1] + ofs, texvec[2], tex->mg_H, tex->mg_lacunarity, @@ -574,7 +574,7 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult tex->noisebasis); texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0], texvec[1], - texvec[2] + offs, + texvec[2] + ofs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, @@ -612,10 +612,10 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu tex->noisebasis); if (texres->nor != NULL) { - float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */ + float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ /* calculate bumpnormal */ - texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + offs, + texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs, texvec[1], texvec[2], tex->mg_H, @@ -625,7 +625,7 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu tex->mg_gain, tex->noisebasis); texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0], - texvec[1] + offs, + texvec[1] + ofs, texvec[2], tex->mg_H, tex->mg_lacunarity, @@ -635,7 +635,7 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu tex->noisebasis); texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0], texvec[1], - texvec[2] + offs, + texvec[2] + ofs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, @@ -666,10 +666,10 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr tex->noisebasis); if (texres->nor != NULL) { - float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */ + float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ /* calculate bumpnormal */ - texres->nor[0] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0] + offs, + texres->nor[0] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0] + ofs, texvec[1], texvec[2], tex->mg_H, @@ -678,7 +678,7 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr tex->mg_offset, tex->noisebasis); texres->nor[1] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0], - texvec[1] + offs, + texvec[1] + ofs, texvec[2], tex->mg_H, tex->mg_lacunarity, @@ -687,7 +687,7 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr tex->noisebasis); texres->nor[2] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0], texvec[1], - texvec[2] + offs, + texvec[2] + ofs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, @@ -711,24 +711,24 @@ static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *tex texvec[0], texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2); if (texres->nor != NULL) { - float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */ + float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ /* calculate bumpnormal */ - texres->nor[0] = BLI_noise_mg_variable_lacunarity(texvec[0] + offs, + texres->nor[0] = BLI_noise_mg_variable_lacunarity(texvec[0] + ofs, texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2); texres->nor[1] = BLI_noise_mg_variable_lacunarity(texvec[0], - texvec[1] + offs, + texvec[1] + ofs, texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2); texres->nor[2] = BLI_noise_mg_variable_lacunarity(texvec[0], texvec[1], - texvec[2] + offs, + texvec[2] + ofs, tex->dist_amount, tex->noisebasis, tex->noisebasis2); @@ -805,14 +805,14 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres) } if (texres->nor != NULL) { - float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */ + float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ /* calculate bumpnormal */ - BLI_noise_voronoi(texvec[0] + offs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); + BLI_noise_voronoi(texvec[0] + ofs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); texres->nor[0] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); - BLI_noise_voronoi(texvec[0], texvec[1] + offs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); + BLI_noise_voronoi(texvec[0], texvec[1] + ofs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); texres->nor[1] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); - BLI_noise_voronoi(texvec[0], texvec[1], texvec[2] + offs, da, pa, tex->vn_mexp, tex->vn_distm); + BLI_noise_voronoi(texvec[0], texvec[1], texvec[2] + ofs, da, pa, tex->vn_mexp, tex->vn_distm); texres->nor[2] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); tex_normal_derivate(tex, texres); -- cgit v1.2.3 From 89757f918cfa9e087f1a55f7c94688a1f623b612 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 8 Mar 2021 08:28:31 +0100 Subject: Revert "Fix T86026: Crash Opening Cryptomatte File." This reverts commit 7f3649874070de38131263317d02906d50279f93. --- source/blender/blenkernel/intern/cryptomatte.cc | 22 +++++++--------------- .../blender/blenkernel/intern/cryptomatte_test.cc | 13 ------------- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc index 9d9cace3a35..3188656aa6b 100644 --- a/source/blender/blenkernel/intern/cryptomatte.cc +++ b/source/blender/blenkernel/intern/cryptomatte.cc @@ -184,30 +184,22 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash) char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage) { - std::stringstream ss; - ss.precision(9); - + DynStr *matte_id = BLI_dynstr_new(); bool first = true; LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) { if (!first) { - ss << ','; + BLI_dynstr_append(matte_id, ","); } - blender::StringRef entry_name(entry->name, BLI_strnlen(entry->name, sizeof(entry->name))); - if (!entry_name.is_empty()) { - ss << entry_name; + if (BLI_strnlen(entry->name, sizeof(entry->name)) != 0) { + BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name)); } else { - ss << '<' << std::scientific << entry->encoded_hash << '>'; + BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash); } first = false; } - - /* Convert result to C string. */ - const std::string result_string = ss.str(); - const char *c_str = result_string.c_str(); - size_t result_len = result_string.size() + 1; - char *result = static_cast(MEM_mallocN(sizeof(char) * result_len, __func__)); - memcpy(result, c_str, result_len); + char *result = BLI_dynstr_get_cstring(matte_id); + BLI_dynstr_free(matte_id); return result; } diff --git a/source/blender/blenkernel/intern/cryptomatte_test.cc b/source/blender/blenkernel/intern/cryptomatte_test.cc index 22abd1a4d56..13e29cecf0a 100644 --- a/source/blender/blenkernel/intern/cryptomatte_test.cc +++ b/source/blender/blenkernel/intern/cryptomatte_test.cc @@ -21,8 +21,6 @@ #include "BKE_cryptomatte.hh" #include "BKE_image.h" -#include "DNA_node_types.h" - #include "RE_pipeline.h" #include "MEM_guardedalloc.h" @@ -176,15 +174,4 @@ TEST(cryptomatte, session_from_stamp_data) BKE_cryptomatte_free(session); } -TEST(cryptomatte, T86026) -{ - NodeCryptomatte storage = {{0.0f}}; - CryptomatteEntry entry = {nullptr}; - BLI_addtail(&storage.entries, &entry); - entry.encoded_hash = 4.76190593e-07; - char *matte_id = BKE_cryptomatte_entries_to_matte_id(&storage); - EXPECT_STREQ("<4.761905927e-07>", matte_id); - MEM_freeN(matte_id); -} - } // namespace blender::bke::cryptomatte::tests -- cgit v1.2.3 From cbf033c05519ffa977693a5f6845b476017af08b Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 8 Mar 2021 08:47:22 +0100 Subject: Fix T86026: Crash Opening Cryptomatte File. But this time the root cause. Writing undo files is done in a separate thread. This patch moved the updating of the matte_id when the user actually changes the matte. --- source/blender/blenkernel/intern/cryptomatte.cc | 11 +++++++++++ source/blender/blenkernel/intern/node.cc | 9 +-------- source/blender/blenloader/intern/versioning_290.c | 1 - source/blender/makesdna/DNA_node_types.h | 3 ++- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc index 3188656aa6b..6db471e830b 100644 --- a/source/blender/blenkernel/intern/cryptomatte.cc +++ b/source/blender/blenkernel/intern/cryptomatte.cc @@ -208,6 +208,17 @@ void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const ch BLI_freelistN(&node_storage->entries); std::optional session = std::nullopt; + if (matte_id == nullptr) { + MEM_SAFE_FREE(node_storage->matte_id); + return; + } + /* Update the matte_id so the files can be opened in versions that don't + * use `CryptomatteEntry`. */ + if (matte_id != node_storage->matte_id && STREQ(node_storage->matte_id, matte_id)) { + MEM_SAFE_FREE(node_storage->matte_id); + node_storage->matte_id = static_cast(MEM_dupallocN(matte_id)); + } + std::istringstream ss(matte_id); while (ss.good()) { CryptomatteEntry *entry = nullptr; diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 6b46ae3430b..c2ce52b1358 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -540,18 +540,11 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) } else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) { NodeCryptomatte *nc = (NodeCryptomatte *)node->storage; - /* Update the matte_id so the files can be opened in versions that don't - * use `CryptomatteEntry`. */ - MEM_SAFE_FREE(nc->matte_id); - nc->matte_id = BKE_cryptomatte_entries_to_matte_id(nc); - if (nc->matte_id) { - BLO_write_string(writer, nc->matte_id); - } + BLO_write_string(writer, nc->matte_id); LISTBASE_FOREACH (CryptomatteEntry *, entry, &nc->entries) { BLO_write_struct(writer, CryptomatteEntry, entry); } BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); - MEM_SAFE_FREE(nc->matte_id); } else if (node->type == FN_NODE_INPUT_STRING) { NodeInputString *storage = (NodeInputString *)node->storage; diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 5c8e9da41c4..1aa1f0302e3 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1469,7 +1469,6 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) continue; } BKE_cryptomatte_matte_id_to_entries(storage, storage->matte_id); - MEM_SAFE_FREE(storage->matte_id); } } } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 8b0bc235861..82509599931 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1070,7 +1070,8 @@ typedef struct CryptomatteEntry { typedef struct NodeCryptomatte { float add[3]; float remove[3]; - char *matte_id DNA_DEPRECATED; + /* Stores `entries` as a string for opening in 2.80-2.91. */ + char *matte_id; /* Contains `CryptomatteEntry`. */ ListBase entries; int num_inputs; -- cgit v1.2.3 From 74c50d0c773cf0e751ba92c6d0d4af668972e564 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 8 Mar 2021 08:52:43 +0100 Subject: Cleanup: Remove unused variable. --- source/blender/blenkernel/intern/cryptomatte.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc index 6db471e830b..55426f738ff 100644 --- a/source/blender/blenkernel/intern/cryptomatte.cc +++ b/source/blender/blenkernel/intern/cryptomatte.cc @@ -206,7 +206,6 @@ char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage) void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const char *matte_id) { BLI_freelistN(&node_storage->entries); - std::optional session = std::nullopt; if (matte_id == nullptr) { MEM_SAFE_FREE(node_storage->matte_id); -- cgit v1.2.3 From 2b9eea17cca4512fc47511ff3c596ce9a8f59356 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Mon, 8 Mar 2021 10:06:25 +0100 Subject: Particles: change default name to "ParticleSystem" Since {rB7a6b46aac56b}, particle systems were named "ParticleSettings" by default, same as particle settings themselves. These are not the same thing and their names should reflect that. Issue came up in T86366. Now name them "ParticleSystem" by default, name uniqueness is preserved for both system and settings. Maniphest Tasks: T86366 Differential Revision: https://developer.blender.org/D10641 --- source/blender/blenkernel/intern/particle.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index acda59ce96c..e50b321900a 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3925,7 +3925,7 @@ static ModifierData *object_add_or_copy_particle_system( } if (name == NULL) { - name = (psys_orig != NULL) ? psys_orig->name : DATA_("ParticleSettings"); + name = (psys_orig != NULL) ? psys_orig->name : DATA_("ParticleSystem"); } psys = ob->particlesystem.first; @@ -3943,7 +3943,7 @@ static ModifierData *object_add_or_copy_particle_system( id_us_plus(&psys->part->id); } else { - psys->part = BKE_particlesettings_add(bmain, psys->name); + psys->part = BKE_particlesettings_add(bmain, DATA_("ParticleSettings")); } md = BKE_modifier_new(eModifierType_ParticleSystem); BLI_strncpy(md->name, psys->name, sizeof(md->name)); -- cgit v1.2.3 From e12ad2bce0cca84a10915d8da1417b71142432d1 Mon Sep 17 00:00:00 2001 From: Leon Leno Date: Mon, 8 Mar 2021 11:37:37 +0100 Subject: Geometry Nodes: support Vector Rotate node Differential Revision: https://developer.blender.org/D10410 --- release/scripts/startup/nodeitems_builtins.py | 1 + .../blender/functions/FN_multi_function_builder.hh | 57 ++++++++++ .../shader/nodes/node_shader_vector_rotate.cc | 125 ++++++++++++++++++++- 3 files changed, 182 insertions(+), 1 deletion(-) diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index ba0a22af0d1..e013317b547 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -543,6 +543,7 @@ geometry_node_categories = [ NodeItem("ShaderNodeSeparateXYZ"), NodeItem("ShaderNodeCombineXYZ"), NodeItem("ShaderNodeVectorMath"), + NodeItem("ShaderNodeVectorRotate"), ]), GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items), GeometryNodeCategory("GEO_LAYOUT", "Layout", items=[ diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh index 6d5ca7f64ad..0cd1bc262be 100644 --- a/source/blender/functions/FN_multi_function_builder.hh +++ b/source/blender/functions/FN_multi_function_builder.hh @@ -168,6 +168,63 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction { } }; +/** + * Generates a multi-function with the following parameters: + * 1. single input (SI) of type In1 + * 2. single input (SI) of type In2 + * 3. single input (SI) of type In3 + * 4. single input (SI) of type In4 + * 5. single output (SO) of type Out1 + */ +template +class CustomMF_SI_SI_SI_SI_SO : public MultiFunction { + private: + using FunctionT = std::function, VSpan, VSpan, VSpan, MutableSpan)>; + FunctionT function_; + + public: + CustomMF_SI_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + { + MFSignatureBuilder signature = this->get_builder(name); + signature.single_input("In1"); + signature.single_input("In2"); + signature.single_input("In3"); + signature.single_input("In4"); + signature.single_output("Out1"); + } + + template + CustomMF_SI_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn) + : CustomMF_SI_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SI_SO::create_function(element_fn)) + { + } + + template static FunctionT create_function(ElementFuncT element_fn) + { + return [=](IndexMask mask, + VSpan in1, + VSpan in2, + VSpan in3, + VSpan in4, + MutableSpan out1) { + mask.foreach_index([&](int i) { + new (static_cast(&out1[i])) Out1(element_fn(in1[i], in2[i], in3[i], in4[i])); + }); + }; + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + VSpan in1 = params.readonly_single_input(0); + VSpan in2 = params.readonly_single_input(1); + VSpan in3 = params.readonly_single_input(2); + VSpan in4 = params.readonly_single_input(3); + MutableSpan out1 = params.uninitialized_single_output(4); + function_(mask, in1, in2, in3, in4, out1); + } +}; + /** * Generates a multi-function with the following parameters: * 1. single mutable (SM) of type Mut1 diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index d6ead5a8b99..30b043439b8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -71,6 +71,128 @@ static int gpu_shader_vector_rotate(GPUMaterial *mat, return 0; } +using blender::float3; + +static float3 sh_node_vector_rotate_around_axis(const float3 vector, + const float3 center, + const float3 axis, + const float angle) +{ + float3 result = vector - center; + float mat[3][3]; + axis_angle_to_mat3(mat, axis, angle); + mul_m3_v3(mat, result); + return result + center; +} + +static float3 sh_node_vector_rotate_euler(const float3 vector, + const float3 center, + const float3 rotation, + const bool invert) +{ + float mat[3][3]; + float3 result = vector - center; + eul_to_mat3(mat, rotation); + if (invert) { + invert_m3(mat); + } + mul_m3_v3(mat, result); + return result + center; +} + +static const blender::fn::MultiFunction &get_multi_function( + blender::nodes::NodeMFNetworkBuilder &builder) +{ + bool invert = builder.bnode().custom2; + const int mode = builder.bnode().custom1; + + switch (mode) { + case NODE_VECTOR_ROTATE_TYPE_AXIS: { + if (invert) { + static blender::fn::CustomMF_SI_SI_SI_SI_SO fn{ + "Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, -angle); + }}; + return fn; + } + static blender::fn::CustomMF_SI_SI_SI_SI_SO fn{ + "Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, angle); + }}; + return fn; + } + case NODE_VECTOR_ROTATE_TYPE_AXIS_X: { + float3 axis = float3(1.0f, 0.0f, 0.0f); + if (invert) { + static blender::fn::CustomMF_SI_SI_SI_SO fn{ + "Rotate X-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, -angle); + }}; + return fn; + } + static blender::fn::CustomMF_SI_SI_SI_SO fn{ + "Rotate X-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, angle); + }}; + return fn; + } + case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: { + float3 axis = float3(0.0f, 1.0f, 0.0f); + if (invert) { + static blender::fn::CustomMF_SI_SI_SI_SO fn{ + "Rotate Y-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, -angle); + }}; + return fn; + } + static blender::fn::CustomMF_SI_SI_SI_SO fn{ + "Rotate Y-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, angle); + }}; + return fn; + } + case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: { + float3 axis = float3(0.0f, 0.0f, 1.0f); + if (invert) { + static blender::fn::CustomMF_SI_SI_SI_SO fn{ + "Rotate Z-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, -angle); + }}; + return fn; + } + static blender::fn::CustomMF_SI_SI_SI_SO fn{ + "Rotate Z-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, angle); + }}; + return fn; + } + case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: { + if (invert) { + static blender::fn::CustomMF_SI_SI_SI_SO fn{ + "Rotate Euler", [](float3 in, float3 center, float3 rotation) { + return sh_node_vector_rotate_euler(in, center, rotation, true); + }}; + return fn; + } + static blender::fn::CustomMF_SI_SI_SI_SO fn{ + "Rotate Euler", [](float3 in, float3 center, float3 rotation) { + return sh_node_vector_rotate_euler(in, center, rotation, false); + }}; + return fn; + } + default: + BLI_assert(false); + return builder.get_not_implemented_fn(); + } +} + +static void sh_node_vector_rotate_expand_in_mf_network( + blender::nodes::NodeMFNetworkBuilder &builder) +{ + const blender::fn::MultiFunction &fn = get_multi_function(builder); + builder.set_matching_fn(fn); +} + static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node) { bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation"); @@ -85,10 +207,11 @@ void register_node_type_sh_vector_rotate(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0); + sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0); node_type_socket_templates(&ntype, sh_node_vector_rotate_in, sh_node_vector_rotate_out); node_type_gpu(&ntype, gpu_shader_vector_rotate); node_type_update(&ntype, node_shader_update_vector_rotate); + ntype.expand_in_mf_network = sh_node_vector_rotate_expand_in_mf_network; nodeRegisterType(&ntype); } -- cgit v1.2.3 From e9e53ff3a6a4a73efe4777551d0cc552a0ea76d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastia=CC=81n=20Barschkis?= Date: Mon, 8 Mar 2021 11:55:35 +0100 Subject: Cleanup: Removed duplicate slash in macOS SDK path Cleanup although it's harmless. --- build_files/cmake/platform/platform_apple_xcode.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_files/cmake/platform/platform_apple_xcode.cmake b/build_files/cmake/platform/platform_apple_xcode.cmake index 43bdafb8ce2..4d15fee75b7 100644 --- a/build_files/cmake/platform/platform_apple_xcode.cmake +++ b/build_files/cmake/platform/platform_apple_xcode.cmake @@ -66,7 +66,7 @@ endif() if(XCODE_VERSION) # Construct SDKs path ourselves, because xcode-select path could be ambiguous. # Both /Applications/Xcode.app/Contents/Developer or /Applications/Xcode.app would be allowed. - set(XCODE_SDK_DIR ${XCODE_DEVELOPER_DIR}/Platforms/MacOSX.platform//Developer/SDKs) + set(XCODE_SDK_DIR ${XCODE_DEVELOPER_DIR}/Platforms/MacOSX.platform/Developer/SDKs) # Detect SDK version to use if(NOT DEFINED OSX_SYSTEM) -- cgit v1.2.3 From b9cd2f4531ca670c196b0b14b1359d0f375103c2 Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Mon, 8 Mar 2021 06:45:45 -0500 Subject: Revert "Fix modernize-raw-string-literal complaints from clang-tidy." This reverts commit 7a34bd7c2886dfc812345c0b1649d63a9ee4666f. Broke windows build. Can apparently fix with /Zc:preprocessor flag for windows but need a Windows dev to make that fix. --- .../blender/blenkernel/intern/cryptomatte_test.cc | 30 ++++++++++++---------- .../blender/blenlib/tests/BLI_delaunay_2d_test.cc | 28 ++++++++++---------- source/blender/blenlib/tests/BLI_string_test.cc | 16 ++++++------ .../blender/blenlib/tests/BLI_string_utf8_test.cc | 4 +-- 4 files changed, 40 insertions(+), 38 deletions(-) diff --git a/source/blender/blenkernel/intern/cryptomatte_test.cc b/source/blender/blenkernel/intern/cryptomatte_test.cc index 13e29cecf0a..d9be252d654 100644 --- a/source/blender/blenkernel/intern/cryptomatte_test.cc +++ b/source/blender/blenkernel/intern/cryptomatte_test.cc @@ -53,17 +53,17 @@ TEST(cryptomatte, layer) ASSERT_EQ("{}", layer.manifest()); layer.add_hash("Object", 123); - ASSERT_EQ(R"({"Object":"0000007b"})", layer.manifest()); + ASSERT_EQ("{\"Object\":\"0000007b\"}", layer.manifest()); layer.add_hash("Object2", 123245678); - ASSERT_EQ(R"({"Object":"0000007b","Object2":"0758946e"})", layer.manifest()); + ASSERT_EQ("{\"Object\":\"0000007b\",\"Object2\":\"0758946e\"}", layer.manifest()); } TEST(cryptomatte, layer_quoted) { blender::bke::cryptomatte::CryptomatteLayer layer; - layer.add_hash(R"("Object")", 123); - ASSERT_EQ(R"({"\"Object\"":"0000007b"})", layer.manifest()); + layer.add_hash("\"Object\"", 123); + ASSERT_EQ("{\"\\\"Object\\\"\":\"0000007b\"}", layer.manifest()); } static void test_cryptomatte_manifest(std::string expected, std::string manifest) @@ -75,15 +75,17 @@ static void test_cryptomatte_manifest(std::string expected, std::string manifest TEST(cryptomatte, layer_from_manifest) { test_cryptomatte_manifest("{}", "{}"); - test_cryptomatte_manifest(R"({"Object":"12345678"})", R"({"Object": "12345678"})"); - test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321"})", - R"({"Object":"12345678","Object2":"87654321"})"); - test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321"})", - R"( { "Object" : "12345678" , "Object2" : "87654321" } )"); - test_cryptomatte_manifest(R"({"Object\"01\"":"12345678"})", R"({"Object\"01\"": "12345678"})"); + test_cryptomatte_manifest("{\"Object\":\"12345678\"}", "{\"Object\": \"12345678\"}"); + test_cryptomatte_manifest("{\"Object\":\"12345678\",\"Object2\":\"87654321\"}", + "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}"); test_cryptomatte_manifest( - R"({"Object\"01\"":"12345678","Object":"12345678","Object2":"87654321"})", - R"({"Object\"01\"":"12345678","Object":"12345678", "Object2":"87654321"})"); + "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}", + " { \"Object\" : \"12345678\" , \"Object2\" : \"87654321\" } "); + test_cryptomatte_manifest("{\"Object\\\"01\\\"\":\"12345678\"}", + "{\"Object\\\"01\\\"\": \"12345678\"}"); + test_cryptomatte_manifest( + "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\",\"Object2\":\"87654321\"}", + "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\", \"Object2\":\"87654321\"}"); } TEST(cryptomatte, extract_layer_hash_from_metadata_key) @@ -151,10 +153,10 @@ TEST(cryptomatte, session_from_stamp_data) MEM_callocN(sizeof(RenderResult), __func__)); BKE_render_result_stamp_data(render_result, "cryptomatte/qwerty/name", "layer1"); BKE_render_result_stamp_data( - render_result, "cryptomatte/qwerty/manifest", R"({"Object":"12345678"})"); + render_result, "cryptomatte/qwerty/manifest", "{\"Object\":\"12345678\"}"); BKE_render_result_stamp_data(render_result, "cryptomatte/uiop/name", "layer2"); BKE_render_result_stamp_data( - render_result, "cryptomatte/uiop/manifest", R"({"Object2":"87654321"})"); + render_result, "cryptomatte/uiop/manifest", "{\"Object2\":\"87654321\"}"); CryptomatteSession *session = BKE_cryptomatte_init_from_render_result(render_result); EXPECT_NE(session, nullptr); RE_FreeRenderResult(render_result); diff --git a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc index aa3e183a382..d00e8bf55fd 100644 --- a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc +++ b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc @@ -333,37 +333,37 @@ void graph_draw(const std::string &label, } f << "
" << label << "
\n
\n" - << R"(n)"; + << "n"; for (const std::pair &e : edges) { const vec2 &uco = verts[e.first]; const vec2 &vco = verts[e.second]; int strokew = thin_line; - f << R"(\n)"; + f << "\n"; f << " [" << e.first << "][" << e.second << "]\n"; f << "\n"; if (draw_edge_labels) { - f << R"()"; + f << ""; f << "[" << e.first << "][" << e.second << "]\n"; } } int i = 0; for (const vec2 &vco : verts) { - f << R"(\n)"; + f << "\n"; f << " [" << i << "]" << vco << "\n"; f << "\n"; if (draw_vert_labels) { - f << R"([)" << i << "]\n"; + f << "[" << i << "]\n"; } ++i; } diff --git a/source/blender/blenlib/tests/BLI_string_test.cc b/source/blender/blenlib/tests/BLI_string_test.cc index 3f7db261ac0..88cecaa5fee 100644 --- a/source/blender/blenlib/tests/BLI_string_test.cc +++ b/source/blender/blenlib/tests/BLI_string_test.cc @@ -845,12 +845,12 @@ TEST_F(StringEscape, Simple) {"\\A", "\\\\A"}, {"A\\B", "A\\\\B"}, {"?", "?"}, - {R"("\)", R"(\"\\)"}, - {R"(\")", R"(\\\")"}, - {R"("\")", R"(\"\\\")"}, + {"\"\\", "\\\"\\\\"}, + {"\\\"", "\\\\\\\""}, + {"\"\\\"", "\\\"\\\\\\\""}, - {R"(""")", R"(\"\"\")"}, - {R"(\\\)", R"(\\\\\\)"}, + {"\"\"\"", "\\\"\\\"\\\""}, + {"\\\\\\", "\\\\\\\\\\\\"}, }; testEscapeWords(equal); @@ -868,9 +868,9 @@ TEST_F(StringEscape, Control) {"\f", "\\f"}, {"A\n", "A\\n"}, {"\nA", "\\nA"}, - {"\n\r\t\a\b\f", R"(\n\r\t\a\b\f)"}, - {"\n_\r_\t_\a_\b_\f", R"(\n_\r_\t_\a_\b_\f)"}, - {"\n\\\r\\\t\\\a\\\b\\\f", R"(\n\\\r\\\t\\\a\\\b\\\f)"}, + {"\n\r\t\a\b\f", "\\n\\r\\t\\a\\b\\f"}, + {"\n_\r_\t_\a_\b_\f", "\\n_\\r_\\t_\\a_\\b_\\f"}, + {"\n\\\r\\\t\\\a\\\b\\\f", "\\n\\\\\\r\\\\\\t\\\\\\a\\\\\\b\\\\\\f"}, }; testEscapeWords(escaped); diff --git a/source/blender/blenlib/tests/BLI_string_utf8_test.cc b/source/blender/blenlib/tests/BLI_string_utf8_test.cc index e93835ba1b6..1833945b3fd 100644 --- a/source/blender/blenlib/tests/BLI_string_utf8_test.cc +++ b/source/blender/blenlib/tests/BLI_string_utf8_test.cc @@ -92,12 +92,12 @@ const char *utf8_invalid_tests[][3] = { "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\" |", - "3.1.9 \"\" |", R"(@)"}, + "3.1.9 \"\" |", "\x40"}, /* 3.2 Lonely start characters * 3.2.1 All 32 first bytes of 2-byte sequences (0xc0-0xdf), each followed by a space character: */ {"3.2.1 \"\xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc \xcd \xce \xcf " "\xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc \xdd \xde \xdf \" |", - "3.2.1 \" \" |", R"( )"}, + "3.2.1 \" \" |", "\x20"}, /* 3.2.2 All 16 first bytes of 3-byte sequences (0xe0-0xef), each followed by a space character: */ {"3.2.2 \"\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef \" |", "3.2.2 \" \" |", "\x10"}, -- cgit v1.2.3 From 1775ea74c152ba7cf27a8bc1f071b40992c89013 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 8 Mar 2021 13:41:52 +0100 Subject: Cleanup: Change extension .cpp to .cc --- source/blender/compositor/CMakeLists.txt | 444 +++---- source/blender/compositor/intern/COM_CPUDevice.cc | 36 + source/blender/compositor/intern/COM_CPUDevice.cpp | 36 - source/blender/compositor/intern/COM_ChunkOrder.cc | 46 + .../blender/compositor/intern/COM_ChunkOrder.cpp | 46 - .../compositor/intern/COM_ChunkOrderHotspot.cc | 36 + .../compositor/intern/COM_ChunkOrderHotspot.cpp | 36 - .../compositor/intern/COM_CompositorContext.cc | 41 + .../compositor/intern/COM_CompositorContext.cpp | 41 - source/blender/compositor/intern/COM_Converter.cc | 562 ++++++++ source/blender/compositor/intern/COM_Converter.cpp | 562 -------- source/blender/compositor/intern/COM_Debug.cc | 532 ++++++++ source/blender/compositor/intern/COM_Debug.cpp | 532 -------- source/blender/compositor/intern/COM_Device.cc | 19 + source/blender/compositor/intern/COM_Device.cpp | 19 - .../compositor/intern/COM_ExecutionGroup.cc | 634 +++++++++ .../compositor/intern/COM_ExecutionGroup.cpp | 634 --------- .../compositor/intern/COM_ExecutionSystem.cc | 219 ++++ .../compositor/intern/COM_ExecutionSystem.cpp | 219 ---- .../blender/compositor/intern/COM_MemoryBuffer.cc | 227 ++++ .../blender/compositor/intern/COM_MemoryBuffer.cpp | 227 ---- .../blender/compositor/intern/COM_MemoryProxy.cc | 45 + .../blender/compositor/intern/COM_MemoryProxy.cpp | 45 - source/blender/compositor/intern/COM_MetaData.cc | 106 ++ source/blender/compositor/intern/COM_MetaData.cpp | 106 -- source/blender/compositor/intern/COM_Node.cc | 210 +++ source/blender/compositor/intern/COM_Node.cpp | 210 --- .../blender/compositor/intern/COM_NodeConverter.cc | 162 +++ .../compositor/intern/COM_NodeConverter.cpp | 162 --- source/blender/compositor/intern/COM_NodeGraph.cc | 333 +++++ source/blender/compositor/intern/COM_NodeGraph.cpp | 333 ----- .../blender/compositor/intern/COM_NodeOperation.cc | 244 ++++ .../compositor/intern/COM_NodeOperation.cpp | 244 ---- .../compositor/intern/COM_NodeOperationBuilder.cc | 722 ++++++++++ .../compositor/intern/COM_NodeOperationBuilder.cpp | 722 ---------- .../blender/compositor/intern/COM_OpenCLDevice.cc | 274 ++++ .../blender/compositor/intern/COM_OpenCLDevice.cpp | 274 ---- .../intern/COM_SingleThreadedOperation.cc | 58 + .../intern/COM_SingleThreadedOperation.cpp | 58 - .../blender/compositor/intern/COM_SocketReader.cc | 19 + .../blender/compositor/intern/COM_SocketReader.cpp | 19 - .../blender/compositor/intern/COM_WorkPackage.cc | 25 + .../blender/compositor/intern/COM_WorkPackage.cpp | 25 - .../blender/compositor/intern/COM_WorkScheduler.cc | 394 ++++++ .../compositor/intern/COM_WorkScheduler.cpp | 394 ------ source/blender/compositor/intern/COM_compositor.cc | 126 ++ .../blender/compositor/intern/COM_compositor.cpp | 126 -- .../blender/compositor/nodes/COM_AlphaOverNode.cc | 66 + .../blender/compositor/nodes/COM_AlphaOverNode.cpp | 66 - .../compositor/nodes/COM_BilateralBlurNode.cc | 41 + .../compositor/nodes/COM_BilateralBlurNode.cpp | 41 - source/blender/compositor/nodes/COM_BlurNode.cc | 170 +++ source/blender/compositor/nodes/COM_BlurNode.cpp | 170 --- .../blender/compositor/nodes/COM_BokehBlurNode.cc | 77 ++ .../blender/compositor/nodes/COM_BokehBlurNode.cpp | 77 -- .../blender/compositor/nodes/COM_BokehImageNode.cc | 38 + .../compositor/nodes/COM_BokehImageNode.cpp | 38 - source/blender/compositor/nodes/COM_BoxMaskNode.cc | 72 + .../blender/compositor/nodes/COM_BoxMaskNode.cpp | 72 - .../blender/compositor/nodes/COM_BrightnessNode.cc | 40 + .../compositor/nodes/COM_BrightnessNode.cpp | 40 - .../compositor/nodes/COM_ChannelMatteNode.cc | 95 ++ .../compositor/nodes/COM_ChannelMatteNode.cpp | 95 -- .../compositor/nodes/COM_ChromaMatteNode.cc | 65 + .../compositor/nodes/COM_ChromaMatteNode.cpp | 65 - .../compositor/nodes/COM_ColorBalanceNode.cc | 73 ++ .../compositor/nodes/COM_ColorBalanceNode.cpp | 73 -- .../compositor/nodes/COM_ColorCorrectionNode.cc | 43 + .../compositor/nodes/COM_ColorCorrectionNode.cpp | 43 - .../blender/compositor/nodes/COM_ColorCurveNode.cc | 57 + .../compositor/nodes/COM_ColorCurveNode.cpp | 57 - .../compositor/nodes/COM_ColorExposureNode.cc | 37 + .../compositor/nodes/COM_ColorExposureNode.cpp | 37 - .../blender/compositor/nodes/COM_ColorMatteNode.cc | 63 + .../compositor/nodes/COM_ColorMatteNode.cpp | 63 - source/blender/compositor/nodes/COM_ColorNode.cc | 39 + source/blender/compositor/nodes/COM_ColorNode.cpp | 39 - .../blender/compositor/nodes/COM_ColorRampNode.cc | 52 + .../blender/compositor/nodes/COM_ColorRampNode.cpp | 52 - .../blender/compositor/nodes/COM_ColorSpillNode.cc | 47 + .../compositor/nodes/COM_ColorSpillNode.cpp | 47 - .../blender/compositor/nodes/COM_ColorToBWNode.cc | 40 + .../blender/compositor/nodes/COM_ColorToBWNode.cpp | 40 - .../compositor/nodes/COM_CombineColorNode.cc | 89 ++ .../compositor/nodes/COM_CombineColorNode.cpp | 89 -- .../blender/compositor/nodes/COM_CompositorNode.cc | 61 + .../compositor/nodes/COM_CompositorNode.cpp | 61 - .../compositor/nodes/COM_ConvertAlphaNode.cc | 41 + .../compositor/nodes/COM_ConvertAlphaNode.cpp | 41 - .../blender/compositor/nodes/COM_CornerPinNode.cc | 55 + .../blender/compositor/nodes/COM_CornerPinNode.cpp | 55 - source/blender/compositor/nodes/COM_CropNode.cc | 47 + source/blender/compositor/nodes/COM_CropNode.cpp | 47 - .../compositor/nodes/COM_CryptomatteNode.cc | 80 ++ .../compositor/nodes/COM_CryptomatteNode.cpp | 80 -- source/blender/compositor/nodes/COM_DefocusNode.cc | 143 ++ .../blender/compositor/nodes/COM_DefocusNode.cpp | 143 -- source/blender/compositor/nodes/COM_DenoiseNode.cc | 43 + .../blender/compositor/nodes/COM_DenoiseNode.cpp | 43 - .../blender/compositor/nodes/COM_DespeckleNode.cc | 48 + .../blender/compositor/nodes/COM_DespeckleNode.cpp | 48 - .../compositor/nodes/COM_DifferenceMatteNode.cc | 54 + .../compositor/nodes/COM_DifferenceMatteNode.cpp | 54 - .../compositor/nodes/COM_DilateErodeNode.cc | 149 +++ .../compositor/nodes/COM_DilateErodeNode.cpp | 149 --- .../compositor/nodes/COM_DirectionalBlurNode.cc | 40 + .../compositor/nodes/COM_DirectionalBlurNode.cpp | 40 - .../blender/compositor/nodes/COM_DisplaceNode.cc | 46 + .../blender/compositor/nodes/COM_DisplaceNode.cpp | 46 - .../compositor/nodes/COM_DistanceMatteNode.cc | 98 ++ .../compositor/nodes/COM_DistanceMatteNode.cpp | 98 -- .../compositor/nodes/COM_DoubleEdgeMaskNode.cc | 42 + .../compositor/nodes/COM_DoubleEdgeMaskNode.cpp | 42 - .../compositor/nodes/COM_EllipseMaskNode.cc | 72 + .../compositor/nodes/COM_EllipseMaskNode.cpp | 72 - source/blender/compositor/nodes/COM_FilterNode.cc | 96 ++ source/blender/compositor/nodes/COM_FilterNode.cpp | 96 -- source/blender/compositor/nodes/COM_FlipNode.cc | 54 + source/blender/compositor/nodes/COM_FlipNode.cpp | 54 - source/blender/compositor/nodes/COM_GammaNode.cc | 37 + source/blender/compositor/nodes/COM_GammaNode.cpp | 37 - source/blender/compositor/nodes/COM_GlareNode.cc | 82 ++ source/blender/compositor/nodes/COM_GlareNode.cpp | 82 -- .../nodes/COM_HueSaturationValueCorrectNode.cc | 64 + .../nodes/COM_HueSaturationValueCorrectNode.cpp | 64 - .../compositor/nodes/COM_HueSaturationValueNode.cc | 67 + .../nodes/COM_HueSaturationValueNode.cpp | 67 - source/blender/compositor/nodes/COM_IDMaskNode.cc | 49 + source/blender/compositor/nodes/COM_IDMaskNode.cpp | 49 - source/blender/compositor/nodes/COM_ImageNode.cc | 299 +++++ source/blender/compositor/nodes/COM_ImageNode.cpp | 299 ----- source/blender/compositor/nodes/COM_InpaintNode.cc | 45 + .../blender/compositor/nodes/COM_InpaintNode.cpp | 45 - source/blender/compositor/nodes/COM_InvertNode.cc | 41 + source/blender/compositor/nodes/COM_InvertNode.cpp | 41 - source/blender/compositor/nodes/COM_KeyingNode.cc | 350 +++++ source/blender/compositor/nodes/COM_KeyingNode.cpp | 350 ----- .../compositor/nodes/COM_KeyingScreenNode.cc | 47 + .../compositor/nodes/COM_KeyingScreenNode.cpp | 47 - .../compositor/nodes/COM_LensDistortionNode.cc | 61 + .../compositor/nodes/COM_LensDistortionNode.cpp | 61 - .../compositor/nodes/COM_LuminanceMatteNode.cc | 53 + .../compositor/nodes/COM_LuminanceMatteNode.cpp | 53 - .../blender/compositor/nodes/COM_MapRangeNode.cc | 49 + .../blender/compositor/nodes/COM_MapRangeNode.cpp | 49 - source/blender/compositor/nodes/COM_MapUVNode.cc | 41 + source/blender/compositor/nodes/COM_MapUVNode.cpp | 41 - .../blender/compositor/nodes/COM_MapValueNode.cc | 43 + .../blender/compositor/nodes/COM_MapValueNode.cpp | 43 - source/blender/compositor/nodes/COM_MaskNode.cc | 70 + source/blender/compositor/nodes/COM_MaskNode.cpp | 70 - source/blender/compositor/nodes/COM_MathNode.cc | 161 +++ source/blender/compositor/nodes/COM_MathNode.cpp | 161 --- source/blender/compositor/nodes/COM_MixNode.cc | 112 ++ source/blender/compositor/nodes/COM_MixNode.cpp | 112 -- .../blender/compositor/nodes/COM_MovieClipNode.cc | 108 ++ .../blender/compositor/nodes/COM_MovieClipNode.cpp | 108 -- .../compositor/nodes/COM_MovieDistortionNode.cc | 46 + .../compositor/nodes/COM_MovieDistortionNode.cpp | 46 - source/blender/compositor/nodes/COM_NormalNode.cc | 56 + source/blender/compositor/nodes/COM_NormalNode.cpp | 56 - .../blender/compositor/nodes/COM_NormalizeNode.cc | 36 + .../blender/compositor/nodes/COM_NormalizeNode.cpp | 36 - .../blender/compositor/nodes/COM_OutputFileNode.cc | 153 +++ .../compositor/nodes/COM_OutputFileNode.cpp | 153 --- .../blender/compositor/nodes/COM_PixelateNode.cc | 46 + .../blender/compositor/nodes/COM_PixelateNode.cpp | 46 - .../compositor/nodes/COM_PlaneTrackDeformNode.cc | 72 + .../compositor/nodes/COM_PlaneTrackDeformNode.cpp | 72 - .../compositor/nodes/COM_RenderLayersNode.cc | 176 +++ .../compositor/nodes/COM_RenderLayersNode.cpp | 176 --- source/blender/compositor/nodes/COM_RotateNode.cc | 47 + source/blender/compositor/nodes/COM_RotateNode.cpp | 47 - source/blender/compositor/nodes/COM_ScaleNode.cc | 107 ++ source/blender/compositor/nodes/COM_ScaleNode.cpp | 107 -- .../compositor/nodes/COM_SeparateColorNode.cc | 121 ++ .../compositor/nodes/COM_SeparateColorNode.cpp | 121 -- .../blender/compositor/nodes/COM_SetAlphaNode.cc | 48 + .../blender/compositor/nodes/COM_SetAlphaNode.cpp | 48 - .../compositor/nodes/COM_SocketProxyNode.cc | 103 ++ .../compositor/nodes/COM_SocketProxyNode.cpp | 103 -- .../compositor/nodes/COM_SplitViewerNode.cc | 75 ++ .../compositor/nodes/COM_SplitViewerNode.cpp | 75 -- .../compositor/nodes/COM_Stabilize2dNode.cc | 113 ++ .../compositor/nodes/COM_Stabilize2dNode.cpp | 113 -- .../blender/compositor/nodes/COM_SunBeamsNode.cc | 39 + .../blender/compositor/nodes/COM_SunBeamsNode.cpp | 39 - source/blender/compositor/nodes/COM_SwitchNode.cc | 40 + source/blender/compositor/nodes/COM_SwitchNode.cpp | 40 - .../blender/compositor/nodes/COM_SwitchViewNode.cc | 40 + .../compositor/nodes/COM_SwitchViewNode.cpp | 40 - source/blender/compositor/nodes/COM_TextureNode.cc | 56 + .../blender/compositor/nodes/COM_TextureNode.cpp | 56 - source/blender/compositor/nodes/COM_TimeNode.cc | 58 + source/blender/compositor/nodes/COM_TimeNode.cpp | 58 - source/blender/compositor/nodes/COM_TonemapNode.cc | 40 + .../blender/compositor/nodes/COM_TonemapNode.cpp | 40 - .../compositor/nodes/COM_TrackPositionNode.cc | 111 ++ .../compositor/nodes/COM_TrackPositionNode.cpp | 111 -- .../blender/compositor/nodes/COM_TransformNode.cc | 68 + .../blender/compositor/nodes/COM_TransformNode.cpp | 68 - .../blender/compositor/nodes/COM_TranslateNode.cc | 71 + .../blender/compositor/nodes/COM_TranslateNode.cpp | 71 - source/blender/compositor/nodes/COM_ValueNode.cc | 37 + source/blender/compositor/nodes/COM_ValueNode.cpp | 37 - .../blender/compositor/nodes/COM_VectorBlurNode.cc | 43 + .../compositor/nodes/COM_VectorBlurNode.cpp | 43 - .../compositor/nodes/COM_VectorCurveNode.cc | 37 + .../compositor/nodes/COM_VectorCurveNode.cpp | 37 - .../blender/compositor/nodes/COM_ViewLevelsNode.cc | 61 + .../compositor/nodes/COM_ViewLevelsNode.cpp | 61 - source/blender/compositor/nodes/COM_ViewerNode.cc | 84 ++ source/blender/compositor/nodes/COM_ViewerNode.cpp | 84 -- .../blender/compositor/nodes/COM_ZCombineNode.cc | 101 ++ .../blender/compositor/nodes/COM_ZCombineNode.cpp | 101 -- .../operations/COM_AlphaOverKeyOperation.cc | 54 + .../operations/COM_AlphaOverKeyOperation.cpp | 54 - .../operations/COM_AlphaOverMixedOperation.cc | 55 + .../operations/COM_AlphaOverMixedOperation.cpp | 55 - .../COM_AlphaOverPremultiplyOperation.cc | 54 + .../COM_AlphaOverPremultiplyOperation.cpp | 54 - .../operations/COM_AntiAliasOperation.cc | 201 +++ .../operations/COM_AntiAliasOperation.cpp | 201 --- .../operations/COM_BilateralBlurOperation.cc | 114 ++ .../operations/COM_BilateralBlurOperation.cpp | 114 -- .../compositor/operations/COM_BlurBaseOperation.cc | 184 +++ .../operations/COM_BlurBaseOperation.cpp | 184 --- .../operations/COM_BokehBlurOperation.cc | 242 ++++ .../operations/COM_BokehBlurOperation.cpp | 242 ---- .../operations/COM_BokehImageOperation.cc | 126 ++ .../operations/COM_BokehImageOperation.cpp | 126 -- .../compositor/operations/COM_BoxMaskOperation.cc | 110 ++ .../compositor/operations/COM_BoxMaskOperation.cpp | 110 -- .../operations/COM_BrightnessOperation.cc | 91 ++ .../operations/COM_BrightnessOperation.cpp | 91 -- .../operations/COM_CalculateMeanOperation.cc | 127 ++ .../operations/COM_CalculateMeanOperation.cpp | 127 -- .../COM_CalculateStandardDeviationOperation.cc | 100 ++ .../COM_CalculateStandardDeviationOperation.cpp | 100 -- .../operations/COM_ChangeHSVOperation.cc | 70 + .../operations/COM_ChangeHSVOperation.cpp | 70 - .../operations/COM_ChannelMatteOperation.cc | 120 ++ .../operations/COM_ChannelMatteOperation.cpp | 120 -- .../operations/COM_ChromaMatteOperation.cc | 109 ++ .../operations/COM_ChromaMatteOperation.cpp | 109 -- .../operations/COM_ColorBalanceASCCDLOperation.cc | 81 ++ .../operations/COM_ColorBalanceASCCDLOperation.cpp | 81 -- .../operations/COM_ColorBalanceLGGOperation.cc | 86 ++ .../operations/COM_ColorBalanceLGGOperation.cpp | 86 -- .../operations/COM_ColorCorrectionOperation.cc | 162 +++ .../operations/COM_ColorCorrectionOperation.cpp | 162 --- .../operations/COM_ColorCurveOperation.cc | 153 +++ .../operations/COM_ColorCurveOperation.cpp | 153 --- .../operations/COM_ColorExposureOperation.cc | 57 + .../operations/COM_ColorExposureOperation.cpp | 57 - .../operations/COM_ColorMatteOperation.cc | 81 ++ .../operations/COM_ColorMatteOperation.cpp | 81 -- .../operations/COM_ColorRampOperation.cc | 50 + .../operations/COM_ColorRampOperation.cpp | 50 - .../operations/COM_ColorSpillOperation.cc | 117 ++ .../operations/COM_ColorSpillOperation.cpp | 117 -- .../operations/COM_CompositorOperation.cc | 244 ++++ .../operations/COM_CompositorOperation.cpp | 244 ---- .../operations/COM_ConvertColorProfileOperation.cc | 50 + .../COM_ConvertColorProfileOperation.cpp | 50 - .../COM_ConvertDepthToRadiusOperation.cc | 115 ++ .../COM_ConvertDepthToRadiusOperation.cpp | 115 -- .../compositor/operations/COM_ConvertOperation.cc | 480 +++++++ .../compositor/operations/COM_ConvertOperation.cpp | 480 ------- .../COM_ConvolutionEdgeFilterOperation.cc | 99 ++ .../COM_ConvolutionEdgeFilterOperation.cpp | 99 -- .../operations/COM_ConvolutionFilterOperation.cc | 126 ++ .../operations/COM_ConvolutionFilterOperation.cpp | 126 -- .../compositor/operations/COM_CropOperation.cc | 135 ++ .../compositor/operations/COM_CropOperation.cpp | 135 -- .../operations/COM_CryptomatteOperation.cc | 70 + .../operations/COM_CryptomatteOperation.cpp | 70 - .../operations/COM_CurveBaseOperation.cc | 55 + .../operations/COM_CurveBaseOperation.cpp | 55 - .../compositor/operations/COM_DenoiseOperation.cc | 166 +++ .../compositor/operations/COM_DenoiseOperation.cpp | 166 --- .../operations/COM_DespeckleOperation.cc | 143 ++ .../operations/COM_DespeckleOperation.cpp | 143 -- .../operations/COM_DifferenceMatteOperation.cc | 85 ++ .../operations/COM_DifferenceMatteOperation.cpp | 85 -- .../operations/COM_DilateErodeOperation.cc | 570 ++++++++ .../operations/COM_DilateErodeOperation.cpp | 570 -------- .../operations/COM_DirectionalBlurOperation.cc | 146 +++ .../operations/COM_DirectionalBlurOperation.cpp | 146 --- .../compositor/operations/COM_DisplaceOperation.cc | 194 +++ .../operations/COM_DisplaceOperation.cpp | 194 --- .../operations/COM_DisplaceSimpleOperation.cc | 131 ++ .../operations/COM_DisplaceSimpleOperation.cpp | 131 -- .../operations/COM_DistanceRGBMatteOperation.cc | 92 ++ .../operations/COM_DistanceRGBMatteOperation.cpp | 92 -- .../operations/COM_DistanceYCCMatteOperation.cc | 31 + .../operations/COM_DistanceYCCMatteOperation.cpp | 31 - .../operations/COM_DotproductOperation.cc | 54 + .../operations/COM_DotproductOperation.cpp | 54 - .../operations/COM_DoubleEdgeMaskOperation.cc | 1381 ++++++++++++++++++++ .../operations/COM_DoubleEdgeMaskOperation.cpp | 1381 -------------------- .../operations/COM_EllipseMaskOperation.cc | 119 ++ .../operations/COM_EllipseMaskOperation.cpp | 119 -- .../operations/COM_FastGaussianBlurOperation.cc | 343 +++++ .../operations/COM_FastGaussianBlurOperation.cpp | 343 ----- .../compositor/operations/COM_FlipOperation.cc | 74 ++ .../compositor/operations/COM_FlipOperation.cpp | 74 -- .../operations/COM_GammaCorrectOperation.cc | 104 ++ .../operations/COM_GammaCorrectOperation.cpp | 104 -- .../compositor/operations/COM_GammaOperation.cc | 56 + .../compositor/operations/COM_GammaOperation.cpp | 56 - .../operations/COM_GaussianAlphaXBlurOperation.cc | 191 +++ .../operations/COM_GaussianAlphaXBlurOperation.cpp | 191 --- .../operations/COM_GaussianAlphaYBlurOperation.cc | 191 +++ .../operations/COM_GaussianAlphaYBlurOperation.cpp | 191 --- .../operations/COM_GaussianBokehBlurOperation.cc | 361 +++++ .../operations/COM_GaussianBokehBlurOperation.cpp | 361 ----- .../operations/COM_GaussianXBlurOperation.cc | 207 +++ .../operations/COM_GaussianXBlurOperation.cpp | 207 --- .../operations/COM_GaussianYBlurOperation.cc | 207 +++ .../operations/COM_GaussianYBlurOperation.cpp | 207 --- .../operations/COM_GlareBaseOperation.cc | 68 + .../operations/COM_GlareBaseOperation.cpp | 68 - .../operations/COM_GlareFogGlowOperation.cc | 444 +++++++ .../operations/COM_GlareFogGlowOperation.cpp | 444 ------- .../operations/COM_GlareGhostOperation.cc | 159 +++ .../operations/COM_GlareGhostOperation.cpp | 159 --- .../operations/COM_GlareSimpleStarOperation.cc | 102 ++ .../operations/COM_GlareSimpleStarOperation.cpp | 102 -- .../operations/COM_GlareStreaksOperation.cc | 102 ++ .../operations/COM_GlareStreaksOperation.cpp | 102 -- .../operations/COM_GlareThresholdOperation.cc | 69 + .../operations/COM_GlareThresholdOperation.cpp | 69 - .../COM_HueSaturationValueCorrectOperation.cc | 72 + .../COM_HueSaturationValueCorrectOperation.cpp | 72 - .../compositor/operations/COM_IDMaskOperation.cc | 41 + .../compositor/operations/COM_IDMaskOperation.cpp | 41 - .../compositor/operations/COM_ImageOperation.cc | 205 +++ .../compositor/operations/COM_ImageOperation.cpp | 205 --- .../compositor/operations/COM_InpaintOperation.cc | 284 ++++ .../compositor/operations/COM_InpaintOperation.cpp | 284 ---- .../compositor/operations/COM_InvertOperation.cc | 69 + .../compositor/operations/COM_InvertOperation.cpp | 69 - .../operations/COM_KeyingBlurOperation.cc | 95 ++ .../operations/COM_KeyingBlurOperation.cpp | 95 -- .../operations/COM_KeyingClipOperation.cc | 129 ++ .../operations/COM_KeyingClipOperation.cpp | 129 -- .../operations/COM_KeyingDespillOperation.cc | 81 ++ .../operations/COM_KeyingDespillOperation.cpp | 81 -- .../compositor/operations/COM_KeyingOperation.cc | 109 ++ .../compositor/operations/COM_KeyingOperation.cpp | 109 -- .../operations/COM_KeyingScreenOperation.cc | 346 +++++ .../operations/COM_KeyingScreenOperation.cpp | 346 ----- .../operations/COM_LuminanceMatteOperation.cc | 77 ++ .../operations/COM_LuminanceMatteOperation.cpp | 77 -- .../compositor/operations/COM_MapRangeOperation.cc | 103 ++ .../operations/COM_MapRangeOperation.cpp | 103 -- .../compositor/operations/COM_MapUVOperation.cc | 185 +++ .../compositor/operations/COM_MapUVOperation.cpp | 185 --- .../compositor/operations/COM_MapValueOperation.cc | 59 + .../operations/COM_MapValueOperation.cpp | 59 - .../compositor/operations/COM_MaskOperation.cc | 160 +++ .../compositor/operations/COM_MaskOperation.cpp | 160 --- .../compositor/operations/COM_MathBaseOperation.cc | 750 +++++++++++ .../operations/COM_MathBaseOperation.cpp | 750 ----------- .../compositor/operations/COM_MixOperation.cc | 946 ++++++++++++++ .../compositor/operations/COM_MixOperation.cpp | 946 -------------- .../operations/COM_MovieClipAttributeOperation.cc | 82 ++ .../operations/COM_MovieClipAttributeOperation.cpp | 82 -- .../operations/COM_MovieClipOperation.cc | 135 ++ .../operations/COM_MovieClipOperation.cpp | 135 -- .../operations/COM_MovieDistortionOperation.cc | 127 ++ .../operations/COM_MovieDistortionOperation.cpp | 127 -- .../operations/COM_MultilayerImageOperation.cc | 157 +++ .../operations/COM_MultilayerImageOperation.cpp | 157 --- .../operations/COM_NormalizeOperation.cc | 126 ++ .../operations/COM_NormalizeOperation.cpp | 126 -- .../operations/COM_OutputFileMultiViewOperation.cc | 382 ++++++ .../COM_OutputFileMultiViewOperation.cpp | 382 ------ .../operations/COM_OutputFileOperation.cc | 443 +++++++ .../operations/COM_OutputFileOperation.cpp | 443 ------- .../compositor/operations/COM_PixelateOperation.cc | 47 + .../operations/COM_PixelateOperation.cpp | 47 - .../operations/COM_PlaneCornerPinOperation.cc | 226 ++++ .../operations/COM_PlaneCornerPinOperation.cpp | 226 ---- .../operations/COM_PlaneDistortCommonOperation.cc | 228 ++++ .../operations/COM_PlaneDistortCommonOperation.cpp | 228 ---- .../operations/COM_PlaneTrackOperation.cc | 123 ++ .../operations/COM_PlaneTrackOperation.cpp | 123 -- .../compositor/operations/COM_PreviewOperation.cc | 161 +++ .../compositor/operations/COM_PreviewOperation.cpp | 161 --- .../COM_ProjectorLensDistortionOperation.cc | 113 ++ .../COM_ProjectorLensDistortionOperation.cpp | 113 -- .../compositor/operations/COM_QualityStepHelper.cc | 66 + .../operations/COM_QualityStepHelper.cpp | 66 - .../operations/COM_ReadBufferOperation.cc | 133 ++ .../operations/COM_ReadBufferOperation.cpp | 133 -- .../compositor/operations/COM_RenderLayersProg.cc | 308 +++++ .../compositor/operations/COM_RenderLayersProg.cpp | 308 ----- .../compositor/operations/COM_RotateOperation.cc | 107 ++ .../compositor/operations/COM_RotateOperation.cpp | 107 -- .../compositor/operations/COM_ScaleOperation.cc | 310 +++++ .../compositor/operations/COM_ScaleOperation.cpp | 310 ----- .../COM_ScreenLensDistortionOperation.cc | 353 +++++ .../COM_ScreenLensDistortionOperation.cpp | 353 ----- .../operations/COM_SetAlphaMultiplyOperation.cc | 55 + .../operations/COM_SetAlphaMultiplyOperation.cpp | 55 - .../operations/COM_SetAlphaReplaceOperation.cc | 53 + .../operations/COM_SetAlphaReplaceOperation.cpp | 53 - .../compositor/operations/COM_SetColorOperation.cc | 39 + .../operations/COM_SetColorOperation.cpp | 39 - .../operations/COM_SetSamplerOperation.cc | 42 + .../operations/COM_SetSamplerOperation.cpp | 42 - .../compositor/operations/COM_SetValueOperation.cc | 39 + .../operations/COM_SetValueOperation.cpp | 39 - .../operations/COM_SetVectorOperation.cc | 42 + .../operations/COM_SetVectorOperation.cpp | 42 - .../operations/COM_SocketProxyOperation.cc | 31 + .../operations/COM_SocketProxyOperation.cpp | 31 - .../compositor/operations/COM_SplitOperation.cc | 78 ++ .../compositor/operations/COM_SplitOperation.cpp | 78 -- .../compositor/operations/COM_SunBeamsOperation.cc | 355 +++++ .../operations/COM_SunBeamsOperation.cpp | 355 ----- .../compositor/operations/COM_TextureOperation.cc | 157 +++ .../compositor/operations/COM_TextureOperation.cpp | 157 --- .../compositor/operations/COM_TonemapOperation.cc | 152 +++ .../compositor/operations/COM_TonemapOperation.cpp | 152 --- .../operations/COM_TrackPositionOperation.cc | 136 ++ .../operations/COM_TrackPositionOperation.cpp | 136 -- .../operations/COM_TranslateOperation.cc | 82 ++ .../operations/COM_TranslateOperation.cpp | 82 -- .../COM_VariableSizeBokehBlurOperation.cc | 383 ++++++ .../COM_VariableSizeBokehBlurOperation.cpp | 383 ------ .../operations/COM_VectorBlurOperation.cc | 899 +++++++++++++ .../operations/COM_VectorBlurOperation.cpp | 899 ------------- .../operations/COM_VectorCurveOperation.cc | 52 + .../operations/COM_VectorCurveOperation.cpp | 52 - .../compositor/operations/COM_ViewerOperation.cc | 204 +++ .../compositor/operations/COM_ViewerOperation.cpp | 204 --- .../compositor/operations/COM_WrapOperation.cc | 117 ++ .../compositor/operations/COM_WrapOperation.cpp | 117 -- .../operations/COM_WriteBufferOperation.cc | 228 ++++ .../operations/COM_WriteBufferOperation.cpp | 228 ---- .../compositor/operations/COM_ZCombineOperation.cc | 160 +++ .../operations/COM_ZCombineOperation.cpp | 160 --- 445 files changed, 31879 insertions(+), 31879 deletions(-) create mode 100644 source/blender/compositor/intern/COM_CPUDevice.cc delete mode 100644 source/blender/compositor/intern/COM_CPUDevice.cpp create mode 100644 source/blender/compositor/intern/COM_ChunkOrder.cc delete mode 100644 source/blender/compositor/intern/COM_ChunkOrder.cpp create mode 100644 source/blender/compositor/intern/COM_ChunkOrderHotspot.cc delete mode 100644 source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp create mode 100644 source/blender/compositor/intern/COM_CompositorContext.cc delete mode 100644 source/blender/compositor/intern/COM_CompositorContext.cpp create mode 100644 source/blender/compositor/intern/COM_Converter.cc delete mode 100644 source/blender/compositor/intern/COM_Converter.cpp create mode 100644 source/blender/compositor/intern/COM_Debug.cc delete mode 100644 source/blender/compositor/intern/COM_Debug.cpp create mode 100644 source/blender/compositor/intern/COM_Device.cc delete mode 100644 source/blender/compositor/intern/COM_Device.cpp create mode 100644 source/blender/compositor/intern/COM_ExecutionGroup.cc delete mode 100644 source/blender/compositor/intern/COM_ExecutionGroup.cpp create mode 100644 source/blender/compositor/intern/COM_ExecutionSystem.cc delete mode 100644 source/blender/compositor/intern/COM_ExecutionSystem.cpp create mode 100644 source/blender/compositor/intern/COM_MemoryBuffer.cc delete mode 100644 source/blender/compositor/intern/COM_MemoryBuffer.cpp create mode 100644 source/blender/compositor/intern/COM_MemoryProxy.cc delete mode 100644 source/blender/compositor/intern/COM_MemoryProxy.cpp create mode 100644 source/blender/compositor/intern/COM_MetaData.cc delete mode 100644 source/blender/compositor/intern/COM_MetaData.cpp create mode 100644 source/blender/compositor/intern/COM_Node.cc delete mode 100644 source/blender/compositor/intern/COM_Node.cpp create mode 100644 source/blender/compositor/intern/COM_NodeConverter.cc delete mode 100644 source/blender/compositor/intern/COM_NodeConverter.cpp create mode 100644 source/blender/compositor/intern/COM_NodeGraph.cc delete mode 100644 source/blender/compositor/intern/COM_NodeGraph.cpp create mode 100644 source/blender/compositor/intern/COM_NodeOperation.cc delete mode 100644 source/blender/compositor/intern/COM_NodeOperation.cpp create mode 100644 source/blender/compositor/intern/COM_NodeOperationBuilder.cc delete mode 100644 source/blender/compositor/intern/COM_NodeOperationBuilder.cpp create mode 100644 source/blender/compositor/intern/COM_OpenCLDevice.cc delete mode 100644 source/blender/compositor/intern/COM_OpenCLDevice.cpp create mode 100644 source/blender/compositor/intern/COM_SingleThreadedOperation.cc delete mode 100644 source/blender/compositor/intern/COM_SingleThreadedOperation.cpp create mode 100644 source/blender/compositor/intern/COM_SocketReader.cc delete mode 100644 source/blender/compositor/intern/COM_SocketReader.cpp create mode 100644 source/blender/compositor/intern/COM_WorkPackage.cc delete mode 100644 source/blender/compositor/intern/COM_WorkPackage.cpp create mode 100644 source/blender/compositor/intern/COM_WorkScheduler.cc delete mode 100644 source/blender/compositor/intern/COM_WorkScheduler.cpp create mode 100644 source/blender/compositor/intern/COM_compositor.cc delete mode 100644 source/blender/compositor/intern/COM_compositor.cpp create mode 100644 source/blender/compositor/nodes/COM_AlphaOverNode.cc delete mode 100644 source/blender/compositor/nodes/COM_AlphaOverNode.cpp create mode 100644 source/blender/compositor/nodes/COM_BilateralBlurNode.cc delete mode 100644 source/blender/compositor/nodes/COM_BilateralBlurNode.cpp create mode 100644 source/blender/compositor/nodes/COM_BlurNode.cc delete mode 100644 source/blender/compositor/nodes/COM_BlurNode.cpp create mode 100644 source/blender/compositor/nodes/COM_BokehBlurNode.cc delete mode 100644 source/blender/compositor/nodes/COM_BokehBlurNode.cpp create mode 100644 source/blender/compositor/nodes/COM_BokehImageNode.cc delete mode 100644 source/blender/compositor/nodes/COM_BokehImageNode.cpp create mode 100644 source/blender/compositor/nodes/COM_BoxMaskNode.cc delete mode 100644 source/blender/compositor/nodes/COM_BoxMaskNode.cpp create mode 100644 source/blender/compositor/nodes/COM_BrightnessNode.cc delete mode 100644 source/blender/compositor/nodes/COM_BrightnessNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ChannelMatteNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ChannelMatteNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ChromaMatteNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ChromaMatteNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ColorBalanceNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ColorBalanceNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ColorCorrectionNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ColorCurveNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ColorCurveNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ColorExposureNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ColorExposureNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ColorMatteNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ColorMatteNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ColorNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ColorNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ColorRampNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ColorRampNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ColorSpillNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ColorSpillNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ColorToBWNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ColorToBWNode.cpp create mode 100644 source/blender/compositor/nodes/COM_CombineColorNode.cc delete mode 100644 source/blender/compositor/nodes/COM_CombineColorNode.cpp create mode 100644 source/blender/compositor/nodes/COM_CompositorNode.cc delete mode 100644 source/blender/compositor/nodes/COM_CompositorNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ConvertAlphaNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp create mode 100644 source/blender/compositor/nodes/COM_CornerPinNode.cc delete mode 100644 source/blender/compositor/nodes/COM_CornerPinNode.cpp create mode 100644 source/blender/compositor/nodes/COM_CropNode.cc delete mode 100644 source/blender/compositor/nodes/COM_CropNode.cpp create mode 100644 source/blender/compositor/nodes/COM_CryptomatteNode.cc delete mode 100644 source/blender/compositor/nodes/COM_CryptomatteNode.cpp create mode 100644 source/blender/compositor/nodes/COM_DefocusNode.cc delete mode 100644 source/blender/compositor/nodes/COM_DefocusNode.cpp create mode 100644 source/blender/compositor/nodes/COM_DenoiseNode.cc delete mode 100644 source/blender/compositor/nodes/COM_DenoiseNode.cpp create mode 100644 source/blender/compositor/nodes/COM_DespeckleNode.cc delete mode 100644 source/blender/compositor/nodes/COM_DespeckleNode.cpp create mode 100644 source/blender/compositor/nodes/COM_DifferenceMatteNode.cc delete mode 100644 source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp create mode 100644 source/blender/compositor/nodes/COM_DilateErodeNode.cc delete mode 100644 source/blender/compositor/nodes/COM_DilateErodeNode.cpp create mode 100644 source/blender/compositor/nodes/COM_DirectionalBlurNode.cc delete mode 100644 source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp create mode 100644 source/blender/compositor/nodes/COM_DisplaceNode.cc delete mode 100644 source/blender/compositor/nodes/COM_DisplaceNode.cpp create mode 100644 source/blender/compositor/nodes/COM_DistanceMatteNode.cc delete mode 100644 source/blender/compositor/nodes/COM_DistanceMatteNode.cpp create mode 100644 source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc delete mode 100644 source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp create mode 100644 source/blender/compositor/nodes/COM_EllipseMaskNode.cc delete mode 100644 source/blender/compositor/nodes/COM_EllipseMaskNode.cpp create mode 100644 source/blender/compositor/nodes/COM_FilterNode.cc delete mode 100644 source/blender/compositor/nodes/COM_FilterNode.cpp create mode 100644 source/blender/compositor/nodes/COM_FlipNode.cc delete mode 100644 source/blender/compositor/nodes/COM_FlipNode.cpp create mode 100644 source/blender/compositor/nodes/COM_GammaNode.cc delete mode 100644 source/blender/compositor/nodes/COM_GammaNode.cpp create mode 100644 source/blender/compositor/nodes/COM_GlareNode.cc delete mode 100644 source/blender/compositor/nodes/COM_GlareNode.cpp create mode 100644 source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc delete mode 100644 source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp create mode 100644 source/blender/compositor/nodes/COM_HueSaturationValueNode.cc delete mode 100644 source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp create mode 100644 source/blender/compositor/nodes/COM_IDMaskNode.cc delete mode 100644 source/blender/compositor/nodes/COM_IDMaskNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ImageNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ImageNode.cpp create mode 100644 source/blender/compositor/nodes/COM_InpaintNode.cc delete mode 100644 source/blender/compositor/nodes/COM_InpaintNode.cpp create mode 100644 source/blender/compositor/nodes/COM_InvertNode.cc delete mode 100644 source/blender/compositor/nodes/COM_InvertNode.cpp create mode 100644 source/blender/compositor/nodes/COM_KeyingNode.cc delete mode 100644 source/blender/compositor/nodes/COM_KeyingNode.cpp create mode 100644 source/blender/compositor/nodes/COM_KeyingScreenNode.cc delete mode 100644 source/blender/compositor/nodes/COM_KeyingScreenNode.cpp create mode 100644 source/blender/compositor/nodes/COM_LensDistortionNode.cc delete mode 100644 source/blender/compositor/nodes/COM_LensDistortionNode.cpp create mode 100644 source/blender/compositor/nodes/COM_LuminanceMatteNode.cc delete mode 100644 source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp create mode 100644 source/blender/compositor/nodes/COM_MapRangeNode.cc delete mode 100644 source/blender/compositor/nodes/COM_MapRangeNode.cpp create mode 100644 source/blender/compositor/nodes/COM_MapUVNode.cc delete mode 100644 source/blender/compositor/nodes/COM_MapUVNode.cpp create mode 100644 source/blender/compositor/nodes/COM_MapValueNode.cc delete mode 100644 source/blender/compositor/nodes/COM_MapValueNode.cpp create mode 100644 source/blender/compositor/nodes/COM_MaskNode.cc delete mode 100644 source/blender/compositor/nodes/COM_MaskNode.cpp create mode 100644 source/blender/compositor/nodes/COM_MathNode.cc delete mode 100644 source/blender/compositor/nodes/COM_MathNode.cpp create mode 100644 source/blender/compositor/nodes/COM_MixNode.cc delete mode 100644 source/blender/compositor/nodes/COM_MixNode.cpp create mode 100644 source/blender/compositor/nodes/COM_MovieClipNode.cc delete mode 100644 source/blender/compositor/nodes/COM_MovieClipNode.cpp create mode 100644 source/blender/compositor/nodes/COM_MovieDistortionNode.cc delete mode 100644 source/blender/compositor/nodes/COM_MovieDistortionNode.cpp create mode 100644 source/blender/compositor/nodes/COM_NormalNode.cc delete mode 100644 source/blender/compositor/nodes/COM_NormalNode.cpp create mode 100644 source/blender/compositor/nodes/COM_NormalizeNode.cc delete mode 100644 source/blender/compositor/nodes/COM_NormalizeNode.cpp create mode 100644 source/blender/compositor/nodes/COM_OutputFileNode.cc delete mode 100644 source/blender/compositor/nodes/COM_OutputFileNode.cpp create mode 100644 source/blender/compositor/nodes/COM_PixelateNode.cc delete mode 100644 source/blender/compositor/nodes/COM_PixelateNode.cpp create mode 100644 source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc delete mode 100644 source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp create mode 100644 source/blender/compositor/nodes/COM_RenderLayersNode.cc delete mode 100644 source/blender/compositor/nodes/COM_RenderLayersNode.cpp create mode 100644 source/blender/compositor/nodes/COM_RotateNode.cc delete mode 100644 source/blender/compositor/nodes/COM_RotateNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ScaleNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ScaleNode.cpp create mode 100644 source/blender/compositor/nodes/COM_SeparateColorNode.cc delete mode 100644 source/blender/compositor/nodes/COM_SeparateColorNode.cpp create mode 100644 source/blender/compositor/nodes/COM_SetAlphaNode.cc delete mode 100644 source/blender/compositor/nodes/COM_SetAlphaNode.cpp create mode 100644 source/blender/compositor/nodes/COM_SocketProxyNode.cc delete mode 100644 source/blender/compositor/nodes/COM_SocketProxyNode.cpp create mode 100644 source/blender/compositor/nodes/COM_SplitViewerNode.cc delete mode 100644 source/blender/compositor/nodes/COM_SplitViewerNode.cpp create mode 100644 source/blender/compositor/nodes/COM_Stabilize2dNode.cc delete mode 100644 source/blender/compositor/nodes/COM_Stabilize2dNode.cpp create mode 100644 source/blender/compositor/nodes/COM_SunBeamsNode.cc delete mode 100644 source/blender/compositor/nodes/COM_SunBeamsNode.cpp create mode 100644 source/blender/compositor/nodes/COM_SwitchNode.cc delete mode 100644 source/blender/compositor/nodes/COM_SwitchNode.cpp create mode 100644 source/blender/compositor/nodes/COM_SwitchViewNode.cc delete mode 100644 source/blender/compositor/nodes/COM_SwitchViewNode.cpp create mode 100644 source/blender/compositor/nodes/COM_TextureNode.cc delete mode 100644 source/blender/compositor/nodes/COM_TextureNode.cpp create mode 100644 source/blender/compositor/nodes/COM_TimeNode.cc delete mode 100644 source/blender/compositor/nodes/COM_TimeNode.cpp create mode 100644 source/blender/compositor/nodes/COM_TonemapNode.cc delete mode 100644 source/blender/compositor/nodes/COM_TonemapNode.cpp create mode 100644 source/blender/compositor/nodes/COM_TrackPositionNode.cc delete mode 100644 source/blender/compositor/nodes/COM_TrackPositionNode.cpp create mode 100644 source/blender/compositor/nodes/COM_TransformNode.cc delete mode 100644 source/blender/compositor/nodes/COM_TransformNode.cpp create mode 100644 source/blender/compositor/nodes/COM_TranslateNode.cc delete mode 100644 source/blender/compositor/nodes/COM_TranslateNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ValueNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ValueNode.cpp create mode 100644 source/blender/compositor/nodes/COM_VectorBlurNode.cc delete mode 100644 source/blender/compositor/nodes/COM_VectorBlurNode.cpp create mode 100644 source/blender/compositor/nodes/COM_VectorCurveNode.cc delete mode 100644 source/blender/compositor/nodes/COM_VectorCurveNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ViewLevelsNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ViewLevelsNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ViewerNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ViewerNode.cpp create mode 100644 source/blender/compositor/nodes/COM_ZCombineNode.cc delete mode 100644 source/blender/compositor/nodes/COM_ZCombineNode.cpp create mode 100644 source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc delete mode 100644 source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp create mode 100644 source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc delete mode 100644 source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp create mode 100644 source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc delete mode 100644 source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp create mode 100644 source/blender/compositor/operations/COM_AntiAliasOperation.cc delete mode 100644 source/blender/compositor/operations/COM_AntiAliasOperation.cpp create mode 100644 source/blender/compositor/operations/COM_BilateralBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_BilateralBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_BlurBaseOperation.cc delete mode 100644 source/blender/compositor/operations/COM_BlurBaseOperation.cpp create mode 100644 source/blender/compositor/operations/COM_BokehBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_BokehBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_BokehImageOperation.cc delete mode 100644 source/blender/compositor/operations/COM_BokehImageOperation.cpp create mode 100644 source/blender/compositor/operations/COM_BoxMaskOperation.cc delete mode 100644 source/blender/compositor/operations/COM_BoxMaskOperation.cpp create mode 100644 source/blender/compositor/operations/COM_BrightnessOperation.cc delete mode 100644 source/blender/compositor/operations/COM_BrightnessOperation.cpp create mode 100644 source/blender/compositor/operations/COM_CalculateMeanOperation.cc delete mode 100644 source/blender/compositor/operations/COM_CalculateMeanOperation.cpp create mode 100644 source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc delete mode 100644 source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ChangeHSVOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ChangeHSVOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ChannelMatteOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ChannelMatteOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ChromaMatteOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ChromaMatteOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ColorCorrectionOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ColorCurveOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ColorCurveOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ColorExposureOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ColorExposureOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ColorMatteOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ColorMatteOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ColorRampOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ColorRampOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ColorSpillOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ColorSpillOperation.cpp create mode 100644 source/blender/compositor/operations/COM_CompositorOperation.cc delete mode 100644 source/blender/compositor/operations/COM_CompositorOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ConvertOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ConvertOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp create mode 100644 source/blender/compositor/operations/COM_CropOperation.cc delete mode 100644 source/blender/compositor/operations/COM_CropOperation.cpp create mode 100644 source/blender/compositor/operations/COM_CryptomatteOperation.cc delete mode 100644 source/blender/compositor/operations/COM_CryptomatteOperation.cpp create mode 100644 source/blender/compositor/operations/COM_CurveBaseOperation.cc delete mode 100644 source/blender/compositor/operations/COM_CurveBaseOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DenoiseOperation.cc delete mode 100644 source/blender/compositor/operations/COM_DenoiseOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DespeckleOperation.cc delete mode 100644 source/blender/compositor/operations/COM_DespeckleOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DifferenceMatteOperation.cc delete mode 100644 source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DilateErodeOperation.cc delete mode 100644 source/blender/compositor/operations/COM_DilateErodeOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DirectionalBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DisplaceOperation.cc delete mode 100644 source/blender/compositor/operations/COM_DisplaceOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc delete mode 100644 source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc delete mode 100644 source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc delete mode 100644 source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DotproductOperation.cc delete mode 100644 source/blender/compositor/operations/COM_DotproductOperation.cpp create mode 100644 source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc delete mode 100644 source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp create mode 100644 source/blender/compositor/operations/COM_EllipseMaskOperation.cc delete mode 100644 source/blender/compositor/operations/COM_EllipseMaskOperation.cpp create mode 100644 source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_FlipOperation.cc delete mode 100644 source/blender/compositor/operations/COM_FlipOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GammaCorrectOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GammaCorrectOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GammaOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GammaOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GaussianXBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GaussianYBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GlareBaseOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GlareBaseOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GlareFogGlowOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GlareGhostOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GlareGhostOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GlareStreaksOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GlareStreaksOperation.cpp create mode 100644 source/blender/compositor/operations/COM_GlareThresholdOperation.cc delete mode 100644 source/blender/compositor/operations/COM_GlareThresholdOperation.cpp create mode 100644 source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc delete mode 100644 source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp create mode 100644 source/blender/compositor/operations/COM_IDMaskOperation.cc delete mode 100644 source/blender/compositor/operations/COM_IDMaskOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ImageOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ImageOperation.cpp create mode 100644 source/blender/compositor/operations/COM_InpaintOperation.cc delete mode 100644 source/blender/compositor/operations/COM_InpaintOperation.cpp create mode 100644 source/blender/compositor/operations/COM_InvertOperation.cc delete mode 100644 source/blender/compositor/operations/COM_InvertOperation.cpp create mode 100644 source/blender/compositor/operations/COM_KeyingBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_KeyingBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_KeyingClipOperation.cc delete mode 100644 source/blender/compositor/operations/COM_KeyingClipOperation.cpp create mode 100644 source/blender/compositor/operations/COM_KeyingDespillOperation.cc delete mode 100644 source/blender/compositor/operations/COM_KeyingDespillOperation.cpp create mode 100644 source/blender/compositor/operations/COM_KeyingOperation.cc delete mode 100644 source/blender/compositor/operations/COM_KeyingOperation.cpp create mode 100644 source/blender/compositor/operations/COM_KeyingScreenOperation.cc delete mode 100644 source/blender/compositor/operations/COM_KeyingScreenOperation.cpp create mode 100644 source/blender/compositor/operations/COM_LuminanceMatteOperation.cc delete mode 100644 source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp create mode 100644 source/blender/compositor/operations/COM_MapRangeOperation.cc delete mode 100644 source/blender/compositor/operations/COM_MapRangeOperation.cpp create mode 100644 source/blender/compositor/operations/COM_MapUVOperation.cc delete mode 100644 source/blender/compositor/operations/COM_MapUVOperation.cpp create mode 100644 source/blender/compositor/operations/COM_MapValueOperation.cc delete mode 100644 source/blender/compositor/operations/COM_MapValueOperation.cpp create mode 100644 source/blender/compositor/operations/COM_MaskOperation.cc delete mode 100644 source/blender/compositor/operations/COM_MaskOperation.cpp create mode 100644 source/blender/compositor/operations/COM_MathBaseOperation.cc delete mode 100644 source/blender/compositor/operations/COM_MathBaseOperation.cpp create mode 100644 source/blender/compositor/operations/COM_MixOperation.cc delete mode 100644 source/blender/compositor/operations/COM_MixOperation.cpp create mode 100644 source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc delete mode 100644 source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp create mode 100644 source/blender/compositor/operations/COM_MovieClipOperation.cc delete mode 100644 source/blender/compositor/operations/COM_MovieClipOperation.cpp create mode 100644 source/blender/compositor/operations/COM_MovieDistortionOperation.cc delete mode 100644 source/blender/compositor/operations/COM_MovieDistortionOperation.cpp create mode 100644 source/blender/compositor/operations/COM_MultilayerImageOperation.cc delete mode 100644 source/blender/compositor/operations/COM_MultilayerImageOperation.cpp create mode 100644 source/blender/compositor/operations/COM_NormalizeOperation.cc delete mode 100644 source/blender/compositor/operations/COM_NormalizeOperation.cpp create mode 100644 source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc delete mode 100644 source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp create mode 100644 source/blender/compositor/operations/COM_OutputFileOperation.cc delete mode 100644 source/blender/compositor/operations/COM_OutputFileOperation.cpp create mode 100644 source/blender/compositor/operations/COM_PixelateOperation.cc delete mode 100644 source/blender/compositor/operations/COM_PixelateOperation.cpp create mode 100644 source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc delete mode 100644 source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp create mode 100644 source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc delete mode 100644 source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp create mode 100644 source/blender/compositor/operations/COM_PlaneTrackOperation.cc delete mode 100644 source/blender/compositor/operations/COM_PlaneTrackOperation.cpp create mode 100644 source/blender/compositor/operations/COM_PreviewOperation.cc delete mode 100644 source/blender/compositor/operations/COM_PreviewOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp create mode 100644 source/blender/compositor/operations/COM_QualityStepHelper.cc delete mode 100644 source/blender/compositor/operations/COM_QualityStepHelper.cpp create mode 100644 source/blender/compositor/operations/COM_ReadBufferOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ReadBufferOperation.cpp create mode 100644 source/blender/compositor/operations/COM_RenderLayersProg.cc delete mode 100644 source/blender/compositor/operations/COM_RenderLayersProg.cpp create mode 100644 source/blender/compositor/operations/COM_RotateOperation.cc delete mode 100644 source/blender/compositor/operations/COM_RotateOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ScaleOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ScaleOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp create mode 100644 source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc delete mode 100644 source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp create mode 100644 source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc delete mode 100644 source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp create mode 100644 source/blender/compositor/operations/COM_SetColorOperation.cc delete mode 100644 source/blender/compositor/operations/COM_SetColorOperation.cpp create mode 100644 source/blender/compositor/operations/COM_SetSamplerOperation.cc delete mode 100644 source/blender/compositor/operations/COM_SetSamplerOperation.cpp create mode 100644 source/blender/compositor/operations/COM_SetValueOperation.cc delete mode 100644 source/blender/compositor/operations/COM_SetValueOperation.cpp create mode 100644 source/blender/compositor/operations/COM_SetVectorOperation.cc delete mode 100644 source/blender/compositor/operations/COM_SetVectorOperation.cpp create mode 100644 source/blender/compositor/operations/COM_SocketProxyOperation.cc delete mode 100644 source/blender/compositor/operations/COM_SocketProxyOperation.cpp create mode 100644 source/blender/compositor/operations/COM_SplitOperation.cc delete mode 100644 source/blender/compositor/operations/COM_SplitOperation.cpp create mode 100644 source/blender/compositor/operations/COM_SunBeamsOperation.cc delete mode 100644 source/blender/compositor/operations/COM_SunBeamsOperation.cpp create mode 100644 source/blender/compositor/operations/COM_TextureOperation.cc delete mode 100644 source/blender/compositor/operations/COM_TextureOperation.cpp create mode 100644 source/blender/compositor/operations/COM_TonemapOperation.cc delete mode 100644 source/blender/compositor/operations/COM_TonemapOperation.cpp create mode 100644 source/blender/compositor/operations/COM_TrackPositionOperation.cc delete mode 100644 source/blender/compositor/operations/COM_TrackPositionOperation.cpp create mode 100644 source/blender/compositor/operations/COM_TranslateOperation.cc delete mode 100644 source/blender/compositor/operations/COM_TranslateOperation.cpp create mode 100644 source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_VectorBlurOperation.cc delete mode 100644 source/blender/compositor/operations/COM_VectorBlurOperation.cpp create mode 100644 source/blender/compositor/operations/COM_VectorCurveOperation.cc delete mode 100644 source/blender/compositor/operations/COM_VectorCurveOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ViewerOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ViewerOperation.cpp create mode 100644 source/blender/compositor/operations/COM_WrapOperation.cc delete mode 100644 source/blender/compositor/operations/COM_WrapOperation.cpp create mode 100644 source/blender/compositor/operations/COM_WriteBufferOperation.cc delete mode 100644 source/blender/compositor/operations/COM_WriteBufferOperation.cpp create mode 100644 source/blender/compositor/operations/COM_ZCombineOperation.cc delete mode 100644 source/blender/compositor/operations/COM_ZCombineOperation.cpp diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index a226b009ec9..64033cbe5c4 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -49,504 +49,504 @@ set(SRC COM_compositor.h COM_defines.h - intern/COM_CPUDevice.cpp + intern/COM_CPUDevice.cc intern/COM_CPUDevice.h - intern/COM_ChunkOrder.cpp + intern/COM_ChunkOrder.cc intern/COM_ChunkOrder.h - intern/COM_ChunkOrderHotspot.cpp + intern/COM_ChunkOrderHotspot.cc intern/COM_ChunkOrderHotspot.h - intern/COM_CompositorContext.cpp + intern/COM_CompositorContext.cc intern/COM_CompositorContext.h - intern/COM_Converter.cpp + intern/COM_Converter.cc intern/COM_Converter.h - intern/COM_Debug.cpp + intern/COM_Debug.cc intern/COM_Debug.h - intern/COM_Device.cpp + intern/COM_Device.cc intern/COM_Device.h - intern/COM_ExecutionGroup.cpp + intern/COM_ExecutionGroup.cc intern/COM_ExecutionGroup.h - intern/COM_ExecutionSystem.cpp + intern/COM_ExecutionSystem.cc intern/COM_ExecutionSystem.h - intern/COM_MemoryBuffer.cpp + intern/COM_MemoryBuffer.cc intern/COM_MemoryBuffer.h - intern/COM_MemoryProxy.cpp + intern/COM_MemoryProxy.cc intern/COM_MemoryProxy.h - intern/COM_MetaData.cpp + intern/COM_MetaData.cc intern/COM_MetaData.h - intern/COM_Node.cpp + intern/COM_Node.cc intern/COM_Node.h - intern/COM_NodeConverter.cpp + intern/COM_NodeConverter.cc intern/COM_NodeConverter.h - intern/COM_NodeGraph.cpp + intern/COM_NodeGraph.cc intern/COM_NodeGraph.h - intern/COM_NodeOperation.cpp + intern/COM_NodeOperation.cc intern/COM_NodeOperation.h - intern/COM_NodeOperationBuilder.cpp + intern/COM_NodeOperationBuilder.cc intern/COM_NodeOperationBuilder.h - intern/COM_OpenCLDevice.cpp + intern/COM_OpenCLDevice.cc intern/COM_OpenCLDevice.h - intern/COM_SingleThreadedOperation.cpp + intern/COM_SingleThreadedOperation.cc intern/COM_SingleThreadedOperation.h - intern/COM_SocketReader.cpp + intern/COM_SocketReader.cc intern/COM_SocketReader.h - intern/COM_WorkPackage.cpp + intern/COM_WorkPackage.cc intern/COM_WorkPackage.h - intern/COM_WorkScheduler.cpp + intern/COM_WorkScheduler.cc intern/COM_WorkScheduler.h - intern/COM_compositor.cpp + intern/COM_compositor.cc - operations/COM_QualityStepHelper.cpp + operations/COM_QualityStepHelper.cc operations/COM_QualityStepHelper.h # Internal nodes - nodes/COM_SocketProxyNode.cpp + nodes/COM_SocketProxyNode.cc nodes/COM_SocketProxyNode.h # input nodes - nodes/COM_BokehImageNode.cpp + nodes/COM_BokehImageNode.cc nodes/COM_BokehImageNode.h - nodes/COM_ColorNode.cpp + nodes/COM_ColorNode.cc nodes/COM_ColorNode.h - nodes/COM_ImageNode.cpp + nodes/COM_ImageNode.cc nodes/COM_ImageNode.h - nodes/COM_MaskNode.cpp + nodes/COM_MaskNode.cc nodes/COM_MaskNode.h - nodes/COM_MovieClipNode.cpp + nodes/COM_MovieClipNode.cc nodes/COM_MovieClipNode.h - nodes/COM_OutputFileNode.cpp + nodes/COM_OutputFileNode.cc nodes/COM_OutputFileNode.h - nodes/COM_RenderLayersNode.cpp + nodes/COM_RenderLayersNode.cc nodes/COM_RenderLayersNode.h - nodes/COM_SwitchNode.cpp + nodes/COM_SwitchNode.cc nodes/COM_SwitchNode.h - nodes/COM_SwitchViewNode.cpp + nodes/COM_SwitchViewNode.cc nodes/COM_SwitchViewNode.h - nodes/COM_TextureNode.cpp + nodes/COM_TextureNode.cc nodes/COM_TextureNode.h - nodes/COM_TimeNode.cpp + nodes/COM_TimeNode.cc nodes/COM_TimeNode.h - nodes/COM_ValueNode.cpp + nodes/COM_ValueNode.cc nodes/COM_ValueNode.h # output nodes - nodes/COM_CompositorNode.cpp + nodes/COM_CompositorNode.cc nodes/COM_CompositorNode.h - nodes/COM_SplitViewerNode.cpp + nodes/COM_SplitViewerNode.cc nodes/COM_SplitViewerNode.h - nodes/COM_ViewLevelsNode.cpp + nodes/COM_ViewLevelsNode.cc nodes/COM_ViewLevelsNode.h - nodes/COM_ViewerNode.cpp + nodes/COM_ViewerNode.cc nodes/COM_ViewerNode.h - operations/COM_CalculateMeanOperation.cpp + operations/COM_CalculateMeanOperation.cc operations/COM_CalculateMeanOperation.h - operations/COM_CalculateStandardDeviationOperation.cpp + operations/COM_CalculateStandardDeviationOperation.cc operations/COM_CalculateStandardDeviationOperation.h # distort nodes - nodes/COM_FlipNode.cpp + nodes/COM_FlipNode.cc nodes/COM_FlipNode.h - nodes/COM_RotateNode.cpp + nodes/COM_RotateNode.cc nodes/COM_RotateNode.h - nodes/COM_ScaleNode.cpp + nodes/COM_ScaleNode.cc nodes/COM_ScaleNode.h - nodes/COM_TranslateNode.cpp + nodes/COM_TranslateNode.cc nodes/COM_TranslateNode.h - nodes/COM_DisplaceNode.cpp + nodes/COM_DisplaceNode.cc nodes/COM_DisplaceNode.h - nodes/COM_MapUVNode.cpp + nodes/COM_MapUVNode.cc nodes/COM_MapUVNode.h - nodes/COM_ChannelMatteNode.cpp + nodes/COM_ChannelMatteNode.cc nodes/COM_ChannelMatteNode.h - nodes/COM_ChromaMatteNode.cpp + nodes/COM_ChromaMatteNode.cc nodes/COM_ChromaMatteNode.h - nodes/COM_ColorMatteNode.cpp + nodes/COM_ColorMatteNode.cc nodes/COM_ColorMatteNode.h - nodes/COM_DifferenceMatteNode.cpp + nodes/COM_DifferenceMatteNode.cc nodes/COM_DifferenceMatteNode.h - nodes/COM_DistanceMatteNode.cpp + nodes/COM_DistanceMatteNode.cc nodes/COM_DistanceMatteNode.h - nodes/COM_LensDistortionNode.cpp + nodes/COM_LensDistortionNode.cc nodes/COM_LensDistortionNode.h - nodes/COM_LuminanceMatteNode.cpp + nodes/COM_LuminanceMatteNode.cc nodes/COM_LuminanceMatteNode.h - nodes/COM_GlareNode.cpp + nodes/COM_GlareNode.cc nodes/COM_GlareNode.h - nodes/COM_SunBeamsNode.cpp + nodes/COM_SunBeamsNode.cc nodes/COM_SunBeamsNode.h - operations/COM_SunBeamsOperation.cpp + operations/COM_SunBeamsOperation.cc operations/COM_SunBeamsOperation.h - nodes/COM_CryptomatteNode.cpp + nodes/COM_CryptomatteNode.cc nodes/COM_CryptomatteNode.h - operations/COM_CryptomatteOperation.cpp + operations/COM_CryptomatteOperation.cc operations/COM_CryptomatteOperation.h - nodes/COM_CornerPinNode.cpp + nodes/COM_CornerPinNode.cc nodes/COM_CornerPinNode.h - nodes/COM_PlaneTrackDeformNode.cpp + nodes/COM_PlaneTrackDeformNode.cc nodes/COM_PlaneTrackDeformNode.h - nodes/COM_CropNode.cpp + nodes/COM_CropNode.cc nodes/COM_CropNode.h - operations/COM_CropOperation.cpp + operations/COM_CropOperation.cc operations/COM_CropOperation.h - nodes/COM_DefocusNode.cpp + nodes/COM_DefocusNode.cc nodes/COM_DefocusNode.h - nodes/COM_MovieDistortionNode.cpp + nodes/COM_MovieDistortionNode.cc nodes/COM_MovieDistortionNode.h - nodes/COM_Stabilize2dNode.cpp + nodes/COM_Stabilize2dNode.cc nodes/COM_Stabilize2dNode.h - nodes/COM_TransformNode.cpp + nodes/COM_TransformNode.cc nodes/COM_TransformNode.h # color nodes - nodes/COM_AlphaOverNode.cpp + nodes/COM_AlphaOverNode.cc nodes/COM_AlphaOverNode.h - nodes/COM_BrightnessNode.cpp + nodes/COM_BrightnessNode.cc nodes/COM_BrightnessNode.h - nodes/COM_ColorBalanceNode.cpp + nodes/COM_ColorBalanceNode.cc nodes/COM_ColorBalanceNode.h - nodes/COM_ColorCorrectionNode.cpp + nodes/COM_ColorCorrectionNode.cc nodes/COM_ColorCorrectionNode.h - nodes/COM_ColorCurveNode.cpp + nodes/COM_ColorCurveNode.cc nodes/COM_ColorCurveNode.h - nodes/COM_ColorExposureNode.cpp + nodes/COM_ColorExposureNode.cc nodes/COM_ColorExposureNode.h - nodes/COM_ColorRampNode.cpp + nodes/COM_ColorRampNode.cc nodes/COM_ColorRampNode.h - nodes/COM_ColorToBWNode.cpp + nodes/COM_ColorToBWNode.cc nodes/COM_ColorToBWNode.h - nodes/COM_ConvertAlphaNode.cpp + nodes/COM_ConvertAlphaNode.cc nodes/COM_ConvertAlphaNode.h - nodes/COM_GammaNode.cpp + nodes/COM_GammaNode.cc nodes/COM_GammaNode.h - nodes/COM_HueSaturationValueCorrectNode.cpp + nodes/COM_HueSaturationValueCorrectNode.cc nodes/COM_HueSaturationValueCorrectNode.h - nodes/COM_HueSaturationValueNode.cpp + nodes/COM_HueSaturationValueNode.cc nodes/COM_HueSaturationValueNode.h - nodes/COM_InvertNode.cpp + nodes/COM_InvertNode.cc nodes/COM_InvertNode.h - nodes/COM_MixNode.cpp + nodes/COM_MixNode.cc nodes/COM_MixNode.h - nodes/COM_SetAlphaNode.cpp + nodes/COM_SetAlphaNode.cc nodes/COM_SetAlphaNode.h - nodes/COM_TonemapNode.cpp + nodes/COM_TonemapNode.cc nodes/COM_TonemapNode.h - nodes/COM_VectorCurveNode.cpp + nodes/COM_VectorCurveNode.cc nodes/COM_VectorCurveNode.h - nodes/COM_ZCombineNode.cpp + nodes/COM_ZCombineNode.cc nodes/COM_ZCombineNode.h - operations/COM_TonemapOperation.cpp + operations/COM_TonemapOperation.cc operations/COM_TonemapOperation.h # converter nodes - nodes/COM_CombineColorNode.cpp + nodes/COM_CombineColorNode.cc nodes/COM_CombineColorNode.h - nodes/COM_IDMaskNode.cpp + nodes/COM_IDMaskNode.cc nodes/COM_IDMaskNode.h - nodes/COM_SeparateColorNode.cpp + nodes/COM_SeparateColorNode.cc nodes/COM_SeparateColorNode.h - nodes/COM_MapRangeNode.cpp + nodes/COM_MapRangeNode.cc nodes/COM_MapRangeNode.h - nodes/COM_MapValueNode.cpp + nodes/COM_MapValueNode.cc nodes/COM_MapValueNode.h - nodes/COM_MathNode.cpp + nodes/COM_MathNode.cc nodes/COM_MathNode.h - nodes/COM_NormalNode.cpp + nodes/COM_NormalNode.cc nodes/COM_NormalNode.h - nodes/COM_NormalizeNode.cpp + nodes/COM_NormalizeNode.cc nodes/COM_NormalizeNode.h - operations/COM_NormalizeOperation.cpp + operations/COM_NormalizeOperation.cc operations/COM_NormalizeOperation.h - nodes/COM_PixelateNode.cpp + nodes/COM_PixelateNode.cc nodes/COM_PixelateNode.h - operations/COM_PixelateOperation.cpp + operations/COM_PixelateOperation.cc operations/COM_PixelateOperation.h # Filter nodes - nodes/COM_BilateralBlurNode.cpp + nodes/COM_BilateralBlurNode.cc nodes/COM_BilateralBlurNode.h - operations/COM_BilateralBlurOperation.cpp + operations/COM_BilateralBlurOperation.cc operations/COM_BilateralBlurOperation.h - nodes/COM_VectorBlurNode.cpp + nodes/COM_VectorBlurNode.cc nodes/COM_VectorBlurNode.h - operations/COM_VectorBlurOperation.cpp + operations/COM_VectorBlurOperation.cc operations/COM_VectorBlurOperation.h - nodes/COM_BlurNode.cpp + nodes/COM_BlurNode.cc nodes/COM_BlurNode.h - nodes/COM_BokehBlurNode.cpp + nodes/COM_BokehBlurNode.cc nodes/COM_BokehBlurNode.h - nodes/COM_DenoiseNode.cpp + nodes/COM_DenoiseNode.cc nodes/COM_DenoiseNode.h - nodes/COM_DespeckleNode.cpp + nodes/COM_DespeckleNode.cc nodes/COM_DespeckleNode.h - nodes/COM_DilateErodeNode.cpp + nodes/COM_DilateErodeNode.cc nodes/COM_DilateErodeNode.h - nodes/COM_DirectionalBlurNode.cpp + nodes/COM_DirectionalBlurNode.cc nodes/COM_DirectionalBlurNode.h - nodes/COM_FilterNode.cpp + nodes/COM_FilterNode.cc nodes/COM_FilterNode.h - nodes/COM_InpaintNode.cpp + nodes/COM_InpaintNode.cc nodes/COM_InpaintNode.h - operations/COM_BlurBaseOperation.cpp + operations/COM_BlurBaseOperation.cc operations/COM_BlurBaseOperation.h - operations/COM_BokehBlurOperation.cpp + operations/COM_BokehBlurOperation.cc operations/COM_BokehBlurOperation.h - operations/COM_DirectionalBlurOperation.cpp + operations/COM_DirectionalBlurOperation.cc operations/COM_DirectionalBlurOperation.h - operations/COM_FastGaussianBlurOperation.cpp + operations/COM_FastGaussianBlurOperation.cc operations/COM_FastGaussianBlurOperation.h - operations/COM_GammaCorrectOperation.cpp + operations/COM_GammaCorrectOperation.cc operations/COM_GammaCorrectOperation.h - operations/COM_GaussianAlphaXBlurOperation.cpp + operations/COM_GaussianAlphaXBlurOperation.cc operations/COM_GaussianAlphaXBlurOperation.h - operations/COM_GaussianAlphaYBlurOperation.cpp + operations/COM_GaussianAlphaYBlurOperation.cc operations/COM_GaussianAlphaYBlurOperation.h - operations/COM_GaussianBokehBlurOperation.cpp + operations/COM_GaussianBokehBlurOperation.cc operations/COM_GaussianBokehBlurOperation.h - operations/COM_GaussianXBlurOperation.cpp + operations/COM_GaussianXBlurOperation.cc operations/COM_GaussianXBlurOperation.h - operations/COM_GaussianYBlurOperation.cpp + operations/COM_GaussianYBlurOperation.cc operations/COM_GaussianYBlurOperation.h - operations/COM_MovieClipAttributeOperation.cpp + operations/COM_MovieClipAttributeOperation.cc operations/COM_MovieClipAttributeOperation.h - operations/COM_MovieDistortionOperation.cpp + operations/COM_MovieDistortionOperation.cc operations/COM_MovieDistortionOperation.h - operations/COM_VariableSizeBokehBlurOperation.cpp + operations/COM_VariableSizeBokehBlurOperation.cc operations/COM_VariableSizeBokehBlurOperation.h # Matte nodes - nodes/COM_BoxMaskNode.cpp + nodes/COM_BoxMaskNode.cc nodes/COM_BoxMaskNode.h - nodes/COM_ColorSpillNode.cpp + nodes/COM_ColorSpillNode.cc nodes/COM_ColorSpillNode.h - nodes/COM_DoubleEdgeMaskNode.cpp + nodes/COM_DoubleEdgeMaskNode.cc nodes/COM_DoubleEdgeMaskNode.h - nodes/COM_EllipseMaskNode.cpp + nodes/COM_EllipseMaskNode.cc nodes/COM_EllipseMaskNode.h - operations/COM_DoubleEdgeMaskOperation.cpp + operations/COM_DoubleEdgeMaskOperation.cc operations/COM_DoubleEdgeMaskOperation.h - nodes/COM_KeyingScreenNode.cpp + nodes/COM_KeyingScreenNode.cc nodes/COM_KeyingScreenNode.h - operations/COM_KeyingScreenOperation.cpp + operations/COM_KeyingScreenOperation.cc operations/COM_KeyingScreenOperation.h - nodes/COM_TrackPositionNode.cpp + nodes/COM_TrackPositionNode.cc nodes/COM_TrackPositionNode.h - operations/COM_TrackPositionOperation.cpp + operations/COM_TrackPositionOperation.cc operations/COM_TrackPositionOperation.h - nodes/COM_KeyingNode.cpp + nodes/COM_KeyingNode.cc nodes/COM_KeyingNode.h - operations/COM_KeyingBlurOperation.cpp + operations/COM_KeyingBlurOperation.cc operations/COM_KeyingBlurOperation.h - operations/COM_KeyingClipOperation.cpp + operations/COM_KeyingClipOperation.cc operations/COM_KeyingClipOperation.h - operations/COM_KeyingDespillOperation.cpp + operations/COM_KeyingDespillOperation.cc operations/COM_KeyingDespillOperation.h - operations/COM_KeyingOperation.cpp + operations/COM_KeyingOperation.cc operations/COM_KeyingOperation.h - operations/COM_ColorSpillOperation.cpp + operations/COM_ColorSpillOperation.cc operations/COM_ColorSpillOperation.h - operations/COM_RenderLayersProg.cpp + operations/COM_RenderLayersProg.cc operations/COM_RenderLayersProg.h - operations/COM_BokehImageOperation.cpp + operations/COM_BokehImageOperation.cc operations/COM_BokehImageOperation.h - operations/COM_ImageOperation.cpp + operations/COM_ImageOperation.cc operations/COM_ImageOperation.h - operations/COM_MultilayerImageOperation.cpp + operations/COM_MultilayerImageOperation.cc operations/COM_MultilayerImageOperation.h - operations/COM_TextureOperation.cpp + operations/COM_TextureOperation.cc operations/COM_TextureOperation.h - operations/COM_SocketProxyOperation.cpp + operations/COM_SocketProxyOperation.cc operations/COM_SocketProxyOperation.h - operations/COM_CompositorOperation.cpp + operations/COM_CompositorOperation.cc operations/COM_CompositorOperation.h - operations/COM_ConvertDepthToRadiusOperation.cpp + operations/COM_ConvertDepthToRadiusOperation.cc operations/COM_ConvertDepthToRadiusOperation.h - operations/COM_OutputFileMultiViewOperation.cpp + operations/COM_OutputFileMultiViewOperation.cc operations/COM_OutputFileMultiViewOperation.h - operations/COM_OutputFileOperation.cpp + operations/COM_OutputFileOperation.cc operations/COM_OutputFileOperation.h - operations/COM_PreviewOperation.cpp + operations/COM_PreviewOperation.cc operations/COM_PreviewOperation.h - operations/COM_SplitOperation.cpp + operations/COM_SplitOperation.cc operations/COM_SplitOperation.h - operations/COM_ViewerOperation.cpp + operations/COM_ViewerOperation.cc operations/COM_ViewerOperation.h - operations/COM_ZCombineOperation.cpp + operations/COM_ZCombineOperation.cc operations/COM_ZCombineOperation.h - operations/COM_ChangeHSVOperation.cpp + operations/COM_ChangeHSVOperation.cc operations/COM_ChangeHSVOperation.h - operations/COM_ChannelMatteOperation.cpp + operations/COM_ChannelMatteOperation.cc operations/COM_ChannelMatteOperation.h - operations/COM_ChromaMatteOperation.cpp + operations/COM_ChromaMatteOperation.cc operations/COM_ChromaMatteOperation.h - operations/COM_ColorCurveOperation.cpp + operations/COM_ColorCurveOperation.cc operations/COM_ColorCurveOperation.h - operations/COM_ColorExposureOperation.cpp + operations/COM_ColorExposureOperation.cc operations/COM_ColorExposureOperation.h - operations/COM_ColorMatteOperation.cpp + operations/COM_ColorMatteOperation.cc operations/COM_ColorMatteOperation.h - operations/COM_ColorRampOperation.cpp + operations/COM_ColorRampOperation.cc operations/COM_ColorRampOperation.h - operations/COM_CurveBaseOperation.cpp + operations/COM_CurveBaseOperation.cc operations/COM_CurveBaseOperation.h - operations/COM_DifferenceMatteOperation.cpp + operations/COM_DifferenceMatteOperation.cc operations/COM_DifferenceMatteOperation.h - operations/COM_DistanceRGBMatteOperation.cpp + operations/COM_DistanceRGBMatteOperation.cc operations/COM_DistanceRGBMatteOperation.h - operations/COM_DistanceYCCMatteOperation.cpp + operations/COM_DistanceYCCMatteOperation.cc operations/COM_DistanceYCCMatteOperation.h - operations/COM_HueSaturationValueCorrectOperation.cpp + operations/COM_HueSaturationValueCorrectOperation.cc operations/COM_HueSaturationValueCorrectOperation.h - operations/COM_LuminanceMatteOperation.cpp + operations/COM_LuminanceMatteOperation.cc operations/COM_LuminanceMatteOperation.h - operations/COM_VectorCurveOperation.cpp + operations/COM_VectorCurveOperation.cc operations/COM_VectorCurveOperation.h - operations/COM_BrightnessOperation.cpp + operations/COM_BrightnessOperation.cc operations/COM_BrightnessOperation.h - operations/COM_ColorCorrectionOperation.cpp + operations/COM_ColorCorrectionOperation.cc operations/COM_ColorCorrectionOperation.h - operations/COM_GammaOperation.cpp + operations/COM_GammaOperation.cc operations/COM_GammaOperation.h - operations/COM_MixOperation.cpp + operations/COM_MixOperation.cc operations/COM_MixOperation.h - operations/COM_ReadBufferOperation.cpp + operations/COM_ReadBufferOperation.cc operations/COM_ReadBufferOperation.h - operations/COM_SetColorOperation.cpp + operations/COM_SetColorOperation.cc operations/COM_SetColorOperation.h - operations/COM_SetValueOperation.cpp + operations/COM_SetValueOperation.cc operations/COM_SetValueOperation.h - operations/COM_SetVectorOperation.cpp + operations/COM_SetVectorOperation.cc operations/COM_SetVectorOperation.h - operations/COM_WriteBufferOperation.cpp + operations/COM_WriteBufferOperation.cc operations/COM_WriteBufferOperation.h - operations/COM_MathBaseOperation.cpp + operations/COM_MathBaseOperation.cc operations/COM_MathBaseOperation.h - operations/COM_AlphaOverKeyOperation.cpp + operations/COM_AlphaOverKeyOperation.cc operations/COM_AlphaOverKeyOperation.h - operations/COM_AlphaOverMixedOperation.cpp + operations/COM_AlphaOverMixedOperation.cc operations/COM_AlphaOverMixedOperation.h - operations/COM_AlphaOverPremultiplyOperation.cpp + operations/COM_AlphaOverPremultiplyOperation.cc operations/COM_AlphaOverPremultiplyOperation.h - operations/COM_ColorBalanceASCCDLOperation.cpp + operations/COM_ColorBalanceASCCDLOperation.cc operations/COM_ColorBalanceASCCDLOperation.h - operations/COM_ColorBalanceLGGOperation.cpp + operations/COM_ColorBalanceLGGOperation.cc operations/COM_ColorBalanceLGGOperation.h - operations/COM_InvertOperation.cpp + operations/COM_InvertOperation.cc operations/COM_InvertOperation.h - operations/COM_MapRangeOperation.cpp + operations/COM_MapRangeOperation.cc operations/COM_MapRangeOperation.h - operations/COM_MapValueOperation.cpp + operations/COM_MapValueOperation.cc operations/COM_MapValueOperation.h - operations/COM_SetAlphaMultiplyOperation.cpp + operations/COM_SetAlphaMultiplyOperation.cc operations/COM_SetAlphaMultiplyOperation.h - operations/COM_SetAlphaReplaceOperation.cpp + operations/COM_SetAlphaReplaceOperation.cc operations/COM_SetAlphaReplaceOperation.h # Distort operation - operations/COM_DisplaceOperation.cpp + operations/COM_DisplaceOperation.cc operations/COM_DisplaceOperation.h - operations/COM_DisplaceSimpleOperation.cpp + operations/COM_DisplaceSimpleOperation.cc operations/COM_DisplaceSimpleOperation.h - operations/COM_FlipOperation.cpp + operations/COM_FlipOperation.cc operations/COM_FlipOperation.h - operations/COM_MapUVOperation.cpp + operations/COM_MapUVOperation.cc operations/COM_MapUVOperation.h - operations/COM_PlaneCornerPinOperation.cpp + operations/COM_PlaneCornerPinOperation.cc operations/COM_PlaneCornerPinOperation.h - operations/COM_PlaneDistortCommonOperation.cpp + operations/COM_PlaneDistortCommonOperation.cc operations/COM_PlaneDistortCommonOperation.h - operations/COM_PlaneTrackOperation.cpp + operations/COM_PlaneTrackOperation.cc operations/COM_PlaneTrackOperation.h - operations/COM_ProjectorLensDistortionOperation.cpp + operations/COM_ProjectorLensDistortionOperation.cc operations/COM_ProjectorLensDistortionOperation.h - operations/COM_RotateOperation.cpp + operations/COM_RotateOperation.cc operations/COM_RotateOperation.h - operations/COM_ScaleOperation.cpp + operations/COM_ScaleOperation.cc operations/COM_ScaleOperation.h - operations/COM_ScreenLensDistortionOperation.cpp + operations/COM_ScreenLensDistortionOperation.cc operations/COM_ScreenLensDistortionOperation.h - operations/COM_TranslateOperation.cpp + operations/COM_TranslateOperation.cc operations/COM_TranslateOperation.h - operations/COM_WrapOperation.cpp + operations/COM_WrapOperation.cc operations/COM_WrapOperation.h # Filter operations - operations/COM_ConvolutionEdgeFilterOperation.cpp + operations/COM_ConvolutionEdgeFilterOperation.cc operations/COM_ConvolutionEdgeFilterOperation.h - operations/COM_ConvolutionFilterOperation.cpp + operations/COM_ConvolutionFilterOperation.cc operations/COM_ConvolutionFilterOperation.h - operations/COM_DenoiseOperation.cpp + operations/COM_DenoiseOperation.cc operations/COM_DenoiseOperation.h - operations/COM_DespeckleOperation.cpp + operations/COM_DespeckleOperation.cc operations/COM_DespeckleOperation.h - operations/COM_DilateErodeOperation.cpp + operations/COM_DilateErodeOperation.cc operations/COM_DilateErodeOperation.h - operations/COM_GlareBaseOperation.cpp + operations/COM_GlareBaseOperation.cc operations/COM_GlareBaseOperation.h - operations/COM_GlareFogGlowOperation.cpp + operations/COM_GlareFogGlowOperation.cc operations/COM_GlareFogGlowOperation.h - operations/COM_GlareGhostOperation.cpp + operations/COM_GlareGhostOperation.cc operations/COM_GlareGhostOperation.h - operations/COM_GlareSimpleStarOperation.cpp + operations/COM_GlareSimpleStarOperation.cc operations/COM_GlareSimpleStarOperation.h - operations/COM_GlareStreaksOperation.cpp + operations/COM_GlareStreaksOperation.cc operations/COM_GlareStreaksOperation.h - operations/COM_GlareThresholdOperation.cpp + operations/COM_GlareThresholdOperation.cc operations/COM_GlareThresholdOperation.h - operations/COM_InpaintOperation.cpp + operations/COM_InpaintOperation.cc operations/COM_InpaintOperation.h - operations/COM_SetSamplerOperation.cpp + operations/COM_SetSamplerOperation.cc operations/COM_SetSamplerOperation.h # Convert operations - operations/COM_ConvertOperation.cpp + operations/COM_ConvertOperation.cc operations/COM_ConvertOperation.h - operations/COM_IDMaskOperation.cpp + operations/COM_IDMaskOperation.cc operations/COM_IDMaskOperation.h - operations/COM_DotproductOperation.cpp + operations/COM_DotproductOperation.cc operations/COM_DotproductOperation.h # Matte operation - operations/COM_BoxMaskOperation.cpp + operations/COM_BoxMaskOperation.cc operations/COM_BoxMaskOperation.h - operations/COM_EllipseMaskOperation.cpp + operations/COM_EllipseMaskOperation.cc operations/COM_EllipseMaskOperation.h - operations/COM_ConvertColorProfileOperation.cpp + operations/COM_ConvertColorProfileOperation.cc operations/COM_ConvertColorProfileOperation.h - operations/COM_MovieClipOperation.cpp + operations/COM_MovieClipOperation.cc operations/COM_MovieClipOperation.h - operations/COM_AntiAliasOperation.cpp + operations/COM_AntiAliasOperation.cc operations/COM_AntiAliasOperation.h - operations/COM_MaskOperation.cpp + operations/COM_MaskOperation.cc operations/COM_MaskOperation.h ) diff --git a/source/blender/compositor/intern/COM_CPUDevice.cc b/source/blender/compositor/intern/COM_CPUDevice.cc new file mode 100644 index 00000000000..b520a437008 --- /dev/null +++ b/source/blender/compositor/intern/COM_CPUDevice.cc @@ -0,0 +1,36 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_CPUDevice.h" + +CPUDevice::CPUDevice(int thread_id) : m_thread_id(thread_id) +{ +} + +void CPUDevice::execute(WorkPackage *work) +{ + const unsigned int chunkNumber = work->chunk_number; + ExecutionGroup *executionGroup = work->execution_group; + rcti rect; + + executionGroup->determineChunkRect(&rect, chunkNumber); + + executionGroup->getOutputOperation()->executeRegion(&rect, chunkNumber); + + executionGroup->finalizeChunkExecution(chunkNumber, nullptr); +} diff --git a/source/blender/compositor/intern/COM_CPUDevice.cpp b/source/blender/compositor/intern/COM_CPUDevice.cpp deleted file mode 100644 index b520a437008..00000000000 --- a/source/blender/compositor/intern/COM_CPUDevice.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_CPUDevice.h" - -CPUDevice::CPUDevice(int thread_id) : m_thread_id(thread_id) -{ -} - -void CPUDevice::execute(WorkPackage *work) -{ - const unsigned int chunkNumber = work->chunk_number; - ExecutionGroup *executionGroup = work->execution_group; - rcti rect; - - executionGroup->determineChunkRect(&rect, chunkNumber); - - executionGroup->getOutputOperation()->executeRegion(&rect, chunkNumber); - - executionGroup->finalizeChunkExecution(chunkNumber, nullptr); -} diff --git a/source/blender/compositor/intern/COM_ChunkOrder.cc b/source/blender/compositor/intern/COM_ChunkOrder.cc new file mode 100644 index 00000000000..3baa50da487 --- /dev/null +++ b/source/blender/compositor/intern/COM_ChunkOrder.cc @@ -0,0 +1,46 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ChunkOrder.h" +#include "BLI_math.h" + +ChunkOrder::ChunkOrder() +{ + distance = 0.0; + number = 0; + x = 0; + y = 0; +} + +void ChunkOrder::update_distance(ChunkOrderHotspot **hotspots, unsigned int len_hotspots) +{ + double new_distance = FLT_MAX; + for (int index = 0; index < len_hotspots; index++) { + ChunkOrderHotspot *hotspot = hotspots[index]; + double distance_to_hotspot = hotspot->calc_distance(x, y); + if (distance_to_hotspot < new_distance) { + new_distance = distance_to_hotspot; + } + } + this->distance = new_distance; +} + +bool operator<(const ChunkOrder &a, const ChunkOrder &b) +{ + return a.distance < b.distance; +} diff --git a/source/blender/compositor/intern/COM_ChunkOrder.cpp b/source/blender/compositor/intern/COM_ChunkOrder.cpp deleted file mode 100644 index 3baa50da487..00000000000 --- a/source/blender/compositor/intern/COM_ChunkOrder.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ChunkOrder.h" -#include "BLI_math.h" - -ChunkOrder::ChunkOrder() -{ - distance = 0.0; - number = 0; - x = 0; - y = 0; -} - -void ChunkOrder::update_distance(ChunkOrderHotspot **hotspots, unsigned int len_hotspots) -{ - double new_distance = FLT_MAX; - for (int index = 0; index < len_hotspots; index++) { - ChunkOrderHotspot *hotspot = hotspots[index]; - double distance_to_hotspot = hotspot->calc_distance(x, y); - if (distance_to_hotspot < new_distance) { - new_distance = distance_to_hotspot; - } - } - this->distance = new_distance; -} - -bool operator<(const ChunkOrder &a, const ChunkOrder &b) -{ - return a.distance < b.distance; -} diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc new file mode 100644 index 00000000000..bbc98d086a6 --- /dev/null +++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc @@ -0,0 +1,36 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ChunkOrderHotspot.h" +#include + +ChunkOrderHotspot::ChunkOrderHotspot(int x, int y, float addition) +{ + x = x; + y = y; + addition = addition; +} + +double ChunkOrderHotspot::calc_distance(int x, int y) +{ + int dx = x - x; + int dy = y - y; + double result = sqrt((double)(dx * dx + dy * dy)); + result += (double)addition; + return result; +} diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp deleted file mode 100644 index bbc98d086a6..00000000000 --- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ChunkOrderHotspot.h" -#include - -ChunkOrderHotspot::ChunkOrderHotspot(int x, int y, float addition) -{ - x = x; - y = y; - addition = addition; -} - -double ChunkOrderHotspot::calc_distance(int x, int y) -{ - int dx = x - x; - int dy = y - y; - double result = sqrt((double)(dx * dx + dy * dy)); - result += (double)addition; - return result; -} diff --git a/source/blender/compositor/intern/COM_CompositorContext.cc b/source/blender/compositor/intern/COM_CompositorContext.cc new file mode 100644 index 00000000000..2e168221b7b --- /dev/null +++ b/source/blender/compositor/intern/COM_CompositorContext.cc @@ -0,0 +1,41 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_CompositorContext.h" +#include "COM_defines.h" +#include + +CompositorContext::CompositorContext() +{ + this->m_scene = nullptr; + this->m_rd = nullptr; + this->m_quality = COM_QUALITY_HIGH; + this->m_hasActiveOpenCLDevices = false; + this->m_fastCalculation = false; + this->m_viewSettings = nullptr; + this->m_displaySettings = nullptr; +} + +int CompositorContext::getFramenumber() const +{ + if (this->m_rd) { + return this->m_rd->cfra; + } + + return -1; /* this should never happen */ +} diff --git a/source/blender/compositor/intern/COM_CompositorContext.cpp b/source/blender/compositor/intern/COM_CompositorContext.cpp deleted file mode 100644 index 2e168221b7b..00000000000 --- a/source/blender/compositor/intern/COM_CompositorContext.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_CompositorContext.h" -#include "COM_defines.h" -#include - -CompositorContext::CompositorContext() -{ - this->m_scene = nullptr; - this->m_rd = nullptr; - this->m_quality = COM_QUALITY_HIGH; - this->m_hasActiveOpenCLDevices = false; - this->m_fastCalculation = false; - this->m_viewSettings = nullptr; - this->m_displaySettings = nullptr; -} - -int CompositorContext::getFramenumber() const -{ - if (this->m_rd) { - return this->m_rd->cfra; - } - - return -1; /* this should never happen */ -} diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc new file mode 100644 index 00000000000..7d897d29576 --- /dev/null +++ b/source/blender/compositor/intern/COM_Converter.cc @@ -0,0 +1,562 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include + +#include "DNA_node_types.h" + +#include "BKE_node.h" + +#include "COM_NodeOperation.h" +#include "COM_NodeOperationBuilder.h" + +#include "COM_AlphaOverNode.h" +#include "COM_BilateralBlurNode.h" +#include "COM_BlurNode.h" +#include "COM_BokehBlurNode.h" +#include "COM_BokehImageNode.h" +#include "COM_BoxMaskNode.h" +#include "COM_BrightnessNode.h" +#include "COM_ChannelMatteNode.h" +#include "COM_ChromaMatteNode.h" +#include "COM_ColorBalanceNode.h" +#include "COM_ColorCorrectionNode.h" +#include "COM_ColorCurveNode.h" +#include "COM_ColorExposureNode.h" +#include "COM_ColorMatteNode.h" +#include "COM_ColorNode.h" +#include "COM_ColorRampNode.h" +#include "COM_ColorSpillNode.h" +#include "COM_ColorToBWNode.h" +#include "COM_CombineColorNode.h" +#include "COM_CompositorNode.h" +#include "COM_ConvertAlphaNode.h" +#include "COM_ConvertOperation.h" +#include "COM_Converter.h" +#include "COM_CornerPinNode.h" +#include "COM_CropNode.h" +#include "COM_CryptomatteNode.h" +#include "COM_DefocusNode.h" +#include "COM_DenoiseNode.h" +#include "COM_DespeckleNode.h" +#include "COM_DifferenceMatteNode.h" +#include "COM_DilateErodeNode.h" +#include "COM_DirectionalBlurNode.h" +#include "COM_DisplaceNode.h" +#include "COM_DistanceMatteNode.h" +#include "COM_DoubleEdgeMaskNode.h" +#include "COM_EllipseMaskNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_FilterNode.h" +#include "COM_FlipNode.h" +#include "COM_GammaNode.h" +#include "COM_GlareNode.h" +#include "COM_HueSaturationValueCorrectNode.h" +#include "COM_HueSaturationValueNode.h" +#include "COM_IDMaskNode.h" +#include "COM_ImageNode.h" +#include "COM_InpaintNode.h" +#include "COM_InvertNode.h" +#include "COM_KeyingNode.h" +#include "COM_KeyingScreenNode.h" +#include "COM_LensDistortionNode.h" +#include "COM_LuminanceMatteNode.h" +#include "COM_MapRangeNode.h" +#include "COM_MapUVNode.h" +#include "COM_MapValueNode.h" +#include "COM_MaskNode.h" +#include "COM_MathNode.h" +#include "COM_MixNode.h" +#include "COM_MovieClipNode.h" +#include "COM_MovieDistortionNode.h" +#include "COM_NormalNode.h" +#include "COM_NormalizeNode.h" +#include "COM_OutputFileNode.h" +#include "COM_PixelateNode.h" +#include "COM_PlaneTrackDeformNode.h" +#include "COM_RenderLayersNode.h" +#include "COM_RotateNode.h" +#include "COM_ScaleNode.h" +#include "COM_ScaleOperation.h" +#include "COM_SeparateColorNode.h" +#include "COM_SetAlphaNode.h" +#include "COM_SetValueOperation.h" +#include "COM_SplitViewerNode.h" +#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" +#include "COM_TrackPositionNode.h" +#include "COM_TransformNode.h" +#include "COM_TranslateNode.h" +#include "COM_TranslateOperation.h" +#include "COM_ValueNode.h" +#include "COM_VectorBlurNode.h" +#include "COM_VectorCurveNode.h" +#include "COM_ViewLevelsNode.h" +#include "COM_ViewerNode.h" +#include "COM_ZCombineNode.h" + +bool COM_bnode_is_fast_node(const bNode &b_node) +{ + return !ELEM(b_node.type, + CMP_NODE_BLUR, + CMP_NODE_VECBLUR, + CMP_NODE_BILATERALBLUR, + CMP_NODE_DEFOCUS, + CMP_NODE_BOKEHBLUR, + CMP_NODE_GLARE, + CMP_NODE_DBLUR, + CMP_NODE_MOVIEDISTORTION, + CMP_NODE_LENSDIST, + CMP_NODE_DOUBLEEDGEMASK, + CMP_NODE_DILATEERODE, + CMP_NODE_DENOISE); +} + +Node *COM_convert_bnode(bNode *b_node) +{ + Node *node = nullptr; + + /* ignore undefined nodes with missing or invalid node data */ + if (nodeTypeUndefined(b_node)) { + return nullptr; + } + + switch (b_node->type) { + case CMP_NODE_COMPOSITE: + node = new CompositorNode(b_node); + break; + case CMP_NODE_R_LAYERS: + node = new RenderLayersNode(b_node); + break; + case CMP_NODE_TEXTURE: + node = new TextureNode(b_node); + break; + case CMP_NODE_RGBTOBW: + node = new ColorToBWNode(b_node); + break; + case CMP_NODE_MIX_RGB: + node = new MixNode(b_node); + break; + case CMP_NODE_TRANSLATE: + node = new TranslateNode(b_node); + break; + case CMP_NODE_SCALE: + node = new ScaleNode(b_node); + break; + case CMP_NODE_ROTATE: + node = new RotateNode(b_node); + break; + case CMP_NODE_FLIP: + node = new FlipNode(b_node); + break; + case CMP_NODE_FILTER: + node = new FilterNode(b_node); + break; + case CMP_NODE_ID_MASK: + node = new IDMaskNode(b_node); + break; + case CMP_NODE_BRIGHTCONTRAST: + node = new BrightnessNode(b_node); + break; + case CMP_NODE_SEPRGBA: + node = new SeparateRGBANode(b_node); + break; + case CMP_NODE_COMBRGBA: + node = new CombineRGBANode(b_node); + break; + case CMP_NODE_SEPHSVA: + node = new SeparateHSVANode(b_node); + break; + case CMP_NODE_COMBHSVA: + node = new CombineHSVANode(b_node); + break; + case CMP_NODE_SEPYUVA: + node = new SeparateYUVANode(b_node); + break; + case CMP_NODE_COMBYUVA: + node = new CombineYUVANode(b_node); + break; + case CMP_NODE_SEPYCCA: + node = new SeparateYCCANode(b_node); + break; + case CMP_NODE_COMBYCCA: + node = new CombineYCCANode(b_node); + break; + case CMP_NODE_ALPHAOVER: + node = new AlphaOverNode(b_node); + break; + case CMP_NODE_COLORBALANCE: + node = new ColorBalanceNode(b_node); + break; + case CMP_NODE_VIEWER: + node = new ViewerNode(b_node); + break; + case CMP_NODE_SPLITVIEWER: + node = new SplitViewerNode(b_node); + break; + case CMP_NODE_INVERT: + node = new InvertNode(b_node); + break; + case NODE_GROUP: + case NODE_GROUP_INPUT: + case NODE_GROUP_OUTPUT: + /* handled in NodeCompiler */ + break; + case CMP_NODE_NORMAL: + node = new NormalNode(b_node); + break; + case CMP_NODE_NORMALIZE: + node = new NormalizeNode(b_node); + break; + case CMP_NODE_IMAGE: + node = new ImageNode(b_node); + break; + case CMP_NODE_SETALPHA: + node = new SetAlphaNode(b_node); + break; + case CMP_NODE_PREMULKEY: + node = new ConvertAlphaNode(b_node); + break; + case CMP_NODE_MATH: + node = new MathNode(b_node); + break; + case CMP_NODE_HUE_SAT: + node = new HueSaturationValueNode(b_node); + break; + case CMP_NODE_COLORCORRECTION: + node = new ColorCorrectionNode(b_node); + break; + case CMP_NODE_MASK_BOX: + node = new BoxMaskNode(b_node); + break; + case CMP_NODE_MASK_ELLIPSE: + node = new EllipseMaskNode(b_node); + break; + case CMP_NODE_GAMMA: + node = new GammaNode(b_node); + break; + case CMP_NODE_CURVE_RGB: + node = new ColorCurveNode(b_node); + break; + case CMP_NODE_CURVE_VEC: + node = new VectorCurveNode(b_node); + break; + case CMP_NODE_HUECORRECT: + node = new HueSaturationValueCorrectNode(b_node); + break; + case CMP_NODE_MAP_UV: + node = new MapUVNode(b_node); + break; + case CMP_NODE_DISPLACE: + node = new DisplaceNode(b_node); + break; + case CMP_NODE_VALTORGB: + node = new ColorRampNode(b_node); + break; + case CMP_NODE_DIFF_MATTE: + node = new DifferenceMatteNode(b_node); + break; + case CMP_NODE_LUMA_MATTE: + node = new LuminanceMatteNode(b_node); + break; + case CMP_NODE_DIST_MATTE: + node = new DistanceMatteNode(b_node); + break; + case CMP_NODE_CHROMA_MATTE: + node = new ChromaMatteNode(b_node); + break; + case CMP_NODE_COLOR_MATTE: + node = new ColorMatteNode(b_node); + break; + case CMP_NODE_CHANNEL_MATTE: + node = new ChannelMatteNode(b_node); + break; + case CMP_NODE_BLUR: + node = new BlurNode(b_node); + break; + case CMP_NODE_BOKEHIMAGE: + node = new BokehImageNode(b_node); + break; + case CMP_NODE_BOKEHBLUR: + node = new BokehBlurNode(b_node); + break; + case CMP_NODE_DILATEERODE: + node = new DilateErodeNode(b_node); + break; + case CMP_NODE_INPAINT: + node = new InpaintNode(b_node); + break; + case CMP_NODE_DESPECKLE: + node = new DespeckleNode(b_node); + break; + case CMP_NODE_LENSDIST: + node = new LensDistortionNode(b_node); + break; + case CMP_NODE_RGB: + node = new ColorNode(b_node); + break; + case CMP_NODE_VALUE: + node = new ValueNode(b_node); + break; + case CMP_NODE_TIME: + node = new TimeNode(b_node); + break; + case CMP_NODE_DBLUR: + node = new DirectionalBlurNode(b_node); + break; + case CMP_NODE_ZCOMBINE: + node = new ZCombineNode(b_node); + break; + case CMP_NODE_TONEMAP: + node = new TonemapNode(b_node); + break; + 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; + case CMP_NODE_MOVIECLIP: + node = new MovieClipNode(b_node); + break; + case CMP_NODE_COLOR_SPILL: + node = new ColorSpillNode(b_node); + break; + case CMP_NODE_OUTPUT_FILE: + node = new OutputFileNode(b_node); + break; + case CMP_NODE_MAP_VALUE: + node = new MapValueNode(b_node); + break; + case CMP_NODE_MAP_RANGE: + node = new MapRangeNode(b_node); + break; + case CMP_NODE_TRANSFORM: + node = new TransformNode(b_node); + break; + case CMP_NODE_STABILIZE2D: + node = new Stabilize2dNode(b_node); + break; + case CMP_NODE_BILATERALBLUR: + node = new BilateralBlurNode(b_node); + break; + case CMP_NODE_VECBLUR: + node = new VectorBlurNode(b_node); + break; + case CMP_NODE_MOVIEDISTORTION: + node = new MovieDistortionNode(b_node); + break; + case CMP_NODE_VIEW_LEVELS: + node = new ViewLevelsNode(b_node); + break; + case CMP_NODE_DEFOCUS: + node = new DefocusNode(b_node); + break; + case CMP_NODE_DOUBLEEDGEMASK: + node = new DoubleEdgeMaskNode(b_node); + break; + case CMP_NODE_CROP: + node = new CropNode(b_node); + break; + case CMP_NODE_MASK: + node = new MaskNode(b_node); + break; + case CMP_NODE_KEYINGSCREEN: + node = new KeyingScreenNode(b_node); + break; + case CMP_NODE_KEYING: + node = new KeyingNode(b_node); + break; + case CMP_NODE_TRACKPOS: + node = new TrackPositionNode(b_node); + break; + /* not implemented yet */ + case CMP_NODE_PIXELATE: + node = new PixelateNode(b_node); + break; + case CMP_NODE_PLANETRACKDEFORM: + node = new PlaneTrackDeformNode(b_node); + break; + case CMP_NODE_CORNERPIN: + node = new CornerPinNode(b_node); + break; + case CMP_NODE_SUNBEAMS: + node = new SunBeamsNode(b_node); + break; + case CMP_NODE_CRYPTOMATTE: + node = new CryptomatteNode(b_node); + break; + case CMP_NODE_DENOISE: + node = new DenoiseNode(b_node); + break; + case CMP_NODE_EXPOSURE: + node = new ExposureNode(b_node); + break; + } + return node; +} + +/* TODO(jbakker): make this an std::optional. */ +NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, const NodeOperationInput &to) +{ + const DataType src_data_type = from.getDataType(); + const DataType dst_data_type = to.getDataType(); + + if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_COLOR) { + return new ConvertValueToColorOperation(); + } + if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_VECTOR) { + return new ConvertValueToVectorOperation(); + } + if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VALUE) { + return new ConvertColorToValueOperation(); + } + if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VECTOR) { + return new ConvertColorToVectorOperation(); + } + if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_VALUE) { + return new ConvertVectorToValueOperation(); + } + if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_COLOR) { + return new ConvertVectorToColorOperation(); + } + + return nullptr; +} + +void COM_convert_resolution(NodeOperationBuilder &builder, + NodeOperationOutput *fromSocket, + NodeOperationInput *toSocket) +{ + InputResizeMode mode = toSocket->getResizeMode(); + + NodeOperation *toOperation = &toSocket->getOperation(); + const float toWidth = toOperation->getWidth(); + const float toHeight = toOperation->getHeight(); + NodeOperation *fromOperation = &fromSocket->getOperation(); + const float fromWidth = fromOperation->getWidth(); + const float fromHeight = fromOperation->getHeight(); + bool doCenter = false; + bool doScale = false; + float addX = (toWidth - fromWidth) / 2.0f; + float addY = (toHeight - fromHeight) / 2.0f; + float scaleX = 0; + float scaleY = 0; + + switch (mode) { + case COM_SC_NO_RESIZE: + break; + case COM_SC_CENTER: + doCenter = true; + break; + case COM_SC_FIT_WIDTH: + doCenter = true; + doScale = true; + scaleX = scaleY = toWidth / fromWidth; + break; + case COM_SC_FIT_HEIGHT: + doCenter = true; + doScale = true; + scaleX = scaleY = toHeight / fromHeight; + break; + case COM_SC_FIT: + doCenter = true; + doScale = true; + scaleX = toWidth / fromWidth; + scaleY = toHeight / fromHeight; + if (scaleX < scaleY) { + scaleX = scaleY; + } + else { + scaleY = scaleX; + } + break; + case COM_SC_STRETCH: + doCenter = true; + doScale = true; + scaleX = toWidth / fromWidth; + scaleY = toHeight / fromHeight; + break; + } + + if (doCenter) { + NodeOperation *first = nullptr; + ScaleOperation *scaleOperation = nullptr; + if (doScale) { + scaleOperation = new ScaleOperation(); + scaleOperation->getInputSocket(1)->setResizeMode(COM_SC_NO_RESIZE); + scaleOperation->getInputSocket(2)->setResizeMode(COM_SC_NO_RESIZE); + first = scaleOperation; + SetValueOperation *sxop = new SetValueOperation(); + sxop->setValue(scaleX); + builder.addLink(sxop->getOutputSocket(), scaleOperation->getInputSocket(1)); + SetValueOperation *syop = new SetValueOperation(); + syop->setValue(scaleY); + builder.addLink(syop->getOutputSocket(), scaleOperation->getInputSocket(2)); + builder.addOperation(sxop); + builder.addOperation(syop); + + unsigned int resolution[2] = {fromOperation->getWidth(), fromOperation->getHeight()}; + scaleOperation->setResolution(resolution); + sxop->setResolution(resolution); + syop->setResolution(resolution); + builder.addOperation(scaleOperation); + } + + TranslateOperation *translateOperation = new TranslateOperation(); + translateOperation->getInputSocket(1)->setResizeMode(COM_SC_NO_RESIZE); + translateOperation->getInputSocket(2)->setResizeMode(COM_SC_NO_RESIZE); + if (!first) { + first = translateOperation; + } + SetValueOperation *xop = new SetValueOperation(); + xop->setValue(addX); + builder.addLink(xop->getOutputSocket(), translateOperation->getInputSocket(1)); + SetValueOperation *yop = new SetValueOperation(); + yop->setValue(addY); + builder.addLink(yop->getOutputSocket(), translateOperation->getInputSocket(2)); + builder.addOperation(xop); + builder.addOperation(yop); + + unsigned int resolution[2] = {toOperation->getWidth(), toOperation->getHeight()}; + translateOperation->setResolution(resolution); + xop->setResolution(resolution); + yop->setResolution(resolution); + builder.addOperation(translateOperation); + + if (doScale) { + translateOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); + builder.addLink(scaleOperation->getOutputSocket(), translateOperation->getInputSocket(0)); + } + + /* remove previous link and replace */ + builder.removeInputLink(toSocket); + first->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); + toSocket->setResizeMode(COM_SC_NO_RESIZE); + builder.addLink(fromSocket, first->getInputSocket(0)); + builder.addLink(translateOperation->getOutputSocket(), toSocket); + } +} diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp deleted file mode 100644 index 7d897d29576..00000000000 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ /dev/null @@ -1,562 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include - -#include "DNA_node_types.h" - -#include "BKE_node.h" - -#include "COM_NodeOperation.h" -#include "COM_NodeOperationBuilder.h" - -#include "COM_AlphaOverNode.h" -#include "COM_BilateralBlurNode.h" -#include "COM_BlurNode.h" -#include "COM_BokehBlurNode.h" -#include "COM_BokehImageNode.h" -#include "COM_BoxMaskNode.h" -#include "COM_BrightnessNode.h" -#include "COM_ChannelMatteNode.h" -#include "COM_ChromaMatteNode.h" -#include "COM_ColorBalanceNode.h" -#include "COM_ColorCorrectionNode.h" -#include "COM_ColorCurveNode.h" -#include "COM_ColorExposureNode.h" -#include "COM_ColorMatteNode.h" -#include "COM_ColorNode.h" -#include "COM_ColorRampNode.h" -#include "COM_ColorSpillNode.h" -#include "COM_ColorToBWNode.h" -#include "COM_CombineColorNode.h" -#include "COM_CompositorNode.h" -#include "COM_ConvertAlphaNode.h" -#include "COM_ConvertOperation.h" -#include "COM_Converter.h" -#include "COM_CornerPinNode.h" -#include "COM_CropNode.h" -#include "COM_CryptomatteNode.h" -#include "COM_DefocusNode.h" -#include "COM_DenoiseNode.h" -#include "COM_DespeckleNode.h" -#include "COM_DifferenceMatteNode.h" -#include "COM_DilateErodeNode.h" -#include "COM_DirectionalBlurNode.h" -#include "COM_DisplaceNode.h" -#include "COM_DistanceMatteNode.h" -#include "COM_DoubleEdgeMaskNode.h" -#include "COM_EllipseMaskNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_FilterNode.h" -#include "COM_FlipNode.h" -#include "COM_GammaNode.h" -#include "COM_GlareNode.h" -#include "COM_HueSaturationValueCorrectNode.h" -#include "COM_HueSaturationValueNode.h" -#include "COM_IDMaskNode.h" -#include "COM_ImageNode.h" -#include "COM_InpaintNode.h" -#include "COM_InvertNode.h" -#include "COM_KeyingNode.h" -#include "COM_KeyingScreenNode.h" -#include "COM_LensDistortionNode.h" -#include "COM_LuminanceMatteNode.h" -#include "COM_MapRangeNode.h" -#include "COM_MapUVNode.h" -#include "COM_MapValueNode.h" -#include "COM_MaskNode.h" -#include "COM_MathNode.h" -#include "COM_MixNode.h" -#include "COM_MovieClipNode.h" -#include "COM_MovieDistortionNode.h" -#include "COM_NormalNode.h" -#include "COM_NormalizeNode.h" -#include "COM_OutputFileNode.h" -#include "COM_PixelateNode.h" -#include "COM_PlaneTrackDeformNode.h" -#include "COM_RenderLayersNode.h" -#include "COM_RotateNode.h" -#include "COM_ScaleNode.h" -#include "COM_ScaleOperation.h" -#include "COM_SeparateColorNode.h" -#include "COM_SetAlphaNode.h" -#include "COM_SetValueOperation.h" -#include "COM_SplitViewerNode.h" -#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" -#include "COM_TrackPositionNode.h" -#include "COM_TransformNode.h" -#include "COM_TranslateNode.h" -#include "COM_TranslateOperation.h" -#include "COM_ValueNode.h" -#include "COM_VectorBlurNode.h" -#include "COM_VectorCurveNode.h" -#include "COM_ViewLevelsNode.h" -#include "COM_ViewerNode.h" -#include "COM_ZCombineNode.h" - -bool COM_bnode_is_fast_node(const bNode &b_node) -{ - return !ELEM(b_node.type, - CMP_NODE_BLUR, - CMP_NODE_VECBLUR, - CMP_NODE_BILATERALBLUR, - CMP_NODE_DEFOCUS, - CMP_NODE_BOKEHBLUR, - CMP_NODE_GLARE, - CMP_NODE_DBLUR, - CMP_NODE_MOVIEDISTORTION, - CMP_NODE_LENSDIST, - CMP_NODE_DOUBLEEDGEMASK, - CMP_NODE_DILATEERODE, - CMP_NODE_DENOISE); -} - -Node *COM_convert_bnode(bNode *b_node) -{ - Node *node = nullptr; - - /* ignore undefined nodes with missing or invalid node data */ - if (nodeTypeUndefined(b_node)) { - return nullptr; - } - - switch (b_node->type) { - case CMP_NODE_COMPOSITE: - node = new CompositorNode(b_node); - break; - case CMP_NODE_R_LAYERS: - node = new RenderLayersNode(b_node); - break; - case CMP_NODE_TEXTURE: - node = new TextureNode(b_node); - break; - case CMP_NODE_RGBTOBW: - node = new ColorToBWNode(b_node); - break; - case CMP_NODE_MIX_RGB: - node = new MixNode(b_node); - break; - case CMP_NODE_TRANSLATE: - node = new TranslateNode(b_node); - break; - case CMP_NODE_SCALE: - node = new ScaleNode(b_node); - break; - case CMP_NODE_ROTATE: - node = new RotateNode(b_node); - break; - case CMP_NODE_FLIP: - node = new FlipNode(b_node); - break; - case CMP_NODE_FILTER: - node = new FilterNode(b_node); - break; - case CMP_NODE_ID_MASK: - node = new IDMaskNode(b_node); - break; - case CMP_NODE_BRIGHTCONTRAST: - node = new BrightnessNode(b_node); - break; - case CMP_NODE_SEPRGBA: - node = new SeparateRGBANode(b_node); - break; - case CMP_NODE_COMBRGBA: - node = new CombineRGBANode(b_node); - break; - case CMP_NODE_SEPHSVA: - node = new SeparateHSVANode(b_node); - break; - case CMP_NODE_COMBHSVA: - node = new CombineHSVANode(b_node); - break; - case CMP_NODE_SEPYUVA: - node = new SeparateYUVANode(b_node); - break; - case CMP_NODE_COMBYUVA: - node = new CombineYUVANode(b_node); - break; - case CMP_NODE_SEPYCCA: - node = new SeparateYCCANode(b_node); - break; - case CMP_NODE_COMBYCCA: - node = new CombineYCCANode(b_node); - break; - case CMP_NODE_ALPHAOVER: - node = new AlphaOverNode(b_node); - break; - case CMP_NODE_COLORBALANCE: - node = new ColorBalanceNode(b_node); - break; - case CMP_NODE_VIEWER: - node = new ViewerNode(b_node); - break; - case CMP_NODE_SPLITVIEWER: - node = new SplitViewerNode(b_node); - break; - case CMP_NODE_INVERT: - node = new InvertNode(b_node); - break; - case NODE_GROUP: - case NODE_GROUP_INPUT: - case NODE_GROUP_OUTPUT: - /* handled in NodeCompiler */ - break; - case CMP_NODE_NORMAL: - node = new NormalNode(b_node); - break; - case CMP_NODE_NORMALIZE: - node = new NormalizeNode(b_node); - break; - case CMP_NODE_IMAGE: - node = new ImageNode(b_node); - break; - case CMP_NODE_SETALPHA: - node = new SetAlphaNode(b_node); - break; - case CMP_NODE_PREMULKEY: - node = new ConvertAlphaNode(b_node); - break; - case CMP_NODE_MATH: - node = new MathNode(b_node); - break; - case CMP_NODE_HUE_SAT: - node = new HueSaturationValueNode(b_node); - break; - case CMP_NODE_COLORCORRECTION: - node = new ColorCorrectionNode(b_node); - break; - case CMP_NODE_MASK_BOX: - node = new BoxMaskNode(b_node); - break; - case CMP_NODE_MASK_ELLIPSE: - node = new EllipseMaskNode(b_node); - break; - case CMP_NODE_GAMMA: - node = new GammaNode(b_node); - break; - case CMP_NODE_CURVE_RGB: - node = new ColorCurveNode(b_node); - break; - case CMP_NODE_CURVE_VEC: - node = new VectorCurveNode(b_node); - break; - case CMP_NODE_HUECORRECT: - node = new HueSaturationValueCorrectNode(b_node); - break; - case CMP_NODE_MAP_UV: - node = new MapUVNode(b_node); - break; - case CMP_NODE_DISPLACE: - node = new DisplaceNode(b_node); - break; - case CMP_NODE_VALTORGB: - node = new ColorRampNode(b_node); - break; - case CMP_NODE_DIFF_MATTE: - node = new DifferenceMatteNode(b_node); - break; - case CMP_NODE_LUMA_MATTE: - node = new LuminanceMatteNode(b_node); - break; - case CMP_NODE_DIST_MATTE: - node = new DistanceMatteNode(b_node); - break; - case CMP_NODE_CHROMA_MATTE: - node = new ChromaMatteNode(b_node); - break; - case CMP_NODE_COLOR_MATTE: - node = new ColorMatteNode(b_node); - break; - case CMP_NODE_CHANNEL_MATTE: - node = new ChannelMatteNode(b_node); - break; - case CMP_NODE_BLUR: - node = new BlurNode(b_node); - break; - case CMP_NODE_BOKEHIMAGE: - node = new BokehImageNode(b_node); - break; - case CMP_NODE_BOKEHBLUR: - node = new BokehBlurNode(b_node); - break; - case CMP_NODE_DILATEERODE: - node = new DilateErodeNode(b_node); - break; - case CMP_NODE_INPAINT: - node = new InpaintNode(b_node); - break; - case CMP_NODE_DESPECKLE: - node = new DespeckleNode(b_node); - break; - case CMP_NODE_LENSDIST: - node = new LensDistortionNode(b_node); - break; - case CMP_NODE_RGB: - node = new ColorNode(b_node); - break; - case CMP_NODE_VALUE: - node = new ValueNode(b_node); - break; - case CMP_NODE_TIME: - node = new TimeNode(b_node); - break; - case CMP_NODE_DBLUR: - node = new DirectionalBlurNode(b_node); - break; - case CMP_NODE_ZCOMBINE: - node = new ZCombineNode(b_node); - break; - case CMP_NODE_TONEMAP: - node = new TonemapNode(b_node); - break; - 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; - case CMP_NODE_MOVIECLIP: - node = new MovieClipNode(b_node); - break; - case CMP_NODE_COLOR_SPILL: - node = new ColorSpillNode(b_node); - break; - case CMP_NODE_OUTPUT_FILE: - node = new OutputFileNode(b_node); - break; - case CMP_NODE_MAP_VALUE: - node = new MapValueNode(b_node); - break; - case CMP_NODE_MAP_RANGE: - node = new MapRangeNode(b_node); - break; - case CMP_NODE_TRANSFORM: - node = new TransformNode(b_node); - break; - case CMP_NODE_STABILIZE2D: - node = new Stabilize2dNode(b_node); - break; - case CMP_NODE_BILATERALBLUR: - node = new BilateralBlurNode(b_node); - break; - case CMP_NODE_VECBLUR: - node = new VectorBlurNode(b_node); - break; - case CMP_NODE_MOVIEDISTORTION: - node = new MovieDistortionNode(b_node); - break; - case CMP_NODE_VIEW_LEVELS: - node = new ViewLevelsNode(b_node); - break; - case CMP_NODE_DEFOCUS: - node = new DefocusNode(b_node); - break; - case CMP_NODE_DOUBLEEDGEMASK: - node = new DoubleEdgeMaskNode(b_node); - break; - case CMP_NODE_CROP: - node = new CropNode(b_node); - break; - case CMP_NODE_MASK: - node = new MaskNode(b_node); - break; - case CMP_NODE_KEYINGSCREEN: - node = new KeyingScreenNode(b_node); - break; - case CMP_NODE_KEYING: - node = new KeyingNode(b_node); - break; - case CMP_NODE_TRACKPOS: - node = new TrackPositionNode(b_node); - break; - /* not implemented yet */ - case CMP_NODE_PIXELATE: - node = new PixelateNode(b_node); - break; - case CMP_NODE_PLANETRACKDEFORM: - node = new PlaneTrackDeformNode(b_node); - break; - case CMP_NODE_CORNERPIN: - node = new CornerPinNode(b_node); - break; - case CMP_NODE_SUNBEAMS: - node = new SunBeamsNode(b_node); - break; - case CMP_NODE_CRYPTOMATTE: - node = new CryptomatteNode(b_node); - break; - case CMP_NODE_DENOISE: - node = new DenoiseNode(b_node); - break; - case CMP_NODE_EXPOSURE: - node = new ExposureNode(b_node); - break; - } - return node; -} - -/* TODO(jbakker): make this an std::optional. */ -NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, const NodeOperationInput &to) -{ - const DataType src_data_type = from.getDataType(); - const DataType dst_data_type = to.getDataType(); - - if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_COLOR) { - return new ConvertValueToColorOperation(); - } - if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_VECTOR) { - return new ConvertValueToVectorOperation(); - } - if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VALUE) { - return new ConvertColorToValueOperation(); - } - if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VECTOR) { - return new ConvertColorToVectorOperation(); - } - if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_VALUE) { - return new ConvertVectorToValueOperation(); - } - if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_COLOR) { - return new ConvertVectorToColorOperation(); - } - - return nullptr; -} - -void COM_convert_resolution(NodeOperationBuilder &builder, - NodeOperationOutput *fromSocket, - NodeOperationInput *toSocket) -{ - InputResizeMode mode = toSocket->getResizeMode(); - - NodeOperation *toOperation = &toSocket->getOperation(); - const float toWidth = toOperation->getWidth(); - const float toHeight = toOperation->getHeight(); - NodeOperation *fromOperation = &fromSocket->getOperation(); - const float fromWidth = fromOperation->getWidth(); - const float fromHeight = fromOperation->getHeight(); - bool doCenter = false; - bool doScale = false; - float addX = (toWidth - fromWidth) / 2.0f; - float addY = (toHeight - fromHeight) / 2.0f; - float scaleX = 0; - float scaleY = 0; - - switch (mode) { - case COM_SC_NO_RESIZE: - break; - case COM_SC_CENTER: - doCenter = true; - break; - case COM_SC_FIT_WIDTH: - doCenter = true; - doScale = true; - scaleX = scaleY = toWidth / fromWidth; - break; - case COM_SC_FIT_HEIGHT: - doCenter = true; - doScale = true; - scaleX = scaleY = toHeight / fromHeight; - break; - case COM_SC_FIT: - doCenter = true; - doScale = true; - scaleX = toWidth / fromWidth; - scaleY = toHeight / fromHeight; - if (scaleX < scaleY) { - scaleX = scaleY; - } - else { - scaleY = scaleX; - } - break; - case COM_SC_STRETCH: - doCenter = true; - doScale = true; - scaleX = toWidth / fromWidth; - scaleY = toHeight / fromHeight; - break; - } - - if (doCenter) { - NodeOperation *first = nullptr; - ScaleOperation *scaleOperation = nullptr; - if (doScale) { - scaleOperation = new ScaleOperation(); - scaleOperation->getInputSocket(1)->setResizeMode(COM_SC_NO_RESIZE); - scaleOperation->getInputSocket(2)->setResizeMode(COM_SC_NO_RESIZE); - first = scaleOperation; - SetValueOperation *sxop = new SetValueOperation(); - sxop->setValue(scaleX); - builder.addLink(sxop->getOutputSocket(), scaleOperation->getInputSocket(1)); - SetValueOperation *syop = new SetValueOperation(); - syop->setValue(scaleY); - builder.addLink(syop->getOutputSocket(), scaleOperation->getInputSocket(2)); - builder.addOperation(sxop); - builder.addOperation(syop); - - unsigned int resolution[2] = {fromOperation->getWidth(), fromOperation->getHeight()}; - scaleOperation->setResolution(resolution); - sxop->setResolution(resolution); - syop->setResolution(resolution); - builder.addOperation(scaleOperation); - } - - TranslateOperation *translateOperation = new TranslateOperation(); - translateOperation->getInputSocket(1)->setResizeMode(COM_SC_NO_RESIZE); - translateOperation->getInputSocket(2)->setResizeMode(COM_SC_NO_RESIZE); - if (!first) { - first = translateOperation; - } - SetValueOperation *xop = new SetValueOperation(); - xop->setValue(addX); - builder.addLink(xop->getOutputSocket(), translateOperation->getInputSocket(1)); - SetValueOperation *yop = new SetValueOperation(); - yop->setValue(addY); - builder.addLink(yop->getOutputSocket(), translateOperation->getInputSocket(2)); - builder.addOperation(xop); - builder.addOperation(yop); - - unsigned int resolution[2] = {toOperation->getWidth(), toOperation->getHeight()}; - translateOperation->setResolution(resolution); - xop->setResolution(resolution); - yop->setResolution(resolution); - builder.addOperation(translateOperation); - - if (doScale) { - translateOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); - builder.addLink(scaleOperation->getOutputSocket(), translateOperation->getInputSocket(0)); - } - - /* remove previous link and replace */ - builder.removeInputLink(toSocket); - first->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); - toSocket->setResizeMode(COM_SC_NO_RESIZE); - builder.addLink(fromSocket, first->getInputSocket(0)); - builder.addLink(translateOperation->getOutputSocket(), toSocket); - } -} diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc new file mode 100644 index 00000000000..b49d575cade --- /dev/null +++ b/source/blender/compositor/intern/COM_Debug.cc @@ -0,0 +1,532 @@ +/* + * 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. + * + * Copyright 2013, Blender Foundation. + */ + +#include "COM_Debug.h" + +#ifdef COM_DEBUG + +# include +# include +# include + +extern "C" { +# include "BLI_fileops.h" +# include "BLI_path_util.h" +# include "BLI_string.h" +# include "BLI_sys_types.h" + +# include "BKE_appdir.h" +# include "BKE_node.h" +# include "DNA_node_types.h" +} + +# include "COM_ExecutionGroup.h" +# include "COM_ExecutionSystem.h" +# include "COM_Node.h" + +# include "COM_ReadBufferOperation.h" +# include "COM_ViewerOperation.h" +# include "COM_WriteBufferOperation.h" + +int DebugInfo::m_file_index = 0; +DebugInfo::NodeNameMap DebugInfo::m_node_names; +DebugInfo::OpNameMap DebugInfo::m_op_names; +std::string DebugInfo::m_current_node_name; +std::string DebugInfo::m_current_op_name; +DebugInfo::GroupStateMap DebugInfo::m_group_states; + +std::string DebugInfo::node_name(const Node *node) +{ + NodeNameMap::const_iterator it = m_node_names.find(node); + if (it != m_node_names.end()) { + return it->second; + } + else { + return ""; + } +} + +std::string DebugInfo::operation_name(const NodeOperation *op) +{ + OpNameMap::const_iterator it = m_op_names.find(op); + if (it != m_op_names.end()) { + return it->second; + } + else { + return ""; + } +} + +void DebugInfo::convert_started() +{ + m_op_names.clear(); +} + +void DebugInfo::execute_started(const ExecutionSystem *system) +{ + m_file_index = 1; + m_group_states.clear(); + for (ExecutionSystem::Groups::const_iterator it = system->m_groups.begin(); + it != system->m_groups.end(); + ++it) { + m_group_states[*it] = EG_WAIT; + } +} + +void DebugInfo::node_added(const Node *node) +{ + m_node_names[node] = std::string(node->getbNode() ? node->getbNode()->name : ""); +} + +void DebugInfo::node_to_operations(const Node *node) +{ + m_current_node_name = m_node_names[node]; +} + +void DebugInfo::operation_added(const NodeOperation *operation) +{ + m_op_names[operation] = m_current_node_name; +} + +void DebugInfo::operation_read_write_buffer(const NodeOperation *operation) +{ + m_current_op_name = m_op_names[operation]; +} + +void DebugInfo::execution_group_started(const ExecutionGroup *group) +{ + m_group_states[group] = EG_RUNNING; +} + +void DebugInfo::execution_group_finished(const ExecutionGroup *group) +{ + m_group_states[group] = EG_FINISHED; +} + +int DebugInfo::graphviz_operation(const ExecutionSystem *system, + const NodeOperation *operation, + const ExecutionGroup *group, + char *str, + int maxlen) +{ + int len = 0; + + std::string fillcolor = "gainsboro"; + if (operation->isViewerOperation()) { + const ViewerOperation *viewer = (const ViewerOperation *)operation; + if (viewer->isActiveViewerOutput()) { + fillcolor = "lightskyblue1"; + } + else { + fillcolor = "lightskyblue3"; + } + } + else if (operation->isOutputOperation(system->getContext().isRendering())) { + fillcolor = "dodgerblue1"; + } + else if (operation->isSetOperation()) { + fillcolor = "khaki1"; + } + else if (operation->isReadBufferOperation()) { + fillcolor = "darkolivegreen3"; + } + else if (operation->isWriteBufferOperation()) { + fillcolor = "darkorange"; + } + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// OPERATION: %p\r\n", operation); + if (group) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\"O_%p_%p\"", operation, group); + } + else { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\"O_%p\"", operation); + } + len += snprintf(str + len, + maxlen > len ? maxlen - len : 0, + " [fillcolor=%s,style=filled,shape=record,label=\"{", + fillcolor.c_str()); + + int totinputs = operation->getNumberOfInputSockets(); + if (totinputs != 0) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{"); + for (int k = 0; k < totinputs; k++) { + NodeOperationInput *socket = operation->getInputSocket(k); + if (k != 0) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); + } + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "", socket); + switch (socket->getDataType()) { + case COM_DT_VALUE: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value"); + break; + case COM_DT_VECTOR: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Vector"); + break; + case COM_DT_COLOR: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Color"); + break; + } + } + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); + } + + len += snprintf(str + len, + maxlen > len ? maxlen - len : 0, + "%s\\n(%s)", + m_op_names[operation].c_str(), + typeid(*operation).name()); + + len += snprintf(str + len, + maxlen > len ? maxlen - len : 0, + " (%u,%u)", + operation->getWidth(), + operation->getHeight()); + + int totoutputs = operation->getNumberOfOutputSockets(); + if (totoutputs != 0) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{"); + for (int k = 0; k < totoutputs; k++) { + NodeOperationOutput *socket = operation->getOutputSocket(k); + if (k != 0) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); + } + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "", socket); + switch (socket->getDataType()) { + case COM_DT_VALUE: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value"); + break; + case COM_DT_VECTOR: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Vector"); + break; + case COM_DT_COLOR: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Color"); + break; + } + } + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}"); + } + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\"]"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); + + return len; +} + +int DebugInfo::graphviz_legend_color(const char *name, const char *color, char *str, int maxlen) +{ + int len = 0; + len += snprintf(str + len, + maxlen > len ? maxlen - len : 0, + "
%s
\r\n", + name, + color); + return len; +} + +int DebugInfo::graphviz_legend_line( + const char * /*name*/, const char * /*color*/, const char * /*style*/, char *str, int maxlen) +{ + /* XXX TODO */ + int len = 0; + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); + return len; +} + +int DebugInfo::graphviz_legend_group( + const char *name, const char *color, const char * /*style*/, char *str, int maxlen) +{ + int len = 0; + len += snprintf(str + len, + maxlen > len ? maxlen - len : 0, + "
%s
\r\n", + name, + color); + return len; +} + +int DebugInfo::graphviz_legend(char *str, int maxlen) +{ + int len = 0; + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "rank = sink;\r\n"); + len += snprintf( + str + len, maxlen > len ? maxlen - len : 0, "Legend [shape=none, margin=0, label=<\r\n"); + + len += snprintf( + str + len, + maxlen > len ? maxlen - len : 0, + " \r\n"); + len += snprintf(str + len, + maxlen > len ? maxlen - len : 0, + "\r\n"); + + len += graphviz_legend_color( + "NodeOperation", "gainsboro", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color( + "Output", "dodgerblue1", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color( + "Viewer", "lightskyblue3", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color( + "Active Viewer", "lightskyblue1", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color( + "Write Buffer", "darkorange", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color( + "Read Buffer", "darkolivegreen3", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color( + "Input Value", "khaki1", str + len, maxlen > len ? maxlen - len : 0); + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); + + len += graphviz_legend_group( + "Group Waiting", "white", "dashed", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_group( + "Group Running", "firebrick1", "solid", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_group( + "Group Finished", "chartreuse4", "solid", str + len, maxlen > len ? maxlen - len : 0); + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "
Legend
\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, ">];\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n"); + + return len; +} + +bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int maxlen) +{ + char strbuf[64]; + int len = 0; + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "digraph compositorexecution {\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "ranksep=1.5\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "rankdir=LR\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "splines=false\r\n"); + +# if 0 + for (ExecutionSystem::Operations::const_iterator it = system->m_operations.begin(); + it != system->m_operations.end(); + ++it) { + NodeOperation *op = *it; + len += snprintf(str + len, + maxlen > len ? maxlen - len : 0, + "// OPERATION: %s\r\n", + node->getbNode()->typeinfo->ui_name); + } +# endif + + int totops = system->m_operations.size(); + int totgroups = system->m_groups.size(); + std::map> op_groups; + for (int i = 0; i < totgroups; i++) { + const ExecutionGroup *group = system->m_groups[i]; + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// GROUP: %d\r\n", i); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "subgraph cluster_%d{\r\n", i); + /* used as a check for executing group */ + if (m_group_states[group] == EG_WAIT) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=dashed\r\n"); + } + else if (m_group_states[group] == EG_RUNNING) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=filled\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "color=black\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "fillcolor=firebrick1\r\n"); + } + else if (m_group_states[group] == EG_FINISHED) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=filled\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "color=black\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "fillcolor=chartreuse4\r\n"); + } + + for (ExecutionGroup::Operations::const_iterator it = group->m_operations.begin(); + it != group->m_operations.end(); + ++it) { + NodeOperation *operation = *it; + + sprintf(strbuf, "_%p", group); + op_groups[operation].push_back(std::string(strbuf)); + + len += graphviz_operation( + system, operation, group, str + len, maxlen > len ? maxlen - len : 0); + } + + // len += snprintf(str+len, + // maxlen>len ? maxlen-len : 0, + // "// OUTPUTOPERATION: %p\r\n", group->getOutputOperation()); + // len += snprintf( + // str+len, maxlen>len ? maxlen-len : 0, + // " O_%p\r\n", group->getOutputOperation()); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n"); + } + + /* operations not included in any group */ + for (int j = 0; j < totops; j++) { + NodeOperation *operation = system->m_operations[j]; + if (op_groups.find(operation) != op_groups.end()) { + continue; + } + + op_groups[operation].push_back(std::string("")); + + len += graphviz_operation(system, operation, 0, str + len, maxlen > len ? maxlen - len : 0); + } + + for (int i = 0; i < totops; i++) { + NodeOperation *operation = system->m_operations[i]; + + if (operation->isReadBufferOperation()) { + ReadBufferOperation *read = (ReadBufferOperation *)operation; + WriteBufferOperation *write = read->getMemoryProxy()->getWriteBufferOperation(); + std::vector &read_groups = op_groups[read]; + std::vector &write_groups = op_groups[write]; + + for (int k = 0; k < write_groups.size(); k++) { + for (int l = 0; l < read_groups.size(); l++) { + len += snprintf(str + len, + maxlen > len ? maxlen - len : 0, + "\"O_%p%s\" -> \"O_%p%s\" [style=dotted]\r\n", + write, + write_groups[k].c_str(), + read, + read_groups[l].c_str()); + } + } + } + } + + for (int i = 0; i < totops; i++) { + NodeOperation *op = system->m_operations[i]; + + for (NodeOperation::Inputs::const_iterator it = op->m_inputs.begin(); it != op->m_inputs.end(); + ++it) { + NodeOperationInput *to = *it; + NodeOperationOutput *from = to->getLink(); + + if (!from) { + continue; + } + + std::string color; + switch (from->getDataType()) { + case COM_DT_VALUE: + color = "gray"; + break; + case COM_DT_VECTOR: + color = "blue"; + break; + case COM_DT_COLOR: + color = "orange"; + break; + } + + NodeOperation *to_op = &to->getOperation(); + NodeOperation *from_op = &from->getOperation(); + std::vector &from_groups = op_groups[from_op]; + std::vector &to_groups = op_groups[to_op]; + + len += snprintf(str + len, + maxlen > len ? maxlen - len : 0, + "// CONNECTION: %p.%p -> %p.%p\r\n", + from_op, + from, + to_op, + to); + for (int k = 0; k < from_groups.size(); k++) { + for (int l = 0; l < to_groups.size(); l++) { + len += snprintf(str + len, + maxlen > len ? maxlen - len : 0, + "\"O_%p%s\":\"OUT_%p\":e -> \"O_%p%s\":\"IN_%p\":w", + from_op, + from_groups[k].c_str(), + from, + to_op, + to_groups[l].c_str(), + to); + len += snprintf( + str + len, maxlen > len ? maxlen - len : 0, " [color=%s]", color.c_str()); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); + } + } + } + } + + len += graphviz_legend(str + len, maxlen > len ? maxlen - len : 0); + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n"); + + return (len < maxlen); +} + +void DebugInfo::graphviz(const ExecutionSystem *system) +{ + char str[1000000]; + if (graphviz_system(system, str, sizeof(str) - 1)) { + char basename[FILE_MAX]; + char filename[FILE_MAX]; + + BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", m_file_index); + BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), basename); + m_file_index++; + + FILE *fp = BLI_fopen(filename, "wb"); + fputs(str, fp); + fclose(fp); + } +} + +#else + +std::string DebugInfo::node_name(const Node * /*node*/) +{ + return ""; +} +std::string DebugInfo::operation_name(const NodeOperation * /*op*/) +{ + return ""; +} +void DebugInfo::convert_started() +{ +} +void DebugInfo::execute_started(const ExecutionSystem * /*system*/) +{ +} +void DebugInfo::node_added(const Node * /*node*/) +{ +} +void DebugInfo::node_to_operations(const Node * /*node*/) +{ +} +void DebugInfo::operation_added(const NodeOperation * /*operation*/) +{ +} +void DebugInfo::operation_read_write_buffer(const NodeOperation * /*operation*/) +{ +} +void DebugInfo::execution_group_started(const ExecutionGroup * /*group*/) +{ +} +void DebugInfo::execution_group_finished(const ExecutionGroup * /*group*/) +{ +} +void DebugInfo::graphviz(const ExecutionSystem * /*system*/) +{ +} + +#endif diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cpp deleted file mode 100644 index b49d575cade..00000000000 --- a/source/blender/compositor/intern/COM_Debug.cpp +++ /dev/null @@ -1,532 +0,0 @@ -/* - * 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. - * - * Copyright 2013, Blender Foundation. - */ - -#include "COM_Debug.h" - -#ifdef COM_DEBUG - -# include -# include -# include - -extern "C" { -# include "BLI_fileops.h" -# include "BLI_path_util.h" -# include "BLI_string.h" -# include "BLI_sys_types.h" - -# include "BKE_appdir.h" -# include "BKE_node.h" -# include "DNA_node_types.h" -} - -# include "COM_ExecutionGroup.h" -# include "COM_ExecutionSystem.h" -# include "COM_Node.h" - -# include "COM_ReadBufferOperation.h" -# include "COM_ViewerOperation.h" -# include "COM_WriteBufferOperation.h" - -int DebugInfo::m_file_index = 0; -DebugInfo::NodeNameMap DebugInfo::m_node_names; -DebugInfo::OpNameMap DebugInfo::m_op_names; -std::string DebugInfo::m_current_node_name; -std::string DebugInfo::m_current_op_name; -DebugInfo::GroupStateMap DebugInfo::m_group_states; - -std::string DebugInfo::node_name(const Node *node) -{ - NodeNameMap::const_iterator it = m_node_names.find(node); - if (it != m_node_names.end()) { - return it->second; - } - else { - return ""; - } -} - -std::string DebugInfo::operation_name(const NodeOperation *op) -{ - OpNameMap::const_iterator it = m_op_names.find(op); - if (it != m_op_names.end()) { - return it->second; - } - else { - return ""; - } -} - -void DebugInfo::convert_started() -{ - m_op_names.clear(); -} - -void DebugInfo::execute_started(const ExecutionSystem *system) -{ - m_file_index = 1; - m_group_states.clear(); - for (ExecutionSystem::Groups::const_iterator it = system->m_groups.begin(); - it != system->m_groups.end(); - ++it) { - m_group_states[*it] = EG_WAIT; - } -} - -void DebugInfo::node_added(const Node *node) -{ - m_node_names[node] = std::string(node->getbNode() ? node->getbNode()->name : ""); -} - -void DebugInfo::node_to_operations(const Node *node) -{ - m_current_node_name = m_node_names[node]; -} - -void DebugInfo::operation_added(const NodeOperation *operation) -{ - m_op_names[operation] = m_current_node_name; -} - -void DebugInfo::operation_read_write_buffer(const NodeOperation *operation) -{ - m_current_op_name = m_op_names[operation]; -} - -void DebugInfo::execution_group_started(const ExecutionGroup *group) -{ - m_group_states[group] = EG_RUNNING; -} - -void DebugInfo::execution_group_finished(const ExecutionGroup *group) -{ - m_group_states[group] = EG_FINISHED; -} - -int DebugInfo::graphviz_operation(const ExecutionSystem *system, - const NodeOperation *operation, - const ExecutionGroup *group, - char *str, - int maxlen) -{ - int len = 0; - - std::string fillcolor = "gainsboro"; - if (operation->isViewerOperation()) { - const ViewerOperation *viewer = (const ViewerOperation *)operation; - if (viewer->isActiveViewerOutput()) { - fillcolor = "lightskyblue1"; - } - else { - fillcolor = "lightskyblue3"; - } - } - else if (operation->isOutputOperation(system->getContext().isRendering())) { - fillcolor = "dodgerblue1"; - } - else if (operation->isSetOperation()) { - fillcolor = "khaki1"; - } - else if (operation->isReadBufferOperation()) { - fillcolor = "darkolivegreen3"; - } - else if (operation->isWriteBufferOperation()) { - fillcolor = "darkorange"; - } - - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// OPERATION: %p\r\n", operation); - if (group) { - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\"O_%p_%p\"", operation, group); - } - else { - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\"O_%p\"", operation); - } - len += snprintf(str + len, - maxlen > len ? maxlen - len : 0, - " [fillcolor=%s,style=filled,shape=record,label=\"{", - fillcolor.c_str()); - - int totinputs = operation->getNumberOfInputSockets(); - if (totinputs != 0) { - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{"); - for (int k = 0; k < totinputs; k++) { - NodeOperationInput *socket = operation->getInputSocket(k); - if (k != 0) { - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); - } - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "", socket); - switch (socket->getDataType()) { - case COM_DT_VALUE: - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value"); - break; - case COM_DT_VECTOR: - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Vector"); - break; - case COM_DT_COLOR: - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Color"); - break; - } - } - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); - } - - len += snprintf(str + len, - maxlen > len ? maxlen - len : 0, - "%s\\n(%s)", - m_op_names[operation].c_str(), - typeid(*operation).name()); - - len += snprintf(str + len, - maxlen > len ? maxlen - len : 0, - " (%u,%u)", - operation->getWidth(), - operation->getHeight()); - - int totoutputs = operation->getNumberOfOutputSockets(); - if (totoutputs != 0) { - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{"); - for (int k = 0; k < totoutputs; k++) { - NodeOperationOutput *socket = operation->getOutputSocket(k); - if (k != 0) { - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); - } - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "", socket); - switch (socket->getDataType()) { - case COM_DT_VALUE: - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value"); - break; - case COM_DT_VECTOR: - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Vector"); - break; - case COM_DT_COLOR: - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Color"); - break; - } - } - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}"); - } - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\"]"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); - - return len; -} - -int DebugInfo::graphviz_legend_color(const char *name, const char *color, char *str, int maxlen) -{ - int len = 0; - len += snprintf(str + len, - maxlen > len ? maxlen - len : 0, - "%s\r\n", - name, - color); - return len; -} - -int DebugInfo::graphviz_legend_line( - const char * /*name*/, const char * /*color*/, const char * /*style*/, char *str, int maxlen) -{ - /* XXX TODO */ - int len = 0; - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); - return len; -} - -int DebugInfo::graphviz_legend_group( - const char *name, const char *color, const char * /*style*/, char *str, int maxlen) -{ - int len = 0; - len += snprintf(str + len, - maxlen > len ? maxlen - len : 0, - "%s
\r\n", - name, - color); - return len; -} - -int DebugInfo::graphviz_legend(char *str, int maxlen) -{ - int len = 0; - - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{\r\n"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "rank = sink;\r\n"); - len += snprintf( - str + len, maxlen > len ? maxlen - len : 0, "Legend [shape=none, margin=0, label=<\r\n"); - - len += snprintf( - str + len, - maxlen > len ? maxlen - len : 0, - " \r\n"); - len += snprintf(str + len, - maxlen > len ? maxlen - len : 0, - "\r\n"); - - len += graphviz_legend_color( - "NodeOperation", "gainsboro", str + len, maxlen > len ? maxlen - len : 0); - len += graphviz_legend_color( - "Output", "dodgerblue1", str + len, maxlen > len ? maxlen - len : 0); - len += graphviz_legend_color( - "Viewer", "lightskyblue3", str + len, maxlen > len ? maxlen - len : 0); - len += graphviz_legend_color( - "Active Viewer", "lightskyblue1", str + len, maxlen > len ? maxlen - len : 0); - len += graphviz_legend_color( - "Write Buffer", "darkorange", str + len, maxlen > len ? maxlen - len : 0); - len += graphviz_legend_color( - "Read Buffer", "darkolivegreen3", str + len, maxlen > len ? maxlen - len : 0); - len += graphviz_legend_color( - "Input Value", "khaki1", str + len, maxlen > len ? maxlen - len : 0); - - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); - - len += graphviz_legend_group( - "Group Waiting", "white", "dashed", str + len, maxlen > len ? maxlen - len : 0); - len += graphviz_legend_group( - "Group Running", "firebrick1", "solid", str + len, maxlen > len ? maxlen - len : 0); - len += graphviz_legend_group( - "Group Finished", "chartreuse4", "solid", str + len, maxlen > len ? maxlen - len : 0); - - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "
Legend
\r\n"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, ">];\r\n"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n"); - - return len; -} - -bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int maxlen) -{ - char strbuf[64]; - int len = 0; - - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "digraph compositorexecution {\r\n"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "ranksep=1.5\r\n"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "rankdir=LR\r\n"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "splines=false\r\n"); - -# if 0 - for (ExecutionSystem::Operations::const_iterator it = system->m_operations.begin(); - it != system->m_operations.end(); - ++it) { - NodeOperation *op = *it; - len += snprintf(str + len, - maxlen > len ? maxlen - len : 0, - "// OPERATION: %s\r\n", - node->getbNode()->typeinfo->ui_name); - } -# endif - - int totops = system->m_operations.size(); - int totgroups = system->m_groups.size(); - std::map> op_groups; - for (int i = 0; i < totgroups; i++) { - const ExecutionGroup *group = system->m_groups[i]; - - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// GROUP: %d\r\n", i); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "subgraph cluster_%d{\r\n", i); - /* used as a check for executing group */ - if (m_group_states[group] == EG_WAIT) { - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=dashed\r\n"); - } - else if (m_group_states[group] == EG_RUNNING) { - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=filled\r\n"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "color=black\r\n"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "fillcolor=firebrick1\r\n"); - } - else if (m_group_states[group] == EG_FINISHED) { - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=filled\r\n"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "color=black\r\n"); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "fillcolor=chartreuse4\r\n"); - } - - for (ExecutionGroup::Operations::const_iterator it = group->m_operations.begin(); - it != group->m_operations.end(); - ++it) { - NodeOperation *operation = *it; - - sprintf(strbuf, "_%p", group); - op_groups[operation].push_back(std::string(strbuf)); - - len += graphviz_operation( - system, operation, group, str + len, maxlen > len ? maxlen - len : 0); - } - - // len += snprintf(str+len, - // maxlen>len ? maxlen-len : 0, - // "// OUTPUTOPERATION: %p\r\n", group->getOutputOperation()); - // len += snprintf( - // str+len, maxlen>len ? maxlen-len : 0, - // " O_%p\r\n", group->getOutputOperation()); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n"); - } - - /* operations not included in any group */ - for (int j = 0; j < totops; j++) { - NodeOperation *operation = system->m_operations[j]; - if (op_groups.find(operation) != op_groups.end()) { - continue; - } - - op_groups[operation].push_back(std::string("")); - - len += graphviz_operation(system, operation, 0, str + len, maxlen > len ? maxlen - len : 0); - } - - for (int i = 0; i < totops; i++) { - NodeOperation *operation = system->m_operations[i]; - - if (operation->isReadBufferOperation()) { - ReadBufferOperation *read = (ReadBufferOperation *)operation; - WriteBufferOperation *write = read->getMemoryProxy()->getWriteBufferOperation(); - std::vector &read_groups = op_groups[read]; - std::vector &write_groups = op_groups[write]; - - for (int k = 0; k < write_groups.size(); k++) { - for (int l = 0; l < read_groups.size(); l++) { - len += snprintf(str + len, - maxlen > len ? maxlen - len : 0, - "\"O_%p%s\" -> \"O_%p%s\" [style=dotted]\r\n", - write, - write_groups[k].c_str(), - read, - read_groups[l].c_str()); - } - } - } - } - - for (int i = 0; i < totops; i++) { - NodeOperation *op = system->m_operations[i]; - - for (NodeOperation::Inputs::const_iterator it = op->m_inputs.begin(); it != op->m_inputs.end(); - ++it) { - NodeOperationInput *to = *it; - NodeOperationOutput *from = to->getLink(); - - if (!from) { - continue; - } - - std::string color; - switch (from->getDataType()) { - case COM_DT_VALUE: - color = "gray"; - break; - case COM_DT_VECTOR: - color = "blue"; - break; - case COM_DT_COLOR: - color = "orange"; - break; - } - - NodeOperation *to_op = &to->getOperation(); - NodeOperation *from_op = &from->getOperation(); - std::vector &from_groups = op_groups[from_op]; - std::vector &to_groups = op_groups[to_op]; - - len += snprintf(str + len, - maxlen > len ? maxlen - len : 0, - "// CONNECTION: %p.%p -> %p.%p\r\n", - from_op, - from, - to_op, - to); - for (int k = 0; k < from_groups.size(); k++) { - for (int l = 0; l < to_groups.size(); l++) { - len += snprintf(str + len, - maxlen > len ? maxlen - len : 0, - "\"O_%p%s\":\"OUT_%p\":e -> \"O_%p%s\":\"IN_%p\":w", - from_op, - from_groups[k].c_str(), - from, - to_op, - to_groups[l].c_str(), - to); - len += snprintf( - str + len, maxlen > len ? maxlen - len : 0, " [color=%s]", color.c_str()); - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); - } - } - } - } - - len += graphviz_legend(str + len, maxlen > len ? maxlen - len : 0); - - len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n"); - - return (len < maxlen); -} - -void DebugInfo::graphviz(const ExecutionSystem *system) -{ - char str[1000000]; - if (graphviz_system(system, str, sizeof(str) - 1)) { - char basename[FILE_MAX]; - char filename[FILE_MAX]; - - BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", m_file_index); - BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), basename); - m_file_index++; - - FILE *fp = BLI_fopen(filename, "wb"); - fputs(str, fp); - fclose(fp); - } -} - -#else - -std::string DebugInfo::node_name(const Node * /*node*/) -{ - return ""; -} -std::string DebugInfo::operation_name(const NodeOperation * /*op*/) -{ - return ""; -} -void DebugInfo::convert_started() -{ -} -void DebugInfo::execute_started(const ExecutionSystem * /*system*/) -{ -} -void DebugInfo::node_added(const Node * /*node*/) -{ -} -void DebugInfo::node_to_operations(const Node * /*node*/) -{ -} -void DebugInfo::operation_added(const NodeOperation * /*operation*/) -{ -} -void DebugInfo::operation_read_write_buffer(const NodeOperation * /*operation*/) -{ -} -void DebugInfo::execution_group_started(const ExecutionGroup * /*group*/) -{ -} -void DebugInfo::execution_group_finished(const ExecutionGroup * /*group*/) -{ -} -void DebugInfo::graphviz(const ExecutionSystem * /*system*/) -{ -} - -#endif diff --git a/source/blender/compositor/intern/COM_Device.cc b/source/blender/compositor/intern/COM_Device.cc new file mode 100644 index 00000000000..38a22369005 --- /dev/null +++ b/source/blender/compositor/intern/COM_Device.cc @@ -0,0 +1,19 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_Device.h" diff --git a/source/blender/compositor/intern/COM_Device.cpp b/source/blender/compositor/intern/COM_Device.cpp deleted file mode 100644 index 38a22369005..00000000000 --- a/source/blender/compositor/intern/COM_Device.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_Device.h" diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cc b/source/blender/compositor/intern/COM_ExecutionGroup.cc new file mode 100644 index 00000000000..37623228183 --- /dev/null +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cc @@ -0,0 +1,634 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include +#include +#include +#include + +#include "atomic_ops.h" + +#include "COM_ChunkOrder.h" +#include "COM_Debug.h" +#include "COM_ExecutionGroup.h" +#include "COM_ExecutionSystem.h" +#include "COM_ReadBufferOperation.h" +#include "COM_ViewerOperation.h" +#include "COM_WorkScheduler.h" +#include "COM_WriteBufferOperation.h" +#include "COM_defines.h" + +#include "BLI_math.h" +#include "BLI_string.h" +#include "BLT_translation.h" +#include "MEM_guardedalloc.h" +#include "PIL_time.h" +#include "WM_api.h" +#include "WM_types.h" + +ExecutionGroup::ExecutionGroup() +{ + this->m_is_output = false; + this->m_complex = false; + this->m_bTree = nullptr; + this->m_height = 0; + this->m_width = 0; + this->m_max_read_buffer_offset = 0; + this->m_x_chunks_len = 0; + this->m_y_chunks_len = 0; + this->m_chunks_len = 0; + this->m_initialized = false; + this->m_openCL = false; + this->m_singleThreaded = false; + this->m_chunks_finished = 0; + BLI_rcti_init(&this->m_viewerBorder, 0, 0, 0, 0); + this->m_executionStartTime = 0; +} + +CompositorPriority ExecutionGroup::getRenderPriotrity() +{ + return this->getOutputOperation()->getRenderPriority(); +} + +bool ExecutionGroup::canContainOperation(NodeOperation *operation) +{ + if (!this->m_initialized) { + return true; + } + + if (operation->isReadBufferOperation()) { + return true; + } + if (operation->isWriteBufferOperation()) { + return false; + } + if (operation->isSetOperation()) { + return true; + } + + /* complex groups don't allow further ops (except read buffer and values, see above) */ + if (m_complex) { + return false; + } + /* complex ops can't be added to other groups (except their own, which they initialize, see + * above) */ + if (operation->isComplex()) { + return false; + } + + return true; +} + +bool ExecutionGroup::addOperation(NodeOperation *operation) +{ + if (!canContainOperation(operation)) { + return false; + } + + if (!operation->isReadBufferOperation() && !operation->isWriteBufferOperation()) { + m_complex = operation->isComplex(); + m_openCL = operation->isOpenCL(); + m_singleThreaded = operation->isSingleThreaded(); + m_initialized = true; + } + + m_operations.append(operation); + + return true; +} + +NodeOperation *ExecutionGroup::getOutputOperation() const +{ + return this + ->m_operations[0]; /* the first operation of the group is always the output operation. */ +} + +void ExecutionGroup::initExecution() +{ + m_chunk_execution_states.clear(); + determineNumberOfChunks(); + + if (this->m_chunks_len != 0) { + m_chunk_execution_states.resize(this->m_chunks_len); + for (int index = 0; index < this->m_chunks_len; index++) { + m_chunk_execution_states[index] = eChunkExecutionState::NOT_SCHEDULED; + } + } + + unsigned int max_offset = 0; + + for (NodeOperation *operation : m_operations) { + if (operation->isReadBufferOperation()) { + ReadBufferOperation *readOperation = static_cast(operation); + this->m_read_operations.append(readOperation); + max_offset = MAX2(max_offset, readOperation->getOffset()); + } + } + max_offset++; + this->m_max_read_buffer_offset = max_offset; +} + +void ExecutionGroup::deinitExecution() +{ + m_chunk_execution_states.clear(); + this->m_chunks_len = 0; + this->m_x_chunks_len = 0; + this->m_y_chunks_len = 0; + this->m_read_operations.clear(); + this->m_bTree = nullptr; +} +void ExecutionGroup::determineResolution(unsigned int resolution[2]) +{ + NodeOperation *operation = this->getOutputOperation(); + resolution[0] = operation->getWidth(); + resolution[1] = operation->getHeight(); + this->setResolution(resolution); + BLI_rcti_init(&this->m_viewerBorder, 0, this->m_width, 0, this->m_height); +} + +void ExecutionGroup::determineNumberOfChunks() +{ + if (this->m_singleThreaded) { + this->m_x_chunks_len = 1; + this->m_y_chunks_len = 1; + this->m_chunks_len = 1; + } + else { + const float chunkSizef = this->m_chunkSize; + const int border_width = BLI_rcti_size_x(&this->m_viewerBorder); + const int border_height = BLI_rcti_size_y(&this->m_viewerBorder); + this->m_x_chunks_len = ceil(border_width / chunkSizef); + this->m_y_chunks_len = ceil(border_height / chunkSizef); + this->m_chunks_len = this->m_x_chunks_len * this->m_y_chunks_len; + } +} + +/** + * this method is called for the top execution groups. containing the compositor node or the + * preview node or the viewer node) + */ +void ExecutionGroup::execute(ExecutionSystem *graph) +{ + const CompositorContext &context = graph->getContext(); + const bNodeTree *bTree = context.getbNodeTree(); + if (this->m_width == 0 || this->m_height == 0) { + return; + } /** \note Break out... no pixels to calculate. */ + if (bTree->test_break && bTree->test_break(bTree->tbh)) { + return; + } /** \note Early break out for blur and preview nodes. */ + if (this->m_chunks_len == 0) { + return; + } /** \note Early break out. */ + unsigned int chunkNumber; + + this->m_executionStartTime = PIL_check_seconds_timer(); + + this->m_chunks_finished = 0; + this->m_bTree = bTree; + unsigned int index; + unsigned int *chunkOrder = (unsigned int *)MEM_mallocN(sizeof(unsigned int) * this->m_chunks_len, + __func__); + + for (chunkNumber = 0; chunkNumber < this->m_chunks_len; chunkNumber++) { + chunkOrder[chunkNumber] = chunkNumber; + } + NodeOperation *operation = this->getOutputOperation(); + float centerX = 0.5; + float centerY = 0.5; + OrderOfChunks chunkorder = COM_ORDER_OF_CHUNKS_DEFAULT; + + if (operation->isViewerOperation()) { + ViewerOperation *viewer = (ViewerOperation *)operation; + centerX = viewer->getCenterX(); + centerY = viewer->getCenterY(); + chunkorder = viewer->getChunkOrder(); + } + + const int border_width = BLI_rcti_size_x(&this->m_viewerBorder); + const int border_height = BLI_rcti_size_y(&this->m_viewerBorder); + + switch (chunkorder) { + case COM_TO_RANDOM: + for (index = 0; index < 2 * this->m_chunks_len; index++) { + int index1 = rand() % this->m_chunks_len; + int index2 = rand() % this->m_chunks_len; + int s = chunkOrder[index1]; + chunkOrder[index1] = chunkOrder[index2]; + chunkOrder[index2] = s; + } + break; + case COM_TO_CENTER_OUT: { + ChunkOrderHotspot *hotspots[1]; + hotspots[0] = new ChunkOrderHotspot(border_width * centerX, border_height * centerY, 0.0f); + rcti rect; + ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len, + __func__); + for (index = 0; index < this->m_chunks_len; index++) { + determineChunkRect(&rect, index); + chunkOrders[index].number = index; + chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin; + chunkOrders[index].y = rect.ymin - this->m_viewerBorder.ymin; + chunkOrders[index].update_distance(hotspots, 1); + } + + std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len - 1]); + for (index = 0; index < this->m_chunks_len; index++) { + chunkOrder[index] = chunkOrders[index].number; + } + + delete hotspots[0]; + MEM_freeN(chunkOrders); + break; + } + case COM_TO_RULE_OF_THIRDS: { + ChunkOrderHotspot *hotspots[9]; + unsigned int tx = border_width / 6; + unsigned int ty = border_height / 6; + unsigned int mx = border_width / 2; + unsigned int my = border_height / 2; + unsigned int bx = mx + 2 * tx; + unsigned int by = my + 2 * ty; + + float addition = this->m_chunks_len / COM_RULE_OF_THIRDS_DIVIDER; + hotspots[0] = new ChunkOrderHotspot(mx, my, addition * 0); + hotspots[1] = new ChunkOrderHotspot(tx, my, addition * 1); + hotspots[2] = new ChunkOrderHotspot(bx, my, addition * 2); + hotspots[3] = new ChunkOrderHotspot(bx, by, addition * 3); + hotspots[4] = new ChunkOrderHotspot(tx, ty, addition * 4); + hotspots[5] = new ChunkOrderHotspot(bx, ty, addition * 5); + hotspots[6] = new ChunkOrderHotspot(tx, by, addition * 6); + hotspots[7] = new ChunkOrderHotspot(mx, ty, addition * 7); + hotspots[8] = new ChunkOrderHotspot(mx, by, addition * 8); + rcti rect; + ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len, + __func__); + for (index = 0; index < this->m_chunks_len; index++) { + determineChunkRect(&rect, index); + chunkOrders[index].number = index; + chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin; + chunkOrders[index].y = rect.ymin - this->m_viewerBorder.ymin; + chunkOrders[index].update_distance(hotspots, 9); + } + + std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len]); + + for (index = 0; index < this->m_chunks_len; index++) { + chunkOrder[index] = chunkOrders[index].number; + } + + delete hotspots[0]; + delete hotspots[1]; + delete hotspots[2]; + delete hotspots[3]; + delete hotspots[4]; + delete hotspots[5]; + delete hotspots[6]; + delete hotspots[7]; + delete hotspots[8]; + MEM_freeN(chunkOrders); + break; + } + case COM_TO_TOP_DOWN: + default: + break; + } + + DebugInfo::execution_group_started(this); + DebugInfo::graphviz(graph); + + bool breaked = false; + bool finished = false; + unsigned int startIndex = 0; + const int maxNumberEvaluated = BLI_system_thread_count() * 2; + + while (!finished && !breaked) { + bool startEvaluated = false; + finished = true; + int numberEvaluated = 0; + + for (index = startIndex; index < this->m_chunks_len && numberEvaluated < maxNumberEvaluated; + index++) { + chunkNumber = chunkOrder[index]; + int yChunk = chunkNumber / this->m_x_chunks_len; + int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len); + switch (m_chunk_execution_states[chunkNumber]) { + case eChunkExecutionState::NOT_SCHEDULED: { + scheduleChunkWhenPossible(graph, xChunk, yChunk); + finished = false; + startEvaluated = true; + numberEvaluated++; + + if (bTree->update_draw) { + bTree->update_draw(bTree->udh); + } + break; + } + case eChunkExecutionState::SCHEDULED: { + finished = false; + startEvaluated = true; + numberEvaluated++; + break; + } + case eChunkExecutionState::EXECUTED: { + if (!startEvaluated) { + startIndex = index + 1; + } + } + }; + } + + WorkScheduler::finish(); + + if (bTree->test_break && bTree->test_break(bTree->tbh)) { + breaked = true; + } + } + DebugInfo::execution_group_finished(this); + DebugInfo::graphviz(graph); + + MEM_freeN(chunkOrder); +} + +MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber) +{ + rcti rect; + std::vector memoryproxies; + determineChunkRect(&rect, chunkNumber); + + this->determineDependingMemoryProxies(&memoryproxies); + MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN( + sizeof(MemoryBuffer *) * this->m_max_read_buffer_offset, __func__); + rcti output; + for (ReadBufferOperation *readOperation : m_read_operations) { + MemoryProxy *memoryProxy = readOperation->getMemoryProxy(); + this->determineDependingAreaOfInterest(&rect, readOperation, &output); + MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer( + memoryProxy, &output); + memoryBuffers[readOperation->getOffset()] = memoryBuffer; + } + return memoryBuffers; +} + +MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *memoryProxy, + rcti *rect) +{ + MemoryBuffer *imageBuffer = memoryProxy->getBuffer(); + MemoryBuffer *result = new MemoryBuffer(memoryProxy, rect); + result->copyContentFrom(imageBuffer); + return result; +} + +void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers) +{ + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) { + this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::EXECUTED; + } + + atomic_add_and_fetch_u(&this->m_chunks_finished, 1); + if (memoryBuffers) { + for (unsigned int index = 0; index < this->m_max_read_buffer_offset; index++) { + MemoryBuffer *buffer = memoryBuffers[index]; + if (buffer) { + if (buffer->isTemporarily()) { + memoryBuffers[index] = nullptr; + delete buffer; + } + } + } + MEM_freeN(memoryBuffers); + } + if (this->m_bTree) { + // status report is only performed for top level Execution Groups. + float progress = this->m_chunks_finished; + progress /= this->m_chunks_len; + this->m_bTree->progress(this->m_bTree->prh, progress); + + char buf[128]; + BLI_snprintf(buf, + sizeof(buf), + TIP_("Compositing | Tile %u-%u"), + this->m_chunks_finished, + this->m_chunks_len); + this->m_bTree->stats_draw(this->m_bTree->sdh, buf); + } +} + +inline void ExecutionGroup::determineChunkRect(rcti *rect, + const unsigned int xChunk, + const unsigned int yChunk) const +{ + const int border_width = BLI_rcti_size_x(&this->m_viewerBorder); + const int border_height = BLI_rcti_size_y(&this->m_viewerBorder); + + if (this->m_singleThreaded) { + BLI_rcti_init( + rect, this->m_viewerBorder.xmin, border_width, this->m_viewerBorder.ymin, border_height); + } + else { + const unsigned int minx = xChunk * this->m_chunkSize + this->m_viewerBorder.xmin; + const unsigned int miny = yChunk * this->m_chunkSize + this->m_viewerBorder.ymin; + const unsigned int width = MIN2((unsigned int)this->m_viewerBorder.xmax, this->m_width); + const unsigned int height = MIN2((unsigned int)this->m_viewerBorder.ymax, this->m_height); + BLI_rcti_init(rect, + MIN2(minx, this->m_width), + MIN2(minx + this->m_chunkSize, width), + MIN2(miny, this->m_height), + MIN2(miny + this->m_chunkSize, height)); + } +} + +void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumber) const +{ + const unsigned int yChunk = chunkNumber / this->m_x_chunks_len; + const unsigned int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len); + determineChunkRect(rect, xChunk, yChunk); +} + +MemoryBuffer *ExecutionGroup::allocateOutputBuffer(int /*chunkNumber*/, rcti *rect) +{ + // we assume that this method is only called from complex execution groups. + NodeOperation *operation = this->getOutputOperation(); + if (operation->isWriteBufferOperation()) { + WriteBufferOperation *writeOperation = (WriteBufferOperation *)operation; + MemoryBuffer *buffer = new MemoryBuffer(writeOperation->getMemoryProxy(), rect); + return buffer; + } + return nullptr; +} + +bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area) +{ + if (this->m_singleThreaded) { + return scheduleChunkWhenPossible(graph, 0, 0); + } + // find all chunks inside the rect + // determine minxchunk, minychunk, maxxchunk, maxychunk where x and y are chunknumbers + + int indexx, indexy; + int minx = max_ii(area->xmin - m_viewerBorder.xmin, 0); + int maxx = min_ii(area->xmax - m_viewerBorder.xmin, m_viewerBorder.xmax - m_viewerBorder.xmin); + int miny = max_ii(area->ymin - m_viewerBorder.ymin, 0); + int maxy = min_ii(area->ymax - m_viewerBorder.ymin, m_viewerBorder.ymax - m_viewerBorder.ymin); + int minxchunk = minx / (int)m_chunkSize; + int maxxchunk = (maxx + (int)m_chunkSize - 1) / (int)m_chunkSize; + int minychunk = miny / (int)m_chunkSize; + int maxychunk = (maxy + (int)m_chunkSize - 1) / (int)m_chunkSize; + minxchunk = max_ii(minxchunk, 0); + minychunk = max_ii(minychunk, 0); + maxxchunk = min_ii(maxxchunk, (int)m_x_chunks_len); + maxychunk = min_ii(maxychunk, (int)m_y_chunks_len); + + bool result = true; + for (indexx = minxchunk; indexx < maxxchunk; indexx++) { + for (indexy = minychunk; indexy < maxychunk; indexy++) { + if (!scheduleChunkWhenPossible(graph, indexx, indexy)) { + result = false; + } + } + } + + return result; +} + +bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber) +{ + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::NOT_SCHEDULED) { + this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::SCHEDULED; + WorkScheduler::schedule(this, chunkNumber); + return true; + } + return false; +} + +bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk) +{ + if (xChunk < 0 || xChunk >= (int)this->m_x_chunks_len) { + return true; + } + if (yChunk < 0 || yChunk >= (int)this->m_y_chunks_len) { + return true; + } + int chunkNumber = yChunk * this->m_x_chunks_len + xChunk; + // chunk is already executed + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::EXECUTED) { + return true; + } + + // chunk is scheduled, but not executed + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) { + return false; + } + + // chunk is nor executed nor scheduled. + std::vector memoryProxies; + this->determineDependingMemoryProxies(&memoryProxies); + + rcti rect; + determineChunkRect(&rect, xChunk, yChunk); + unsigned int index; + bool canBeExecuted = true; + rcti area; + + for (index = 0; index < m_read_operations.size(); index++) { + ReadBufferOperation *readOperation = m_read_operations[index]; + BLI_rcti_init(&area, 0, 0, 0, 0); + MemoryProxy *memoryProxy = memoryProxies[index]; + determineDependingAreaOfInterest(&rect, readOperation, &area); + ExecutionGroup *group = memoryProxy->getExecutor(); + + if (group != nullptr) { + if (!group->scheduleAreaWhenPossible(graph, &area)) { + canBeExecuted = false; + } + } + else { + throw "ERROR"; + } + } + + if (canBeExecuted) { + scheduleChunk(chunkNumber); + } + + return false; +} + +void ExecutionGroup::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + this->getOutputOperation()->determineDependingAreaOfInterest(input, readOperation, output); +} + +void ExecutionGroup::determineDependingMemoryProxies(std::vector *memoryProxies) +{ + for (ReadBufferOperation *readOperation : m_read_operations) { + memoryProxies->push_back(readOperation->getMemoryProxy()); + } +} + +bool ExecutionGroup::isOpenCL() +{ + return this->m_openCL; +} + +void ExecutionGroup::setViewerBorder(float xmin, float xmax, float ymin, float ymax) +{ + NodeOperation *operation = this->getOutputOperation(); + + if (operation->isViewerOperation() || operation->isPreviewOperation()) { + BLI_rcti_init(&this->m_viewerBorder, + xmin * this->m_width, + xmax * this->m_width, + ymin * this->m_height, + ymax * this->m_height); + } +} + +void ExecutionGroup::setRenderBorder(float xmin, float xmax, float ymin, float ymax) +{ + NodeOperation *operation = this->getOutputOperation(); + + if (operation->isOutputOperation(true)) { + /* Basically, setting border need to happen for only operations + * which operates in render resolution buffers (like compositor + * output nodes). + * + * In this cases adding border will lead to mapping coordinates + * from output buffer space to input buffer spaces when executing + * operation. + * + * But nodes like viewer and file output just shall display or + * safe the same exact buffer which goes to their input, no need + * in any kind of coordinates mapping. + */ + + bool operationNeedsBorder = !(operation->isViewerOperation() || + operation->isPreviewOperation() || + operation->isFileOutputOperation()); + + if (operationNeedsBorder) { + BLI_rcti_init(&this->m_viewerBorder, + xmin * this->m_width, + xmax * this->m_width, + ymin * this->m_height, + ymax * this->m_height); + } + } +} diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp deleted file mode 100644 index 37623228183..00000000000 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ /dev/null @@ -1,634 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include -#include -#include -#include - -#include "atomic_ops.h" - -#include "COM_ChunkOrder.h" -#include "COM_Debug.h" -#include "COM_ExecutionGroup.h" -#include "COM_ExecutionSystem.h" -#include "COM_ReadBufferOperation.h" -#include "COM_ViewerOperation.h" -#include "COM_WorkScheduler.h" -#include "COM_WriteBufferOperation.h" -#include "COM_defines.h" - -#include "BLI_math.h" -#include "BLI_string.h" -#include "BLT_translation.h" -#include "MEM_guardedalloc.h" -#include "PIL_time.h" -#include "WM_api.h" -#include "WM_types.h" - -ExecutionGroup::ExecutionGroup() -{ - this->m_is_output = false; - this->m_complex = false; - this->m_bTree = nullptr; - this->m_height = 0; - this->m_width = 0; - this->m_max_read_buffer_offset = 0; - this->m_x_chunks_len = 0; - this->m_y_chunks_len = 0; - this->m_chunks_len = 0; - this->m_initialized = false; - this->m_openCL = false; - this->m_singleThreaded = false; - this->m_chunks_finished = 0; - BLI_rcti_init(&this->m_viewerBorder, 0, 0, 0, 0); - this->m_executionStartTime = 0; -} - -CompositorPriority ExecutionGroup::getRenderPriotrity() -{ - return this->getOutputOperation()->getRenderPriority(); -} - -bool ExecutionGroup::canContainOperation(NodeOperation *operation) -{ - if (!this->m_initialized) { - return true; - } - - if (operation->isReadBufferOperation()) { - return true; - } - if (operation->isWriteBufferOperation()) { - return false; - } - if (operation->isSetOperation()) { - return true; - } - - /* complex groups don't allow further ops (except read buffer and values, see above) */ - if (m_complex) { - return false; - } - /* complex ops can't be added to other groups (except their own, which they initialize, see - * above) */ - if (operation->isComplex()) { - return false; - } - - return true; -} - -bool ExecutionGroup::addOperation(NodeOperation *operation) -{ - if (!canContainOperation(operation)) { - return false; - } - - if (!operation->isReadBufferOperation() && !operation->isWriteBufferOperation()) { - m_complex = operation->isComplex(); - m_openCL = operation->isOpenCL(); - m_singleThreaded = operation->isSingleThreaded(); - m_initialized = true; - } - - m_operations.append(operation); - - return true; -} - -NodeOperation *ExecutionGroup::getOutputOperation() const -{ - return this - ->m_operations[0]; /* the first operation of the group is always the output operation. */ -} - -void ExecutionGroup::initExecution() -{ - m_chunk_execution_states.clear(); - determineNumberOfChunks(); - - if (this->m_chunks_len != 0) { - m_chunk_execution_states.resize(this->m_chunks_len); - for (int index = 0; index < this->m_chunks_len; index++) { - m_chunk_execution_states[index] = eChunkExecutionState::NOT_SCHEDULED; - } - } - - unsigned int max_offset = 0; - - for (NodeOperation *operation : m_operations) { - if (operation->isReadBufferOperation()) { - ReadBufferOperation *readOperation = static_cast(operation); - this->m_read_operations.append(readOperation); - max_offset = MAX2(max_offset, readOperation->getOffset()); - } - } - max_offset++; - this->m_max_read_buffer_offset = max_offset; -} - -void ExecutionGroup::deinitExecution() -{ - m_chunk_execution_states.clear(); - this->m_chunks_len = 0; - this->m_x_chunks_len = 0; - this->m_y_chunks_len = 0; - this->m_read_operations.clear(); - this->m_bTree = nullptr; -} -void ExecutionGroup::determineResolution(unsigned int resolution[2]) -{ - NodeOperation *operation = this->getOutputOperation(); - resolution[0] = operation->getWidth(); - resolution[1] = operation->getHeight(); - this->setResolution(resolution); - BLI_rcti_init(&this->m_viewerBorder, 0, this->m_width, 0, this->m_height); -} - -void ExecutionGroup::determineNumberOfChunks() -{ - if (this->m_singleThreaded) { - this->m_x_chunks_len = 1; - this->m_y_chunks_len = 1; - this->m_chunks_len = 1; - } - else { - const float chunkSizef = this->m_chunkSize; - const int border_width = BLI_rcti_size_x(&this->m_viewerBorder); - const int border_height = BLI_rcti_size_y(&this->m_viewerBorder); - this->m_x_chunks_len = ceil(border_width / chunkSizef); - this->m_y_chunks_len = ceil(border_height / chunkSizef); - this->m_chunks_len = this->m_x_chunks_len * this->m_y_chunks_len; - } -} - -/** - * this method is called for the top execution groups. containing the compositor node or the - * preview node or the viewer node) - */ -void ExecutionGroup::execute(ExecutionSystem *graph) -{ - const CompositorContext &context = graph->getContext(); - const bNodeTree *bTree = context.getbNodeTree(); - if (this->m_width == 0 || this->m_height == 0) { - return; - } /** \note Break out... no pixels to calculate. */ - if (bTree->test_break && bTree->test_break(bTree->tbh)) { - return; - } /** \note Early break out for blur and preview nodes. */ - if (this->m_chunks_len == 0) { - return; - } /** \note Early break out. */ - unsigned int chunkNumber; - - this->m_executionStartTime = PIL_check_seconds_timer(); - - this->m_chunks_finished = 0; - this->m_bTree = bTree; - unsigned int index; - unsigned int *chunkOrder = (unsigned int *)MEM_mallocN(sizeof(unsigned int) * this->m_chunks_len, - __func__); - - for (chunkNumber = 0; chunkNumber < this->m_chunks_len; chunkNumber++) { - chunkOrder[chunkNumber] = chunkNumber; - } - NodeOperation *operation = this->getOutputOperation(); - float centerX = 0.5; - float centerY = 0.5; - OrderOfChunks chunkorder = COM_ORDER_OF_CHUNKS_DEFAULT; - - if (operation->isViewerOperation()) { - ViewerOperation *viewer = (ViewerOperation *)operation; - centerX = viewer->getCenterX(); - centerY = viewer->getCenterY(); - chunkorder = viewer->getChunkOrder(); - } - - const int border_width = BLI_rcti_size_x(&this->m_viewerBorder); - const int border_height = BLI_rcti_size_y(&this->m_viewerBorder); - - switch (chunkorder) { - case COM_TO_RANDOM: - for (index = 0; index < 2 * this->m_chunks_len; index++) { - int index1 = rand() % this->m_chunks_len; - int index2 = rand() % this->m_chunks_len; - int s = chunkOrder[index1]; - chunkOrder[index1] = chunkOrder[index2]; - chunkOrder[index2] = s; - } - break; - case COM_TO_CENTER_OUT: { - ChunkOrderHotspot *hotspots[1]; - hotspots[0] = new ChunkOrderHotspot(border_width * centerX, border_height * centerY, 0.0f); - rcti rect; - ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len, - __func__); - for (index = 0; index < this->m_chunks_len; index++) { - determineChunkRect(&rect, index); - chunkOrders[index].number = index; - chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin; - chunkOrders[index].y = rect.ymin - this->m_viewerBorder.ymin; - chunkOrders[index].update_distance(hotspots, 1); - } - - std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len - 1]); - for (index = 0; index < this->m_chunks_len; index++) { - chunkOrder[index] = chunkOrders[index].number; - } - - delete hotspots[0]; - MEM_freeN(chunkOrders); - break; - } - case COM_TO_RULE_OF_THIRDS: { - ChunkOrderHotspot *hotspots[9]; - unsigned int tx = border_width / 6; - unsigned int ty = border_height / 6; - unsigned int mx = border_width / 2; - unsigned int my = border_height / 2; - unsigned int bx = mx + 2 * tx; - unsigned int by = my + 2 * ty; - - float addition = this->m_chunks_len / COM_RULE_OF_THIRDS_DIVIDER; - hotspots[0] = new ChunkOrderHotspot(mx, my, addition * 0); - hotspots[1] = new ChunkOrderHotspot(tx, my, addition * 1); - hotspots[2] = new ChunkOrderHotspot(bx, my, addition * 2); - hotspots[3] = new ChunkOrderHotspot(bx, by, addition * 3); - hotspots[4] = new ChunkOrderHotspot(tx, ty, addition * 4); - hotspots[5] = new ChunkOrderHotspot(bx, ty, addition * 5); - hotspots[6] = new ChunkOrderHotspot(tx, by, addition * 6); - hotspots[7] = new ChunkOrderHotspot(mx, ty, addition * 7); - hotspots[8] = new ChunkOrderHotspot(mx, by, addition * 8); - rcti rect; - ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len, - __func__); - for (index = 0; index < this->m_chunks_len; index++) { - determineChunkRect(&rect, index); - chunkOrders[index].number = index; - chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin; - chunkOrders[index].y = rect.ymin - this->m_viewerBorder.ymin; - chunkOrders[index].update_distance(hotspots, 9); - } - - std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len]); - - for (index = 0; index < this->m_chunks_len; index++) { - chunkOrder[index] = chunkOrders[index].number; - } - - delete hotspots[0]; - delete hotspots[1]; - delete hotspots[2]; - delete hotspots[3]; - delete hotspots[4]; - delete hotspots[5]; - delete hotspots[6]; - delete hotspots[7]; - delete hotspots[8]; - MEM_freeN(chunkOrders); - break; - } - case COM_TO_TOP_DOWN: - default: - break; - } - - DebugInfo::execution_group_started(this); - DebugInfo::graphviz(graph); - - bool breaked = false; - bool finished = false; - unsigned int startIndex = 0; - const int maxNumberEvaluated = BLI_system_thread_count() * 2; - - while (!finished && !breaked) { - bool startEvaluated = false; - finished = true; - int numberEvaluated = 0; - - for (index = startIndex; index < this->m_chunks_len && numberEvaluated < maxNumberEvaluated; - index++) { - chunkNumber = chunkOrder[index]; - int yChunk = chunkNumber / this->m_x_chunks_len; - int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len); - switch (m_chunk_execution_states[chunkNumber]) { - case eChunkExecutionState::NOT_SCHEDULED: { - scheduleChunkWhenPossible(graph, xChunk, yChunk); - finished = false; - startEvaluated = true; - numberEvaluated++; - - if (bTree->update_draw) { - bTree->update_draw(bTree->udh); - } - break; - } - case eChunkExecutionState::SCHEDULED: { - finished = false; - startEvaluated = true; - numberEvaluated++; - break; - } - case eChunkExecutionState::EXECUTED: { - if (!startEvaluated) { - startIndex = index + 1; - } - } - }; - } - - WorkScheduler::finish(); - - if (bTree->test_break && bTree->test_break(bTree->tbh)) { - breaked = true; - } - } - DebugInfo::execution_group_finished(this); - DebugInfo::graphviz(graph); - - MEM_freeN(chunkOrder); -} - -MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber) -{ - rcti rect; - std::vector memoryproxies; - determineChunkRect(&rect, chunkNumber); - - this->determineDependingMemoryProxies(&memoryproxies); - MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN( - sizeof(MemoryBuffer *) * this->m_max_read_buffer_offset, __func__); - rcti output; - for (ReadBufferOperation *readOperation : m_read_operations) { - MemoryProxy *memoryProxy = readOperation->getMemoryProxy(); - this->determineDependingAreaOfInterest(&rect, readOperation, &output); - MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer( - memoryProxy, &output); - memoryBuffers[readOperation->getOffset()] = memoryBuffer; - } - return memoryBuffers; -} - -MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *memoryProxy, - rcti *rect) -{ - MemoryBuffer *imageBuffer = memoryProxy->getBuffer(); - MemoryBuffer *result = new MemoryBuffer(memoryProxy, rect); - result->copyContentFrom(imageBuffer); - return result; -} - -void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers) -{ - if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) { - this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::EXECUTED; - } - - atomic_add_and_fetch_u(&this->m_chunks_finished, 1); - if (memoryBuffers) { - for (unsigned int index = 0; index < this->m_max_read_buffer_offset; index++) { - MemoryBuffer *buffer = memoryBuffers[index]; - if (buffer) { - if (buffer->isTemporarily()) { - memoryBuffers[index] = nullptr; - delete buffer; - } - } - } - MEM_freeN(memoryBuffers); - } - if (this->m_bTree) { - // status report is only performed for top level Execution Groups. - float progress = this->m_chunks_finished; - progress /= this->m_chunks_len; - this->m_bTree->progress(this->m_bTree->prh, progress); - - char buf[128]; - BLI_snprintf(buf, - sizeof(buf), - TIP_("Compositing | Tile %u-%u"), - this->m_chunks_finished, - this->m_chunks_len); - this->m_bTree->stats_draw(this->m_bTree->sdh, buf); - } -} - -inline void ExecutionGroup::determineChunkRect(rcti *rect, - const unsigned int xChunk, - const unsigned int yChunk) const -{ - const int border_width = BLI_rcti_size_x(&this->m_viewerBorder); - const int border_height = BLI_rcti_size_y(&this->m_viewerBorder); - - if (this->m_singleThreaded) { - BLI_rcti_init( - rect, this->m_viewerBorder.xmin, border_width, this->m_viewerBorder.ymin, border_height); - } - else { - const unsigned int minx = xChunk * this->m_chunkSize + this->m_viewerBorder.xmin; - const unsigned int miny = yChunk * this->m_chunkSize + this->m_viewerBorder.ymin; - const unsigned int width = MIN2((unsigned int)this->m_viewerBorder.xmax, this->m_width); - const unsigned int height = MIN2((unsigned int)this->m_viewerBorder.ymax, this->m_height); - BLI_rcti_init(rect, - MIN2(minx, this->m_width), - MIN2(minx + this->m_chunkSize, width), - MIN2(miny, this->m_height), - MIN2(miny + this->m_chunkSize, height)); - } -} - -void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumber) const -{ - const unsigned int yChunk = chunkNumber / this->m_x_chunks_len; - const unsigned int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len); - determineChunkRect(rect, xChunk, yChunk); -} - -MemoryBuffer *ExecutionGroup::allocateOutputBuffer(int /*chunkNumber*/, rcti *rect) -{ - // we assume that this method is only called from complex execution groups. - NodeOperation *operation = this->getOutputOperation(); - if (operation->isWriteBufferOperation()) { - WriteBufferOperation *writeOperation = (WriteBufferOperation *)operation; - MemoryBuffer *buffer = new MemoryBuffer(writeOperation->getMemoryProxy(), rect); - return buffer; - } - return nullptr; -} - -bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area) -{ - if (this->m_singleThreaded) { - return scheduleChunkWhenPossible(graph, 0, 0); - } - // find all chunks inside the rect - // determine minxchunk, minychunk, maxxchunk, maxychunk where x and y are chunknumbers - - int indexx, indexy; - int minx = max_ii(area->xmin - m_viewerBorder.xmin, 0); - int maxx = min_ii(area->xmax - m_viewerBorder.xmin, m_viewerBorder.xmax - m_viewerBorder.xmin); - int miny = max_ii(area->ymin - m_viewerBorder.ymin, 0); - int maxy = min_ii(area->ymax - m_viewerBorder.ymin, m_viewerBorder.ymax - m_viewerBorder.ymin); - int minxchunk = minx / (int)m_chunkSize; - int maxxchunk = (maxx + (int)m_chunkSize - 1) / (int)m_chunkSize; - int minychunk = miny / (int)m_chunkSize; - int maxychunk = (maxy + (int)m_chunkSize - 1) / (int)m_chunkSize; - minxchunk = max_ii(minxchunk, 0); - minychunk = max_ii(minychunk, 0); - maxxchunk = min_ii(maxxchunk, (int)m_x_chunks_len); - maxychunk = min_ii(maxychunk, (int)m_y_chunks_len); - - bool result = true; - for (indexx = minxchunk; indexx < maxxchunk; indexx++) { - for (indexy = minychunk; indexy < maxychunk; indexy++) { - if (!scheduleChunkWhenPossible(graph, indexx, indexy)) { - result = false; - } - } - } - - return result; -} - -bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber) -{ - if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::NOT_SCHEDULED) { - this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::SCHEDULED; - WorkScheduler::schedule(this, chunkNumber); - return true; - } - return false; -} - -bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk) -{ - if (xChunk < 0 || xChunk >= (int)this->m_x_chunks_len) { - return true; - } - if (yChunk < 0 || yChunk >= (int)this->m_y_chunks_len) { - return true; - } - int chunkNumber = yChunk * this->m_x_chunks_len + xChunk; - // chunk is already executed - if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::EXECUTED) { - return true; - } - - // chunk is scheduled, but not executed - if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) { - return false; - } - - // chunk is nor executed nor scheduled. - std::vector memoryProxies; - this->determineDependingMemoryProxies(&memoryProxies); - - rcti rect; - determineChunkRect(&rect, xChunk, yChunk); - unsigned int index; - bool canBeExecuted = true; - rcti area; - - for (index = 0; index < m_read_operations.size(); index++) { - ReadBufferOperation *readOperation = m_read_operations[index]; - BLI_rcti_init(&area, 0, 0, 0, 0); - MemoryProxy *memoryProxy = memoryProxies[index]; - determineDependingAreaOfInterest(&rect, readOperation, &area); - ExecutionGroup *group = memoryProxy->getExecutor(); - - if (group != nullptr) { - if (!group->scheduleAreaWhenPossible(graph, &area)) { - canBeExecuted = false; - } - } - else { - throw "ERROR"; - } - } - - if (canBeExecuted) { - scheduleChunk(chunkNumber); - } - - return false; -} - -void ExecutionGroup::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - this->getOutputOperation()->determineDependingAreaOfInterest(input, readOperation, output); -} - -void ExecutionGroup::determineDependingMemoryProxies(std::vector *memoryProxies) -{ - for (ReadBufferOperation *readOperation : m_read_operations) { - memoryProxies->push_back(readOperation->getMemoryProxy()); - } -} - -bool ExecutionGroup::isOpenCL() -{ - return this->m_openCL; -} - -void ExecutionGroup::setViewerBorder(float xmin, float xmax, float ymin, float ymax) -{ - NodeOperation *operation = this->getOutputOperation(); - - if (operation->isViewerOperation() || operation->isPreviewOperation()) { - BLI_rcti_init(&this->m_viewerBorder, - xmin * this->m_width, - xmax * this->m_width, - ymin * this->m_height, - ymax * this->m_height); - } -} - -void ExecutionGroup::setRenderBorder(float xmin, float xmax, float ymin, float ymax) -{ - NodeOperation *operation = this->getOutputOperation(); - - if (operation->isOutputOperation(true)) { - /* Basically, setting border need to happen for only operations - * which operates in render resolution buffers (like compositor - * output nodes). - * - * In this cases adding border will lead to mapping coordinates - * from output buffer space to input buffer spaces when executing - * operation. - * - * But nodes like viewer and file output just shall display or - * safe the same exact buffer which goes to their input, no need - * in any kind of coordinates mapping. - */ - - bool operationNeedsBorder = !(operation->isViewerOperation() || - operation->isPreviewOperation() || - operation->isFileOutputOperation()); - - if (operationNeedsBorder) { - BLI_rcti_init(&this->m_viewerBorder, - xmin * this->m_width, - xmax * this->m_width, - ymin * this->m_height, - ymax * this->m_height); - } - } -} diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cc b/source/blender/compositor/intern/COM_ExecutionSystem.cc new file mode 100644 index 00000000000..6691e5feb5f --- /dev/null +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc @@ -0,0 +1,219 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ExecutionSystem.h" + +#include "BLI_utildefines.h" +#include "PIL_time.h" + +#include "BKE_node.h" + +#include "BLT_translation.h" + +#include "COM_Converter.h" +#include "COM_Debug.h" +#include "COM_ExecutionGroup.h" +#include "COM_NodeOperation.h" +#include "COM_NodeOperationBuilder.h" +#include "COM_ReadBufferOperation.h" +#include "COM_WorkScheduler.h" + +#ifdef WITH_CXX_GUARDEDALLOC +# include "MEM_guardedalloc.h" +#endif + +ExecutionSystem::ExecutionSystem(RenderData *rd, + Scene *scene, + bNodeTree *editingtree, + bool rendering, + bool fastcalculation, + 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); + this->m_context.setFastCalculation(fastcalculation); + /* initialize the CompositorContext */ + if (rendering) { + this->m_context.setQuality((CompositorQuality)editingtree->render_quality); + } + else { + this->m_context.setQuality((CompositorQuality)editingtree->edit_quality); + } + this->m_context.setRendering(rendering); + this->m_context.setHasActiveOpenCLDevices(WorkScheduler::has_gpu_devices() && + (editingtree->flag & NTREE_COM_OPENCL)); + + this->m_context.setRenderData(rd); + this->m_context.setViewSettings(viewSettings); + this->m_context.setDisplaySettings(displaySettings); + + { + NodeOperationBuilder builder(&m_context, editingtree); + builder.convertToOperations(this); + } + + unsigned int index; + unsigned int resolution[2]; + + rctf *viewer_border = &editingtree->viewer_border; + bool use_viewer_border = (editingtree->flag & NTREE_VIEWER_BORDER) && + viewer_border->xmin < viewer_border->xmax && + viewer_border->ymin < viewer_border->ymax; + + editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | Determining resolution")); + + for (index = 0; index < this->m_groups.size(); index++) { + resolution[0] = 0; + resolution[1] = 0; + ExecutionGroup *executionGroup = this->m_groups[index]; + executionGroup->determineResolution(resolution); + + if (rendering) { + /* case when cropping to render border happens is handled in + * compositor output and render layer nodes + */ + if ((rd->mode & R_BORDER) && !(rd->mode & R_CROP)) { + executionGroup->setRenderBorder( + rd->border.xmin, rd->border.xmax, rd->border.ymin, rd->border.ymax); + } + } + + if (use_viewer_border) { + executionGroup->setViewerBorder( + viewer_border->xmin, viewer_border->xmax, viewer_border->ymin, viewer_border->ymax); + } + } + + // DebugInfo::graphviz(this); +} + +ExecutionSystem::~ExecutionSystem() +{ + unsigned int index; + for (index = 0; index < this->m_operations.size(); index++) { + NodeOperation *operation = this->m_operations[index]; + delete operation; + } + this->m_operations.clear(); + for (index = 0; index < this->m_groups.size(); index++) { + ExecutionGroup *group = this->m_groups[index]; + delete group; + } + this->m_groups.clear(); +} + +void ExecutionSystem::set_operations(const blender::Vector &operations, + const blender::Vector &groups) +{ + m_operations = operations; + m_groups = groups; +} + +void ExecutionSystem::execute() +{ + const bNodeTree *editingtree = this->m_context.getbNodeTree(); + editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | Initializing execution")); + + DebugInfo::execute_started(this); + + unsigned int order = 0; + for (NodeOperation *operation : m_operations) { + if (operation->isReadBufferOperation()) { + ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; + readOperation->setOffset(order); + order++; + } + } + unsigned int index; + + // First allocale all write buffer + for (index = 0; index < this->m_operations.size(); index++) { + NodeOperation *operation = this->m_operations[index]; + if (operation->isWriteBufferOperation()) { + operation->setbNodeTree(this->m_context.getbNodeTree()); + operation->initExecution(); + } + } + // Connect read buffers to their write buffers + for (index = 0; index < this->m_operations.size(); index++) { + NodeOperation *operation = this->m_operations[index]; + if (operation->isReadBufferOperation()) { + ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; + readOperation->updateMemoryBuffer(); + } + } + // initialize other operations + for (index = 0; index < this->m_operations.size(); index++) { + NodeOperation *operation = this->m_operations[index]; + if (!operation->isWriteBufferOperation()) { + operation->setbNodeTree(this->m_context.getbNodeTree()); + operation->initExecution(); + } + } + for (index = 0; index < this->m_groups.size(); index++) { + ExecutionGroup *executionGroup = this->m_groups[index]; + executionGroup->setChunksize(this->m_context.getChunksize()); + executionGroup->initExecution(); + } + + WorkScheduler::start(this->m_context); + + execute_groups(COM_PRIORITY_HIGH); + if (!this->getContext().isFastCalculation()) { + execute_groups(COM_PRIORITY_MEDIUM); + execute_groups(COM_PRIORITY_LOW); + } + + WorkScheduler::finish(); + WorkScheduler::stop(); + + editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | De-initializing execution")); + for (index = 0; index < this->m_operations.size(); index++) { + NodeOperation *operation = this->m_operations[index]; + operation->deinitExecution(); + } + for (index = 0; index < this->m_groups.size(); index++) { + ExecutionGroup *executionGroup = this->m_groups[index]; + executionGroup->deinitExecution(); + } +} + +void ExecutionSystem::execute_groups(CompositorPriority priority) +{ + blender::Vector execution_groups = find_output_execution_groups(priority); + for (ExecutionGroup *group : execution_groups) { + group->execute(this); + } +} + +blender::Vector ExecutionSystem::find_output_execution_groups( + CompositorPriority priority) const +{ + blender::Vector result; + + for (ExecutionGroup *group : m_groups) { + if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) { + result.append(group); + } + } + return result; +} diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp deleted file mode 100644 index 6691e5feb5f..00000000000 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ExecutionSystem.h" - -#include "BLI_utildefines.h" -#include "PIL_time.h" - -#include "BKE_node.h" - -#include "BLT_translation.h" - -#include "COM_Converter.h" -#include "COM_Debug.h" -#include "COM_ExecutionGroup.h" -#include "COM_NodeOperation.h" -#include "COM_NodeOperationBuilder.h" -#include "COM_ReadBufferOperation.h" -#include "COM_WorkScheduler.h" - -#ifdef WITH_CXX_GUARDEDALLOC -# include "MEM_guardedalloc.h" -#endif - -ExecutionSystem::ExecutionSystem(RenderData *rd, - Scene *scene, - bNodeTree *editingtree, - bool rendering, - bool fastcalculation, - 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); - this->m_context.setFastCalculation(fastcalculation); - /* initialize the CompositorContext */ - if (rendering) { - this->m_context.setQuality((CompositorQuality)editingtree->render_quality); - } - else { - this->m_context.setQuality((CompositorQuality)editingtree->edit_quality); - } - this->m_context.setRendering(rendering); - this->m_context.setHasActiveOpenCLDevices(WorkScheduler::has_gpu_devices() && - (editingtree->flag & NTREE_COM_OPENCL)); - - this->m_context.setRenderData(rd); - this->m_context.setViewSettings(viewSettings); - this->m_context.setDisplaySettings(displaySettings); - - { - NodeOperationBuilder builder(&m_context, editingtree); - builder.convertToOperations(this); - } - - unsigned int index; - unsigned int resolution[2]; - - rctf *viewer_border = &editingtree->viewer_border; - bool use_viewer_border = (editingtree->flag & NTREE_VIEWER_BORDER) && - viewer_border->xmin < viewer_border->xmax && - viewer_border->ymin < viewer_border->ymax; - - editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | Determining resolution")); - - for (index = 0; index < this->m_groups.size(); index++) { - resolution[0] = 0; - resolution[1] = 0; - ExecutionGroup *executionGroup = this->m_groups[index]; - executionGroup->determineResolution(resolution); - - if (rendering) { - /* case when cropping to render border happens is handled in - * compositor output and render layer nodes - */ - if ((rd->mode & R_BORDER) && !(rd->mode & R_CROP)) { - executionGroup->setRenderBorder( - rd->border.xmin, rd->border.xmax, rd->border.ymin, rd->border.ymax); - } - } - - if (use_viewer_border) { - executionGroup->setViewerBorder( - viewer_border->xmin, viewer_border->xmax, viewer_border->ymin, viewer_border->ymax); - } - } - - // DebugInfo::graphviz(this); -} - -ExecutionSystem::~ExecutionSystem() -{ - unsigned int index; - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; - delete operation; - } - this->m_operations.clear(); - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *group = this->m_groups[index]; - delete group; - } - this->m_groups.clear(); -} - -void ExecutionSystem::set_operations(const blender::Vector &operations, - const blender::Vector &groups) -{ - m_operations = operations; - m_groups = groups; -} - -void ExecutionSystem::execute() -{ - const bNodeTree *editingtree = this->m_context.getbNodeTree(); - editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | Initializing execution")); - - DebugInfo::execute_started(this); - - unsigned int order = 0; - for (NodeOperation *operation : m_operations) { - if (operation->isReadBufferOperation()) { - ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; - readOperation->setOffset(order); - order++; - } - } - unsigned int index; - - // First allocale all write buffer - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; - if (operation->isWriteBufferOperation()) { - operation->setbNodeTree(this->m_context.getbNodeTree()); - operation->initExecution(); - } - } - // Connect read buffers to their write buffers - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; - if (operation->isReadBufferOperation()) { - ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; - readOperation->updateMemoryBuffer(); - } - } - // initialize other operations - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; - if (!operation->isWriteBufferOperation()) { - operation->setbNodeTree(this->m_context.getbNodeTree()); - operation->initExecution(); - } - } - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *executionGroup = this->m_groups[index]; - executionGroup->setChunksize(this->m_context.getChunksize()); - executionGroup->initExecution(); - } - - WorkScheduler::start(this->m_context); - - execute_groups(COM_PRIORITY_HIGH); - if (!this->getContext().isFastCalculation()) { - execute_groups(COM_PRIORITY_MEDIUM); - execute_groups(COM_PRIORITY_LOW); - } - - WorkScheduler::finish(); - WorkScheduler::stop(); - - editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | De-initializing execution")); - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; - operation->deinitExecution(); - } - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *executionGroup = this->m_groups[index]; - executionGroup->deinitExecution(); - } -} - -void ExecutionSystem::execute_groups(CompositorPriority priority) -{ - blender::Vector execution_groups = find_output_execution_groups(priority); - for (ExecutionGroup *group : execution_groups) { - group->execute(this); - } -} - -blender::Vector ExecutionSystem::find_output_execution_groups( - CompositorPriority priority) const -{ - blender::Vector result; - - for (ExecutionGroup *group : m_groups) { - if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) { - result.append(group); - } - } - return result; -} diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc new file mode 100644 index 00000000000..17a73efeab2 --- /dev/null +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc @@ -0,0 +1,227 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MemoryBuffer.h" + +#include "MEM_guardedalloc.h" + +static unsigned int determine_num_channels(DataType datatype) +{ + switch (datatype) { + case COM_DT_VALUE: + return COM_NUM_CHANNELS_VALUE; + case COM_DT_VECTOR: + return COM_NUM_CHANNELS_VECTOR; + case COM_DT_COLOR: + default: + return COM_NUM_CHANNELS_COLOR; + } +} + +unsigned int MemoryBuffer::determineBufferSize() +{ + return getWidth() * getHeight(); +} + +int MemoryBuffer::getWidth() const +{ + return this->m_width; +} +int MemoryBuffer::getHeight() const +{ + return this->m_height; +} + +MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber, rcti *rect) +{ + BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax); + this->m_width = BLI_rcti_size_x(&this->m_rect); + this->m_height = BLI_rcti_size_y(&this->m_rect); + this->m_memoryProxy = memoryProxy; + this->m_chunkNumber = chunkNumber; + this->m_num_channels = determine_num_channels(memoryProxy->getDataType()); + this->m_buffer = (float *)MEM_mallocN_aligned( + sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer"); + this->m_state = COM_MB_ALLOCATED; + this->m_datatype = memoryProxy->getDataType(); +} + +MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, rcti *rect) +{ + BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax); + this->m_width = BLI_rcti_size_x(&this->m_rect); + this->m_height = BLI_rcti_size_y(&this->m_rect); + this->m_memoryProxy = memoryProxy; + this->m_chunkNumber = -1; + this->m_num_channels = determine_num_channels(memoryProxy->getDataType()); + this->m_buffer = (float *)MEM_mallocN_aligned( + sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer"); + this->m_state = COM_MB_TEMPORARILY; + this->m_datatype = memoryProxy->getDataType(); +} +MemoryBuffer::MemoryBuffer(DataType dataType, rcti *rect) +{ + BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax); + this->m_width = BLI_rcti_size_x(&this->m_rect); + this->m_height = BLI_rcti_size_y(&this->m_rect); + this->m_height = this->m_rect.ymax - this->m_rect.ymin; + this->m_memoryProxy = nullptr; + this->m_chunkNumber = -1; + this->m_num_channels = determine_num_channels(dataType); + this->m_buffer = (float *)MEM_mallocN_aligned( + sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer"); + this->m_state = COM_MB_TEMPORARILY; + this->m_datatype = dataType; +} +MemoryBuffer *MemoryBuffer::duplicate() +{ + MemoryBuffer *result = new MemoryBuffer(this->m_memoryProxy, &this->m_rect); + memcpy(result->m_buffer, + this->m_buffer, + this->determineBufferSize() * this->m_num_channels * sizeof(float)); + return result; +} +void MemoryBuffer::clear() +{ + memset(this->m_buffer, 0, this->determineBufferSize() * this->m_num_channels * sizeof(float)); +} + +float MemoryBuffer::getMaximumValue() +{ + float result = this->m_buffer[0]; + const unsigned int size = this->determineBufferSize(); + unsigned int i; + + const float *fp_src = this->m_buffer; + + for (i = 0; i < size; i++, fp_src += this->m_num_channels) { + float value = *fp_src; + if (value > result) { + result = value; + } + } + + return result; +} + +float MemoryBuffer::getMaximumValue(rcti *rect) +{ + rcti rect_clamp; + + /* first clamp the rect by the bounds or we get un-initialized values */ + BLI_rcti_isect(rect, &this->m_rect, &rect_clamp); + + if (!BLI_rcti_is_empty(&rect_clamp)) { + MemoryBuffer *temp = new MemoryBuffer(this->m_datatype, &rect_clamp); + temp->copyContentFrom(this); + float result = temp->getMaximumValue(); + delete temp; + return result; + } + + BLI_assert(0); + return 0.0f; +} + +MemoryBuffer::~MemoryBuffer() +{ + if (this->m_buffer) { + MEM_freeN(this->m_buffer); + this->m_buffer = nullptr; + } +} + +void MemoryBuffer::copyContentFrom(MemoryBuffer *otherBuffer) +{ + if (!otherBuffer) { + BLI_assert(0); + return; + } + unsigned int otherY; + unsigned int minX = MAX2(this->m_rect.xmin, otherBuffer->m_rect.xmin); + unsigned int maxX = MIN2(this->m_rect.xmax, otherBuffer->m_rect.xmax); + unsigned int minY = MAX2(this->m_rect.ymin, otherBuffer->m_rect.ymin); + unsigned int maxY = MIN2(this->m_rect.ymax, otherBuffer->m_rect.ymax); + int offset; + int otherOffset; + + for (otherY = minY; otherY < maxY; otherY++) { + otherOffset = ((otherY - otherBuffer->m_rect.ymin) * otherBuffer->m_width + minX - + otherBuffer->m_rect.xmin) * + this->m_num_channels; + offset = ((otherY - this->m_rect.ymin) * this->m_width + minX - this->m_rect.xmin) * + this->m_num_channels; + memcpy(&this->m_buffer[offset], + &otherBuffer->m_buffer[otherOffset], + (maxX - minX) * this->m_num_channels * sizeof(float)); + } +} + +void MemoryBuffer::writePixel(int x, int y, const float color[4]) +{ + if (x >= this->m_rect.xmin && x < this->m_rect.xmax && y >= this->m_rect.ymin && + y < this->m_rect.ymax) { + const int offset = (this->m_width * (y - this->m_rect.ymin) + x - this->m_rect.xmin) * + this->m_num_channels; + memcpy(&this->m_buffer[offset], color, sizeof(float) * this->m_num_channels); + } +} + +void MemoryBuffer::addPixel(int x, int y, const float color[4]) +{ + if (x >= this->m_rect.xmin && x < this->m_rect.xmax && y >= this->m_rect.ymin && + y < this->m_rect.ymax) { + const int offset = (this->m_width * (y - this->m_rect.ymin) + x - this->m_rect.xmin) * + this->m_num_channels; + float *dst = &this->m_buffer[offset]; + const float *src = color; + for (int i = 0; i < this->m_num_channels; i++, dst++, src++) { + *dst += *src; + } + } +} + +static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4]) +{ + MemoryBuffer *buffer = (MemoryBuffer *)userdata; + buffer->read(result, x, y); +} + +void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2]) +{ + BLI_assert(this->m_datatype == COM_DT_COLOR); + float inv_width = 1.0f / (float)this->getWidth(), inv_height = 1.0f / (float)this->getHeight(); + /* TODO(sergey): Render pipeline uses normalized coordinates and derivatives, + * but compositor uses pixel space. For now let's just divide the values and + * switch compositor to normalized space for EWA later. + */ + float uv_normal[2] = {uv[0] * inv_width, uv[1] * inv_height}; + float du_normal[2] = {derivatives[0][0] * inv_width, derivatives[0][1] * inv_height}; + float dv_normal[2] = {derivatives[1][0] * inv_width, derivatives[1][1] * inv_height}; + + BLI_ewa_filter(this->getWidth(), + this->getHeight(), + false, + true, + uv_normal, + du_normal, + dv_normal, + read_ewa_pixel_sampled, + this, + result); +} diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cpp deleted file mode 100644 index 17a73efeab2..00000000000 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MemoryBuffer.h" - -#include "MEM_guardedalloc.h" - -static unsigned int determine_num_channels(DataType datatype) -{ - switch (datatype) { - case COM_DT_VALUE: - return COM_NUM_CHANNELS_VALUE; - case COM_DT_VECTOR: - return COM_NUM_CHANNELS_VECTOR; - case COM_DT_COLOR: - default: - return COM_NUM_CHANNELS_COLOR; - } -} - -unsigned int MemoryBuffer::determineBufferSize() -{ - return getWidth() * getHeight(); -} - -int MemoryBuffer::getWidth() const -{ - return this->m_width; -} -int MemoryBuffer::getHeight() const -{ - return this->m_height; -} - -MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber, rcti *rect) -{ - BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax); - this->m_width = BLI_rcti_size_x(&this->m_rect); - this->m_height = BLI_rcti_size_y(&this->m_rect); - this->m_memoryProxy = memoryProxy; - this->m_chunkNumber = chunkNumber; - this->m_num_channels = determine_num_channels(memoryProxy->getDataType()); - this->m_buffer = (float *)MEM_mallocN_aligned( - sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer"); - this->m_state = COM_MB_ALLOCATED; - this->m_datatype = memoryProxy->getDataType(); -} - -MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, rcti *rect) -{ - BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax); - this->m_width = BLI_rcti_size_x(&this->m_rect); - this->m_height = BLI_rcti_size_y(&this->m_rect); - this->m_memoryProxy = memoryProxy; - this->m_chunkNumber = -1; - this->m_num_channels = determine_num_channels(memoryProxy->getDataType()); - this->m_buffer = (float *)MEM_mallocN_aligned( - sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer"); - this->m_state = COM_MB_TEMPORARILY; - this->m_datatype = memoryProxy->getDataType(); -} -MemoryBuffer::MemoryBuffer(DataType dataType, rcti *rect) -{ - BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax); - this->m_width = BLI_rcti_size_x(&this->m_rect); - this->m_height = BLI_rcti_size_y(&this->m_rect); - this->m_height = this->m_rect.ymax - this->m_rect.ymin; - this->m_memoryProxy = nullptr; - this->m_chunkNumber = -1; - this->m_num_channels = determine_num_channels(dataType); - this->m_buffer = (float *)MEM_mallocN_aligned( - sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer"); - this->m_state = COM_MB_TEMPORARILY; - this->m_datatype = dataType; -} -MemoryBuffer *MemoryBuffer::duplicate() -{ - MemoryBuffer *result = new MemoryBuffer(this->m_memoryProxy, &this->m_rect); - memcpy(result->m_buffer, - this->m_buffer, - this->determineBufferSize() * this->m_num_channels * sizeof(float)); - return result; -} -void MemoryBuffer::clear() -{ - memset(this->m_buffer, 0, this->determineBufferSize() * this->m_num_channels * sizeof(float)); -} - -float MemoryBuffer::getMaximumValue() -{ - float result = this->m_buffer[0]; - const unsigned int size = this->determineBufferSize(); - unsigned int i; - - const float *fp_src = this->m_buffer; - - for (i = 0; i < size; i++, fp_src += this->m_num_channels) { - float value = *fp_src; - if (value > result) { - result = value; - } - } - - return result; -} - -float MemoryBuffer::getMaximumValue(rcti *rect) -{ - rcti rect_clamp; - - /* first clamp the rect by the bounds or we get un-initialized values */ - BLI_rcti_isect(rect, &this->m_rect, &rect_clamp); - - if (!BLI_rcti_is_empty(&rect_clamp)) { - MemoryBuffer *temp = new MemoryBuffer(this->m_datatype, &rect_clamp); - temp->copyContentFrom(this); - float result = temp->getMaximumValue(); - delete temp; - return result; - } - - BLI_assert(0); - return 0.0f; -} - -MemoryBuffer::~MemoryBuffer() -{ - if (this->m_buffer) { - MEM_freeN(this->m_buffer); - this->m_buffer = nullptr; - } -} - -void MemoryBuffer::copyContentFrom(MemoryBuffer *otherBuffer) -{ - if (!otherBuffer) { - BLI_assert(0); - return; - } - unsigned int otherY; - unsigned int minX = MAX2(this->m_rect.xmin, otherBuffer->m_rect.xmin); - unsigned int maxX = MIN2(this->m_rect.xmax, otherBuffer->m_rect.xmax); - unsigned int minY = MAX2(this->m_rect.ymin, otherBuffer->m_rect.ymin); - unsigned int maxY = MIN2(this->m_rect.ymax, otherBuffer->m_rect.ymax); - int offset; - int otherOffset; - - for (otherY = minY; otherY < maxY; otherY++) { - otherOffset = ((otherY - otherBuffer->m_rect.ymin) * otherBuffer->m_width + minX - - otherBuffer->m_rect.xmin) * - this->m_num_channels; - offset = ((otherY - this->m_rect.ymin) * this->m_width + minX - this->m_rect.xmin) * - this->m_num_channels; - memcpy(&this->m_buffer[offset], - &otherBuffer->m_buffer[otherOffset], - (maxX - minX) * this->m_num_channels * sizeof(float)); - } -} - -void MemoryBuffer::writePixel(int x, int y, const float color[4]) -{ - if (x >= this->m_rect.xmin && x < this->m_rect.xmax && y >= this->m_rect.ymin && - y < this->m_rect.ymax) { - const int offset = (this->m_width * (y - this->m_rect.ymin) + x - this->m_rect.xmin) * - this->m_num_channels; - memcpy(&this->m_buffer[offset], color, sizeof(float) * this->m_num_channels); - } -} - -void MemoryBuffer::addPixel(int x, int y, const float color[4]) -{ - if (x >= this->m_rect.xmin && x < this->m_rect.xmax && y >= this->m_rect.ymin && - y < this->m_rect.ymax) { - const int offset = (this->m_width * (y - this->m_rect.ymin) + x - this->m_rect.xmin) * - this->m_num_channels; - float *dst = &this->m_buffer[offset]; - const float *src = color; - for (int i = 0; i < this->m_num_channels; i++, dst++, src++) { - *dst += *src; - } - } -} - -static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4]) -{ - MemoryBuffer *buffer = (MemoryBuffer *)userdata; - buffer->read(result, x, y); -} - -void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2]) -{ - BLI_assert(this->m_datatype == COM_DT_COLOR); - float inv_width = 1.0f / (float)this->getWidth(), inv_height = 1.0f / (float)this->getHeight(); - /* TODO(sergey): Render pipeline uses normalized coordinates and derivatives, - * but compositor uses pixel space. For now let's just divide the values and - * switch compositor to normalized space for EWA later. - */ - float uv_normal[2] = {uv[0] * inv_width, uv[1] * inv_height}; - float du_normal[2] = {derivatives[0][0] * inv_width, derivatives[0][1] * inv_height}; - float dv_normal[2] = {derivatives[1][0] * inv_width, derivatives[1][1] * inv_height}; - - BLI_ewa_filter(this->getWidth(), - this->getHeight(), - false, - true, - uv_normal, - du_normal, - dv_normal, - read_ewa_pixel_sampled, - this, - result); -} diff --git a/source/blender/compositor/intern/COM_MemoryProxy.cc b/source/blender/compositor/intern/COM_MemoryProxy.cc new file mode 100644 index 00000000000..7d590cd0ef6 --- /dev/null +++ b/source/blender/compositor/intern/COM_MemoryProxy.cc @@ -0,0 +1,45 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MemoryProxy.h" + +MemoryProxy::MemoryProxy(DataType datatype) +{ + this->m_writeBufferOperation = nullptr; + this->m_executor = nullptr; + this->m_datatype = datatype; +} + +void MemoryProxy::allocate(unsigned int width, unsigned int height) +{ + rcti result; + result.xmin = 0; + result.xmax = width; + result.ymin = 0; + result.ymax = height; + + this->m_buffer = new MemoryBuffer(this, 1, &result); +} + +void MemoryProxy::free() +{ + if (this->m_buffer) { + delete this->m_buffer; + this->m_buffer = nullptr; + } +} diff --git a/source/blender/compositor/intern/COM_MemoryProxy.cpp b/source/blender/compositor/intern/COM_MemoryProxy.cpp deleted file mode 100644 index 7d590cd0ef6..00000000000 --- a/source/blender/compositor/intern/COM_MemoryProxy.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MemoryProxy.h" - -MemoryProxy::MemoryProxy(DataType datatype) -{ - this->m_writeBufferOperation = nullptr; - this->m_executor = nullptr; - this->m_datatype = datatype; -} - -void MemoryProxy::allocate(unsigned int width, unsigned int height) -{ - rcti result; - result.xmin = 0; - result.xmax = width; - result.ymin = 0; - result.ymax = height; - - this->m_buffer = new MemoryBuffer(this, 1, &result); -} - -void MemoryProxy::free() -{ - if (this->m_buffer) { - delete this->m_buffer; - this->m_buffer = nullptr; - } -} diff --git a/source/blender/compositor/intern/COM_MetaData.cc b/source/blender/compositor/intern/COM_MetaData.cc new file mode 100644 index 00000000000..a6306f6c657 --- /dev/null +++ b/source/blender/compositor/intern/COM_MetaData.cc @@ -0,0 +1,106 @@ +/* + * 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. + * + * Copyright 2021, Blender Foundation. + */ + +#include "COM_MetaData.h" + +#include "BKE_image.h" + +#include "RE_pipeline.h" + +#include + +void MetaData::add(const blender::StringRef key, const blender::StringRef value) +{ + entries_.add(key, value); +} + +void MetaData::addCryptomatteEntry(const blender::StringRef layer_name, + const blender::StringRefNull key, + const blender::StringRef value) +{ + add(blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(layer_name, key), value); +} + +/* Replace the hash neutral cryptomatte keys with hashed versions. + * + * When a conversion happens it will also add the cryptomatte name key with the given + * `layer_name`.*/ +void MetaData::replaceHashNeutralCryptomatteKeys(const blender::StringRef layer_name) +{ + std::string cryptomatte_hash = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_HASH, ""); + std::string cryptomatte_conversion = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_CONVERSION, + ""); + std::string cryptomatte_manifest = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_MANIFEST, ""); + + if (cryptomatte_hash.length() || cryptomatte_conversion.length() || + cryptomatte_manifest.length()) { + addCryptomatteEntry(layer_name, "name", layer_name); + } + if (cryptomatte_hash.length()) { + addCryptomatteEntry(layer_name, "hash", cryptomatte_hash); + } + if (cryptomatte_conversion.length()) { + addCryptomatteEntry(layer_name, "conversion", cryptomatte_conversion); + } + if (cryptomatte_manifest.length()) { + addCryptomatteEntry(layer_name, "manifest", cryptomatte_manifest); + } +} + +void MetaData::addToRenderResult(RenderResult *render_result) const +{ + for (blender::Map::Item entry : entries_.items()) { + BKE_render_result_stamp_data(render_result, entry.key.c_str(), entry.value.c_str()); + } +} + +void MetaDataExtractCallbackData::addMetaData(blender::StringRef key, blender::StringRefNull value) +{ + if (!meta_data) { + meta_data = std::make_unique(); + } + meta_data->add(key, value); +} + +void MetaDataExtractCallbackData::setCryptomatteKeys(blender::StringRef cryptomatte_layer_name) +{ + manifest_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, + "manifest"); + hash_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, + "hash"); + conversion_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, + "conversion"); +} + +void MetaDataExtractCallbackData::extract_cryptomatte_meta_data(void *_data, + const char *propname, + char *propvalue, + int UNUSED(len)) +{ + MetaDataExtractCallbackData *data = static_cast(_data); + blender::StringRefNull key(propname); + if (key == data->hash_key) { + data->addMetaData(META_DATA_KEY_CRYPTOMATTE_HASH, propvalue); + } + else if (key == data->conversion_key) { + data->addMetaData(META_DATA_KEY_CRYPTOMATTE_CONVERSION, propvalue); + } + else if (key == data->manifest_key) { + data->addMetaData(META_DATA_KEY_CRYPTOMATTE_MANIFEST, propvalue); + } +} \ No newline at end of file diff --git a/source/blender/compositor/intern/COM_MetaData.cpp b/source/blender/compositor/intern/COM_MetaData.cpp deleted file mode 100644 index a6306f6c657..00000000000 --- a/source/blender/compositor/intern/COM_MetaData.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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. - * - * Copyright 2021, Blender Foundation. - */ - -#include "COM_MetaData.h" - -#include "BKE_image.h" - -#include "RE_pipeline.h" - -#include - -void MetaData::add(const blender::StringRef key, const blender::StringRef value) -{ - entries_.add(key, value); -} - -void MetaData::addCryptomatteEntry(const blender::StringRef layer_name, - const blender::StringRefNull key, - const blender::StringRef value) -{ - add(blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(layer_name, key), value); -} - -/* Replace the hash neutral cryptomatte keys with hashed versions. - * - * When a conversion happens it will also add the cryptomatte name key with the given - * `layer_name`.*/ -void MetaData::replaceHashNeutralCryptomatteKeys(const blender::StringRef layer_name) -{ - std::string cryptomatte_hash = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_HASH, ""); - std::string cryptomatte_conversion = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_CONVERSION, - ""); - std::string cryptomatte_manifest = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_MANIFEST, ""); - - if (cryptomatte_hash.length() || cryptomatte_conversion.length() || - cryptomatte_manifest.length()) { - addCryptomatteEntry(layer_name, "name", layer_name); - } - if (cryptomatte_hash.length()) { - addCryptomatteEntry(layer_name, "hash", cryptomatte_hash); - } - if (cryptomatte_conversion.length()) { - addCryptomatteEntry(layer_name, "conversion", cryptomatte_conversion); - } - if (cryptomatte_manifest.length()) { - addCryptomatteEntry(layer_name, "manifest", cryptomatte_manifest); - } -} - -void MetaData::addToRenderResult(RenderResult *render_result) const -{ - for (blender::Map::Item entry : entries_.items()) { - BKE_render_result_stamp_data(render_result, entry.key.c_str(), entry.value.c_str()); - } -} - -void MetaDataExtractCallbackData::addMetaData(blender::StringRef key, blender::StringRefNull value) -{ - if (!meta_data) { - meta_data = std::make_unique(); - } - meta_data->add(key, value); -} - -void MetaDataExtractCallbackData::setCryptomatteKeys(blender::StringRef cryptomatte_layer_name) -{ - manifest_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, - "manifest"); - hash_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, - "hash"); - conversion_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, - "conversion"); -} - -void MetaDataExtractCallbackData::extract_cryptomatte_meta_data(void *_data, - const char *propname, - char *propvalue, - int UNUSED(len)) -{ - MetaDataExtractCallbackData *data = static_cast(_data); - blender::StringRefNull key(propname); - if (key == data->hash_key) { - data->addMetaData(META_DATA_KEY_CRYPTOMATTE_HASH, propvalue); - } - else if (key == data->conversion_key) { - data->addMetaData(META_DATA_KEY_CRYPTOMATTE_CONVERSION, propvalue); - } - else if (key == data->manifest_key) { - data->addMetaData(META_DATA_KEY_CRYPTOMATTE_MANIFEST, propvalue); - } -} \ No newline at end of file diff --git a/source/blender/compositor/intern/COM_Node.cc b/source/blender/compositor/intern/COM_Node.cc new file mode 100644 index 00000000000..897d4e1df02 --- /dev/null +++ b/source/blender/compositor/intern/COM_Node.cc @@ -0,0 +1,210 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include + +#include "BKE_node.h" + +#include "RNA_access.h" + +#include "COM_ExecutionSystem.h" +#include "COM_NodeOperation.h" +#include "COM_TranslateOperation.h" + +#include "COM_SocketProxyNode.h" + +#include "COM_defines.h" + +#include "COM_Node.h" /* own include */ + +/************** + **** Node **** + **************/ + +Node::Node(bNode *editorNode, bool create_sockets) + : m_editorNodeTree(nullptr), + m_editorNode(editorNode), + m_inActiveGroup(false), + m_instanceKey(NODE_INSTANCE_KEY_NONE) +{ + if (create_sockets) { + bNodeSocket *input = (bNodeSocket *)editorNode->inputs.first; + while (input != nullptr) { + DataType dt = COM_DT_VALUE; + if (input->type == SOCK_RGBA) { + dt = COM_DT_COLOR; + } + if (input->type == SOCK_VECTOR) { + dt = COM_DT_VECTOR; + } + + this->addInputSocket(dt, input); + input = input->next; + } + bNodeSocket *output = (bNodeSocket *)editorNode->outputs.first; + while (output != nullptr) { + DataType dt = COM_DT_VALUE; + if (output->type == SOCK_RGBA) { + dt = COM_DT_COLOR; + } + if (output->type == SOCK_VECTOR) { + dt = COM_DT_VECTOR; + } + + this->addOutputSocket(dt, output); + output = output->next; + } + } +} + +Node::~Node() +{ + while (!this->m_outputsockets.empty()) { + delete (this->m_outputsockets.back()); + this->m_outputsockets.pop_back(); + } + while (!this->m_inputsockets.empty()) { + delete (this->m_inputsockets.back()); + this->m_inputsockets.pop_back(); + } +} + +void Node::addInputSocket(DataType datatype) +{ + this->addInputSocket(datatype, nullptr); +} + +void Node::addInputSocket(DataType datatype, bNodeSocket *bSocket) +{ + NodeInput *socket = new NodeInput(this, bSocket, datatype); + this->m_inputsockets.push_back(socket); +} + +void Node::addOutputSocket(DataType datatype) +{ + this->addOutputSocket(datatype, nullptr); +} +void Node::addOutputSocket(DataType datatype, bNodeSocket *bSocket) +{ + NodeOutput *socket = new NodeOutput(this, bSocket, datatype); + this->m_outputsockets.push_back(socket); +} + +NodeOutput *Node::getOutputSocket(unsigned int index) const +{ + BLI_assert(index < this->m_outputsockets.size()); + return this->m_outputsockets[index]; +} + +NodeInput *Node::getInputSocket(unsigned int index) const +{ + BLI_assert(index < this->m_inputsockets.size()); + return this->m_inputsockets[index]; +} + +bNodeSocket *Node::getEditorInputSocket(int editorNodeInputSocketIndex) +{ + bNodeSocket *bSock = (bNodeSocket *)this->getbNode()->inputs.first; + int index = 0; + while (bSock != nullptr) { + if (index == editorNodeInputSocketIndex) { + return bSock; + } + index++; + bSock = bSock->next; + } + return nullptr; +} +bNodeSocket *Node::getEditorOutputSocket(int editorNodeOutputSocketIndex) +{ + bNodeSocket *bSock = (bNodeSocket *)this->getbNode()->outputs.first; + int index = 0; + while (bSock != nullptr) { + if (index == editorNodeOutputSocketIndex) { + return bSock; + } + index++; + bSock = bSock->next; + } + return nullptr; +} + +/******************* + **** NodeInput **** + *******************/ + +NodeInput::NodeInput(Node *node, bNodeSocket *b_socket, DataType datatype) + : m_node(node), m_editorSocket(b_socket), m_datatype(datatype), m_link(nullptr) +{ +} + +void NodeInput::setLink(NodeOutput *link) +{ + m_link = link; +} + +float NodeInput::getEditorValueFloat() +{ + PointerRNA ptr; + RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); + return RNA_float_get(&ptr, "default_value"); +} + +void NodeInput::getEditorValueColor(float *value) +{ + PointerRNA ptr; + RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); + return RNA_float_get_array(&ptr, "default_value", value); +} + +void NodeInput::getEditorValueVector(float *value) +{ + PointerRNA ptr; + RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); + return RNA_float_get_array(&ptr, "default_value", value); +} + +/******************** + **** NodeOutput **** + ********************/ + +NodeOutput::NodeOutput(Node *node, bNodeSocket *b_socket, DataType datatype) + : m_node(node), m_editorSocket(b_socket), m_datatype(datatype) +{ +} + +float NodeOutput::getEditorValueFloat() +{ + PointerRNA ptr; + RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); + return RNA_float_get(&ptr, "default_value"); +} + +void NodeOutput::getEditorValueColor(float *value) +{ + PointerRNA ptr; + RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); + return RNA_float_get_array(&ptr, "default_value", value); +} + +void NodeOutput::getEditorValueVector(float *value) +{ + PointerRNA ptr; + RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); + return RNA_float_get_array(&ptr, "default_value", value); +} diff --git a/source/blender/compositor/intern/COM_Node.cpp b/source/blender/compositor/intern/COM_Node.cpp deleted file mode 100644 index 897d4e1df02..00000000000 --- a/source/blender/compositor/intern/COM_Node.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include - -#include "BKE_node.h" - -#include "RNA_access.h" - -#include "COM_ExecutionSystem.h" -#include "COM_NodeOperation.h" -#include "COM_TranslateOperation.h" - -#include "COM_SocketProxyNode.h" - -#include "COM_defines.h" - -#include "COM_Node.h" /* own include */ - -/************** - **** Node **** - **************/ - -Node::Node(bNode *editorNode, bool create_sockets) - : m_editorNodeTree(nullptr), - m_editorNode(editorNode), - m_inActiveGroup(false), - m_instanceKey(NODE_INSTANCE_KEY_NONE) -{ - if (create_sockets) { - bNodeSocket *input = (bNodeSocket *)editorNode->inputs.first; - while (input != nullptr) { - DataType dt = COM_DT_VALUE; - if (input->type == SOCK_RGBA) { - dt = COM_DT_COLOR; - } - if (input->type == SOCK_VECTOR) { - dt = COM_DT_VECTOR; - } - - this->addInputSocket(dt, input); - input = input->next; - } - bNodeSocket *output = (bNodeSocket *)editorNode->outputs.first; - while (output != nullptr) { - DataType dt = COM_DT_VALUE; - if (output->type == SOCK_RGBA) { - dt = COM_DT_COLOR; - } - if (output->type == SOCK_VECTOR) { - dt = COM_DT_VECTOR; - } - - this->addOutputSocket(dt, output); - output = output->next; - } - } -} - -Node::~Node() -{ - while (!this->m_outputsockets.empty()) { - delete (this->m_outputsockets.back()); - this->m_outputsockets.pop_back(); - } - while (!this->m_inputsockets.empty()) { - delete (this->m_inputsockets.back()); - this->m_inputsockets.pop_back(); - } -} - -void Node::addInputSocket(DataType datatype) -{ - this->addInputSocket(datatype, nullptr); -} - -void Node::addInputSocket(DataType datatype, bNodeSocket *bSocket) -{ - NodeInput *socket = new NodeInput(this, bSocket, datatype); - this->m_inputsockets.push_back(socket); -} - -void Node::addOutputSocket(DataType datatype) -{ - this->addOutputSocket(datatype, nullptr); -} -void Node::addOutputSocket(DataType datatype, bNodeSocket *bSocket) -{ - NodeOutput *socket = new NodeOutput(this, bSocket, datatype); - this->m_outputsockets.push_back(socket); -} - -NodeOutput *Node::getOutputSocket(unsigned int index) const -{ - BLI_assert(index < this->m_outputsockets.size()); - return this->m_outputsockets[index]; -} - -NodeInput *Node::getInputSocket(unsigned int index) const -{ - BLI_assert(index < this->m_inputsockets.size()); - return this->m_inputsockets[index]; -} - -bNodeSocket *Node::getEditorInputSocket(int editorNodeInputSocketIndex) -{ - bNodeSocket *bSock = (bNodeSocket *)this->getbNode()->inputs.first; - int index = 0; - while (bSock != nullptr) { - if (index == editorNodeInputSocketIndex) { - return bSock; - } - index++; - bSock = bSock->next; - } - return nullptr; -} -bNodeSocket *Node::getEditorOutputSocket(int editorNodeOutputSocketIndex) -{ - bNodeSocket *bSock = (bNodeSocket *)this->getbNode()->outputs.first; - int index = 0; - while (bSock != nullptr) { - if (index == editorNodeOutputSocketIndex) { - return bSock; - } - index++; - bSock = bSock->next; - } - return nullptr; -} - -/******************* - **** NodeInput **** - *******************/ - -NodeInput::NodeInput(Node *node, bNodeSocket *b_socket, DataType datatype) - : m_node(node), m_editorSocket(b_socket), m_datatype(datatype), m_link(nullptr) -{ -} - -void NodeInput::setLink(NodeOutput *link) -{ - m_link = link; -} - -float NodeInput::getEditorValueFloat() -{ - PointerRNA ptr; - RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); - return RNA_float_get(&ptr, "default_value"); -} - -void NodeInput::getEditorValueColor(float *value) -{ - PointerRNA ptr; - RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); - return RNA_float_get_array(&ptr, "default_value", value); -} - -void NodeInput::getEditorValueVector(float *value) -{ - PointerRNA ptr; - RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); - return RNA_float_get_array(&ptr, "default_value", value); -} - -/******************** - **** NodeOutput **** - ********************/ - -NodeOutput::NodeOutput(Node *node, bNodeSocket *b_socket, DataType datatype) - : m_node(node), m_editorSocket(b_socket), m_datatype(datatype) -{ -} - -float NodeOutput::getEditorValueFloat() -{ - PointerRNA ptr; - RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); - return RNA_float_get(&ptr, "default_value"); -} - -void NodeOutput::getEditorValueColor(float *value) -{ - PointerRNA ptr; - RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); - return RNA_float_get_array(&ptr, "default_value", value); -} - -void NodeOutput::getEditorValueVector(float *value) -{ - PointerRNA ptr; - RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); - return RNA_float_get_array(&ptr, "default_value", value); -} diff --git a/source/blender/compositor/intern/COM_NodeConverter.cc b/source/blender/compositor/intern/COM_NodeConverter.cc new file mode 100644 index 00000000000..2db31bd4133 --- /dev/null +++ b/source/blender/compositor/intern/COM_NodeConverter.cc @@ -0,0 +1,162 @@ +/* + * 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. + * + * Copyright 2013, Blender Foundation. + */ + +#include "BLI_utildefines.h" + +#include "COM_Debug.h" + +#include "COM_NodeOperation.h" +#include "COM_NodeOperationBuilder.h" +#include "COM_SetColorOperation.h" +#include "COM_SetValueOperation.h" +#include "COM_SetVectorOperation.h" +#include "COM_SocketProxyOperation.h" + +#include "COM_NodeConverter.h" /* own include */ + +NodeConverter::NodeConverter(NodeOperationBuilder *builder) : m_builder(builder) +{ +} + +void NodeConverter::addOperation(NodeOperation *operation) +{ + m_builder->addOperation(operation); +} + +void NodeConverter::mapInputSocket(NodeInput *node_socket, NodeOperationInput *operation_socket) +{ + m_builder->mapInputSocket(node_socket, operation_socket); +} + +void NodeConverter::mapOutputSocket(NodeOutput *node_socket, NodeOperationOutput *operation_socket) +{ + m_builder->mapOutputSocket(node_socket, operation_socket); +} + +void NodeConverter::addLink(NodeOperationOutput *from, NodeOperationInput *to) +{ + m_builder->addLink(from, to); +} + +void NodeConverter::addPreview(NodeOperationOutput *output) +{ + m_builder->addPreview(output); +} + +void NodeConverter::addNodeInputPreview(NodeInput *input) +{ + m_builder->addNodeInputPreview(input); +} + +NodeOperation *NodeConverter::setInvalidOutput(NodeOutput *output) +{ + /* this is a really bad situation - bring on the pink! - so artists know this is bad */ + const float warning_color[4] = {1.0f, 0.0f, 1.0f, 1.0f}; + + SetColorOperation *operation = new SetColorOperation(); + operation->setChannels(warning_color); + + m_builder->addOperation(operation); + m_builder->mapOutputSocket(output, operation->getOutputSocket()); + + return operation; +} + +NodeOperationOutput *NodeConverter::addInputProxy(NodeInput *input, bool use_conversion) +{ + SocketProxyOperation *proxy = new SocketProxyOperation(input->getDataType(), use_conversion); + m_builder->addOperation(proxy); + + m_builder->mapInputSocket(input, proxy->getInputSocket(0)); + + return proxy->getOutputSocket(); +} + +NodeOperationInput *NodeConverter::addOutputProxy(NodeOutput *output, bool use_conversion) +{ + SocketProxyOperation *proxy = new SocketProxyOperation(output->getDataType(), use_conversion); + m_builder->addOperation(proxy); + + m_builder->mapOutputSocket(output, proxy->getOutputSocket()); + + return proxy->getInputSocket(0); +} + +void NodeConverter::addInputValue(NodeOperationInput *input, float value) +{ + SetValueOperation *operation = new SetValueOperation(); + operation->setValue(value); + + m_builder->addOperation(operation); + m_builder->addLink(operation->getOutputSocket(), input); +} + +void NodeConverter::addInputColor(NodeOperationInput *input, const float value[4]) +{ + SetColorOperation *operation = new SetColorOperation(); + operation->setChannels(value); + + m_builder->addOperation(operation); + m_builder->addLink(operation->getOutputSocket(), input); +} + +void NodeConverter::addInputVector(NodeOperationInput *input, const float value[3]) +{ + SetVectorOperation *operation = new SetVectorOperation(); + operation->setVector(value); + + m_builder->addOperation(operation); + m_builder->addLink(operation->getOutputSocket(), input); +} + +void NodeConverter::addOutputValue(NodeOutput *output, float value) +{ + SetValueOperation *operation = new SetValueOperation(); + operation->setValue(value); + + m_builder->addOperation(operation); + m_builder->mapOutputSocket(output, operation->getOutputSocket()); +} + +void NodeConverter::addOutputColor(NodeOutput *output, const float value[4]) +{ + SetColorOperation *operation = new SetColorOperation(); + operation->setChannels(value); + + m_builder->addOperation(operation); + m_builder->mapOutputSocket(output, operation->getOutputSocket()); +} + +void NodeConverter::addOutputVector(NodeOutput *output, const float value[3]) +{ + SetVectorOperation *operation = new SetVectorOperation(); + operation->setVector(value); + + m_builder->addOperation(operation); + m_builder->mapOutputSocket(output, operation->getOutputSocket()); +} + +void NodeConverter::registerViewer(ViewerOperation *viewer) +{ + m_builder->registerViewer(viewer); +} + +ViewerOperation *NodeConverter::active_viewer() const +{ + return m_builder->active_viewer(); +} diff --git a/source/blender/compositor/intern/COM_NodeConverter.cpp b/source/blender/compositor/intern/COM_NodeConverter.cpp deleted file mode 100644 index 2db31bd4133..00000000000 --- a/source/blender/compositor/intern/COM_NodeConverter.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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. - * - * Copyright 2013, Blender Foundation. - */ - -#include "BLI_utildefines.h" - -#include "COM_Debug.h" - -#include "COM_NodeOperation.h" -#include "COM_NodeOperationBuilder.h" -#include "COM_SetColorOperation.h" -#include "COM_SetValueOperation.h" -#include "COM_SetVectorOperation.h" -#include "COM_SocketProxyOperation.h" - -#include "COM_NodeConverter.h" /* own include */ - -NodeConverter::NodeConverter(NodeOperationBuilder *builder) : m_builder(builder) -{ -} - -void NodeConverter::addOperation(NodeOperation *operation) -{ - m_builder->addOperation(operation); -} - -void NodeConverter::mapInputSocket(NodeInput *node_socket, NodeOperationInput *operation_socket) -{ - m_builder->mapInputSocket(node_socket, operation_socket); -} - -void NodeConverter::mapOutputSocket(NodeOutput *node_socket, NodeOperationOutput *operation_socket) -{ - m_builder->mapOutputSocket(node_socket, operation_socket); -} - -void NodeConverter::addLink(NodeOperationOutput *from, NodeOperationInput *to) -{ - m_builder->addLink(from, to); -} - -void NodeConverter::addPreview(NodeOperationOutput *output) -{ - m_builder->addPreview(output); -} - -void NodeConverter::addNodeInputPreview(NodeInput *input) -{ - m_builder->addNodeInputPreview(input); -} - -NodeOperation *NodeConverter::setInvalidOutput(NodeOutput *output) -{ - /* this is a really bad situation - bring on the pink! - so artists know this is bad */ - const float warning_color[4] = {1.0f, 0.0f, 1.0f, 1.0f}; - - SetColorOperation *operation = new SetColorOperation(); - operation->setChannels(warning_color); - - m_builder->addOperation(operation); - m_builder->mapOutputSocket(output, operation->getOutputSocket()); - - return operation; -} - -NodeOperationOutput *NodeConverter::addInputProxy(NodeInput *input, bool use_conversion) -{ - SocketProxyOperation *proxy = new SocketProxyOperation(input->getDataType(), use_conversion); - m_builder->addOperation(proxy); - - m_builder->mapInputSocket(input, proxy->getInputSocket(0)); - - return proxy->getOutputSocket(); -} - -NodeOperationInput *NodeConverter::addOutputProxy(NodeOutput *output, bool use_conversion) -{ - SocketProxyOperation *proxy = new SocketProxyOperation(output->getDataType(), use_conversion); - m_builder->addOperation(proxy); - - m_builder->mapOutputSocket(output, proxy->getOutputSocket()); - - return proxy->getInputSocket(0); -} - -void NodeConverter::addInputValue(NodeOperationInput *input, float value) -{ - SetValueOperation *operation = new SetValueOperation(); - operation->setValue(value); - - m_builder->addOperation(operation); - m_builder->addLink(operation->getOutputSocket(), input); -} - -void NodeConverter::addInputColor(NodeOperationInput *input, const float value[4]) -{ - SetColorOperation *operation = new SetColorOperation(); - operation->setChannels(value); - - m_builder->addOperation(operation); - m_builder->addLink(operation->getOutputSocket(), input); -} - -void NodeConverter::addInputVector(NodeOperationInput *input, const float value[3]) -{ - SetVectorOperation *operation = new SetVectorOperation(); - operation->setVector(value); - - m_builder->addOperation(operation); - m_builder->addLink(operation->getOutputSocket(), input); -} - -void NodeConverter::addOutputValue(NodeOutput *output, float value) -{ - SetValueOperation *operation = new SetValueOperation(); - operation->setValue(value); - - m_builder->addOperation(operation); - m_builder->mapOutputSocket(output, operation->getOutputSocket()); -} - -void NodeConverter::addOutputColor(NodeOutput *output, const float value[4]) -{ - SetColorOperation *operation = new SetColorOperation(); - operation->setChannels(value); - - m_builder->addOperation(operation); - m_builder->mapOutputSocket(output, operation->getOutputSocket()); -} - -void NodeConverter::addOutputVector(NodeOutput *output, const float value[3]) -{ - SetVectorOperation *operation = new SetVectorOperation(); - operation->setVector(value); - - m_builder->addOperation(operation); - m_builder->mapOutputSocket(output, operation->getOutputSocket()); -} - -void NodeConverter::registerViewer(ViewerOperation *viewer) -{ - m_builder->registerViewer(viewer); -} - -ViewerOperation *NodeConverter::active_viewer() const -{ - return m_builder->active_viewer(); -} diff --git a/source/blender/compositor/intern/COM_NodeGraph.cc b/source/blender/compositor/intern/COM_NodeGraph.cc new file mode 100644 index 00000000000..421a762d9b5 --- /dev/null +++ b/source/blender/compositor/intern/COM_NodeGraph.cc @@ -0,0 +1,333 @@ +/* + * 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. + * + * Copyright 2013, Blender Foundation. + */ + +#include + +#include "BLI_listbase.h" +#include "BLI_utildefines.h" + +#include "DNA_node_types.h" + +#include "BKE_node.h" + +#include "COM_CompositorContext.h" +#include "COM_Converter.h" +#include "COM_Debug.h" +#include "COM_Node.h" +#include "COM_SocketProxyNode.h" + +#include "COM_NodeGraph.h" /* own include */ + +/******************* + **** NodeGraph **** + *******************/ + +NodeGraph::NodeGraph() +{ +} + +NodeGraph::~NodeGraph() +{ + for (int index = 0; index < this->m_nodes.size(); index++) { + Node *node = this->m_nodes[index]; + delete node; + } +} + +void NodeGraph::from_bNodeTree(const CompositorContext &context, bNodeTree *tree) +{ + add_bNodeTree(context, 0, tree, NODE_INSTANCE_KEY_BASE); +} + +bNodeSocket *NodeGraph::find_b_node_input(bNode *b_node, const char *identifier) +{ + for (bNodeSocket *b_sock = (bNodeSocket *)b_node->inputs.first; b_sock; b_sock = b_sock->next) { + if (STREQ(b_sock->identifier, identifier)) { + return b_sock; + } + } + return nullptr; +} + +bNodeSocket *NodeGraph::find_b_node_output(bNode *b_node, const char *identifier) +{ + for (bNodeSocket *b_sock = (bNodeSocket *)b_node->outputs.first; b_sock; b_sock = b_sock->next) { + if (STREQ(b_sock->identifier, identifier)) { + return b_sock; + } + } + return nullptr; +} + +void NodeGraph::add_node(Node *node, + bNodeTree *b_ntree, + bNodeInstanceKey key, + bool is_active_group) +{ + node->setbNodeTree(b_ntree); + node->setInstanceKey(key); + node->setIsInActiveGroup(is_active_group); + + m_nodes.push_back(node); + + DebugInfo::node_added(node); +} + +void NodeGraph::add_link(NodeOutput *fromSocket, NodeInput *toSocket) +{ + m_links.append(Link(fromSocket, toSocket)); + + /* register with the input */ + toSocket->setLink(fromSocket); +} + +void NodeGraph::add_bNodeTree(const CompositorContext &context, + int nodes_start, + bNodeTree *tree, + bNodeInstanceKey parent_key) +{ + const bNodeTree *basetree = context.getbNodeTree(); + + /* update viewers in the active edittree as well the base tree (for backdrop) */ + bool is_active_group = (parent_key.value == basetree->active_viewer_key.value); + + /* add all nodes of the tree to the node list */ + for (bNode *node = (bNode *)tree->nodes.first; node; node = node->next) { + bNodeInstanceKey key = BKE_node_instance_key(parent_key, tree, node); + add_bNode(context, tree, node, key, is_active_group); + } + + NodeRange node_range(m_nodes.begin() + nodes_start, m_nodes.end()); + /* add all nodelinks of the tree to the link list */ + for (bNodeLink *nodelink = (bNodeLink *)tree->links.first; nodelink; nodelink = nodelink->next) { + add_bNodeLink(node_range, nodelink); + } +} + +void NodeGraph::add_bNode(const CompositorContext &context, + bNodeTree *b_ntree, + bNode *b_node, + bNodeInstanceKey key, + bool is_active_group) +{ + /* replace muted nodes by proxies for internal links */ + if (b_node->flag & NODE_MUTED) { + add_proxies_mute(b_ntree, b_node, key, is_active_group); + return; + } + + /* replace slow nodes with proxies for fast execution */ + if (context.isFastCalculation() && !COM_bnode_is_fast_node(*b_node)) { + add_proxies_skip(b_ntree, b_node, key, is_active_group); + return; + } + + /* special node types */ + if (ELEM(b_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { + add_proxies_group(context, b_node, key); + } + else if (b_node->type == NODE_REROUTE) { + add_proxies_reroute(b_ntree, b_node, key, is_active_group); + } + else { + /* regular nodes, handled in Converter */ + Node *node = COM_convert_bnode(b_node); + if (node) { + add_node(node, b_ntree, key, is_active_group); + } + } +} + +NodeGraph::NodeInputs NodeGraph::find_inputs(const NodeRange &node_range, bNodeSocket *b_socket) +{ + NodeInputs result; + for (NodeGraph::NodeIterator it = node_range.first; it != node_range.second; ++it) { + Node *node = *it; + for (int index = 0; index < node->getNumberOfInputSockets(); index++) { + NodeInput *input = node->getInputSocket(index); + if (input->getbNodeSocket() == b_socket) { + result.push_back(input); + } + } + } + return result; +} + +NodeOutput *NodeGraph::find_output(const NodeRange &node_range, bNodeSocket *b_socket) +{ + for (NodeGraph::NodeIterator it = node_range.first; it != node_range.second; ++it) { + Node *node = *it; + for (int index = 0; index < node->getNumberOfOutputSockets(); index++) { + NodeOutput *output = node->getOutputSocket(index); + if (output->getbNodeSocket() == b_socket) { + return output; + } + } + } + return nullptr; +} + +void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink) +{ + /** \note Ignore invalid links. */ + if (!(b_nodelink->flag & NODE_LINK_VALID)) { + return; + } + if ((b_nodelink->fromsock->flag & SOCK_UNAVAIL) || (b_nodelink->tosock->flag & SOCK_UNAVAIL)) { + return; + } + + /* Note: a DNA input socket can have multiple NodeInput in the compositor tree! (proxies) + * The output then gets linked to each one of them. + */ + + NodeOutput *output = find_output(node_range, b_nodelink->fromsock); + if (!output) { + return; + } + + NodeInputs inputs = find_inputs(node_range, b_nodelink->tosock); + for (NodeInputs::const_iterator it = inputs.begin(); it != inputs.end(); ++it) { + NodeInput *input = *it; + if (input->isLinked()) { + continue; + } + add_link(output, input); + } +} + +/* **** Special proxy node type conversions **** */ + +void NodeGraph::add_proxies_mute(bNodeTree *b_ntree, + bNode *b_node, + bNodeInstanceKey key, + bool is_active_group) +{ + for (bNodeLink *b_link = (bNodeLink *)b_node->internal_links.first; b_link; + b_link = b_link->next) { + SocketProxyNode *proxy = new SocketProxyNode(b_node, b_link->fromsock, b_link->tosock, false); + add_node(proxy, b_ntree, key, is_active_group); + } +} + +void NodeGraph::add_proxies_skip(bNodeTree *b_ntree, + bNode *b_node, + bNodeInstanceKey key, + bool is_active_group) +{ + for (bNodeSocket *output = (bNodeSocket *)b_node->outputs.first; output; output = output->next) { + bNodeSocket *input; + + /* look for first input with matching datatype for each output */ + for (input = (bNodeSocket *)b_node->inputs.first; input; input = input->next) { + if (input->type == output->type) { + break; + } + } + + if (input) { + SocketProxyNode *proxy = new SocketProxyNode(b_node, input, output, true); + add_node(proxy, b_ntree, key, is_active_group); + } + } +} + +void NodeGraph::add_proxies_group_inputs(bNode *b_node, bNode *b_node_io) +{ + bNodeTree *b_group_tree = (bNodeTree *)b_node->id; + BLI_assert(b_group_tree); /* should have been checked in advance */ + + /* not important for proxies */ + bNodeInstanceKey key = NODE_INSTANCE_KEY_BASE; + bool is_active_group = false; + + for (bNodeSocket *b_sock_io = (bNodeSocket *)b_node_io->outputs.first; b_sock_io; + b_sock_io = b_sock_io->next) { + bNodeSocket *b_sock_group = find_b_node_input(b_node, b_sock_io->identifier); + if (b_sock_group) { + SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_group, b_sock_io, true); + add_node(proxy, b_group_tree, key, is_active_group); + } + } +} + +void NodeGraph::add_proxies_group_outputs(bNode *b_node, bNode *b_node_io, bool use_buffer) +{ + bNodeTree *b_group_tree = (bNodeTree *)b_node->id; + BLI_assert(b_group_tree); /* should have been checked in advance */ + + /* not important for proxies */ + bNodeInstanceKey key = NODE_INSTANCE_KEY_BASE; + bool is_active_group = false; + + for (bNodeSocket *b_sock_io = (bNodeSocket *)b_node_io->inputs.first; b_sock_io; + b_sock_io = b_sock_io->next) { + bNodeSocket *b_sock_group = find_b_node_output(b_node, b_sock_io->identifier); + if (b_sock_group) { + if (use_buffer) { + SocketBufferNode *buffer = new SocketBufferNode(b_node_io, b_sock_io, b_sock_group); + add_node(buffer, b_group_tree, key, is_active_group); + } + else { + SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_io, b_sock_group, true); + add_node(proxy, b_group_tree, key, is_active_group); + } + } + } +} + +void NodeGraph::add_proxies_group(const CompositorContext &context, + bNode *b_node, + bNodeInstanceKey key) +{ + bNodeTree *b_group_tree = (bNodeTree *)b_node->id; + + /* missing node group datablock can happen with library linking */ + if (!b_group_tree) { + /* This error case its handled in convertToOperations() + * so we don't get un-converted sockets. */ + return; + } + + /* use node list size before adding proxies, so they can be connected in add_bNodeTree */ + int nodes_start = m_nodes.size(); + + /* create proxy nodes for group input/output nodes */ + for (bNode *b_node_io = (bNode *)b_group_tree->nodes.first; b_node_io; + b_node_io = b_node_io->next) { + if (b_node_io->type == NODE_GROUP_INPUT) { + add_proxies_group_inputs(b_node, b_node_io); + } + + if (b_node_io->type == NODE_GROUP_OUTPUT && (b_node_io->flag & NODE_DO_OUTPUT)) { + add_proxies_group_outputs(b_node, b_node_io, context.isGroupnodeBufferEnabled()); + } + } + + add_bNodeTree(context, nodes_start, b_group_tree, key); +} + +void NodeGraph::add_proxies_reroute(bNodeTree *b_ntree, + bNode *b_node, + bNodeInstanceKey key, + bool is_active_group) +{ + SocketProxyNode *proxy = new SocketProxyNode( + b_node, (bNodeSocket *)b_node->inputs.first, (bNodeSocket *)b_node->outputs.first, false); + add_node(proxy, b_ntree, key, is_active_group); +} diff --git a/source/blender/compositor/intern/COM_NodeGraph.cpp b/source/blender/compositor/intern/COM_NodeGraph.cpp deleted file mode 100644 index 421a762d9b5..00000000000 --- a/source/blender/compositor/intern/COM_NodeGraph.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/* - * 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. - * - * Copyright 2013, Blender Foundation. - */ - -#include - -#include "BLI_listbase.h" -#include "BLI_utildefines.h" - -#include "DNA_node_types.h" - -#include "BKE_node.h" - -#include "COM_CompositorContext.h" -#include "COM_Converter.h" -#include "COM_Debug.h" -#include "COM_Node.h" -#include "COM_SocketProxyNode.h" - -#include "COM_NodeGraph.h" /* own include */ - -/******************* - **** NodeGraph **** - *******************/ - -NodeGraph::NodeGraph() -{ -} - -NodeGraph::~NodeGraph() -{ - for (int index = 0; index < this->m_nodes.size(); index++) { - Node *node = this->m_nodes[index]; - delete node; - } -} - -void NodeGraph::from_bNodeTree(const CompositorContext &context, bNodeTree *tree) -{ - add_bNodeTree(context, 0, tree, NODE_INSTANCE_KEY_BASE); -} - -bNodeSocket *NodeGraph::find_b_node_input(bNode *b_node, const char *identifier) -{ - for (bNodeSocket *b_sock = (bNodeSocket *)b_node->inputs.first; b_sock; b_sock = b_sock->next) { - if (STREQ(b_sock->identifier, identifier)) { - return b_sock; - } - } - return nullptr; -} - -bNodeSocket *NodeGraph::find_b_node_output(bNode *b_node, const char *identifier) -{ - for (bNodeSocket *b_sock = (bNodeSocket *)b_node->outputs.first; b_sock; b_sock = b_sock->next) { - if (STREQ(b_sock->identifier, identifier)) { - return b_sock; - } - } - return nullptr; -} - -void NodeGraph::add_node(Node *node, - bNodeTree *b_ntree, - bNodeInstanceKey key, - bool is_active_group) -{ - node->setbNodeTree(b_ntree); - node->setInstanceKey(key); - node->setIsInActiveGroup(is_active_group); - - m_nodes.push_back(node); - - DebugInfo::node_added(node); -} - -void NodeGraph::add_link(NodeOutput *fromSocket, NodeInput *toSocket) -{ - m_links.append(Link(fromSocket, toSocket)); - - /* register with the input */ - toSocket->setLink(fromSocket); -} - -void NodeGraph::add_bNodeTree(const CompositorContext &context, - int nodes_start, - bNodeTree *tree, - bNodeInstanceKey parent_key) -{ - const bNodeTree *basetree = context.getbNodeTree(); - - /* update viewers in the active edittree as well the base tree (for backdrop) */ - bool is_active_group = (parent_key.value == basetree->active_viewer_key.value); - - /* add all nodes of the tree to the node list */ - for (bNode *node = (bNode *)tree->nodes.first; node; node = node->next) { - bNodeInstanceKey key = BKE_node_instance_key(parent_key, tree, node); - add_bNode(context, tree, node, key, is_active_group); - } - - NodeRange node_range(m_nodes.begin() + nodes_start, m_nodes.end()); - /* add all nodelinks of the tree to the link list */ - for (bNodeLink *nodelink = (bNodeLink *)tree->links.first; nodelink; nodelink = nodelink->next) { - add_bNodeLink(node_range, nodelink); - } -} - -void NodeGraph::add_bNode(const CompositorContext &context, - bNodeTree *b_ntree, - bNode *b_node, - bNodeInstanceKey key, - bool is_active_group) -{ - /* replace muted nodes by proxies for internal links */ - if (b_node->flag & NODE_MUTED) { - add_proxies_mute(b_ntree, b_node, key, is_active_group); - return; - } - - /* replace slow nodes with proxies for fast execution */ - if (context.isFastCalculation() && !COM_bnode_is_fast_node(*b_node)) { - add_proxies_skip(b_ntree, b_node, key, is_active_group); - return; - } - - /* special node types */ - if (ELEM(b_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { - add_proxies_group(context, b_node, key); - } - else if (b_node->type == NODE_REROUTE) { - add_proxies_reroute(b_ntree, b_node, key, is_active_group); - } - else { - /* regular nodes, handled in Converter */ - Node *node = COM_convert_bnode(b_node); - if (node) { - add_node(node, b_ntree, key, is_active_group); - } - } -} - -NodeGraph::NodeInputs NodeGraph::find_inputs(const NodeRange &node_range, bNodeSocket *b_socket) -{ - NodeInputs result; - for (NodeGraph::NodeIterator it = node_range.first; it != node_range.second; ++it) { - Node *node = *it; - for (int index = 0; index < node->getNumberOfInputSockets(); index++) { - NodeInput *input = node->getInputSocket(index); - if (input->getbNodeSocket() == b_socket) { - result.push_back(input); - } - } - } - return result; -} - -NodeOutput *NodeGraph::find_output(const NodeRange &node_range, bNodeSocket *b_socket) -{ - for (NodeGraph::NodeIterator it = node_range.first; it != node_range.second; ++it) { - Node *node = *it; - for (int index = 0; index < node->getNumberOfOutputSockets(); index++) { - NodeOutput *output = node->getOutputSocket(index); - if (output->getbNodeSocket() == b_socket) { - return output; - } - } - } - return nullptr; -} - -void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink) -{ - /** \note Ignore invalid links. */ - if (!(b_nodelink->flag & NODE_LINK_VALID)) { - return; - } - if ((b_nodelink->fromsock->flag & SOCK_UNAVAIL) || (b_nodelink->tosock->flag & SOCK_UNAVAIL)) { - return; - } - - /* Note: a DNA input socket can have multiple NodeInput in the compositor tree! (proxies) - * The output then gets linked to each one of them. - */ - - NodeOutput *output = find_output(node_range, b_nodelink->fromsock); - if (!output) { - return; - } - - NodeInputs inputs = find_inputs(node_range, b_nodelink->tosock); - for (NodeInputs::const_iterator it = inputs.begin(); it != inputs.end(); ++it) { - NodeInput *input = *it; - if (input->isLinked()) { - continue; - } - add_link(output, input); - } -} - -/* **** Special proxy node type conversions **** */ - -void NodeGraph::add_proxies_mute(bNodeTree *b_ntree, - bNode *b_node, - bNodeInstanceKey key, - bool is_active_group) -{ - for (bNodeLink *b_link = (bNodeLink *)b_node->internal_links.first; b_link; - b_link = b_link->next) { - SocketProxyNode *proxy = new SocketProxyNode(b_node, b_link->fromsock, b_link->tosock, false); - add_node(proxy, b_ntree, key, is_active_group); - } -} - -void NodeGraph::add_proxies_skip(bNodeTree *b_ntree, - bNode *b_node, - bNodeInstanceKey key, - bool is_active_group) -{ - for (bNodeSocket *output = (bNodeSocket *)b_node->outputs.first; output; output = output->next) { - bNodeSocket *input; - - /* look for first input with matching datatype for each output */ - for (input = (bNodeSocket *)b_node->inputs.first; input; input = input->next) { - if (input->type == output->type) { - break; - } - } - - if (input) { - SocketProxyNode *proxy = new SocketProxyNode(b_node, input, output, true); - add_node(proxy, b_ntree, key, is_active_group); - } - } -} - -void NodeGraph::add_proxies_group_inputs(bNode *b_node, bNode *b_node_io) -{ - bNodeTree *b_group_tree = (bNodeTree *)b_node->id; - BLI_assert(b_group_tree); /* should have been checked in advance */ - - /* not important for proxies */ - bNodeInstanceKey key = NODE_INSTANCE_KEY_BASE; - bool is_active_group = false; - - for (bNodeSocket *b_sock_io = (bNodeSocket *)b_node_io->outputs.first; b_sock_io; - b_sock_io = b_sock_io->next) { - bNodeSocket *b_sock_group = find_b_node_input(b_node, b_sock_io->identifier); - if (b_sock_group) { - SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_group, b_sock_io, true); - add_node(proxy, b_group_tree, key, is_active_group); - } - } -} - -void NodeGraph::add_proxies_group_outputs(bNode *b_node, bNode *b_node_io, bool use_buffer) -{ - bNodeTree *b_group_tree = (bNodeTree *)b_node->id; - BLI_assert(b_group_tree); /* should have been checked in advance */ - - /* not important for proxies */ - bNodeInstanceKey key = NODE_INSTANCE_KEY_BASE; - bool is_active_group = false; - - for (bNodeSocket *b_sock_io = (bNodeSocket *)b_node_io->inputs.first; b_sock_io; - b_sock_io = b_sock_io->next) { - bNodeSocket *b_sock_group = find_b_node_output(b_node, b_sock_io->identifier); - if (b_sock_group) { - if (use_buffer) { - SocketBufferNode *buffer = new SocketBufferNode(b_node_io, b_sock_io, b_sock_group); - add_node(buffer, b_group_tree, key, is_active_group); - } - else { - SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_io, b_sock_group, true); - add_node(proxy, b_group_tree, key, is_active_group); - } - } - } -} - -void NodeGraph::add_proxies_group(const CompositorContext &context, - bNode *b_node, - bNodeInstanceKey key) -{ - bNodeTree *b_group_tree = (bNodeTree *)b_node->id; - - /* missing node group datablock can happen with library linking */ - if (!b_group_tree) { - /* This error case its handled in convertToOperations() - * so we don't get un-converted sockets. */ - return; - } - - /* use node list size before adding proxies, so they can be connected in add_bNodeTree */ - int nodes_start = m_nodes.size(); - - /* create proxy nodes for group input/output nodes */ - for (bNode *b_node_io = (bNode *)b_group_tree->nodes.first; b_node_io; - b_node_io = b_node_io->next) { - if (b_node_io->type == NODE_GROUP_INPUT) { - add_proxies_group_inputs(b_node, b_node_io); - } - - if (b_node_io->type == NODE_GROUP_OUTPUT && (b_node_io->flag & NODE_DO_OUTPUT)) { - add_proxies_group_outputs(b_node, b_node_io, context.isGroupnodeBufferEnabled()); - } - } - - add_bNodeTree(context, nodes_start, b_group_tree, key); -} - -void NodeGraph::add_proxies_reroute(bNodeTree *b_ntree, - bNode *b_node, - bNodeInstanceKey key, - bool is_active_group) -{ - SocketProxyNode *proxy = new SocketProxyNode( - b_node, (bNodeSocket *)b_node->inputs.first, (bNodeSocket *)b_node->outputs.first, false); - add_node(proxy, b_ntree, key, is_active_group); -} diff --git a/source/blender/compositor/intern/COM_NodeOperation.cc b/source/blender/compositor/intern/COM_NodeOperation.cc new file mode 100644 index 00000000000..ce7d3a6389e --- /dev/null +++ b/source/blender/compositor/intern/COM_NodeOperation.cc @@ -0,0 +1,244 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include +#include + +#include "COM_ExecutionSystem.h" +#include "COM_defines.h" + +#include "COM_NodeOperation.h" /* own include */ + +/******************* + **** NodeOperation **** + *******************/ + +NodeOperation::NodeOperation() +{ + this->m_resolutionInputSocketIndex = 0; + this->m_complex = false; + this->m_width = 0; + this->m_height = 0; + this->m_isResolutionSet = false; + this->m_openCL = false; + this->m_btree = nullptr; +} + +NodeOperation::~NodeOperation() +{ + while (!this->m_outputs.empty()) { + delete (this->m_outputs.back()); + this->m_outputs.pop_back(); + } + while (!this->m_inputs.empty()) { + delete (this->m_inputs.back()); + this->m_inputs.pop_back(); + } +} + +NodeOperationOutput *NodeOperation::getOutputSocket(unsigned int index) const +{ + BLI_assert(index < m_outputs.size()); + return m_outputs[index]; +} + +NodeOperationInput *NodeOperation::getInputSocket(unsigned int index) const +{ + BLI_assert(index < m_inputs.size()); + return m_inputs[index]; +} + +void NodeOperation::addInputSocket(DataType datatype, InputResizeMode resize_mode) +{ + NodeOperationInput *socket = new NodeOperationInput(this, datatype, resize_mode); + m_inputs.push_back(socket); +} + +void NodeOperation::addOutputSocket(DataType datatype) +{ + NodeOperationOutput *socket = new NodeOperationOutput(this, datatype); + m_outputs.push_back(socket); +} + +void NodeOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + unsigned int temp[2]; + unsigned int temp2[2]; + + for (unsigned int index = 0; index < m_inputs.size(); index++) { + NodeOperationInput *input = m_inputs[index]; + if (input->isConnected()) { + if (index == this->m_resolutionInputSocketIndex) { + input->determineResolution(resolution, preferredResolution); + temp2[0] = resolution[0]; + temp2[1] = resolution[1]; + break; + } + } + } + for (unsigned int index = 0; index < m_inputs.size(); index++) { + NodeOperationInput *input = m_inputs[index]; + if (input->isConnected()) { + if (index != this->m_resolutionInputSocketIndex) { + input->determineResolution(temp, temp2); + } + } + } +} +void NodeOperation::setResolutionInputSocketIndex(unsigned int index) +{ + this->m_resolutionInputSocketIndex = index; +} +void NodeOperation::initExecution() +{ + /* pass */ +} + +void NodeOperation::initMutex() +{ + BLI_mutex_init(&this->m_mutex); +} + +void NodeOperation::lockMutex() +{ + BLI_mutex_lock(&this->m_mutex); +} + +void NodeOperation::unlockMutex() +{ + BLI_mutex_unlock(&this->m_mutex); +} + +void NodeOperation::deinitMutex() +{ + BLI_mutex_end(&this->m_mutex); +} + +void NodeOperation::deinitExecution() +{ + /* pass */ +} +SocketReader *NodeOperation::getInputSocketReader(unsigned int inputSocketIndex) +{ + return this->getInputSocket(inputSocketIndex)->getReader(); +} + +NodeOperation *NodeOperation::getInputOperation(unsigned int inputSocketIndex) +{ + NodeOperationInput *input = getInputSocket(inputSocketIndex); + if (input && input->isConnected()) { + return &input->getLink()->getOperation(); + } + + return nullptr; +} + +void NodeOperation::getConnectedInputSockets(Inputs *sockets) +{ + for (Inputs::const_iterator it = m_inputs.begin(); it != m_inputs.end(); ++it) { + NodeOperationInput *input = *it; + if (input->isConnected()) { + sockets->push_back(input); + } + } +} + +bool NodeOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + if (isInputOperation()) { + BLI_rcti_init(output, input->xmin, input->xmax, input->ymin, input->ymax); + return false; + } + + rcti tempOutput; + bool first = true; + for (int i = 0; i < getNumberOfInputSockets(); i++) { + NodeOperation *inputOperation = this->getInputOperation(i); + if (inputOperation && + inputOperation->determineDependingAreaOfInterest(input, readOperation, &tempOutput)) { + if (first) { + output->xmin = tempOutput.xmin; + output->ymin = tempOutput.ymin; + output->xmax = tempOutput.xmax; + output->ymax = tempOutput.ymax; + first = false; + } + else { + output->xmin = MIN2(output->xmin, tempOutput.xmin); + output->ymin = MIN2(output->ymin, tempOutput.ymin); + output->xmax = MAX2(output->xmax, tempOutput.xmax); + output->ymax = MAX2(output->ymax, tempOutput.ymax); + } + } + } + return !first; +} + +/***************** + **** OpInput **** + *****************/ + +NodeOperationInput::NodeOperationInput(NodeOperation *op, + DataType datatype, + InputResizeMode resizeMode) + : m_operation(op), m_datatype(datatype), m_resizeMode(resizeMode), m_link(nullptr) +{ +} + +SocketReader *NodeOperationInput::getReader() +{ + if (isConnected()) { + return &m_link->getOperation(); + } + + return nullptr; +} + +void NodeOperationInput::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + if (m_link) { + m_link->determineResolution(resolution, preferredResolution); + } +} + +/****************** + **** OpOutput **** + ******************/ + +NodeOperationOutput::NodeOperationOutput(NodeOperation *op, DataType datatype) + : m_operation(op), m_datatype(datatype) +{ +} + +void NodeOperationOutput::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + NodeOperation &operation = getOperation(); + if (operation.isResolutionSet()) { + resolution[0] = operation.getWidth(); + resolution[1] = operation.getHeight(); + } + else { + operation.determineResolution(resolution, preferredResolution); + operation.setResolution(resolution); + } +} diff --git a/source/blender/compositor/intern/COM_NodeOperation.cpp b/source/blender/compositor/intern/COM_NodeOperation.cpp deleted file mode 100644 index ce7d3a6389e..00000000000 --- a/source/blender/compositor/intern/COM_NodeOperation.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include -#include - -#include "COM_ExecutionSystem.h" -#include "COM_defines.h" - -#include "COM_NodeOperation.h" /* own include */ - -/******************* - **** NodeOperation **** - *******************/ - -NodeOperation::NodeOperation() -{ - this->m_resolutionInputSocketIndex = 0; - this->m_complex = false; - this->m_width = 0; - this->m_height = 0; - this->m_isResolutionSet = false; - this->m_openCL = false; - this->m_btree = nullptr; -} - -NodeOperation::~NodeOperation() -{ - while (!this->m_outputs.empty()) { - delete (this->m_outputs.back()); - this->m_outputs.pop_back(); - } - while (!this->m_inputs.empty()) { - delete (this->m_inputs.back()); - this->m_inputs.pop_back(); - } -} - -NodeOperationOutput *NodeOperation::getOutputSocket(unsigned int index) const -{ - BLI_assert(index < m_outputs.size()); - return m_outputs[index]; -} - -NodeOperationInput *NodeOperation::getInputSocket(unsigned int index) const -{ - BLI_assert(index < m_inputs.size()); - return m_inputs[index]; -} - -void NodeOperation::addInputSocket(DataType datatype, InputResizeMode resize_mode) -{ - NodeOperationInput *socket = new NodeOperationInput(this, datatype, resize_mode); - m_inputs.push_back(socket); -} - -void NodeOperation::addOutputSocket(DataType datatype) -{ - NodeOperationOutput *socket = new NodeOperationOutput(this, datatype); - m_outputs.push_back(socket); -} - -void NodeOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - unsigned int temp[2]; - unsigned int temp2[2]; - - for (unsigned int index = 0; index < m_inputs.size(); index++) { - NodeOperationInput *input = m_inputs[index]; - if (input->isConnected()) { - if (index == this->m_resolutionInputSocketIndex) { - input->determineResolution(resolution, preferredResolution); - temp2[0] = resolution[0]; - temp2[1] = resolution[1]; - break; - } - } - } - for (unsigned int index = 0; index < m_inputs.size(); index++) { - NodeOperationInput *input = m_inputs[index]; - if (input->isConnected()) { - if (index != this->m_resolutionInputSocketIndex) { - input->determineResolution(temp, temp2); - } - } - } -} -void NodeOperation::setResolutionInputSocketIndex(unsigned int index) -{ - this->m_resolutionInputSocketIndex = index; -} -void NodeOperation::initExecution() -{ - /* pass */ -} - -void NodeOperation::initMutex() -{ - BLI_mutex_init(&this->m_mutex); -} - -void NodeOperation::lockMutex() -{ - BLI_mutex_lock(&this->m_mutex); -} - -void NodeOperation::unlockMutex() -{ - BLI_mutex_unlock(&this->m_mutex); -} - -void NodeOperation::deinitMutex() -{ - BLI_mutex_end(&this->m_mutex); -} - -void NodeOperation::deinitExecution() -{ - /* pass */ -} -SocketReader *NodeOperation::getInputSocketReader(unsigned int inputSocketIndex) -{ - return this->getInputSocket(inputSocketIndex)->getReader(); -} - -NodeOperation *NodeOperation::getInputOperation(unsigned int inputSocketIndex) -{ - NodeOperationInput *input = getInputSocket(inputSocketIndex); - if (input && input->isConnected()) { - return &input->getLink()->getOperation(); - } - - return nullptr; -} - -void NodeOperation::getConnectedInputSockets(Inputs *sockets) -{ - for (Inputs::const_iterator it = m_inputs.begin(); it != m_inputs.end(); ++it) { - NodeOperationInput *input = *it; - if (input->isConnected()) { - sockets->push_back(input); - } - } -} - -bool NodeOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - if (isInputOperation()) { - BLI_rcti_init(output, input->xmin, input->xmax, input->ymin, input->ymax); - return false; - } - - rcti tempOutput; - bool first = true; - for (int i = 0; i < getNumberOfInputSockets(); i++) { - NodeOperation *inputOperation = this->getInputOperation(i); - if (inputOperation && - inputOperation->determineDependingAreaOfInterest(input, readOperation, &tempOutput)) { - if (first) { - output->xmin = tempOutput.xmin; - output->ymin = tempOutput.ymin; - output->xmax = tempOutput.xmax; - output->ymax = tempOutput.ymax; - first = false; - } - else { - output->xmin = MIN2(output->xmin, tempOutput.xmin); - output->ymin = MIN2(output->ymin, tempOutput.ymin); - output->xmax = MAX2(output->xmax, tempOutput.xmax); - output->ymax = MAX2(output->ymax, tempOutput.ymax); - } - } - } - return !first; -} - -/***************** - **** OpInput **** - *****************/ - -NodeOperationInput::NodeOperationInput(NodeOperation *op, - DataType datatype, - InputResizeMode resizeMode) - : m_operation(op), m_datatype(datatype), m_resizeMode(resizeMode), m_link(nullptr) -{ -} - -SocketReader *NodeOperationInput::getReader() -{ - if (isConnected()) { - return &m_link->getOperation(); - } - - return nullptr; -} - -void NodeOperationInput::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - if (m_link) { - m_link->determineResolution(resolution, preferredResolution); - } -} - -/****************** - **** OpOutput **** - ******************/ - -NodeOperationOutput::NodeOperationOutput(NodeOperation *op, DataType datatype) - : m_operation(op), m_datatype(datatype) -{ -} - -void NodeOperationOutput::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - NodeOperation &operation = getOperation(); - if (operation.isResolutionSet()) { - resolution[0] = operation.getWidth(); - resolution[1] = operation.getHeight(); - } - else { - operation.determineResolution(resolution, preferredResolution); - operation.setResolution(resolution); - } -} diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc new file mode 100644 index 00000000000..688b693080f --- /dev/null +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc @@ -0,0 +1,722 @@ +/* + * 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. + * + * Copyright 2013, Blender Foundation. + */ + +#include "BLI_utildefines.h" + +#include "COM_Converter.h" +#include "COM_Debug.h" +#include "COM_ExecutionSystem.h" +#include "COM_Node.h" +#include "COM_NodeConverter.h" +#include "COM_SocketProxyNode.h" + +#include "COM_NodeOperation.h" +#include "COM_PreviewOperation.h" +#include "COM_ReadBufferOperation.h" +#include "COM_SetColorOperation.h" +#include "COM_SetValueOperation.h" +#include "COM_SetVectorOperation.h" +#include "COM_SocketProxyOperation.h" +#include "COM_ViewerOperation.h" +#include "COM_WriteBufferOperation.h" + +#include "COM_NodeOperationBuilder.h" /* own include */ + +NodeOperationBuilder::NodeOperationBuilder(const CompositorContext *context, bNodeTree *b_nodetree) + : m_context(context), m_current_node(nullptr), m_active_viewer(nullptr) +{ + m_graph.from_bNodeTree(*context, b_nodetree); +} + +NodeOperationBuilder::~NodeOperationBuilder() +{ +} + +void NodeOperationBuilder::convertToOperations(ExecutionSystem *system) +{ + /* interface handle for nodes */ + NodeConverter converter(this); + + for (int index = 0; index < m_graph.nodes().size(); index++) { + Node *node = (Node *)m_graph.nodes()[index]; + + m_current_node = node; + + DebugInfo::node_to_operations(node); + node->convertToOperations(converter, *m_context); + } + + m_current_node = nullptr; + + /* The input map constructed by nodes maps operation inputs to node inputs. + * Inverting yields a map of node inputs to all connected operation inputs, + * so multiple operations can use the same node input. + */ + OpInputInverseMap inverse_input_map; + for (InputSocketMap::const_iterator it = m_input_map.begin(); it != m_input_map.end(); ++it) { + inverse_input_map[it->second].push_back(it->first); + } + + for (const NodeGraph::Link &link : m_graph.links()) { + NodeOutput *from = link.from; + NodeInput *to = link.to; + + NodeOperationOutput *op_from = find_operation_output(m_output_map, from); + const OpInputs &op_to_list = find_operation_inputs(inverse_input_map, to); + if (!op_from || op_to_list.empty()) { + /* XXX allow this? error/debug message? */ + // BLI_assert(false); + /* XXX note: this can happen with certain nodes (e.g. OutputFile) + * which only generate operations in certain circumstances (rendering) + * just let this pass silently for now ... + */ + continue; + } + + for (OpInputs::const_iterator it = op_to_list.begin(); it != op_to_list.end(); ++it) { + NodeOperationInput *op_to = *it; + addLink(op_from, op_to); + } + } + + add_operation_input_constants(); + + resolve_proxies(); + + add_datatype_conversions(); + + determineResolutions(); + + /* surround complex ops with read/write buffer */ + add_complex_operation_buffers(); + + /* links not available from here on */ + /* XXX make m_links a local variable to avoid confusion! */ + m_links.clear(); + + prune_operations(); + + /* ensure topological (link-based) order of nodes */ + /*sort_operations();*/ /* not needed yet */ + + /* create execution groups */ + group_operations(); + + /* transfer resulting operations to the system */ + system->set_operations(m_operations, m_groups); +} + +void NodeOperationBuilder::addOperation(NodeOperation *operation) +{ + m_operations.append(operation); +} + +void NodeOperationBuilder::mapInputSocket(NodeInput *node_socket, + NodeOperationInput *operation_socket) +{ + BLI_assert(m_current_node); + BLI_assert(node_socket->getNode() == m_current_node); + + /* note: this maps operation sockets to node sockets. + * for resolving links the map will be inverted first in convertToOperations, + * to get a list of links for each node input socket. + */ + m_input_map[operation_socket] = node_socket; +} + +void NodeOperationBuilder::mapOutputSocket(NodeOutput *node_socket, + NodeOperationOutput *operation_socket) +{ + BLI_assert(m_current_node); + BLI_assert(node_socket->getNode() == m_current_node); + + m_output_map[node_socket] = operation_socket; +} + +void NodeOperationBuilder::addLink(NodeOperationOutput *from, NodeOperationInput *to) +{ + if (to->isConnected()) { + return; + } + + m_links.push_back(Link(from, to)); + + /* register with the input */ + to->setLink(from); +} + +void NodeOperationBuilder::removeInputLink(NodeOperationInput *to) +{ + for (Links::iterator it = m_links.begin(); it != m_links.end(); ++it) { + Link &link = *it; + if (link.to() == to) { + /* unregister with the input */ + to->setLink(nullptr); + + m_links.erase(it); + return; + } + } +} + +NodeInput *NodeOperationBuilder::find_node_input(const InputSocketMap &map, + NodeOperationInput *op_input) +{ + InputSocketMap::const_iterator it = map.find(op_input); + return (it != map.end() ? it->second : NULL); +} + +const NodeOperationBuilder::OpInputs &NodeOperationBuilder::find_operation_inputs( + const OpInputInverseMap &map, NodeInput *node_input) +{ + static const OpInputs empty_list; + OpInputInverseMap::const_iterator it = map.find(node_input); + return (it != map.end() ? it->second : empty_list); +} + +NodeOperationOutput *NodeOperationBuilder::find_operation_output(const OutputSocketMap &map, + NodeOutput *node_output) +{ + OutputSocketMap::const_iterator it = map.find(node_output); + return (it != map.end() ? it->second : NULL); +} + +PreviewOperation *NodeOperationBuilder::make_preview_operation() const +{ + BLI_assert(m_current_node); + + if (!(m_current_node->getbNode()->flag & NODE_PREVIEW)) { + return nullptr; + } + /* previews only in the active group */ + if (!m_current_node->isInActiveGroup()) { + return nullptr; + } + /* do not calculate previews of hidden nodes */ + if (m_current_node->getbNode()->flag & NODE_HIDDEN) { + return nullptr; + } + + bNodeInstanceHash *previews = m_context->getPreviewHash(); + if (previews) { + PreviewOperation *operation = new PreviewOperation(m_context->getViewSettings(), + m_context->getDisplaySettings()); + operation->setbNodeTree(m_context->getbNodeTree()); + operation->verifyPreview(previews, m_current_node->getInstanceKey()); + return operation; + } + + return nullptr; +} + +void NodeOperationBuilder::addPreview(NodeOperationOutput *output) +{ + PreviewOperation *operation = make_preview_operation(); + if (operation) { + addOperation(operation); + + addLink(output, operation->getInputSocket(0)); + } +} + +void NodeOperationBuilder::addNodeInputPreview(NodeInput *input) +{ + PreviewOperation *operation = make_preview_operation(); + if (operation) { + addOperation(operation); + + mapInputSocket(input, operation->getInputSocket(0)); + } +} + +void NodeOperationBuilder::registerViewer(ViewerOperation *viewer) +{ + if (m_active_viewer) { + if (m_current_node->isInActiveGroup()) { + /* deactivate previous viewer */ + m_active_viewer->setActive(false); + + m_active_viewer = viewer; + viewer->setActive(true); + } + } + else { + if (m_current_node->getbNodeTree() == m_context->getbNodeTree()) { + m_active_viewer = viewer; + viewer->setActive(true); + } + } +} + +/**************************** + **** Optimization Steps **** + ****************************/ + +void NodeOperationBuilder::add_datatype_conversions() +{ + Links convert_links; + for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) { + const Link &link = *it; + + /* proxy operations can skip data type conversion */ + NodeOperation *from_op = &link.from()->getOperation(); + NodeOperation *to_op = &link.to()->getOperation(); + if (!(from_op->useDatatypeConversion() || to_op->useDatatypeConversion())) { + continue; + } + + if (link.from()->getDataType() != link.to()->getDataType()) { + convert_links.push_back(link); + } + } + for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) { + const Link &link = *it; + NodeOperation *converter = COM_convert_data_type(*link.from(), *link.to()); + if (converter) { + addOperation(converter); + + removeInputLink(link.to()); + addLink(link.from(), converter->getInputSocket(0)); + addLink(converter->getOutputSocket(0), link.to()); + } + } +} + +void NodeOperationBuilder::add_operation_input_constants() +{ + /* Note: unconnected inputs cached first to avoid modifying + * m_operations while iterating over it + */ + using Inputs = std::vector; + Inputs pending_inputs; + for (NodeOperation *op : m_operations) { + for (int k = 0; k < op->getNumberOfInputSockets(); ++k) { + NodeOperationInput *input = op->getInputSocket(k); + if (!input->isConnected()) { + pending_inputs.push_back(input); + } + } + } + for (Inputs::const_iterator it = pending_inputs.begin(); it != pending_inputs.end(); ++it) { + NodeOperationInput *input = *it; + add_input_constant_value(input, find_node_input(m_input_map, input)); + } +} + +void NodeOperationBuilder::add_input_constant_value(NodeOperationInput *input, + NodeInput *node_input) +{ + switch (input->getDataType()) { + case COM_DT_VALUE: { + float value; + if (node_input && node_input->getbNodeSocket()) { + value = node_input->getEditorValueFloat(); + } + else { + value = 0.0f; + } + + SetValueOperation *op = new SetValueOperation(); + op->setValue(value); + addOperation(op); + addLink(op->getOutputSocket(), input); + break; + } + case COM_DT_COLOR: { + float value[4]; + if (node_input && node_input->getbNodeSocket()) { + node_input->getEditorValueColor(value); + } + else { + zero_v4(value); + } + + SetColorOperation *op = new SetColorOperation(); + op->setChannels(value); + addOperation(op); + addLink(op->getOutputSocket(), input); + break; + } + case COM_DT_VECTOR: { + float value[3]; + if (node_input && node_input->getbNodeSocket()) { + node_input->getEditorValueVector(value); + } + else { + zero_v3(value); + } + + SetVectorOperation *op = new SetVectorOperation(); + op->setVector(value); + addOperation(op); + addLink(op->getOutputSocket(), input); + break; + } + } +} + +void NodeOperationBuilder::resolve_proxies() +{ + Links proxy_links; + for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) { + const Link &link = *it; + /* don't replace links from proxy to proxy, since we may need them for replacing others! */ + if (link.from()->getOperation().isProxyOperation() && + !link.to()->getOperation().isProxyOperation()) { + proxy_links.push_back(link); + } + } + + for (Links::const_iterator it = proxy_links.begin(); it != proxy_links.end(); ++it) { + const Link &link = *it; + + NodeOperationInput *to = link.to(); + NodeOperationOutput *from = link.from(); + do { + /* walk upstream bypassing the proxy operation */ + from = from->getOperation().getInputSocket(0)->getLink(); + } while (from && from->getOperation().isProxyOperation()); + + removeInputLink(to); + /* we may not have a final proxy input link, + * in that case it just gets dropped + */ + if (from) { + addLink(from, to); + } + } +} + +void NodeOperationBuilder::determineResolutions() +{ + /* determine all resolutions of the operations (Width/Height) */ + for (NodeOperation *op : m_operations) { + if (op->isOutputOperation(m_context->isRendering()) && !op->isPreviewOperation()) { + unsigned int resolution[2] = {0, 0}; + unsigned int preferredResolution[2] = {0, 0}; + op->determineResolution(resolution, preferredResolution); + op->setResolution(resolution); + } + } + + for (NodeOperation *op : m_operations) { + if (op->isOutputOperation(m_context->isRendering()) && op->isPreviewOperation()) { + unsigned int resolution[2] = {0, 0}; + unsigned int preferredResolution[2] = {0, 0}; + op->determineResolution(resolution, preferredResolution); + op->setResolution(resolution); + } + } + + /* add convert resolution operations when needed */ + { + Links convert_links; + for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) { + const Link &link = *it; + + if (link.to()->getResizeMode() != COM_SC_NO_RESIZE) { + NodeOperation &from_op = link.from()->getOperation(); + NodeOperation &to_op = link.to()->getOperation(); + if (from_op.getWidth() != to_op.getWidth() || from_op.getHeight() != to_op.getHeight()) { + convert_links.push_back(link); + } + } + } + for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) { + const Link &link = *it; + COM_convert_resolution(*this, link.from(), link.to()); + } + } +} + +NodeOperationBuilder::OpInputs NodeOperationBuilder::cache_output_links( + NodeOperationOutput *output) const +{ + OpInputs inputs; + for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) { + const Link &link = *it; + if (link.from() == output) { + inputs.push_back(link.to()); + } + } + return inputs; +} + +WriteBufferOperation *NodeOperationBuilder::find_attached_write_buffer_operation( + NodeOperationOutput *output) const +{ + for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) { + const Link &link = *it; + if (link.from() == output) { + NodeOperation &op = link.to()->getOperation(); + if (op.isWriteBufferOperation()) { + return (WriteBufferOperation *)(&op); + } + } + } + return nullptr; +} + +void NodeOperationBuilder::add_input_buffers(NodeOperation * /*operation*/, + NodeOperationInput *input) +{ + if (!input->isConnected()) { + return; + } + + NodeOperationOutput *output = input->getLink(); + if (output->getOperation().isReadBufferOperation()) { + /* input is already buffered, no need to add another */ + return; + } + + /* this link will be replaced below */ + removeInputLink(input); + + /* check of other end already has write operation, otherwise add a new one */ + WriteBufferOperation *writeoperation = find_attached_write_buffer_operation(output); + if (!writeoperation) { + writeoperation = new WriteBufferOperation(output->getDataType()); + writeoperation->setbNodeTree(m_context->getbNodeTree()); + addOperation(writeoperation); + + addLink(output, writeoperation->getInputSocket(0)); + + writeoperation->readResolutionFromInputSocket(); + } + + /* add readbuffer op for the input */ + ReadBufferOperation *readoperation = new ReadBufferOperation(output->getDataType()); + readoperation->setMemoryProxy(writeoperation->getMemoryProxy()); + this->addOperation(readoperation); + + addLink(readoperation->getOutputSocket(), input); + + readoperation->readResolutionFromWriteBuffer(); +} + +void NodeOperationBuilder::add_output_buffers(NodeOperation *operation, + NodeOperationOutput *output) +{ + /* cache connected sockets, so we can safely remove links first before replacing them */ + OpInputs targets = cache_output_links(output); + if (targets.empty()) { + return; + } + + WriteBufferOperation *writeOperation = nullptr; + for (OpInputs::const_iterator it = targets.begin(); it != targets.end(); ++it) { + NodeOperationInput *target = *it; + + /* try to find existing write buffer operation */ + if (target->getOperation().isWriteBufferOperation()) { + BLI_assert(writeOperation == nullptr); /* there should only be one write op connected */ + writeOperation = (WriteBufferOperation *)(&target->getOperation()); + } + else { + /* remove all links to other nodes */ + removeInputLink(target); + } + } + + /* if no write buffer operation exists yet, create a new one */ + if (!writeOperation) { + writeOperation = new WriteBufferOperation(operation->getOutputSocket()->getDataType()); + writeOperation->setbNodeTree(m_context->getbNodeTree()); + addOperation(writeOperation); + + addLink(output, writeOperation->getInputSocket(0)); + } + + writeOperation->readResolutionFromInputSocket(); + + /* add readbuffer op for every former connected input */ + for (OpInputs::const_iterator it = targets.begin(); it != targets.end(); ++it) { + NodeOperationInput *target = *it; + if (&target->getOperation() == writeOperation) { + continue; /* skip existing write op links */ + } + + ReadBufferOperation *readoperation = new ReadBufferOperation( + operation->getOutputSocket()->getDataType()); + readoperation->setMemoryProxy(writeOperation->getMemoryProxy()); + addOperation(readoperation); + + addLink(readoperation->getOutputSocket(), target); + + readoperation->readResolutionFromWriteBuffer(); + } +} + +void NodeOperationBuilder::add_complex_operation_buffers() +{ + /* note: complex ops and get cached here first, since adding operations + * will invalidate iterators over the main m_operations + */ + blender::Vector complex_ops; + for (NodeOperation *operation : m_operations) { + if (operation->isComplex()) { + complex_ops.append(operation); + } + } + + for (NodeOperation *op : complex_ops) { + DebugInfo::operation_read_write_buffer(op); + + for (int index = 0; index < op->getNumberOfInputSockets(); index++) { + add_input_buffers(op, op->getInputSocket(index)); + } + + for (int index = 0; index < op->getNumberOfOutputSockets(); index++) { + add_output_buffers(op, op->getOutputSocket(index)); + } + } +} + +using Tags = std::set; + +static void find_reachable_operations_recursive(Tags &reachable, NodeOperation *op) +{ + if (reachable.find(op) != reachable.end()) { + return; + } + reachable.insert(op); + + for (int i = 0; i < op->getNumberOfInputSockets(); i++) { + NodeOperationInput *input = op->getInputSocket(i); + if (input->isConnected()) { + find_reachable_operations_recursive(reachable, &input->getLink()->getOperation()); + } + } + + /* associated write-buffer operations are executed as well */ + if (op->isReadBufferOperation()) { + ReadBufferOperation *read_op = (ReadBufferOperation *)op; + MemoryProxy *memproxy = read_op->getMemoryProxy(); + find_reachable_operations_recursive(reachable, memproxy->getWriteBufferOperation()); + } +} + +void NodeOperationBuilder::prune_operations() +{ + Tags reachable; + for (NodeOperation *op : m_operations) { + /* output operations are primary executed operations */ + if (op->isOutputOperation(m_context->isRendering())) { + find_reachable_operations_recursive(reachable, op); + } + } + + /* delete unreachable operations */ + blender::Vector reachable_ops; + for (NodeOperation *op : m_operations) { + if (reachable.find(op) != reachable.end()) { + reachable_ops.append(op); + } + else { + delete op; + } + } + /* finally replace the operations list with the pruned list */ + m_operations = reachable_ops; +} + +/* topological (depth-first) sorting of operations */ +static void sort_operations_recursive(blender::Vector &sorted, + Tags &visited, + NodeOperation *op) +{ + if (visited.find(op) != visited.end()) { + return; + } + visited.insert(op); + + for (int i = 0; i < op->getNumberOfInputSockets(); i++) { + NodeOperationInput *input = op->getInputSocket(i); + if (input->isConnected()) { + sort_operations_recursive(sorted, visited, &input->getLink()->getOperation()); + } + } + + sorted.append(op); +} + +void NodeOperationBuilder::sort_operations() +{ + blender::Vector sorted; + sorted.reserve(m_operations.size()); + Tags visited; + + for (NodeOperation *operation : m_operations) { + sort_operations_recursive(sorted, visited, operation); + } + + m_operations = sorted; +} + +static void add_group_operations_recursive(Tags &visited, NodeOperation *op, ExecutionGroup *group) +{ + if (visited.find(op) != visited.end()) { + return; + } + visited.insert(op); + + if (!group->addOperation(op)) { + return; + } + + /* add all eligible input ops to the group */ + for (int i = 0; i < op->getNumberOfInputSockets(); i++) { + NodeOperationInput *input = op->getInputSocket(i); + if (input->isConnected()) { + add_group_operations_recursive(visited, &input->getLink()->getOperation(), group); + } + } +} + +ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op) +{ + ExecutionGroup *group = new ExecutionGroup(); + m_groups.append(group); + + Tags visited; + add_group_operations_recursive(visited, op, group); + + return group; +} + +void NodeOperationBuilder::group_operations() +{ + for (NodeOperation *op : m_operations) { + if (op->isOutputOperation(m_context->isRendering())) { + ExecutionGroup *group = make_group(op); + group->setOutputExecutionGroup(true); + } + + /* add new groups for associated memory proxies where needed */ + if (op->isReadBufferOperation()) { + ReadBufferOperation *read_op = (ReadBufferOperation *)op; + MemoryProxy *memproxy = read_op->getMemoryProxy(); + + if (memproxy->getExecutor() == nullptr) { + ExecutionGroup *group = make_group(memproxy->getWriteBufferOperation()); + memproxy->setExecutor(group); + } + } + } +} diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp deleted file mode 100644 index 688b693080f..00000000000 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ /dev/null @@ -1,722 +0,0 @@ -/* - * 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. - * - * Copyright 2013, Blender Foundation. - */ - -#include "BLI_utildefines.h" - -#include "COM_Converter.h" -#include "COM_Debug.h" -#include "COM_ExecutionSystem.h" -#include "COM_Node.h" -#include "COM_NodeConverter.h" -#include "COM_SocketProxyNode.h" - -#include "COM_NodeOperation.h" -#include "COM_PreviewOperation.h" -#include "COM_ReadBufferOperation.h" -#include "COM_SetColorOperation.h" -#include "COM_SetValueOperation.h" -#include "COM_SetVectorOperation.h" -#include "COM_SocketProxyOperation.h" -#include "COM_ViewerOperation.h" -#include "COM_WriteBufferOperation.h" - -#include "COM_NodeOperationBuilder.h" /* own include */ - -NodeOperationBuilder::NodeOperationBuilder(const CompositorContext *context, bNodeTree *b_nodetree) - : m_context(context), m_current_node(nullptr), m_active_viewer(nullptr) -{ - m_graph.from_bNodeTree(*context, b_nodetree); -} - -NodeOperationBuilder::~NodeOperationBuilder() -{ -} - -void NodeOperationBuilder::convertToOperations(ExecutionSystem *system) -{ - /* interface handle for nodes */ - NodeConverter converter(this); - - for (int index = 0; index < m_graph.nodes().size(); index++) { - Node *node = (Node *)m_graph.nodes()[index]; - - m_current_node = node; - - DebugInfo::node_to_operations(node); - node->convertToOperations(converter, *m_context); - } - - m_current_node = nullptr; - - /* The input map constructed by nodes maps operation inputs to node inputs. - * Inverting yields a map of node inputs to all connected operation inputs, - * so multiple operations can use the same node input. - */ - OpInputInverseMap inverse_input_map; - for (InputSocketMap::const_iterator it = m_input_map.begin(); it != m_input_map.end(); ++it) { - inverse_input_map[it->second].push_back(it->first); - } - - for (const NodeGraph::Link &link : m_graph.links()) { - NodeOutput *from = link.from; - NodeInput *to = link.to; - - NodeOperationOutput *op_from = find_operation_output(m_output_map, from); - const OpInputs &op_to_list = find_operation_inputs(inverse_input_map, to); - if (!op_from || op_to_list.empty()) { - /* XXX allow this? error/debug message? */ - // BLI_assert(false); - /* XXX note: this can happen with certain nodes (e.g. OutputFile) - * which only generate operations in certain circumstances (rendering) - * just let this pass silently for now ... - */ - continue; - } - - for (OpInputs::const_iterator it = op_to_list.begin(); it != op_to_list.end(); ++it) { - NodeOperationInput *op_to = *it; - addLink(op_from, op_to); - } - } - - add_operation_input_constants(); - - resolve_proxies(); - - add_datatype_conversions(); - - determineResolutions(); - - /* surround complex ops with read/write buffer */ - add_complex_operation_buffers(); - - /* links not available from here on */ - /* XXX make m_links a local variable to avoid confusion! */ - m_links.clear(); - - prune_operations(); - - /* ensure topological (link-based) order of nodes */ - /*sort_operations();*/ /* not needed yet */ - - /* create execution groups */ - group_operations(); - - /* transfer resulting operations to the system */ - system->set_operations(m_operations, m_groups); -} - -void NodeOperationBuilder::addOperation(NodeOperation *operation) -{ - m_operations.append(operation); -} - -void NodeOperationBuilder::mapInputSocket(NodeInput *node_socket, - NodeOperationInput *operation_socket) -{ - BLI_assert(m_current_node); - BLI_assert(node_socket->getNode() == m_current_node); - - /* note: this maps operation sockets to node sockets. - * for resolving links the map will be inverted first in convertToOperations, - * to get a list of links for each node input socket. - */ - m_input_map[operation_socket] = node_socket; -} - -void NodeOperationBuilder::mapOutputSocket(NodeOutput *node_socket, - NodeOperationOutput *operation_socket) -{ - BLI_assert(m_current_node); - BLI_assert(node_socket->getNode() == m_current_node); - - m_output_map[node_socket] = operation_socket; -} - -void NodeOperationBuilder::addLink(NodeOperationOutput *from, NodeOperationInput *to) -{ - if (to->isConnected()) { - return; - } - - m_links.push_back(Link(from, to)); - - /* register with the input */ - to->setLink(from); -} - -void NodeOperationBuilder::removeInputLink(NodeOperationInput *to) -{ - for (Links::iterator it = m_links.begin(); it != m_links.end(); ++it) { - Link &link = *it; - if (link.to() == to) { - /* unregister with the input */ - to->setLink(nullptr); - - m_links.erase(it); - return; - } - } -} - -NodeInput *NodeOperationBuilder::find_node_input(const InputSocketMap &map, - NodeOperationInput *op_input) -{ - InputSocketMap::const_iterator it = map.find(op_input); - return (it != map.end() ? it->second : NULL); -} - -const NodeOperationBuilder::OpInputs &NodeOperationBuilder::find_operation_inputs( - const OpInputInverseMap &map, NodeInput *node_input) -{ - static const OpInputs empty_list; - OpInputInverseMap::const_iterator it = map.find(node_input); - return (it != map.end() ? it->second : empty_list); -} - -NodeOperationOutput *NodeOperationBuilder::find_operation_output(const OutputSocketMap &map, - NodeOutput *node_output) -{ - OutputSocketMap::const_iterator it = map.find(node_output); - return (it != map.end() ? it->second : NULL); -} - -PreviewOperation *NodeOperationBuilder::make_preview_operation() const -{ - BLI_assert(m_current_node); - - if (!(m_current_node->getbNode()->flag & NODE_PREVIEW)) { - return nullptr; - } - /* previews only in the active group */ - if (!m_current_node->isInActiveGroup()) { - return nullptr; - } - /* do not calculate previews of hidden nodes */ - if (m_current_node->getbNode()->flag & NODE_HIDDEN) { - return nullptr; - } - - bNodeInstanceHash *previews = m_context->getPreviewHash(); - if (previews) { - PreviewOperation *operation = new PreviewOperation(m_context->getViewSettings(), - m_context->getDisplaySettings()); - operation->setbNodeTree(m_context->getbNodeTree()); - operation->verifyPreview(previews, m_current_node->getInstanceKey()); - return operation; - } - - return nullptr; -} - -void NodeOperationBuilder::addPreview(NodeOperationOutput *output) -{ - PreviewOperation *operation = make_preview_operation(); - if (operation) { - addOperation(operation); - - addLink(output, operation->getInputSocket(0)); - } -} - -void NodeOperationBuilder::addNodeInputPreview(NodeInput *input) -{ - PreviewOperation *operation = make_preview_operation(); - if (operation) { - addOperation(operation); - - mapInputSocket(input, operation->getInputSocket(0)); - } -} - -void NodeOperationBuilder::registerViewer(ViewerOperation *viewer) -{ - if (m_active_viewer) { - if (m_current_node->isInActiveGroup()) { - /* deactivate previous viewer */ - m_active_viewer->setActive(false); - - m_active_viewer = viewer; - viewer->setActive(true); - } - } - else { - if (m_current_node->getbNodeTree() == m_context->getbNodeTree()) { - m_active_viewer = viewer; - viewer->setActive(true); - } - } -} - -/**************************** - **** Optimization Steps **** - ****************************/ - -void NodeOperationBuilder::add_datatype_conversions() -{ - Links convert_links; - for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) { - const Link &link = *it; - - /* proxy operations can skip data type conversion */ - NodeOperation *from_op = &link.from()->getOperation(); - NodeOperation *to_op = &link.to()->getOperation(); - if (!(from_op->useDatatypeConversion() || to_op->useDatatypeConversion())) { - continue; - } - - if (link.from()->getDataType() != link.to()->getDataType()) { - convert_links.push_back(link); - } - } - for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) { - const Link &link = *it; - NodeOperation *converter = COM_convert_data_type(*link.from(), *link.to()); - if (converter) { - addOperation(converter); - - removeInputLink(link.to()); - addLink(link.from(), converter->getInputSocket(0)); - addLink(converter->getOutputSocket(0), link.to()); - } - } -} - -void NodeOperationBuilder::add_operation_input_constants() -{ - /* Note: unconnected inputs cached first to avoid modifying - * m_operations while iterating over it - */ - using Inputs = std::vector; - Inputs pending_inputs; - for (NodeOperation *op : m_operations) { - for (int k = 0; k < op->getNumberOfInputSockets(); ++k) { - NodeOperationInput *input = op->getInputSocket(k); - if (!input->isConnected()) { - pending_inputs.push_back(input); - } - } - } - for (Inputs::const_iterator it = pending_inputs.begin(); it != pending_inputs.end(); ++it) { - NodeOperationInput *input = *it; - add_input_constant_value(input, find_node_input(m_input_map, input)); - } -} - -void NodeOperationBuilder::add_input_constant_value(NodeOperationInput *input, - NodeInput *node_input) -{ - switch (input->getDataType()) { - case COM_DT_VALUE: { - float value; - if (node_input && node_input->getbNodeSocket()) { - value = node_input->getEditorValueFloat(); - } - else { - value = 0.0f; - } - - SetValueOperation *op = new SetValueOperation(); - op->setValue(value); - addOperation(op); - addLink(op->getOutputSocket(), input); - break; - } - case COM_DT_COLOR: { - float value[4]; - if (node_input && node_input->getbNodeSocket()) { - node_input->getEditorValueColor(value); - } - else { - zero_v4(value); - } - - SetColorOperation *op = new SetColorOperation(); - op->setChannels(value); - addOperation(op); - addLink(op->getOutputSocket(), input); - break; - } - case COM_DT_VECTOR: { - float value[3]; - if (node_input && node_input->getbNodeSocket()) { - node_input->getEditorValueVector(value); - } - else { - zero_v3(value); - } - - SetVectorOperation *op = new SetVectorOperation(); - op->setVector(value); - addOperation(op); - addLink(op->getOutputSocket(), input); - break; - } - } -} - -void NodeOperationBuilder::resolve_proxies() -{ - Links proxy_links; - for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) { - const Link &link = *it; - /* don't replace links from proxy to proxy, since we may need them for replacing others! */ - if (link.from()->getOperation().isProxyOperation() && - !link.to()->getOperation().isProxyOperation()) { - proxy_links.push_back(link); - } - } - - for (Links::const_iterator it = proxy_links.begin(); it != proxy_links.end(); ++it) { - const Link &link = *it; - - NodeOperationInput *to = link.to(); - NodeOperationOutput *from = link.from(); - do { - /* walk upstream bypassing the proxy operation */ - from = from->getOperation().getInputSocket(0)->getLink(); - } while (from && from->getOperation().isProxyOperation()); - - removeInputLink(to); - /* we may not have a final proxy input link, - * in that case it just gets dropped - */ - if (from) { - addLink(from, to); - } - } -} - -void NodeOperationBuilder::determineResolutions() -{ - /* determine all resolutions of the operations (Width/Height) */ - for (NodeOperation *op : m_operations) { - if (op->isOutputOperation(m_context->isRendering()) && !op->isPreviewOperation()) { - unsigned int resolution[2] = {0, 0}; - unsigned int preferredResolution[2] = {0, 0}; - op->determineResolution(resolution, preferredResolution); - op->setResolution(resolution); - } - } - - for (NodeOperation *op : m_operations) { - if (op->isOutputOperation(m_context->isRendering()) && op->isPreviewOperation()) { - unsigned int resolution[2] = {0, 0}; - unsigned int preferredResolution[2] = {0, 0}; - op->determineResolution(resolution, preferredResolution); - op->setResolution(resolution); - } - } - - /* add convert resolution operations when needed */ - { - Links convert_links; - for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) { - const Link &link = *it; - - if (link.to()->getResizeMode() != COM_SC_NO_RESIZE) { - NodeOperation &from_op = link.from()->getOperation(); - NodeOperation &to_op = link.to()->getOperation(); - if (from_op.getWidth() != to_op.getWidth() || from_op.getHeight() != to_op.getHeight()) { - convert_links.push_back(link); - } - } - } - for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) { - const Link &link = *it; - COM_convert_resolution(*this, link.from(), link.to()); - } - } -} - -NodeOperationBuilder::OpInputs NodeOperationBuilder::cache_output_links( - NodeOperationOutput *output) const -{ - OpInputs inputs; - for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) { - const Link &link = *it; - if (link.from() == output) { - inputs.push_back(link.to()); - } - } - return inputs; -} - -WriteBufferOperation *NodeOperationBuilder::find_attached_write_buffer_operation( - NodeOperationOutput *output) const -{ - for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) { - const Link &link = *it; - if (link.from() == output) { - NodeOperation &op = link.to()->getOperation(); - if (op.isWriteBufferOperation()) { - return (WriteBufferOperation *)(&op); - } - } - } - return nullptr; -} - -void NodeOperationBuilder::add_input_buffers(NodeOperation * /*operation*/, - NodeOperationInput *input) -{ - if (!input->isConnected()) { - return; - } - - NodeOperationOutput *output = input->getLink(); - if (output->getOperation().isReadBufferOperation()) { - /* input is already buffered, no need to add another */ - return; - } - - /* this link will be replaced below */ - removeInputLink(input); - - /* check of other end already has write operation, otherwise add a new one */ - WriteBufferOperation *writeoperation = find_attached_write_buffer_operation(output); - if (!writeoperation) { - writeoperation = new WriteBufferOperation(output->getDataType()); - writeoperation->setbNodeTree(m_context->getbNodeTree()); - addOperation(writeoperation); - - addLink(output, writeoperation->getInputSocket(0)); - - writeoperation->readResolutionFromInputSocket(); - } - - /* add readbuffer op for the input */ - ReadBufferOperation *readoperation = new ReadBufferOperation(output->getDataType()); - readoperation->setMemoryProxy(writeoperation->getMemoryProxy()); - this->addOperation(readoperation); - - addLink(readoperation->getOutputSocket(), input); - - readoperation->readResolutionFromWriteBuffer(); -} - -void NodeOperationBuilder::add_output_buffers(NodeOperation *operation, - NodeOperationOutput *output) -{ - /* cache connected sockets, so we can safely remove links first before replacing them */ - OpInputs targets = cache_output_links(output); - if (targets.empty()) { - return; - } - - WriteBufferOperation *writeOperation = nullptr; - for (OpInputs::const_iterator it = targets.begin(); it != targets.end(); ++it) { - NodeOperationInput *target = *it; - - /* try to find existing write buffer operation */ - if (target->getOperation().isWriteBufferOperation()) { - BLI_assert(writeOperation == nullptr); /* there should only be one write op connected */ - writeOperation = (WriteBufferOperation *)(&target->getOperation()); - } - else { - /* remove all links to other nodes */ - removeInputLink(target); - } - } - - /* if no write buffer operation exists yet, create a new one */ - if (!writeOperation) { - writeOperation = new WriteBufferOperation(operation->getOutputSocket()->getDataType()); - writeOperation->setbNodeTree(m_context->getbNodeTree()); - addOperation(writeOperation); - - addLink(output, writeOperation->getInputSocket(0)); - } - - writeOperation->readResolutionFromInputSocket(); - - /* add readbuffer op for every former connected input */ - for (OpInputs::const_iterator it = targets.begin(); it != targets.end(); ++it) { - NodeOperationInput *target = *it; - if (&target->getOperation() == writeOperation) { - continue; /* skip existing write op links */ - } - - ReadBufferOperation *readoperation = new ReadBufferOperation( - operation->getOutputSocket()->getDataType()); - readoperation->setMemoryProxy(writeOperation->getMemoryProxy()); - addOperation(readoperation); - - addLink(readoperation->getOutputSocket(), target); - - readoperation->readResolutionFromWriteBuffer(); - } -} - -void NodeOperationBuilder::add_complex_operation_buffers() -{ - /* note: complex ops and get cached here first, since adding operations - * will invalidate iterators over the main m_operations - */ - blender::Vector complex_ops; - for (NodeOperation *operation : m_operations) { - if (operation->isComplex()) { - complex_ops.append(operation); - } - } - - for (NodeOperation *op : complex_ops) { - DebugInfo::operation_read_write_buffer(op); - - for (int index = 0; index < op->getNumberOfInputSockets(); index++) { - add_input_buffers(op, op->getInputSocket(index)); - } - - for (int index = 0; index < op->getNumberOfOutputSockets(); index++) { - add_output_buffers(op, op->getOutputSocket(index)); - } - } -} - -using Tags = std::set; - -static void find_reachable_operations_recursive(Tags &reachable, NodeOperation *op) -{ - if (reachable.find(op) != reachable.end()) { - return; - } - reachable.insert(op); - - for (int i = 0; i < op->getNumberOfInputSockets(); i++) { - NodeOperationInput *input = op->getInputSocket(i); - if (input->isConnected()) { - find_reachable_operations_recursive(reachable, &input->getLink()->getOperation()); - } - } - - /* associated write-buffer operations are executed as well */ - if (op->isReadBufferOperation()) { - ReadBufferOperation *read_op = (ReadBufferOperation *)op; - MemoryProxy *memproxy = read_op->getMemoryProxy(); - find_reachable_operations_recursive(reachable, memproxy->getWriteBufferOperation()); - } -} - -void NodeOperationBuilder::prune_operations() -{ - Tags reachable; - for (NodeOperation *op : m_operations) { - /* output operations are primary executed operations */ - if (op->isOutputOperation(m_context->isRendering())) { - find_reachable_operations_recursive(reachable, op); - } - } - - /* delete unreachable operations */ - blender::Vector reachable_ops; - for (NodeOperation *op : m_operations) { - if (reachable.find(op) != reachable.end()) { - reachable_ops.append(op); - } - else { - delete op; - } - } - /* finally replace the operations list with the pruned list */ - m_operations = reachable_ops; -} - -/* topological (depth-first) sorting of operations */ -static void sort_operations_recursive(blender::Vector &sorted, - Tags &visited, - NodeOperation *op) -{ - if (visited.find(op) != visited.end()) { - return; - } - visited.insert(op); - - for (int i = 0; i < op->getNumberOfInputSockets(); i++) { - NodeOperationInput *input = op->getInputSocket(i); - if (input->isConnected()) { - sort_operations_recursive(sorted, visited, &input->getLink()->getOperation()); - } - } - - sorted.append(op); -} - -void NodeOperationBuilder::sort_operations() -{ - blender::Vector sorted; - sorted.reserve(m_operations.size()); - Tags visited; - - for (NodeOperation *operation : m_operations) { - sort_operations_recursive(sorted, visited, operation); - } - - m_operations = sorted; -} - -static void add_group_operations_recursive(Tags &visited, NodeOperation *op, ExecutionGroup *group) -{ - if (visited.find(op) != visited.end()) { - return; - } - visited.insert(op); - - if (!group->addOperation(op)) { - return; - } - - /* add all eligible input ops to the group */ - for (int i = 0; i < op->getNumberOfInputSockets(); i++) { - NodeOperationInput *input = op->getInputSocket(i); - if (input->isConnected()) { - add_group_operations_recursive(visited, &input->getLink()->getOperation(), group); - } - } -} - -ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op) -{ - ExecutionGroup *group = new ExecutionGroup(); - m_groups.append(group); - - Tags visited; - add_group_operations_recursive(visited, op, group); - - return group; -} - -void NodeOperationBuilder::group_operations() -{ - for (NodeOperation *op : m_operations) { - if (op->isOutputOperation(m_context->isRendering())) { - ExecutionGroup *group = make_group(op); - group->setOutputExecutionGroup(true); - } - - /* add new groups for associated memory proxies where needed */ - if (op->isReadBufferOperation()) { - ReadBufferOperation *read_op = (ReadBufferOperation *)op; - MemoryProxy *memproxy = read_op->getMemoryProxy(); - - if (memproxy->getExecutor() == nullptr) { - ExecutionGroup *group = make_group(memproxy->getWriteBufferOperation()); - memproxy->setExecutor(group); - } - } - } -} diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cc b/source/blender/compositor/intern/COM_OpenCLDevice.cc new file mode 100644 index 00000000000..34450366aec --- /dev/null +++ b/source/blender/compositor/intern/COM_OpenCLDevice.cc @@ -0,0 +1,274 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_OpenCLDevice.h" +#include "COM_WorkScheduler.h" + +enum COM_VendorID { NVIDIA = 0x10DE, AMD = 0x1002 }; +const cl_image_format IMAGE_FORMAT_COLOR = { + CL_RGBA, + CL_FLOAT, +}; +const cl_image_format IMAGE_FORMAT_VECTOR = { + CL_RGB, + CL_FLOAT, +}; +const cl_image_format IMAGE_FORMAT_VALUE = { + CL_R, + CL_FLOAT, +}; + +OpenCLDevice::OpenCLDevice(cl_context context, + cl_device_id device, + cl_program program, + cl_int vendorId) +{ + this->m_device = device; + this->m_context = context; + this->m_program = program; + this->m_queue = nullptr; + this->m_vendorID = vendorId; +} + +bool OpenCLDevice::initialize() +{ + cl_int error; + this->m_queue = clCreateCommandQueue(this->m_context, this->m_device, 0, &error); + return false; +} + +void OpenCLDevice::deinitialize() +{ + if (this->m_queue) { + clReleaseCommandQueue(this->m_queue); + } +} + +void OpenCLDevice::execute(WorkPackage *work) +{ + const unsigned int chunkNumber = work->chunk_number; + ExecutionGroup *executionGroup = work->execution_group; + rcti rect; + + executionGroup->determineChunkRect(&rect, chunkNumber); + MemoryBuffer **inputBuffers = executionGroup->getInputBuffersOpenCL(chunkNumber); + MemoryBuffer *outputBuffer = executionGroup->allocateOutputBuffer(chunkNumber, &rect); + + executionGroup->getOutputOperation()->executeOpenCLRegion( + this, &rect, chunkNumber, inputBuffers, outputBuffer); + + delete outputBuffer; + + executionGroup->finalizeChunkExecution(chunkNumber, inputBuffers); +} +cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, + int parameterIndex, + int offsetIndex, + std::list *cleanup, + MemoryBuffer **inputMemoryBuffers, + SocketReader *reader) +{ + return COM_clAttachMemoryBufferToKernelParameter(kernel, + parameterIndex, + offsetIndex, + cleanup, + inputMemoryBuffers, + (ReadBufferOperation *)reader); +} + +const cl_image_format *OpenCLDevice::determineImageFormat(MemoryBuffer *memoryBuffer) +{ + const cl_image_format *imageFormat; + int num_channels = memoryBuffer->get_num_channels(); + if (num_channels == 1) { + imageFormat = &IMAGE_FORMAT_VALUE; + } + else if (num_channels == 3) { + imageFormat = &IMAGE_FORMAT_VECTOR; + } + else { + imageFormat = &IMAGE_FORMAT_COLOR; + } + + return imageFormat; +} + +cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, + int parameterIndex, + int offsetIndex, + std::list *cleanup, + MemoryBuffer **inputMemoryBuffers, + ReadBufferOperation *reader) +{ + cl_int error; + + MemoryBuffer *result = reader->getInputMemoryBuffer(inputMemoryBuffers); + + const cl_image_format *imageFormat = determineImageFormat(result); + + cl_mem clBuffer = clCreateImage2D(this->m_context, + CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, + imageFormat, + result->getWidth(), + result->getHeight(), + 0, + result->getBuffer(), + &error); + + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + if (error == CL_SUCCESS) { + cleanup->push_back(clBuffer); + } + + error = clSetKernelArg(kernel, parameterIndex, sizeof(cl_mem), &clBuffer); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + + COM_clAttachMemoryBufferOffsetToKernelParameter(kernel, offsetIndex, result); + return clBuffer; +} + +void OpenCLDevice::COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel kernel, + int offsetIndex, + MemoryBuffer *memoryBuffer) +{ + if (offsetIndex != -1) { + cl_int error; + rcti *rect = memoryBuffer->getRect(); + cl_int2 offset = {{rect->xmin, rect->ymin}}; + + error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + } +} + +void OpenCLDevice::COM_clAttachSizeToKernelParameter(cl_kernel kernel, + int offsetIndex, + NodeOperation *operation) +{ + if (offsetIndex != -1) { + cl_int error; + cl_int2 offset = {{(cl_int)operation->getWidth(), (cl_int)operation->getHeight()}}; + + error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + } +} + +void OpenCLDevice::COM_clAttachOutputMemoryBufferToKernelParameter(cl_kernel kernel, + int parameterIndex, + cl_mem clOutputMemoryBuffer) +{ + cl_int error; + error = clSetKernelArg(kernel, parameterIndex, sizeof(cl_mem), &clOutputMemoryBuffer); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } +} + +void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemoryBuffer) +{ + cl_int error; + const size_t size[] = { + (size_t)outputMemoryBuffer->getWidth(), + (size_t)outputMemoryBuffer->getHeight(), + }; + + error = clEnqueueNDRangeKernel( + this->m_queue, kernel, 2, nullptr, size, nullptr, 0, nullptr, nullptr); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } +} + +void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, + MemoryBuffer *outputMemoryBuffer, + int offsetIndex, + NodeOperation *operation) +{ + cl_int error; + const int width = outputMemoryBuffer->getWidth(); + const int height = outputMemoryBuffer->getHeight(); + int offsetx; + int offsety; + int localSize = 1024; + size_t size[2]; + cl_int2 offset; + + if (this->m_vendorID == NVIDIA) { + localSize = 32; + } + + bool breaked = false; + for (offsety = 0; offsety < height && (!breaked); offsety += localSize) { + offset.s[1] = offsety; + if (offsety + localSize < height) { + size[1] = localSize; + } + else { + size[1] = height - offsety; + } + + for (offsetx = 0; offsetx < width && (!breaked); offsetx += localSize) { + if (offsetx + localSize < width) { + size[0] = localSize; + } + else { + size[0] = width - offsetx; + } + offset.s[0] = offsetx; + + error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + error = clEnqueueNDRangeKernel( + this->m_queue, kernel, 2, nullptr, size, nullptr, 0, nullptr, nullptr); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + clFlush(this->m_queue); + if (operation->isBraked()) { + breaked = false; + } + } + } +} + +cl_kernel OpenCLDevice::COM_clCreateKernel(const char *kernelname, + std::list *clKernelsToCleanUp) +{ + cl_int error; + cl_kernel kernel = clCreateKernel(this->m_program, kernelname, &error); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + else { + if (clKernelsToCleanUp) { + clKernelsToCleanUp->push_back(kernel); + } + } + return kernel; +} diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp deleted file mode 100644 index 34450366aec..00000000000 --- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_OpenCLDevice.h" -#include "COM_WorkScheduler.h" - -enum COM_VendorID { NVIDIA = 0x10DE, AMD = 0x1002 }; -const cl_image_format IMAGE_FORMAT_COLOR = { - CL_RGBA, - CL_FLOAT, -}; -const cl_image_format IMAGE_FORMAT_VECTOR = { - CL_RGB, - CL_FLOAT, -}; -const cl_image_format IMAGE_FORMAT_VALUE = { - CL_R, - CL_FLOAT, -}; - -OpenCLDevice::OpenCLDevice(cl_context context, - cl_device_id device, - cl_program program, - cl_int vendorId) -{ - this->m_device = device; - this->m_context = context; - this->m_program = program; - this->m_queue = nullptr; - this->m_vendorID = vendorId; -} - -bool OpenCLDevice::initialize() -{ - cl_int error; - this->m_queue = clCreateCommandQueue(this->m_context, this->m_device, 0, &error); - return false; -} - -void OpenCLDevice::deinitialize() -{ - if (this->m_queue) { - clReleaseCommandQueue(this->m_queue); - } -} - -void OpenCLDevice::execute(WorkPackage *work) -{ - const unsigned int chunkNumber = work->chunk_number; - ExecutionGroup *executionGroup = work->execution_group; - rcti rect; - - executionGroup->determineChunkRect(&rect, chunkNumber); - MemoryBuffer **inputBuffers = executionGroup->getInputBuffersOpenCL(chunkNumber); - MemoryBuffer *outputBuffer = executionGroup->allocateOutputBuffer(chunkNumber, &rect); - - executionGroup->getOutputOperation()->executeOpenCLRegion( - this, &rect, chunkNumber, inputBuffers, outputBuffer); - - delete outputBuffer; - - executionGroup->finalizeChunkExecution(chunkNumber, inputBuffers); -} -cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, - int parameterIndex, - int offsetIndex, - std::list *cleanup, - MemoryBuffer **inputMemoryBuffers, - SocketReader *reader) -{ - return COM_clAttachMemoryBufferToKernelParameter(kernel, - parameterIndex, - offsetIndex, - cleanup, - inputMemoryBuffers, - (ReadBufferOperation *)reader); -} - -const cl_image_format *OpenCLDevice::determineImageFormat(MemoryBuffer *memoryBuffer) -{ - const cl_image_format *imageFormat; - int num_channels = memoryBuffer->get_num_channels(); - if (num_channels == 1) { - imageFormat = &IMAGE_FORMAT_VALUE; - } - else if (num_channels == 3) { - imageFormat = &IMAGE_FORMAT_VECTOR; - } - else { - imageFormat = &IMAGE_FORMAT_COLOR; - } - - return imageFormat; -} - -cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, - int parameterIndex, - int offsetIndex, - std::list *cleanup, - MemoryBuffer **inputMemoryBuffers, - ReadBufferOperation *reader) -{ - cl_int error; - - MemoryBuffer *result = reader->getInputMemoryBuffer(inputMemoryBuffers); - - const cl_image_format *imageFormat = determineImageFormat(result); - - cl_mem clBuffer = clCreateImage2D(this->m_context, - CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, - imageFormat, - result->getWidth(), - result->getHeight(), - 0, - result->getBuffer(), - &error); - - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - if (error == CL_SUCCESS) { - cleanup->push_back(clBuffer); - } - - error = clSetKernelArg(kernel, parameterIndex, sizeof(cl_mem), &clBuffer); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - - COM_clAttachMemoryBufferOffsetToKernelParameter(kernel, offsetIndex, result); - return clBuffer; -} - -void OpenCLDevice::COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel kernel, - int offsetIndex, - MemoryBuffer *memoryBuffer) -{ - if (offsetIndex != -1) { - cl_int error; - rcti *rect = memoryBuffer->getRect(); - cl_int2 offset = {{rect->xmin, rect->ymin}}; - - error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - } -} - -void OpenCLDevice::COM_clAttachSizeToKernelParameter(cl_kernel kernel, - int offsetIndex, - NodeOperation *operation) -{ - if (offsetIndex != -1) { - cl_int error; - cl_int2 offset = {{(cl_int)operation->getWidth(), (cl_int)operation->getHeight()}}; - - error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - } -} - -void OpenCLDevice::COM_clAttachOutputMemoryBufferToKernelParameter(cl_kernel kernel, - int parameterIndex, - cl_mem clOutputMemoryBuffer) -{ - cl_int error; - error = clSetKernelArg(kernel, parameterIndex, sizeof(cl_mem), &clOutputMemoryBuffer); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } -} - -void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemoryBuffer) -{ - cl_int error; - const size_t size[] = { - (size_t)outputMemoryBuffer->getWidth(), - (size_t)outputMemoryBuffer->getHeight(), - }; - - error = clEnqueueNDRangeKernel( - this->m_queue, kernel, 2, nullptr, size, nullptr, 0, nullptr, nullptr); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } -} - -void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, - MemoryBuffer *outputMemoryBuffer, - int offsetIndex, - NodeOperation *operation) -{ - cl_int error; - const int width = outputMemoryBuffer->getWidth(); - const int height = outputMemoryBuffer->getHeight(); - int offsetx; - int offsety; - int localSize = 1024; - size_t size[2]; - cl_int2 offset; - - if (this->m_vendorID == NVIDIA) { - localSize = 32; - } - - bool breaked = false; - for (offsety = 0; offsety < height && (!breaked); offsety += localSize) { - offset.s[1] = offsety; - if (offsety + localSize < height) { - size[1] = localSize; - } - else { - size[1] = height - offsety; - } - - for (offsetx = 0; offsetx < width && (!breaked); offsetx += localSize) { - if (offsetx + localSize < width) { - size[0] = localSize; - } - else { - size[0] = width - offsetx; - } - offset.s[0] = offsetx; - - error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - error = clEnqueueNDRangeKernel( - this->m_queue, kernel, 2, nullptr, size, nullptr, 0, nullptr, nullptr); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - clFlush(this->m_queue); - if (operation->isBraked()) { - breaked = false; - } - } - } -} - -cl_kernel OpenCLDevice::COM_clCreateKernel(const char *kernelname, - std::list *clKernelsToCleanUp) -{ - cl_int error; - cl_kernel kernel = clCreateKernel(this->m_program, kernelname, &error); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - else { - if (clKernelsToCleanUp) { - clKernelsToCleanUp->push_back(kernel); - } - } - return kernel; -} diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.cc b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc new file mode 100644 index 00000000000..5febf3802de --- /dev/null +++ b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc @@ -0,0 +1,58 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SingleThreadedOperation.h" + +SingleThreadedOperation::SingleThreadedOperation() +{ + this->m_cachedInstance = nullptr; + setComplex(true); +} + +void SingleThreadedOperation::initExecution() +{ + initMutex(); +} + +void SingleThreadedOperation::executePixel(float output[4], int x, int y, void * /*data*/) +{ + this->m_cachedInstance->readNoCheck(output, x, y); +} + +void SingleThreadedOperation::deinitExecution() +{ + deinitMutex(); + if (this->m_cachedInstance) { + delete this->m_cachedInstance; + this->m_cachedInstance = nullptr; + } +} +void *SingleThreadedOperation::initializeTileData(rcti *rect) +{ + if (this->m_cachedInstance) { + return this->m_cachedInstance; + } + + lockMutex(); + if (this->m_cachedInstance == nullptr) { + // + this->m_cachedInstance = createMemoryBuffer(rect); + } + unlockMutex(); + return this->m_cachedInstance; +} diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp b/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp deleted file mode 100644 index 5febf3802de..00000000000 --- a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SingleThreadedOperation.h" - -SingleThreadedOperation::SingleThreadedOperation() -{ - this->m_cachedInstance = nullptr; - setComplex(true); -} - -void SingleThreadedOperation::initExecution() -{ - initMutex(); -} - -void SingleThreadedOperation::executePixel(float output[4], int x, int y, void * /*data*/) -{ - this->m_cachedInstance->readNoCheck(output, x, y); -} - -void SingleThreadedOperation::deinitExecution() -{ - deinitMutex(); - if (this->m_cachedInstance) { - delete this->m_cachedInstance; - this->m_cachedInstance = nullptr; - } -} -void *SingleThreadedOperation::initializeTileData(rcti *rect) -{ - if (this->m_cachedInstance) { - return this->m_cachedInstance; - } - - lockMutex(); - if (this->m_cachedInstance == nullptr) { - // - this->m_cachedInstance = createMemoryBuffer(rect); - } - unlockMutex(); - return this->m_cachedInstance; -} diff --git a/source/blender/compositor/intern/COM_SocketReader.cc b/source/blender/compositor/intern/COM_SocketReader.cc new file mode 100644 index 00000000000..93c8a143b86 --- /dev/null +++ b/source/blender/compositor/intern/COM_SocketReader.cc @@ -0,0 +1,19 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SocketReader.h" diff --git a/source/blender/compositor/intern/COM_SocketReader.cpp b/source/blender/compositor/intern/COM_SocketReader.cpp deleted file mode 100644 index 93c8a143b86..00000000000 --- a/source/blender/compositor/intern/COM_SocketReader.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SocketReader.h" diff --git a/source/blender/compositor/intern/COM_WorkPackage.cc b/source/blender/compositor/intern/COM_WorkPackage.cc new file mode 100644 index 00000000000..60684f2c45c --- /dev/null +++ b/source/blender/compositor/intern/COM_WorkPackage.cc @@ -0,0 +1,25 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_WorkPackage.h" + +WorkPackage::WorkPackage(ExecutionGroup *execution_group, unsigned int chunk_number) +{ + this->execution_group = execution_group; + this->chunk_number = chunk_number; +} diff --git a/source/blender/compositor/intern/COM_WorkPackage.cpp b/source/blender/compositor/intern/COM_WorkPackage.cpp deleted file mode 100644 index 60684f2c45c..00000000000 --- a/source/blender/compositor/intern/COM_WorkPackage.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_WorkPackage.h" - -WorkPackage::WorkPackage(ExecutionGroup *execution_group, unsigned int chunk_number) -{ - this->execution_group = execution_group; - this->chunk_number = chunk_number; -} diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cc b/source/blender/compositor/intern/COM_WorkScheduler.cc new file mode 100644 index 00000000000..a70b6ba4abe --- /dev/null +++ b/source/blender/compositor/intern/COM_WorkScheduler.cc @@ -0,0 +1,394 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include +#include + +#include "COM_CPUDevice.h" +#include "COM_OpenCLDevice.h" +#include "COM_OpenCLKernels.cl.h" +#include "COM_WorkScheduler.h" +#include "COM_WriteBufferOperation.h" +#include "COM_compositor.h" +#include "clew.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_threads.h" +#include "PIL_time.h" + +#include "BKE_global.h" + +#if COM_CURRENT_THREADING_MODEL == COM_TM_NOTHREAD +# ifndef DEBUG /* test this so we dont get warnings in debug builds */ +# warning COM_CURRENT_THREADING_MODEL COM_TM_NOTHREAD is activated. Use only for debugging. +# endif +#elif COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE +/* do nothing - default */ +#else +# error COM_CURRENT_THREADING_MODEL No threading model selected +#endif + +static ThreadLocal(CPUDevice *) g_thread_device; +static struct { + /** \brief list of all CPUDevices. for every hardware thread an instance of CPUDevice is created + */ + std::vector cpu_devices; + +#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE + /** \brief list of all thread for every CPUDevice in cpudevices a thread exists. */ + ListBase cpu_threads; + bool cpu_initialized = false; + /** \brief all scheduled work for the cpu */ + ThreadQueue *cpu_queue; + ThreadQueue *gpu_queue; +# ifdef COM_OPENCL_ENABLED + cl_context opencl_context; + cl_program opencl_program; + /** \brief list of all OpenCLDevices. for every OpenCL GPU device an instance of OpenCLDevice is + * created. */ + std::vector gpu_devices; + /** \brief list of all thread for every GPUDevice in cpudevices a thread exists. */ + ListBase gpu_threads; + /** \brief all scheduled work for the GPU. */ + bool opencl_active = false; + bool opencl_initialized = false; +# endif +#endif + +} g_work_scheduler; + +#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE +void *WorkScheduler::thread_execute_cpu(void *data) +{ + CPUDevice *device = (CPUDevice *)data; + WorkPackage *work; + BLI_thread_local_set(g_thread_device, device); + while ((work = (WorkPackage *)BLI_thread_queue_pop(g_work_scheduler.cpu_queue))) { + device->execute(work); + delete work; + } + + return nullptr; +} + +void *WorkScheduler::thread_execute_gpu(void *data) +{ + Device *device = (Device *)data; + WorkPackage *work; + + while ((work = (WorkPackage *)BLI_thread_queue_pop(g_work_scheduler.gpu_queue))) { + device->execute(work); + delete work; + } + + return nullptr; +} +#endif + +void WorkScheduler::schedule(ExecutionGroup *group, int chunkNumber) +{ + WorkPackage *package = new WorkPackage(group, chunkNumber); +#if COM_CURRENT_THREADING_MODEL == COM_TM_NOTHREAD + CPUDevice device(0); + device.execute(package); + delete package; +#elif COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE +# ifdef COM_OPENCL_ENABLED + if (group->isOpenCL() && g_work_scheduler.opencl_active) { + BLI_thread_queue_push(g_work_scheduler.gpu_queue, package); + } + else { + BLI_thread_queue_push(g_work_scheduler.cpu_queue, package); + } +# else + BLI_thread_queue_push(g_work_scheduler.cpu_queue, package); +# endif +#endif +} + +void WorkScheduler::start(CompositorContext &context) +{ +#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE + unsigned int index; + g_work_scheduler.cpu_queue = BLI_thread_queue_init(); + BLI_threadpool_init( + &g_work_scheduler.cpu_threads, thread_execute_cpu, g_work_scheduler.cpu_devices.size()); + for (index = 0; index < g_work_scheduler.cpu_devices.size(); index++) { + Device *device = g_work_scheduler.cpu_devices[index]; + BLI_threadpool_insert(&g_work_scheduler.cpu_threads, device); + } +# ifdef COM_OPENCL_ENABLED + if (context.getHasActiveOpenCLDevices()) { + g_work_scheduler.gpu_queue = BLI_thread_queue_init(); + BLI_threadpool_init( + &g_work_scheduler.gpu_threads, thread_execute_gpu, g_work_scheduler.gpu_devices.size()); + for (index = 0; index < g_work_scheduler.gpu_devices.size(); index++) { + Device *device = g_work_scheduler.gpu_devices[index]; + BLI_threadpool_insert(&g_work_scheduler.gpu_threads, device); + } + g_work_scheduler.opencl_active = true; + } + else { + g_work_scheduler.opencl_active = false; + } +# endif +#endif +} +void WorkScheduler::finish() +{ +#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE +# ifdef COM_OPENCL_ENABLED + if (g_work_scheduler.opencl_active) { + BLI_thread_queue_wait_finish(g_work_scheduler.gpu_queue); + BLI_thread_queue_wait_finish(g_work_scheduler.cpu_queue); + } + else { + BLI_thread_queue_wait_finish(g_work_scheduler.cpu_queue); + } +# else + BLI_thread_queue_wait_finish(cpuqueue); +# endif +#endif +} +void WorkScheduler::stop() +{ +#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE + BLI_thread_queue_nowait(g_work_scheduler.cpu_queue); + BLI_threadpool_end(&g_work_scheduler.cpu_threads); + BLI_thread_queue_free(g_work_scheduler.cpu_queue); + g_work_scheduler.cpu_queue = nullptr; +# ifdef COM_OPENCL_ENABLED + if (g_work_scheduler.opencl_active) { + BLI_thread_queue_nowait(g_work_scheduler.gpu_queue); + BLI_threadpool_end(&g_work_scheduler.gpu_threads); + BLI_thread_queue_free(g_work_scheduler.gpu_queue); + g_work_scheduler.gpu_queue = nullptr; + } +# endif +#endif +} + +bool WorkScheduler::has_gpu_devices() +{ +#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE +# ifdef COM_OPENCL_ENABLED + return !g_work_scheduler.gpu_devices.empty(); +# else + return 0; +# endif +#else + return 0; +#endif +} + +#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE +static void CL_CALLBACK clContextError(const char *errinfo, + const void * /*private_info*/, + size_t /*cb*/, + void * /*user_data*/) +{ + printf("OPENCL error: %s\n", errinfo); +} +#endif + +void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads) +{ +#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE + /* deinitialize if number of threads doesn't match */ + if (g_work_scheduler.cpu_devices.size() != num_cpu_threads) { + Device *device; + + while (!g_work_scheduler.cpu_devices.empty()) { + device = g_work_scheduler.cpu_devices.back(); + g_work_scheduler.cpu_devices.pop_back(); + device->deinitialize(); + delete device; + } + if (g_work_scheduler.cpu_initialized) { + BLI_thread_local_delete(g_thread_device); + } + g_work_scheduler.cpu_initialized = false; + } + + /* initialize CPU threads */ + if (!g_work_scheduler.cpu_initialized) { + for (int index = 0; index < num_cpu_threads; index++) { + CPUDevice *device = new CPUDevice(index); + device->initialize(); + g_work_scheduler.cpu_devices.push_back(device); + } + BLI_thread_local_create(g_thread_device); + g_work_scheduler.cpu_initialized = true; + } + +# ifdef COM_OPENCL_ENABLED + /* deinitialize OpenCL GPU's */ + if (use_opencl && !g_work_scheduler.opencl_initialized) { + g_work_scheduler.opencl_context = nullptr; + g_work_scheduler.opencl_program = nullptr; + + /* This will check for errors and skip if already initialized. */ + if (clewInit() != CLEW_SUCCESS) { + return; + } + + if (clCreateContextFromType) { + cl_uint numberOfPlatforms = 0; + cl_int error; + error = clGetPlatformIDs(0, nullptr, &numberOfPlatforms); + if (error == -1001) { + } /* GPU not supported */ + else if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + if (G.f & G_DEBUG) { + printf("%u number of platforms\n", numberOfPlatforms); + } + cl_platform_id *platforms = (cl_platform_id *)MEM_mallocN( + sizeof(cl_platform_id) * numberOfPlatforms, __func__); + error = clGetPlatformIDs(numberOfPlatforms, platforms, nullptr); + unsigned int indexPlatform; + for (indexPlatform = 0; indexPlatform < numberOfPlatforms; indexPlatform++) { + cl_platform_id platform = platforms[indexPlatform]; + cl_uint numberOfDevices = 0; + clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, nullptr, &numberOfDevices); + if (numberOfDevices <= 0) { + continue; + } + + cl_device_id *cldevices = (cl_device_id *)MEM_mallocN( + sizeof(cl_device_id) * numberOfDevices, __func__); + clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, numberOfDevices, cldevices, nullptr); + + g_work_scheduler.opencl_context = clCreateContext( + nullptr, numberOfDevices, cldevices, clContextError, nullptr, &error); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + const char *cl_str[2] = {datatoc_COM_OpenCLKernels_cl, nullptr}; + g_work_scheduler.opencl_program = clCreateProgramWithSource( + g_work_scheduler.opencl_context, 1, cl_str, nullptr, &error); + error = clBuildProgram(g_work_scheduler.opencl_program, + numberOfDevices, + cldevices, + nullptr, + nullptr, + nullptr); + if (error != CL_SUCCESS) { + cl_int error2; + size_t ret_val_size = 0; + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + error2 = clGetProgramBuildInfo(g_work_scheduler.opencl_program, + cldevices[0], + CL_PROGRAM_BUILD_LOG, + 0, + nullptr, + &ret_val_size); + if (error2 != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + char *build_log = (char *)MEM_mallocN(sizeof(char) * ret_val_size + 1, __func__); + error2 = clGetProgramBuildInfo(g_work_scheduler.opencl_program, + cldevices[0], + CL_PROGRAM_BUILD_LOG, + ret_val_size, + build_log, + nullptr); + if (error2 != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + build_log[ret_val_size] = '\0'; + printf("%s", build_log); + MEM_freeN(build_log); + } + else { + unsigned int indexDevices; + for (indexDevices = 0; indexDevices < numberOfDevices; indexDevices++) { + cl_device_id device = cldevices[indexDevices]; + cl_int vendorID = 0; + cl_int error2 = clGetDeviceInfo( + device, CL_DEVICE_VENDOR_ID, sizeof(cl_int), &vendorID, nullptr); + if (error2 != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error2, clewErrorString(error2)); + } + OpenCLDevice *clDevice = new OpenCLDevice(g_work_scheduler.opencl_context, + device, + g_work_scheduler.opencl_program, + vendorID); + clDevice->initialize(); + g_work_scheduler.gpu_devices.push_back(clDevice); + } + } + MEM_freeN(cldevices); + } + MEM_freeN(platforms); + } + + g_work_scheduler.opencl_initialized = true; + } +# endif +#endif +} + +void WorkScheduler::deinitialize() +{ +#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE + /* deinitialize CPU threads */ + if (g_work_scheduler.cpu_initialized) { + Device *device; + while (!g_work_scheduler.cpu_devices.empty()) { + device = g_work_scheduler.cpu_devices.back(); + g_work_scheduler.cpu_devices.pop_back(); + device->deinitialize(); + delete device; + } + BLI_thread_local_delete(g_thread_device); + g_work_scheduler.cpu_initialized = false; + } + +# ifdef COM_OPENCL_ENABLED + /* deinitialize OpenCL GPU's */ + if (g_work_scheduler.opencl_initialized) { + Device *device; + while (!g_work_scheduler.gpu_devices.empty()) { + device = g_work_scheduler.gpu_devices.back(); + g_work_scheduler.gpu_devices.pop_back(); + device->deinitialize(); + delete device; + } + if (g_work_scheduler.opencl_program) { + clReleaseProgram(g_work_scheduler.opencl_program); + g_work_scheduler.opencl_program = nullptr; + } + if (g_work_scheduler.opencl_context) { + clReleaseContext(g_work_scheduler.opencl_context); + g_work_scheduler.opencl_context = nullptr; + } + + g_work_scheduler.opencl_initialized = false; + } +# endif +#endif +} + +int WorkScheduler::current_thread_id() +{ + CPUDevice *device = (CPUDevice *)BLI_thread_local_get(g_thread_device); + return device->thread_id(); +} diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp deleted file mode 100644 index a70b6ba4abe..00000000000 --- a/source/blender/compositor/intern/COM_WorkScheduler.cpp +++ /dev/null @@ -1,394 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include -#include - -#include "COM_CPUDevice.h" -#include "COM_OpenCLDevice.h" -#include "COM_OpenCLKernels.cl.h" -#include "COM_WorkScheduler.h" -#include "COM_WriteBufferOperation.h" -#include "COM_compositor.h" -#include "clew.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_threads.h" -#include "PIL_time.h" - -#include "BKE_global.h" - -#if COM_CURRENT_THREADING_MODEL == COM_TM_NOTHREAD -# ifndef DEBUG /* test this so we dont get warnings in debug builds */ -# warning COM_CURRENT_THREADING_MODEL COM_TM_NOTHREAD is activated. Use only for debugging. -# endif -#elif COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE -/* do nothing - default */ -#else -# error COM_CURRENT_THREADING_MODEL No threading model selected -#endif - -static ThreadLocal(CPUDevice *) g_thread_device; -static struct { - /** \brief list of all CPUDevices. for every hardware thread an instance of CPUDevice is created - */ - std::vector cpu_devices; - -#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE - /** \brief list of all thread for every CPUDevice in cpudevices a thread exists. */ - ListBase cpu_threads; - bool cpu_initialized = false; - /** \brief all scheduled work for the cpu */ - ThreadQueue *cpu_queue; - ThreadQueue *gpu_queue; -# ifdef COM_OPENCL_ENABLED - cl_context opencl_context; - cl_program opencl_program; - /** \brief list of all OpenCLDevices. for every OpenCL GPU device an instance of OpenCLDevice is - * created. */ - std::vector gpu_devices; - /** \brief list of all thread for every GPUDevice in cpudevices a thread exists. */ - ListBase gpu_threads; - /** \brief all scheduled work for the GPU. */ - bool opencl_active = false; - bool opencl_initialized = false; -# endif -#endif - -} g_work_scheduler; - -#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE -void *WorkScheduler::thread_execute_cpu(void *data) -{ - CPUDevice *device = (CPUDevice *)data; - WorkPackage *work; - BLI_thread_local_set(g_thread_device, device); - while ((work = (WorkPackage *)BLI_thread_queue_pop(g_work_scheduler.cpu_queue))) { - device->execute(work); - delete work; - } - - return nullptr; -} - -void *WorkScheduler::thread_execute_gpu(void *data) -{ - Device *device = (Device *)data; - WorkPackage *work; - - while ((work = (WorkPackage *)BLI_thread_queue_pop(g_work_scheduler.gpu_queue))) { - device->execute(work); - delete work; - } - - return nullptr; -} -#endif - -void WorkScheduler::schedule(ExecutionGroup *group, int chunkNumber) -{ - WorkPackage *package = new WorkPackage(group, chunkNumber); -#if COM_CURRENT_THREADING_MODEL == COM_TM_NOTHREAD - CPUDevice device(0); - device.execute(package); - delete package; -#elif COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE -# ifdef COM_OPENCL_ENABLED - if (group->isOpenCL() && g_work_scheduler.opencl_active) { - BLI_thread_queue_push(g_work_scheduler.gpu_queue, package); - } - else { - BLI_thread_queue_push(g_work_scheduler.cpu_queue, package); - } -# else - BLI_thread_queue_push(g_work_scheduler.cpu_queue, package); -# endif -#endif -} - -void WorkScheduler::start(CompositorContext &context) -{ -#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE - unsigned int index; - g_work_scheduler.cpu_queue = BLI_thread_queue_init(); - BLI_threadpool_init( - &g_work_scheduler.cpu_threads, thread_execute_cpu, g_work_scheduler.cpu_devices.size()); - for (index = 0; index < g_work_scheduler.cpu_devices.size(); index++) { - Device *device = g_work_scheduler.cpu_devices[index]; - BLI_threadpool_insert(&g_work_scheduler.cpu_threads, device); - } -# ifdef COM_OPENCL_ENABLED - if (context.getHasActiveOpenCLDevices()) { - g_work_scheduler.gpu_queue = BLI_thread_queue_init(); - BLI_threadpool_init( - &g_work_scheduler.gpu_threads, thread_execute_gpu, g_work_scheduler.gpu_devices.size()); - for (index = 0; index < g_work_scheduler.gpu_devices.size(); index++) { - Device *device = g_work_scheduler.gpu_devices[index]; - BLI_threadpool_insert(&g_work_scheduler.gpu_threads, device); - } - g_work_scheduler.opencl_active = true; - } - else { - g_work_scheduler.opencl_active = false; - } -# endif -#endif -} -void WorkScheduler::finish() -{ -#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE -# ifdef COM_OPENCL_ENABLED - if (g_work_scheduler.opencl_active) { - BLI_thread_queue_wait_finish(g_work_scheduler.gpu_queue); - BLI_thread_queue_wait_finish(g_work_scheduler.cpu_queue); - } - else { - BLI_thread_queue_wait_finish(g_work_scheduler.cpu_queue); - } -# else - BLI_thread_queue_wait_finish(cpuqueue); -# endif -#endif -} -void WorkScheduler::stop() -{ -#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE - BLI_thread_queue_nowait(g_work_scheduler.cpu_queue); - BLI_threadpool_end(&g_work_scheduler.cpu_threads); - BLI_thread_queue_free(g_work_scheduler.cpu_queue); - g_work_scheduler.cpu_queue = nullptr; -# ifdef COM_OPENCL_ENABLED - if (g_work_scheduler.opencl_active) { - BLI_thread_queue_nowait(g_work_scheduler.gpu_queue); - BLI_threadpool_end(&g_work_scheduler.gpu_threads); - BLI_thread_queue_free(g_work_scheduler.gpu_queue); - g_work_scheduler.gpu_queue = nullptr; - } -# endif -#endif -} - -bool WorkScheduler::has_gpu_devices() -{ -#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE -# ifdef COM_OPENCL_ENABLED - return !g_work_scheduler.gpu_devices.empty(); -# else - return 0; -# endif -#else - return 0; -#endif -} - -#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE -static void CL_CALLBACK clContextError(const char *errinfo, - const void * /*private_info*/, - size_t /*cb*/, - void * /*user_data*/) -{ - printf("OPENCL error: %s\n", errinfo); -} -#endif - -void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads) -{ -#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE - /* deinitialize if number of threads doesn't match */ - if (g_work_scheduler.cpu_devices.size() != num_cpu_threads) { - Device *device; - - while (!g_work_scheduler.cpu_devices.empty()) { - device = g_work_scheduler.cpu_devices.back(); - g_work_scheduler.cpu_devices.pop_back(); - device->deinitialize(); - delete device; - } - if (g_work_scheduler.cpu_initialized) { - BLI_thread_local_delete(g_thread_device); - } - g_work_scheduler.cpu_initialized = false; - } - - /* initialize CPU threads */ - if (!g_work_scheduler.cpu_initialized) { - for (int index = 0; index < num_cpu_threads; index++) { - CPUDevice *device = new CPUDevice(index); - device->initialize(); - g_work_scheduler.cpu_devices.push_back(device); - } - BLI_thread_local_create(g_thread_device); - g_work_scheduler.cpu_initialized = true; - } - -# ifdef COM_OPENCL_ENABLED - /* deinitialize OpenCL GPU's */ - if (use_opencl && !g_work_scheduler.opencl_initialized) { - g_work_scheduler.opencl_context = nullptr; - g_work_scheduler.opencl_program = nullptr; - - /* This will check for errors and skip if already initialized. */ - if (clewInit() != CLEW_SUCCESS) { - return; - } - - if (clCreateContextFromType) { - cl_uint numberOfPlatforms = 0; - cl_int error; - error = clGetPlatformIDs(0, nullptr, &numberOfPlatforms); - if (error == -1001) { - } /* GPU not supported */ - else if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - if (G.f & G_DEBUG) { - printf("%u number of platforms\n", numberOfPlatforms); - } - cl_platform_id *platforms = (cl_platform_id *)MEM_mallocN( - sizeof(cl_platform_id) * numberOfPlatforms, __func__); - error = clGetPlatformIDs(numberOfPlatforms, platforms, nullptr); - unsigned int indexPlatform; - for (indexPlatform = 0; indexPlatform < numberOfPlatforms; indexPlatform++) { - cl_platform_id platform = platforms[indexPlatform]; - cl_uint numberOfDevices = 0; - clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, nullptr, &numberOfDevices); - if (numberOfDevices <= 0) { - continue; - } - - cl_device_id *cldevices = (cl_device_id *)MEM_mallocN( - sizeof(cl_device_id) * numberOfDevices, __func__); - clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, numberOfDevices, cldevices, nullptr); - - g_work_scheduler.opencl_context = clCreateContext( - nullptr, numberOfDevices, cldevices, clContextError, nullptr, &error); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - const char *cl_str[2] = {datatoc_COM_OpenCLKernels_cl, nullptr}; - g_work_scheduler.opencl_program = clCreateProgramWithSource( - g_work_scheduler.opencl_context, 1, cl_str, nullptr, &error); - error = clBuildProgram(g_work_scheduler.opencl_program, - numberOfDevices, - cldevices, - nullptr, - nullptr, - nullptr); - if (error != CL_SUCCESS) { - cl_int error2; - size_t ret_val_size = 0; - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - error2 = clGetProgramBuildInfo(g_work_scheduler.opencl_program, - cldevices[0], - CL_PROGRAM_BUILD_LOG, - 0, - nullptr, - &ret_val_size); - if (error2 != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - char *build_log = (char *)MEM_mallocN(sizeof(char) * ret_val_size + 1, __func__); - error2 = clGetProgramBuildInfo(g_work_scheduler.opencl_program, - cldevices[0], - CL_PROGRAM_BUILD_LOG, - ret_val_size, - build_log, - nullptr); - if (error2 != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - build_log[ret_val_size] = '\0'; - printf("%s", build_log); - MEM_freeN(build_log); - } - else { - unsigned int indexDevices; - for (indexDevices = 0; indexDevices < numberOfDevices; indexDevices++) { - cl_device_id device = cldevices[indexDevices]; - cl_int vendorID = 0; - cl_int error2 = clGetDeviceInfo( - device, CL_DEVICE_VENDOR_ID, sizeof(cl_int), &vendorID, nullptr); - if (error2 != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error2, clewErrorString(error2)); - } - OpenCLDevice *clDevice = new OpenCLDevice(g_work_scheduler.opencl_context, - device, - g_work_scheduler.opencl_program, - vendorID); - clDevice->initialize(); - g_work_scheduler.gpu_devices.push_back(clDevice); - } - } - MEM_freeN(cldevices); - } - MEM_freeN(platforms); - } - - g_work_scheduler.opencl_initialized = true; - } -# endif -#endif -} - -void WorkScheduler::deinitialize() -{ -#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE - /* deinitialize CPU threads */ - if (g_work_scheduler.cpu_initialized) { - Device *device; - while (!g_work_scheduler.cpu_devices.empty()) { - device = g_work_scheduler.cpu_devices.back(); - g_work_scheduler.cpu_devices.pop_back(); - device->deinitialize(); - delete device; - } - BLI_thread_local_delete(g_thread_device); - g_work_scheduler.cpu_initialized = false; - } - -# ifdef COM_OPENCL_ENABLED - /* deinitialize OpenCL GPU's */ - if (g_work_scheduler.opencl_initialized) { - Device *device; - while (!g_work_scheduler.gpu_devices.empty()) { - device = g_work_scheduler.gpu_devices.back(); - g_work_scheduler.gpu_devices.pop_back(); - device->deinitialize(); - delete device; - } - if (g_work_scheduler.opencl_program) { - clReleaseProgram(g_work_scheduler.opencl_program); - g_work_scheduler.opencl_program = nullptr; - } - if (g_work_scheduler.opencl_context) { - clReleaseContext(g_work_scheduler.opencl_context); - g_work_scheduler.opencl_context = nullptr; - } - - g_work_scheduler.opencl_initialized = false; - } -# endif -#endif -} - -int WorkScheduler::current_thread_id() -{ - CPUDevice *device = (CPUDevice *)BLI_thread_local_get(g_thread_device); - return device->thread_id(); -} diff --git a/source/blender/compositor/intern/COM_compositor.cc b/source/blender/compositor/intern/COM_compositor.cc new file mode 100644 index 00000000000..68e4f80f91f --- /dev/null +++ b/source/blender/compositor/intern/COM_compositor.cc @@ -0,0 +1,126 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "BLI_threads.h" + +#include "BLT_translation.h" + +#include "BKE_node.h" +#include "BKE_scene.h" + +#include "COM_ExecutionSystem.h" +#include "COM_MovieDistortionOperation.h" +#include "COM_WorkScheduler.h" +#include "COM_compositor.h" +#include "clew.h" + +static struct { + bool is_initialized = false; + ThreadMutex mutex; +} g_compositor; + +/* Make sure node tree has previews. + * Don't create previews in advance, this is done when adding preview operations. + * Reserved preview size is determined by render output for now. */ +static void compositor_init_node_previews(const RenderData *render_data, bNodeTree *node_tree) +{ + /* We fit the aspect into COM_PREVIEW_SIZE x COM_PREVIEW_SIZE image to avoid + * insane preview resolution, which might even overflow preview dimensions. */ + const float aspect = render_data->xsch > 0 ? + (float)render_data->ysch / (float)render_data->xsch : + 1.0f; + int preview_width, preview_height; + if (aspect < 1.0f) { + preview_width = COM_PREVIEW_SIZE; + preview_height = (int)(COM_PREVIEW_SIZE * aspect); + } + else { + preview_width = (int)(COM_PREVIEW_SIZE / aspect); + preview_height = COM_PREVIEW_SIZE; + } + BKE_node_preview_init_tree(node_tree, preview_width, preview_height, false); +} + +static void compositor_reset_node_tree_status(bNodeTree *node_tree) +{ + node_tree->progress(node_tree->prh, 0.0); + node_tree->stats_draw(node_tree->sdh, IFACE_("Compositing")); +} + +void COM_execute(RenderData *render_data, + Scene *scene, + bNodeTree *node_tree, + int rendering, + const ColorManagedViewSettings *viewSettings, + 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 + * initializations can be done lazily. */ + if (!g_compositor.is_initialized) { + BLI_mutex_init(&g_compositor.mutex); + g_compositor.is_initialized = true; + } + + BLI_mutex_lock(&g_compositor.mutex); + + if (node_tree->test_break(node_tree->tbh)) { + /* During editing multiple compositor executions can be triggered. + * Make sure this is the most recent one. */ + BLI_mutex_unlock(&g_compositor.mutex); + return; + } + + compositor_init_node_previews(render_data, node_tree); + compositor_reset_node_tree_status(node_tree); + + /* Initialize workscheduler. */ + const bool use_opencl = (node_tree->flag & NTREE_COM_OPENCL) != 0; + WorkScheduler::initialize(use_opencl, BKE_render_num_threads(render_data)); + + /* Execute. */ + const bool twopass = (node_tree->flag & NTREE_TWO_PASS) && !rendering; + if (twopass) { + ExecutionSystem fast_pass( + render_data, scene, node_tree, rendering, true, viewSettings, displaySettings, viewName); + fast_pass.execute(); + + if (node_tree->test_break(node_tree->tbh)) { + BLI_mutex_unlock(&g_compositor.mutex); + return; + } + } + + ExecutionSystem system( + render_data, scene, node_tree, rendering, false, viewSettings, displaySettings, viewName); + system.execute(); + + BLI_mutex_unlock(&g_compositor.mutex); +} + +void COM_deinitialize() +{ + if (g_compositor.is_initialized) { + BLI_mutex_lock(&g_compositor.mutex); + WorkScheduler::deinitialize(); + g_compositor.is_initialized = false; + BLI_mutex_unlock(&g_compositor.mutex); + BLI_mutex_end(&g_compositor.mutex); + } +} diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp deleted file mode 100644 index 68e4f80f91f..00000000000 --- a/source/blender/compositor/intern/COM_compositor.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "BLI_threads.h" - -#include "BLT_translation.h" - -#include "BKE_node.h" -#include "BKE_scene.h" - -#include "COM_ExecutionSystem.h" -#include "COM_MovieDistortionOperation.h" -#include "COM_WorkScheduler.h" -#include "COM_compositor.h" -#include "clew.h" - -static struct { - bool is_initialized = false; - ThreadMutex mutex; -} g_compositor; - -/* Make sure node tree has previews. - * Don't create previews in advance, this is done when adding preview operations. - * Reserved preview size is determined by render output for now. */ -static void compositor_init_node_previews(const RenderData *render_data, bNodeTree *node_tree) -{ - /* We fit the aspect into COM_PREVIEW_SIZE x COM_PREVIEW_SIZE image to avoid - * insane preview resolution, which might even overflow preview dimensions. */ - const float aspect = render_data->xsch > 0 ? - (float)render_data->ysch / (float)render_data->xsch : - 1.0f; - int preview_width, preview_height; - if (aspect < 1.0f) { - preview_width = COM_PREVIEW_SIZE; - preview_height = (int)(COM_PREVIEW_SIZE * aspect); - } - else { - preview_width = (int)(COM_PREVIEW_SIZE / aspect); - preview_height = COM_PREVIEW_SIZE; - } - BKE_node_preview_init_tree(node_tree, preview_width, preview_height, false); -} - -static void compositor_reset_node_tree_status(bNodeTree *node_tree) -{ - node_tree->progress(node_tree->prh, 0.0); - node_tree->stats_draw(node_tree->sdh, IFACE_("Compositing")); -} - -void COM_execute(RenderData *render_data, - Scene *scene, - bNodeTree *node_tree, - int rendering, - const ColorManagedViewSettings *viewSettings, - 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 - * initializations can be done lazily. */ - if (!g_compositor.is_initialized) { - BLI_mutex_init(&g_compositor.mutex); - g_compositor.is_initialized = true; - } - - BLI_mutex_lock(&g_compositor.mutex); - - if (node_tree->test_break(node_tree->tbh)) { - /* During editing multiple compositor executions can be triggered. - * Make sure this is the most recent one. */ - BLI_mutex_unlock(&g_compositor.mutex); - return; - } - - compositor_init_node_previews(render_data, node_tree); - compositor_reset_node_tree_status(node_tree); - - /* Initialize workscheduler. */ - const bool use_opencl = (node_tree->flag & NTREE_COM_OPENCL) != 0; - WorkScheduler::initialize(use_opencl, BKE_render_num_threads(render_data)); - - /* Execute. */ - const bool twopass = (node_tree->flag & NTREE_TWO_PASS) && !rendering; - if (twopass) { - ExecutionSystem fast_pass( - render_data, scene, node_tree, rendering, true, viewSettings, displaySettings, viewName); - fast_pass.execute(); - - if (node_tree->test_break(node_tree->tbh)) { - BLI_mutex_unlock(&g_compositor.mutex); - return; - } - } - - ExecutionSystem system( - render_data, scene, node_tree, rendering, false, viewSettings, displaySettings, viewName); - system.execute(); - - BLI_mutex_unlock(&g_compositor.mutex); -} - -void COM_deinitialize() -{ - if (g_compositor.is_initialized) { - BLI_mutex_lock(&g_compositor.mutex); - WorkScheduler::deinitialize(); - g_compositor.is_initialized = false; - BLI_mutex_unlock(&g_compositor.mutex); - BLI_mutex_end(&g_compositor.mutex); - } -} diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.cc b/source/blender/compositor/nodes/COM_AlphaOverNode.cc new file mode 100644 index 00000000000..640fbf49808 --- /dev/null +++ b/source/blender/compositor/nodes/COM_AlphaOverNode.cc @@ -0,0 +1,66 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_AlphaOverNode.h" + +#include "COM_AlphaOverKeyOperation.h" +#include "COM_AlphaOverMixedOperation.h" +#include "COM_AlphaOverPremultiplyOperation.h" +#include "COM_MixOperation.h" + +#include "COM_SetValueOperation.h" +#include "DNA_material_types.h" /* the ramp types */ + +void AlphaOverNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *color1Socket = this->getInputSocket(1); + NodeInput *color2Socket = this->getInputSocket(2); + bNode *editorNode = this->getbNode(); + + MixBaseOperation *convertProg; + NodeTwoFloats *ntf = (NodeTwoFloats *)editorNode->storage; + if (ntf->x != 0.0f) { + AlphaOverMixedOperation *mixOperation = new AlphaOverMixedOperation(); + mixOperation->setX(ntf->x); + convertProg = mixOperation; + } + else if (editorNode->custom1) { + convertProg = new AlphaOverKeyOperation(); + } + else { + convertProg = new AlphaOverPremultiplyOperation(); + } + + convertProg->setUseValueAlphaMultiply(false); + if (color1Socket->isLinked()) { + convertProg->setResolutionInputSocketIndex(1); + } + else if (color2Socket->isLinked()) { + convertProg->setResolutionInputSocketIndex(2); + } + else { + convertProg->setResolutionInputSocketIndex(0); + } + + converter.addOperation(convertProg); + converter.mapInputSocket(getInputSocket(0), convertProg->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), convertProg->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), convertProg->getInputSocket(2)); + converter.mapOutputSocket(getOutputSocket(0), convertProg->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp b/source/blender/compositor/nodes/COM_AlphaOverNode.cpp deleted file mode 100644 index 640fbf49808..00000000000 --- a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_AlphaOverNode.h" - -#include "COM_AlphaOverKeyOperation.h" -#include "COM_AlphaOverMixedOperation.h" -#include "COM_AlphaOverPremultiplyOperation.h" -#include "COM_MixOperation.h" - -#include "COM_SetValueOperation.h" -#include "DNA_material_types.h" /* the ramp types */ - -void AlphaOverNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *color1Socket = this->getInputSocket(1); - NodeInput *color2Socket = this->getInputSocket(2); - bNode *editorNode = this->getbNode(); - - MixBaseOperation *convertProg; - NodeTwoFloats *ntf = (NodeTwoFloats *)editorNode->storage; - if (ntf->x != 0.0f) { - AlphaOverMixedOperation *mixOperation = new AlphaOverMixedOperation(); - mixOperation->setX(ntf->x); - convertProg = mixOperation; - } - else if (editorNode->custom1) { - convertProg = new AlphaOverKeyOperation(); - } - else { - convertProg = new AlphaOverPremultiplyOperation(); - } - - convertProg->setUseValueAlphaMultiply(false); - if (color1Socket->isLinked()) { - convertProg->setResolutionInputSocketIndex(1); - } - else if (color2Socket->isLinked()) { - convertProg->setResolutionInputSocketIndex(2); - } - else { - convertProg->setResolutionInputSocketIndex(0); - } - - converter.addOperation(convertProg); - converter.mapInputSocket(getInputSocket(0), convertProg->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), convertProg->getInputSocket(1)); - converter.mapInputSocket(getInputSocket(2), convertProg->getInputSocket(2)); - converter.mapOutputSocket(getOutputSocket(0), convertProg->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_BilateralBlurNode.cc b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc new file mode 100644 index 00000000000..e8037f923f2 --- /dev/null +++ b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc @@ -0,0 +1,41 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BilateralBlurNode.h" +#include "COM_BilateralBlurOperation.h" +#include "COM_ExecutionSystem.h" +#include "DNA_node_types.h" + +BilateralBlurNode::BilateralBlurNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void BilateralBlurNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + NodeBilateralBlurData *data = (NodeBilateralBlurData *)this->getbNode()->storage; + BilateralBlurOperation *operation = new BilateralBlurOperation(); + operation->setQuality(context.getQuality()); + operation->setData(data); + + converter.addOperation(operation); + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_BilateralBlurNode.cpp b/source/blender/compositor/nodes/COM_BilateralBlurNode.cpp deleted file mode 100644 index e8037f923f2..00000000000 --- a/source/blender/compositor/nodes/COM_BilateralBlurNode.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BilateralBlurNode.h" -#include "COM_BilateralBlurOperation.h" -#include "COM_ExecutionSystem.h" -#include "DNA_node_types.h" - -BilateralBlurNode::BilateralBlurNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void BilateralBlurNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - NodeBilateralBlurData *data = (NodeBilateralBlurData *)this->getbNode()->storage; - BilateralBlurOperation *operation = new BilateralBlurOperation(); - operation->setQuality(context.getQuality()); - operation->setData(data); - - converter.addOperation(operation); - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_BlurNode.cc b/source/blender/compositor/nodes/COM_BlurNode.cc new file mode 100644 index 00000000000..b82bede8443 --- /dev/null +++ b/source/blender/compositor/nodes/COM_BlurNode.cc @@ -0,0 +1,170 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BlurNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_FastGaussianBlurOperation.h" +#include "COM_GammaCorrectOperation.h" +#include "COM_GaussianAlphaXBlurOperation.h" +#include "COM_GaussianAlphaYBlurOperation.h" +#include "COM_GaussianBokehBlurOperation.h" +#include "COM_GaussianXBlurOperation.h" +#include "COM_GaussianYBlurOperation.h" +#include "COM_MathBaseOperation.h" +#include "COM_SetValueOperation.h" +#include "DNA_node_types.h" + +BlurNode::BlurNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void BlurNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *editorNode = this->getbNode(); + NodeBlurData *data = (NodeBlurData *)editorNode->storage; + NodeInput *inputSizeSocket = this->getInputSocket(1); + bool connectedSizeSocket = inputSizeSocket->isLinked(); + + const float size = this->getInputSocket(1)->getEditorValueFloat(); + const bool extend_bounds = (editorNode->custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS) != 0; + + CompositorQuality quality = context.getQuality(); + NodeOperation *input_operation = nullptr, *output_operation = nullptr; + + if (data->filtertype == R_FILTER_FAST_GAUSS) { + FastGaussianBlurOperation *operationfgb = new FastGaussianBlurOperation(); + operationfgb->setData(data); + operationfgb->setExtendBounds(extend_bounds); + converter.addOperation(operationfgb); + + converter.mapInputSocket(getInputSocket(1), operationfgb->getInputSocket(1)); + + input_operation = operationfgb; + output_operation = operationfgb; + } + else if (editorNode->custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE) { + MathAddOperation *clamp = new MathAddOperation(); + SetValueOperation *zero = new SetValueOperation(); + zero->setValue(0.0f); + clamp->setUseClamp(true); + + converter.addOperation(clamp); + converter.addOperation(zero); + converter.mapInputSocket(getInputSocket(1), clamp->getInputSocket(0)); + converter.addLink(zero->getOutputSocket(), clamp->getInputSocket(1)); + + GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation(); + operationx->setData(data); + operationx->setQuality(quality); + operationx->setSize(1.0f); + operationx->setFalloff(PROP_SMOOTH); + operationx->setSubtract(false); + operationx->setExtendBounds(extend_bounds); + + converter.addOperation(operationx); + converter.addLink(clamp->getOutputSocket(), operationx->getInputSocket(0)); + + GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation(); + operationy->setData(data); + operationy->setQuality(quality); + operationy->setSize(1.0f); + operationy->setFalloff(PROP_SMOOTH); + operationy->setSubtract(false); + operationy->setExtendBounds(extend_bounds); + + converter.addOperation(operationy); + converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0)); + + GaussianBlurReferenceOperation *operation = new GaussianBlurReferenceOperation(); + operation->setData(data); + operation->setQuality(quality); + operation->setExtendBounds(extend_bounds); + + converter.addOperation(operation); + converter.addLink(operationy->getOutputSocket(), operation->getInputSocket(1)); + + output_operation = operation; + input_operation = operation; + } + else if (!data->bokeh) { + GaussianXBlurOperation *operationx = new GaussianXBlurOperation(); + operationx->setData(data); + operationx->setQuality(quality); + operationx->checkOpenCL(); + operationx->setExtendBounds(extend_bounds); + + converter.addOperation(operationx); + converter.mapInputSocket(getInputSocket(1), operationx->getInputSocket(1)); + + GaussianYBlurOperation *operationy = new GaussianYBlurOperation(); + operationy->setData(data); + operationy->setQuality(quality); + operationy->checkOpenCL(); + operationy->setExtendBounds(extend_bounds); + + converter.addOperation(operationy); + converter.mapInputSocket(getInputSocket(1), operationy->getInputSocket(1)); + converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0)); + + if (!connectedSizeSocket) { + operationx->setSize(size); + operationy->setSize(size); + } + + input_operation = operationx; + output_operation = operationy; + } + else { + GaussianBokehBlurOperation *operation = new GaussianBokehBlurOperation(); + operation->setData(data); + operation->setQuality(quality); + operation->setExtendBounds(extend_bounds); + + converter.addOperation(operation); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + + if (!connectedSizeSocket) { + operation->setSize(size); + } + + input_operation = operation; + output_operation = operation; + } + + if (data->gamma) { + GammaCorrectOperation *correct = new GammaCorrectOperation(); + GammaUncorrectOperation *inverse = new GammaUncorrectOperation(); + converter.addOperation(correct); + converter.addOperation(inverse); + + converter.mapInputSocket(getInputSocket(0), correct->getInputSocket(0)); + converter.addLink(correct->getOutputSocket(), input_operation->getInputSocket(0)); + converter.addLink(output_operation->getOutputSocket(), inverse->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(), inverse->getOutputSocket()); + + converter.addPreview(inverse->getOutputSocket()); + } + else { + converter.mapInputSocket(getInputSocket(0), input_operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(), output_operation->getOutputSocket()); + + converter.addPreview(output_operation->getOutputSocket()); + } +} diff --git a/source/blender/compositor/nodes/COM_BlurNode.cpp b/source/blender/compositor/nodes/COM_BlurNode.cpp deleted file mode 100644 index b82bede8443..00000000000 --- a/source/blender/compositor/nodes/COM_BlurNode.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BlurNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_FastGaussianBlurOperation.h" -#include "COM_GammaCorrectOperation.h" -#include "COM_GaussianAlphaXBlurOperation.h" -#include "COM_GaussianAlphaYBlurOperation.h" -#include "COM_GaussianBokehBlurOperation.h" -#include "COM_GaussianXBlurOperation.h" -#include "COM_GaussianYBlurOperation.h" -#include "COM_MathBaseOperation.h" -#include "COM_SetValueOperation.h" -#include "DNA_node_types.h" - -BlurNode::BlurNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void BlurNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *editorNode = this->getbNode(); - NodeBlurData *data = (NodeBlurData *)editorNode->storage; - NodeInput *inputSizeSocket = this->getInputSocket(1); - bool connectedSizeSocket = inputSizeSocket->isLinked(); - - const float size = this->getInputSocket(1)->getEditorValueFloat(); - const bool extend_bounds = (editorNode->custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS) != 0; - - CompositorQuality quality = context.getQuality(); - NodeOperation *input_operation = nullptr, *output_operation = nullptr; - - if (data->filtertype == R_FILTER_FAST_GAUSS) { - FastGaussianBlurOperation *operationfgb = new FastGaussianBlurOperation(); - operationfgb->setData(data); - operationfgb->setExtendBounds(extend_bounds); - converter.addOperation(operationfgb); - - converter.mapInputSocket(getInputSocket(1), operationfgb->getInputSocket(1)); - - input_operation = operationfgb; - output_operation = operationfgb; - } - else if (editorNode->custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE) { - MathAddOperation *clamp = new MathAddOperation(); - SetValueOperation *zero = new SetValueOperation(); - zero->setValue(0.0f); - clamp->setUseClamp(true); - - converter.addOperation(clamp); - converter.addOperation(zero); - converter.mapInputSocket(getInputSocket(1), clamp->getInputSocket(0)); - converter.addLink(zero->getOutputSocket(), clamp->getInputSocket(1)); - - GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation(); - operationx->setData(data); - operationx->setQuality(quality); - operationx->setSize(1.0f); - operationx->setFalloff(PROP_SMOOTH); - operationx->setSubtract(false); - operationx->setExtendBounds(extend_bounds); - - converter.addOperation(operationx); - converter.addLink(clamp->getOutputSocket(), operationx->getInputSocket(0)); - - GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation(); - operationy->setData(data); - operationy->setQuality(quality); - operationy->setSize(1.0f); - operationy->setFalloff(PROP_SMOOTH); - operationy->setSubtract(false); - operationy->setExtendBounds(extend_bounds); - - converter.addOperation(operationy); - converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0)); - - GaussianBlurReferenceOperation *operation = new GaussianBlurReferenceOperation(); - operation->setData(data); - operation->setQuality(quality); - operation->setExtendBounds(extend_bounds); - - converter.addOperation(operation); - converter.addLink(operationy->getOutputSocket(), operation->getInputSocket(1)); - - output_operation = operation; - input_operation = operation; - } - else if (!data->bokeh) { - GaussianXBlurOperation *operationx = new GaussianXBlurOperation(); - operationx->setData(data); - operationx->setQuality(quality); - operationx->checkOpenCL(); - operationx->setExtendBounds(extend_bounds); - - converter.addOperation(operationx); - converter.mapInputSocket(getInputSocket(1), operationx->getInputSocket(1)); - - GaussianYBlurOperation *operationy = new GaussianYBlurOperation(); - operationy->setData(data); - operationy->setQuality(quality); - operationy->checkOpenCL(); - operationy->setExtendBounds(extend_bounds); - - converter.addOperation(operationy); - converter.mapInputSocket(getInputSocket(1), operationy->getInputSocket(1)); - converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0)); - - if (!connectedSizeSocket) { - operationx->setSize(size); - operationy->setSize(size); - } - - input_operation = operationx; - output_operation = operationy; - } - else { - GaussianBokehBlurOperation *operation = new GaussianBokehBlurOperation(); - operation->setData(data); - operation->setQuality(quality); - operation->setExtendBounds(extend_bounds); - - converter.addOperation(operation); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - - if (!connectedSizeSocket) { - operation->setSize(size); - } - - input_operation = operation; - output_operation = operation; - } - - if (data->gamma) { - GammaCorrectOperation *correct = new GammaCorrectOperation(); - GammaUncorrectOperation *inverse = new GammaUncorrectOperation(); - converter.addOperation(correct); - converter.addOperation(inverse); - - converter.mapInputSocket(getInputSocket(0), correct->getInputSocket(0)); - converter.addLink(correct->getOutputSocket(), input_operation->getInputSocket(0)); - converter.addLink(output_operation->getOutputSocket(), inverse->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(), inverse->getOutputSocket()); - - converter.addPreview(inverse->getOutputSocket()); - } - else { - converter.mapInputSocket(getInputSocket(0), input_operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(), output_operation->getOutputSocket()); - - converter.addPreview(output_operation->getOutputSocket()); - } -} diff --git a/source/blender/compositor/nodes/COM_BokehBlurNode.cc b/source/blender/compositor/nodes/COM_BokehBlurNode.cc new file mode 100644 index 00000000000..5096dbef608 --- /dev/null +++ b/source/blender/compositor/nodes/COM_BokehBlurNode.cc @@ -0,0 +1,77 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BokehBlurNode.h" +#include "COM_BokehBlurOperation.h" +#include "COM_ConvertDepthToRadiusOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_VariableSizeBokehBlurOperation.h" +#include "DNA_camera_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" + +BokehBlurNode::BokehBlurNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void BokehBlurNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *b_node = this->getbNode(); + + NodeInput *inputSizeSocket = this->getInputSocket(2); + + bool connectedSizeSocket = inputSizeSocket->isLinked(); + const bool extend_bounds = (b_node->custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS) != 0; + + if ((b_node->custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE) && connectedSizeSocket) { + VariableSizeBokehBlurOperation *operation = new VariableSizeBokehBlurOperation(); + operation->setQuality(context.getQuality()); + operation->setThreshold(0.0f); + operation->setMaxBlur(b_node->custom4); + operation->setDoScaleSize(true); + + converter.addOperation(operation); + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); + } + else { + BokehBlurOperation *operation = new BokehBlurOperation(); + operation->setQuality(context.getQuality()); + operation->setExtendBounds(extend_bounds); + + converter.addOperation(operation); + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + + // NOTE: on the bokeh blur operation the sockets are switched. + // for this reason the next two lines are correct. + // Fix for T43771 + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(3)); + converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(2)); + + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); + + if (!connectedSizeSocket) { + operation->setSize(this->getInputSocket(2)->getEditorValueFloat()); + } + } +} diff --git a/source/blender/compositor/nodes/COM_BokehBlurNode.cpp b/source/blender/compositor/nodes/COM_BokehBlurNode.cpp deleted file mode 100644 index 5096dbef608..00000000000 --- a/source/blender/compositor/nodes/COM_BokehBlurNode.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BokehBlurNode.h" -#include "COM_BokehBlurOperation.h" -#include "COM_ConvertDepthToRadiusOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_VariableSizeBokehBlurOperation.h" -#include "DNA_camera_types.h" -#include "DNA_node_types.h" -#include "DNA_object_types.h" - -BokehBlurNode::BokehBlurNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void BokehBlurNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *b_node = this->getbNode(); - - NodeInput *inputSizeSocket = this->getInputSocket(2); - - bool connectedSizeSocket = inputSizeSocket->isLinked(); - const bool extend_bounds = (b_node->custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS) != 0; - - if ((b_node->custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE) && connectedSizeSocket) { - VariableSizeBokehBlurOperation *operation = new VariableSizeBokehBlurOperation(); - operation->setQuality(context.getQuality()); - operation->setThreshold(0.0f); - operation->setMaxBlur(b_node->custom4); - operation->setDoScaleSize(true); - - converter.addOperation(operation); - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); - } - else { - BokehBlurOperation *operation = new BokehBlurOperation(); - operation->setQuality(context.getQuality()); - operation->setExtendBounds(extend_bounds); - - converter.addOperation(operation); - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - - // NOTE: on the bokeh blur operation the sockets are switched. - // for this reason the next two lines are correct. - // Fix for T43771 - converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(3)); - converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(2)); - - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); - - if (!connectedSizeSocket) { - operation->setSize(this->getInputSocket(2)->getEditorValueFloat()); - } - } -} diff --git a/source/blender/compositor/nodes/COM_BokehImageNode.cc b/source/blender/compositor/nodes/COM_BokehImageNode.cc new file mode 100644 index 00000000000..87fe4979c1d --- /dev/null +++ b/source/blender/compositor/nodes/COM_BokehImageNode.cc @@ -0,0 +1,38 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BokehImageNode.h" +#include "COM_BokehImageOperation.h" +#include "COM_ExecutionSystem.h" + +BokehImageNode::BokehImageNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void BokehImageNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + BokehImageOperation *operation = new BokehImageOperation(); + operation->setData((NodeBokehImage *)this->getbNode()->storage); + + converter.addOperation(operation); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); + + converter.addPreview(operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_BokehImageNode.cpp b/source/blender/compositor/nodes/COM_BokehImageNode.cpp deleted file mode 100644 index 87fe4979c1d..00000000000 --- a/source/blender/compositor/nodes/COM_BokehImageNode.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BokehImageNode.h" -#include "COM_BokehImageOperation.h" -#include "COM_ExecutionSystem.h" - -BokehImageNode::BokehImageNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void BokehImageNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - BokehImageOperation *operation = new BokehImageOperation(); - operation->setData((NodeBokehImage *)this->getbNode()->storage); - - converter.addOperation(operation); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); - - converter.addPreview(operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_BoxMaskNode.cc b/source/blender/compositor/nodes/COM_BoxMaskNode.cc new file mode 100644 index 00000000000..fe59bd32939 --- /dev/null +++ b/source/blender/compositor/nodes/COM_BoxMaskNode.cc @@ -0,0 +1,72 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BoxMaskNode.h" +#include "COM_BoxMaskOperation.h" +#include "COM_ExecutionSystem.h" + +#include "COM_ScaleOperation.h" +#include "COM_SetValueOperation.h" + +BoxMaskNode::BoxMaskNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void BoxMaskNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeOutput *outputSocket = this->getOutputSocket(0); + + BoxMaskOperation *operation; + operation = new BoxMaskOperation(); + operation->setData((NodeBoxMask *)this->getbNode()->storage); + operation->setMaskType(this->getbNode()->custom1); + converter.addOperation(operation); + + if (inputSocket->isLinked()) { + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); + } + else { + /* Value operation to produce original transparent image */ + SetValueOperation *valueOperation = new SetValueOperation(); + valueOperation->setValue(0.0f); + converter.addOperation(valueOperation); + + /* Scale that image up to render resolution */ + const RenderData *rd = context.getRenderData(); + const float render_size_factor = context.getRenderPercentageAsFactor(); + ScaleFixedSizeOperation *scaleOperation = new ScaleFixedSizeOperation(); + + scaleOperation->setIsAspect(false); + scaleOperation->setIsCrop(false); + scaleOperation->setOffset(0.0f, 0.0f); + scaleOperation->setNewWidth(rd->xsch * render_size_factor); + scaleOperation->setNewHeight(rd->ysch * render_size_factor); + scaleOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); + converter.addOperation(scaleOperation); + + converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); + converter.addLink(scaleOperation->getOutputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + } + + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); +} diff --git a/source/blender/compositor/nodes/COM_BoxMaskNode.cpp b/source/blender/compositor/nodes/COM_BoxMaskNode.cpp deleted file mode 100644 index fe59bd32939..00000000000 --- a/source/blender/compositor/nodes/COM_BoxMaskNode.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BoxMaskNode.h" -#include "COM_BoxMaskOperation.h" -#include "COM_ExecutionSystem.h" - -#include "COM_ScaleOperation.h" -#include "COM_SetValueOperation.h" - -BoxMaskNode::BoxMaskNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void BoxMaskNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - NodeInput *inputSocket = this->getInputSocket(0); - NodeOutput *outputSocket = this->getOutputSocket(0); - - BoxMaskOperation *operation; - operation = new BoxMaskOperation(); - operation->setData((NodeBoxMask *)this->getbNode()->storage); - operation->setMaskType(this->getbNode()->custom1); - converter.addOperation(operation); - - if (inputSocket->isLinked()) { - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); - } - else { - /* Value operation to produce original transparent image */ - SetValueOperation *valueOperation = new SetValueOperation(); - valueOperation->setValue(0.0f); - converter.addOperation(valueOperation); - - /* Scale that image up to render resolution */ - const RenderData *rd = context.getRenderData(); - const float render_size_factor = context.getRenderPercentageAsFactor(); - ScaleFixedSizeOperation *scaleOperation = new ScaleFixedSizeOperation(); - - scaleOperation->setIsAspect(false); - scaleOperation->setIsCrop(false); - scaleOperation->setOffset(0.0f, 0.0f); - scaleOperation->setNewWidth(rd->xsch * render_size_factor); - scaleOperation->setNewHeight(rd->ysch * render_size_factor); - scaleOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); - converter.addOperation(scaleOperation); - - converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); - converter.addLink(scaleOperation->getOutputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); - } - - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); -} diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.cc b/source/blender/compositor/nodes/COM_BrightnessNode.cc new file mode 100644 index 00000000000..fcd2a6de1f4 --- /dev/null +++ b/source/blender/compositor/nodes/COM_BrightnessNode.cc @@ -0,0 +1,40 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BrightnessNode.h" +#include "COM_BrightnessOperation.h" +#include "COM_ExecutionSystem.h" + +BrightnessNode::BrightnessNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void BrightnessNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *bnode = this->getbNode(); + BrightnessOperation *operation = new BrightnessOperation(); + operation->setUsePremultiply((bnode->custom1 & 1) != 0); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.cpp b/source/blender/compositor/nodes/COM_BrightnessNode.cpp deleted file mode 100644 index fcd2a6de1f4..00000000000 --- a/source/blender/compositor/nodes/COM_BrightnessNode.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BrightnessNode.h" -#include "COM_BrightnessOperation.h" -#include "COM_ExecutionSystem.h" - -BrightnessNode::BrightnessNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void BrightnessNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *bnode = this->getbNode(); - BrightnessOperation *operation = new BrightnessOperation(); - operation->setUsePremultiply((bnode->custom1 & 1) != 0); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cc b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc new file mode 100644 index 00000000000..598cd7b7745 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc @@ -0,0 +1,95 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_ChannelMatteNode.h" +#include "BKE_node.h" +#include "COM_ChannelMatteOperation.h" +#include "COM_ConvertOperation.h" +#include "COM_SetAlphaMultiplyOperation.h" + +ChannelMatteNode::ChannelMatteNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ChannelMatteNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *node = this->getbNode(); + + NodeInput *inputSocketImage = this->getInputSocket(0); + NodeOutput *outputSocketImage = this->getOutputSocket(0); + NodeOutput *outputSocketMatte = this->getOutputSocket(1); + + NodeOperation *convert = nullptr, *inv_convert = nullptr; + /* colorspace */ + switch (node->custom1) { + case CMP_NODE_CHANNEL_MATTE_CS_RGB: + break; + case CMP_NODE_CHANNEL_MATTE_CS_HSV: /* HSV */ + convert = new ConvertRGBToHSVOperation(); + inv_convert = new ConvertHSVToRGBOperation(); + break; + case CMP_NODE_CHANNEL_MATTE_CS_YUV: /* YUV */ + convert = new ConvertRGBToYUVOperation(); + inv_convert = new ConvertYUVToRGBOperation(); + break; + case CMP_NODE_CHANNEL_MATTE_CS_YCC: /* YCC */ + convert = new ConvertRGBToYCCOperation(); + ((ConvertRGBToYCCOperation *)convert)->setMode(BLI_YCC_ITU_BT709); + inv_convert = new ConvertYCCToRGBOperation(); + ((ConvertYCCToRGBOperation *)inv_convert)->setMode(BLI_YCC_ITU_BT709); + break; + default: + break; + } + + ChannelMatteOperation *operation = new ChannelMatteOperation(); + /* pass the ui properties to the operation */ + operation->setSettings((NodeChroma *)node->storage, node->custom2); + converter.addOperation(operation); + + SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation(); + converter.addOperation(operationAlpha); + + if (convert != nullptr) { + converter.addOperation(convert); + + converter.mapInputSocket(inputSocketImage, convert->getInputSocket(0)); + converter.addLink(convert->getOutputSocket(), operation->getInputSocket(0)); + converter.addLink(convert->getOutputSocket(), operationAlpha->getInputSocket(0)); + } + else { + converter.mapInputSocket(inputSocketImage, operation->getInputSocket(0)); + converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); + } + + converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0)); + converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1)); + + if (inv_convert != nullptr) { + converter.addOperation(inv_convert); + converter.addLink(operationAlpha->getOutputSocket(0), inv_convert->getInputSocket(0)); + converter.mapOutputSocket(outputSocketImage, inv_convert->getOutputSocket()); + converter.addPreview(inv_convert->getOutputSocket()); + } + else { + converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); + converter.addPreview(operationAlpha->getOutputSocket()); + } +} diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp b/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp deleted file mode 100644 index 598cd7b7745..00000000000 --- a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_ChannelMatteNode.h" -#include "BKE_node.h" -#include "COM_ChannelMatteOperation.h" -#include "COM_ConvertOperation.h" -#include "COM_SetAlphaMultiplyOperation.h" - -ChannelMatteNode::ChannelMatteNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ChannelMatteNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *node = this->getbNode(); - - NodeInput *inputSocketImage = this->getInputSocket(0); - NodeOutput *outputSocketImage = this->getOutputSocket(0); - NodeOutput *outputSocketMatte = this->getOutputSocket(1); - - NodeOperation *convert = nullptr, *inv_convert = nullptr; - /* colorspace */ - switch (node->custom1) { - case CMP_NODE_CHANNEL_MATTE_CS_RGB: - break; - case CMP_NODE_CHANNEL_MATTE_CS_HSV: /* HSV */ - convert = new ConvertRGBToHSVOperation(); - inv_convert = new ConvertHSVToRGBOperation(); - break; - case CMP_NODE_CHANNEL_MATTE_CS_YUV: /* YUV */ - convert = new ConvertRGBToYUVOperation(); - inv_convert = new ConvertYUVToRGBOperation(); - break; - case CMP_NODE_CHANNEL_MATTE_CS_YCC: /* YCC */ - convert = new ConvertRGBToYCCOperation(); - ((ConvertRGBToYCCOperation *)convert)->setMode(BLI_YCC_ITU_BT709); - inv_convert = new ConvertYCCToRGBOperation(); - ((ConvertYCCToRGBOperation *)inv_convert)->setMode(BLI_YCC_ITU_BT709); - break; - default: - break; - } - - ChannelMatteOperation *operation = new ChannelMatteOperation(); - /* pass the ui properties to the operation */ - operation->setSettings((NodeChroma *)node->storage, node->custom2); - converter.addOperation(operation); - - SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation(); - converter.addOperation(operationAlpha); - - if (convert != nullptr) { - converter.addOperation(convert); - - converter.mapInputSocket(inputSocketImage, convert->getInputSocket(0)); - converter.addLink(convert->getOutputSocket(), operation->getInputSocket(0)); - converter.addLink(convert->getOutputSocket(), operationAlpha->getInputSocket(0)); - } - else { - converter.mapInputSocket(inputSocketImage, operation->getInputSocket(0)); - converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); - } - - converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0)); - converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1)); - - if (inv_convert != nullptr) { - converter.addOperation(inv_convert); - converter.addLink(operationAlpha->getOutputSocket(0), inv_convert->getInputSocket(0)); - converter.mapOutputSocket(outputSocketImage, inv_convert->getOutputSocket()); - converter.addPreview(inv_convert->getOutputSocket()); - } - else { - converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); - converter.addPreview(operationAlpha->getOutputSocket()); - } -} diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.cc b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc new file mode 100644 index 00000000000..83e88b35f92 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc @@ -0,0 +1,65 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ChromaMatteNode.h" +#include "BKE_node.h" +#include "COM_ChromaMatteOperation.h" +#include "COM_ConvertOperation.h" +#include "COM_SetAlphaMultiplyOperation.h" + +ChromaMatteNode::ChromaMatteNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ChromaMatteNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *editorsnode = getbNode(); + + NodeInput *inputSocketImage = this->getInputSocket(0); + NodeInput *inputSocketKey = this->getInputSocket(1); + NodeOutput *outputSocketImage = this->getOutputSocket(0); + NodeOutput *outputSocketMatte = this->getOutputSocket(1); + + ConvertRGBToYCCOperation *operationRGBToYCC_Image = new ConvertRGBToYCCOperation(); + ConvertRGBToYCCOperation *operationRGBToYCC_Key = new ConvertRGBToYCCOperation(); + operationRGBToYCC_Image->setMode(BLI_YCC_ITU_BT709); + operationRGBToYCC_Key->setMode(BLI_YCC_ITU_BT709); + converter.addOperation(operationRGBToYCC_Image); + converter.addOperation(operationRGBToYCC_Key); + + ChromaMatteOperation *operation = new ChromaMatteOperation(); + operation->setSettings((NodeChroma *)editorsnode->storage); + converter.addOperation(operation); + + SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation(); + converter.addOperation(operationAlpha); + + converter.mapInputSocket(inputSocketImage, operationRGBToYCC_Image->getInputSocket(0)); + converter.mapInputSocket(inputSocketKey, operationRGBToYCC_Key->getInputSocket(0)); + converter.addLink(operationRGBToYCC_Image->getOutputSocket(), operation->getInputSocket(0)); + converter.addLink(operationRGBToYCC_Key->getOutputSocket(), operation->getInputSocket(1)); + converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket()); + + converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); + converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1)); + converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); + + converter.addPreview(operationAlpha->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp b/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp deleted file mode 100644 index 83e88b35f92..00000000000 --- a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ChromaMatteNode.h" -#include "BKE_node.h" -#include "COM_ChromaMatteOperation.h" -#include "COM_ConvertOperation.h" -#include "COM_SetAlphaMultiplyOperation.h" - -ChromaMatteNode::ChromaMatteNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ChromaMatteNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *editorsnode = getbNode(); - - NodeInput *inputSocketImage = this->getInputSocket(0); - NodeInput *inputSocketKey = this->getInputSocket(1); - NodeOutput *outputSocketImage = this->getOutputSocket(0); - NodeOutput *outputSocketMatte = this->getOutputSocket(1); - - ConvertRGBToYCCOperation *operationRGBToYCC_Image = new ConvertRGBToYCCOperation(); - ConvertRGBToYCCOperation *operationRGBToYCC_Key = new ConvertRGBToYCCOperation(); - operationRGBToYCC_Image->setMode(BLI_YCC_ITU_BT709); - operationRGBToYCC_Key->setMode(BLI_YCC_ITU_BT709); - converter.addOperation(operationRGBToYCC_Image); - converter.addOperation(operationRGBToYCC_Key); - - ChromaMatteOperation *operation = new ChromaMatteOperation(); - operation->setSettings((NodeChroma *)editorsnode->storage); - converter.addOperation(operation); - - SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation(); - converter.addOperation(operationAlpha); - - converter.mapInputSocket(inputSocketImage, operationRGBToYCC_Image->getInputSocket(0)); - converter.mapInputSocket(inputSocketKey, operationRGBToYCC_Key->getInputSocket(0)); - converter.addLink(operationRGBToYCC_Image->getOutputSocket(), operation->getInputSocket(0)); - converter.addLink(operationRGBToYCC_Key->getOutputSocket(), operation->getInputSocket(1)); - converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket()); - - converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); - converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1)); - converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); - - converter.addPreview(operationAlpha->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.cc b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc new file mode 100644 index 00000000000..596d9631297 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc @@ -0,0 +1,73 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorBalanceNode.h" +#include "BKE_node.h" +#include "COM_ColorBalanceASCCDLOperation.h" +#include "COM_ColorBalanceLGGOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_MixOperation.h" + +ColorBalanceNode::ColorBalanceNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ColorBalanceNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *node = this->getbNode(); + NodeColorBalance *n = (NodeColorBalance *)node->storage; + + NodeInput *inputSocket = this->getInputSocket(0); + NodeInput *inputImageSocket = this->getInputSocket(1); + NodeOutput *outputSocket = this->getOutputSocket(0); + + NodeOperation *operation; + if (node->custom1 == 0) { + ColorBalanceLGGOperation *operationLGG = new ColorBalanceLGGOperation(); + + float lift_lgg[3], gamma_inv[3]; + for (int c = 0; c < 3; c++) { + lift_lgg[c] = 2.0f - n->lift[c]; + gamma_inv[c] = (n->gamma[c] != 0.0f) ? 1.0f / n->gamma[c] : 1000000.0f; + } + + operationLGG->setGain(n->gain); + operationLGG->setLift(lift_lgg); + operationLGG->setGammaInv(gamma_inv); + operation = operationLGG; + } + else { + ColorBalanceASCCDLOperation *operationCDL = new ColorBalanceASCCDLOperation(); + + float offset[3]; + copy_v3_fl(offset, n->offset_basis); + add_v3_v3(offset, n->offset); + + operationCDL->setOffset(offset); + operationCDL->setPower(n->power); + operationCDL->setSlope(n->slope); + operation = operationCDL; + } + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapInputSocket(inputImageSocket, operation->getInputSocket(1)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp b/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp deleted file mode 100644 index 596d9631297..00000000000 --- a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorBalanceNode.h" -#include "BKE_node.h" -#include "COM_ColorBalanceASCCDLOperation.h" -#include "COM_ColorBalanceLGGOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_MixOperation.h" - -ColorBalanceNode::ColorBalanceNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ColorBalanceNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *node = this->getbNode(); - NodeColorBalance *n = (NodeColorBalance *)node->storage; - - NodeInput *inputSocket = this->getInputSocket(0); - NodeInput *inputImageSocket = this->getInputSocket(1); - NodeOutput *outputSocket = this->getOutputSocket(0); - - NodeOperation *operation; - if (node->custom1 == 0) { - ColorBalanceLGGOperation *operationLGG = new ColorBalanceLGGOperation(); - - float lift_lgg[3], gamma_inv[3]; - for (int c = 0; c < 3; c++) { - lift_lgg[c] = 2.0f - n->lift[c]; - gamma_inv[c] = (n->gamma[c] != 0.0f) ? 1.0f / n->gamma[c] : 1000000.0f; - } - - operationLGG->setGain(n->gain); - operationLGG->setLift(lift_lgg); - operationLGG->setGammaInv(gamma_inv); - operation = operationLGG; - } - else { - ColorBalanceASCCDLOperation *operationCDL = new ColorBalanceASCCDLOperation(); - - float offset[3]; - copy_v3_fl(offset, n->offset_basis); - add_v3_v3(offset, n->offset); - - operationCDL->setOffset(offset); - operationCDL->setPower(n->power); - operationCDL->setSlope(n->slope); - operation = operationCDL; - } - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.mapInputSocket(inputImageSocket, operation->getInputSocket(1)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc new file mode 100644 index 00000000000..92b334fddb9 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc @@ -0,0 +1,43 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorCorrectionNode.h" +#include "COM_ColorCorrectionOperation.h" +#include "COM_ExecutionSystem.h" + +ColorCorrectionNode::ColorCorrectionNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ColorCorrectionNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *editorNode = getbNode(); + + ColorCorrectionOperation *operation = new ColorCorrectionOperation(); + operation->setData((NodeColorCorrection *)editorNode->storage); + operation->setRedChannelEnabled((editorNode->custom1 & 1) != 0); + operation->setGreenChannelEnabled((editorNode->custom1 & 2) != 0); + operation->setBlueChannelEnabled((editorNode->custom1 & 4) != 0); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp deleted file mode 100644 index 92b334fddb9..00000000000 --- a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorCorrectionNode.h" -#include "COM_ColorCorrectionOperation.h" -#include "COM_ExecutionSystem.h" - -ColorCorrectionNode::ColorCorrectionNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ColorCorrectionNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *editorNode = getbNode(); - - ColorCorrectionOperation *operation = new ColorCorrectionOperation(); - operation->setData((NodeColorCorrection *)editorNode->storage); - operation->setRedChannelEnabled((editorNode->custom1 & 1) != 0); - operation->setGreenChannelEnabled((editorNode->custom1 & 2) != 0); - operation->setBlueChannelEnabled((editorNode->custom1 & 4) != 0); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_ColorCurveNode.cc b/source/blender/compositor/nodes/COM_ColorCurveNode.cc new file mode 100644 index 00000000000..e1888f3f0bc --- /dev/null +++ b/source/blender/compositor/nodes/COM_ColorCurveNode.cc @@ -0,0 +1,57 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorCurveNode.h" +#include "COM_ColorCurveOperation.h" +#include "COM_ExecutionSystem.h" + +ColorCurveNode::ColorCurveNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ColorCurveNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + if (this->getInputSocket(2)->isLinked() || this->getInputSocket(3)->isLinked()) { + ColorCurveOperation *operation = new ColorCurveOperation(); + operation->setCurveMapping((CurveMapping *)this->getbNode()->storage); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); + converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(3)); + + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); + } + else { + ConstantLevelColorCurveOperation *operation = new ConstantLevelColorCurveOperation(); + float col[4]; + this->getInputSocket(2)->getEditorValueColor(col); + operation->setBlackLevel(col); + this->getInputSocket(3)->getEditorValueColor(col); + operation->setWhiteLevel(col); + operation->setCurveMapping((CurveMapping *)this->getbNode()->storage); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); + } +} diff --git a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp b/source/blender/compositor/nodes/COM_ColorCurveNode.cpp deleted file mode 100644 index e1888f3f0bc..00000000000 --- a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorCurveNode.h" -#include "COM_ColorCurveOperation.h" -#include "COM_ExecutionSystem.h" - -ColorCurveNode::ColorCurveNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ColorCurveNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - if (this->getInputSocket(2)->isLinked() || this->getInputSocket(3)->isLinked()) { - ColorCurveOperation *operation = new ColorCurveOperation(); - operation->setCurveMapping((CurveMapping *)this->getbNode()->storage); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); - converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(3)); - - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); - } - else { - ConstantLevelColorCurveOperation *operation = new ConstantLevelColorCurveOperation(); - float col[4]; - this->getInputSocket(2)->getEditorValueColor(col); - operation->setBlackLevel(col); - this->getInputSocket(3)->getEditorValueColor(col); - operation->setWhiteLevel(col); - operation->setCurveMapping((CurveMapping *)this->getbNode()->storage); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); - } -} diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.cc b/source/blender/compositor/nodes/COM_ColorExposureNode.cc new file mode 100644 index 00000000000..cd0285ac373 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ColorExposureNode.cc @@ -0,0 +1,37 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +#include "COM_ColorExposureNode.h" +#include "COM_ColorExposureOperation.h" +#include "COM_ExecutionSystem.h" + +ExposureNode::ExposureNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ExposureNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + ExposureOperation *operation = new ExposureOperation(); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.cpp b/source/blender/compositor/nodes/COM_ColorExposureNode.cpp deleted file mode 100644 index cd0285ac373..00000000000 --- a/source/blender/compositor/nodes/COM_ColorExposureNode.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - * - * Copyright 2020, Blender Foundation. - */ - -#include "COM_ColorExposureNode.h" -#include "COM_ColorExposureOperation.h" -#include "COM_ExecutionSystem.h" - -ExposureNode::ExposureNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ExposureNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - ExposureOperation *operation = new ExposureOperation(); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.cc b/source/blender/compositor/nodes/COM_ColorMatteNode.cc new file mode 100644 index 00000000000..865eee5427f --- /dev/null +++ b/source/blender/compositor/nodes/COM_ColorMatteNode.cc @@ -0,0 +1,63 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorMatteNode.h" +#include "BKE_node.h" +#include "COM_ColorMatteOperation.h" +#include "COM_ConvertOperation.h" +#include "COM_SetAlphaMultiplyOperation.h" + +ColorMatteNode::ColorMatteNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ColorMatteNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *editorsnode = getbNode(); + + NodeInput *inputSocketImage = this->getInputSocket(0); + NodeInput *inputSocketKey = this->getInputSocket(1); + NodeOutput *outputSocketImage = this->getOutputSocket(0); + NodeOutput *outputSocketMatte = this->getOutputSocket(1); + + ConvertRGBToHSVOperation *operationRGBToHSV_Image = new ConvertRGBToHSVOperation(); + ConvertRGBToHSVOperation *operationRGBToHSV_Key = new ConvertRGBToHSVOperation(); + converter.addOperation(operationRGBToHSV_Image); + converter.addOperation(operationRGBToHSV_Key); + + ColorMatteOperation *operation = new ColorMatteOperation(); + operation->setSettings((NodeChroma *)editorsnode->storage); + converter.addOperation(operation); + + SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation(); + converter.addOperation(operationAlpha); + + converter.mapInputSocket(inputSocketImage, operationRGBToHSV_Image->getInputSocket(0)); + converter.mapInputSocket(inputSocketKey, operationRGBToHSV_Key->getInputSocket(0)); + converter.addLink(operationRGBToHSV_Image->getOutputSocket(), operation->getInputSocket(0)); + converter.addLink(operationRGBToHSV_Key->getOutputSocket(), operation->getInputSocket(1)); + converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0)); + + converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); + converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1)); + converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); + + converter.addPreview(operationAlpha->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp b/source/blender/compositor/nodes/COM_ColorMatteNode.cpp deleted file mode 100644 index 865eee5427f..00000000000 --- a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorMatteNode.h" -#include "BKE_node.h" -#include "COM_ColorMatteOperation.h" -#include "COM_ConvertOperation.h" -#include "COM_SetAlphaMultiplyOperation.h" - -ColorMatteNode::ColorMatteNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ColorMatteNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *editorsnode = getbNode(); - - NodeInput *inputSocketImage = this->getInputSocket(0); - NodeInput *inputSocketKey = this->getInputSocket(1); - NodeOutput *outputSocketImage = this->getOutputSocket(0); - NodeOutput *outputSocketMatte = this->getOutputSocket(1); - - ConvertRGBToHSVOperation *operationRGBToHSV_Image = new ConvertRGBToHSVOperation(); - ConvertRGBToHSVOperation *operationRGBToHSV_Key = new ConvertRGBToHSVOperation(); - converter.addOperation(operationRGBToHSV_Image); - converter.addOperation(operationRGBToHSV_Key); - - ColorMatteOperation *operation = new ColorMatteOperation(); - operation->setSettings((NodeChroma *)editorsnode->storage); - converter.addOperation(operation); - - SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation(); - converter.addOperation(operationAlpha); - - converter.mapInputSocket(inputSocketImage, operationRGBToHSV_Image->getInputSocket(0)); - converter.mapInputSocket(inputSocketKey, operationRGBToHSV_Key->getInputSocket(0)); - converter.addLink(operationRGBToHSV_Image->getOutputSocket(), operation->getInputSocket(0)); - converter.addLink(operationRGBToHSV_Key->getOutputSocket(), operation->getInputSocket(1)); - converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0)); - - converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); - converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1)); - converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); - - converter.addPreview(operationAlpha->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_ColorNode.cc b/source/blender/compositor/nodes/COM_ColorNode.cc new file mode 100644 index 00000000000..e6f8bfa01fe --- /dev/null +++ b/source/blender/compositor/nodes/COM_ColorNode.cc @@ -0,0 +1,39 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_SetColorOperation.h" + +ColorNode::ColorNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ColorNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + SetColorOperation *operation = new SetColorOperation(); + NodeOutput *output = this->getOutputSocket(0); + float col[4]; + output->getEditorValueColor(col); + operation->setChannels(col); + converter.addOperation(operation); + + converter.mapOutputSocket(output, operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_ColorNode.cpp b/source/blender/compositor/nodes/COM_ColorNode.cpp deleted file mode 100644 index e6f8bfa01fe..00000000000 --- a/source/blender/compositor/nodes/COM_ColorNode.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_SetColorOperation.h" - -ColorNode::ColorNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ColorNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - SetColorOperation *operation = new SetColorOperation(); - NodeOutput *output = this->getOutputSocket(0); - float col[4]; - output->getEditorValueColor(col); - operation->setChannels(col); - converter.addOperation(operation); - - converter.mapOutputSocket(output, operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.cc b/source/blender/compositor/nodes/COM_ColorRampNode.cc new file mode 100644 index 00000000000..1504a76cee7 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ColorRampNode.cc @@ -0,0 +1,52 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorRampNode.h" +#include "BKE_node.h" +#include "COM_ColorRampOperation.h" +#include "COM_ConvertOperation.h" +#include "COM_ExecutionSystem.h" +#include "DNA_texture_types.h" + +ColorRampNode::ColorRampNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ColorRampNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeOutput *outputSocket = this->getOutputSocket(0); + NodeOutput *outputSocketAlpha = this->getOutputSocket(1); + bNode *editorNode = this->getbNode(); + + ColorRampOperation *operation = new ColorRampOperation(); + operation->setColorBand((ColorBand *)editorNode->storage); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + + SeparateChannelOperation *operation2 = new SeparateChannelOperation(); + operation2->setChannel(3); + converter.addOperation(operation2); + + converter.addLink(operation->getOutputSocket(), operation2->getInputSocket(0)); + converter.mapOutputSocket(outputSocketAlpha, operation2->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.cpp b/source/blender/compositor/nodes/COM_ColorRampNode.cpp deleted file mode 100644 index 1504a76cee7..00000000000 --- a/source/blender/compositor/nodes/COM_ColorRampNode.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorRampNode.h" -#include "BKE_node.h" -#include "COM_ColorRampOperation.h" -#include "COM_ConvertOperation.h" -#include "COM_ExecutionSystem.h" -#include "DNA_texture_types.h" - -ColorRampNode::ColorRampNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ColorRampNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *inputSocket = this->getInputSocket(0); - NodeOutput *outputSocket = this->getOutputSocket(0); - NodeOutput *outputSocketAlpha = this->getOutputSocket(1); - bNode *editorNode = this->getbNode(); - - ColorRampOperation *operation = new ColorRampOperation(); - operation->setColorBand((ColorBand *)editorNode->storage); - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); - - SeparateChannelOperation *operation2 = new SeparateChannelOperation(); - operation2->setChannel(3); - converter.addOperation(operation2); - - converter.addLink(operation->getOutputSocket(), operation2->getInputSocket(0)); - converter.mapOutputSocket(outputSocketAlpha, operation2->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_ColorSpillNode.cc b/source/blender/compositor/nodes/COM_ColorSpillNode.cc new file mode 100644 index 00000000000..d1a3099e998 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ColorSpillNode.cc @@ -0,0 +1,47 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorSpillNode.h" +#include "BKE_node.h" +#include "COM_ColorSpillOperation.h" + +ColorSpillNode::ColorSpillNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ColorSpillNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *editorsnode = getbNode(); + + NodeInput *inputSocketImage = this->getInputSocket(0); + NodeInput *inputSocketFac = this->getInputSocket(1); + NodeOutput *outputSocketImage = this->getOutputSocket(0); + + ColorSpillOperation *operation; + operation = new ColorSpillOperation(); + operation->setSettings((NodeColorspill *)editorsnode->storage); + operation->setSpillChannel(editorsnode->custom1 - 1); // Channel for spilling + operation->setSpillMethod(editorsnode->custom2); // Channel method + converter.addOperation(operation); + + converter.mapInputSocket(inputSocketImage, operation->getInputSocket(0)); + converter.mapInputSocket(inputSocketFac, operation->getInputSocket(1)); + converter.mapOutputSocket(outputSocketImage, operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp b/source/blender/compositor/nodes/COM_ColorSpillNode.cpp deleted file mode 100644 index d1a3099e998..00000000000 --- a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorSpillNode.h" -#include "BKE_node.h" -#include "COM_ColorSpillOperation.h" - -ColorSpillNode::ColorSpillNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ColorSpillNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *editorsnode = getbNode(); - - NodeInput *inputSocketImage = this->getInputSocket(0); - NodeInput *inputSocketFac = this->getInputSocket(1); - NodeOutput *outputSocketImage = this->getOutputSocket(0); - - ColorSpillOperation *operation; - operation = new ColorSpillOperation(); - operation->setSettings((NodeColorspill *)editorsnode->storage); - operation->setSpillChannel(editorsnode->custom1 - 1); // Channel for spilling - operation->setSpillMethod(editorsnode->custom2); // Channel method - converter.addOperation(operation); - - converter.mapInputSocket(inputSocketImage, operation->getInputSocket(0)); - converter.mapInputSocket(inputSocketFac, operation->getInputSocket(1)); - converter.mapOutputSocket(outputSocketImage, operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.cc b/source/blender/compositor/nodes/COM_ColorToBWNode.cc new file mode 100644 index 00000000000..4115bad5d3f --- /dev/null +++ b/source/blender/compositor/nodes/COM_ColorToBWNode.cc @@ -0,0 +1,40 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorToBWNode.h" + +#include "COM_ConvertOperation.h" +#include "COM_ExecutionSystem.h" + +ColorToBWNode::ColorToBWNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ColorToBWNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *colorSocket = this->getInputSocket(0); + NodeOutput *valueSocket = this->getOutputSocket(0); + + ConvertColorToBWOperation *convertProg = new ConvertColorToBWOperation(); + converter.addOperation(convertProg); + + converter.mapInputSocket(colorSocket, convertProg->getInputSocket(0)); + converter.mapOutputSocket(valueSocket, convertProg->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp b/source/blender/compositor/nodes/COM_ColorToBWNode.cpp deleted file mode 100644 index 4115bad5d3f..00000000000 --- a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorToBWNode.h" - -#include "COM_ConvertOperation.h" -#include "COM_ExecutionSystem.h" - -ColorToBWNode::ColorToBWNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ColorToBWNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *colorSocket = this->getInputSocket(0); - NodeOutput *valueSocket = this->getOutputSocket(0); - - ConvertColorToBWOperation *convertProg = new ConvertColorToBWOperation(); - converter.addOperation(convertProg); - - converter.mapInputSocket(colorSocket, convertProg->getInputSocket(0)); - converter.mapOutputSocket(valueSocket, convertProg->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.cc b/source/blender/compositor/nodes/COM_CombineColorNode.cc new file mode 100644 index 00000000000..12968f06a10 --- /dev/null +++ b/source/blender/compositor/nodes/COM_CombineColorNode.cc @@ -0,0 +1,89 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_CombineColorNode.h" + +#include "COM_ConvertOperation.h" + +CombineColorNode::CombineColorNode(bNode *editorNode) : Node(editorNode) +{ +} + +void CombineColorNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + NodeInput *inputRSocket = this->getInputSocket(0); + NodeInput *inputGSocket = this->getInputSocket(1); + NodeInput *inputBSocket = this->getInputSocket(2); + NodeInput *inputASocket = this->getInputSocket(3); + NodeOutput *outputSocket = this->getOutputSocket(0); + + CombineChannelsOperation *operation = new CombineChannelsOperation(); + if (inputRSocket->isLinked()) { + operation->setResolutionInputSocketIndex(0); + } + else if (inputGSocket->isLinked()) { + operation->setResolutionInputSocketIndex(1); + } + else if (inputBSocket->isLinked()) { + operation->setResolutionInputSocketIndex(2); + } + else { + operation->setResolutionInputSocketIndex(3); + } + converter.addOperation(operation); + + converter.mapInputSocket(inputRSocket, operation->getInputSocket(0)); + converter.mapInputSocket(inputGSocket, operation->getInputSocket(1)); + converter.mapInputSocket(inputBSocket, operation->getInputSocket(2)); + converter.mapInputSocket(inputASocket, operation->getInputSocket(3)); + + NodeOperation *color_conv = getColorConverter(context); + if (color_conv) { + converter.addOperation(color_conv); + + converter.addLink(operation->getOutputSocket(), color_conv->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, color_conv->getOutputSocket()); + } + else { + converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); + } +} + +NodeOperation *CombineRGBANode::getColorConverter(const CompositorContext & /*context*/) const +{ + return nullptr; /* no conversion needed */ +} + +NodeOperation *CombineHSVANode::getColorConverter(const CompositorContext & /*context*/) const +{ + return new ConvertHSVToRGBOperation(); +} + +NodeOperation *CombineYCCANode::getColorConverter(const CompositorContext & /*context*/) const +{ + ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation(); + bNode *editorNode = this->getbNode(); + operation->setMode(editorNode->custom1); + return operation; +} + +NodeOperation *CombineYUVANode::getColorConverter(const CompositorContext & /*context*/) const +{ + return new ConvertYUVToRGBOperation(); +} diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.cpp b/source/blender/compositor/nodes/COM_CombineColorNode.cpp deleted file mode 100644 index 12968f06a10..00000000000 --- a/source/blender/compositor/nodes/COM_CombineColorNode.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_CombineColorNode.h" - -#include "COM_ConvertOperation.h" - -CombineColorNode::CombineColorNode(bNode *editorNode) : Node(editorNode) -{ -} - -void CombineColorNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - NodeInput *inputRSocket = this->getInputSocket(0); - NodeInput *inputGSocket = this->getInputSocket(1); - NodeInput *inputBSocket = this->getInputSocket(2); - NodeInput *inputASocket = this->getInputSocket(3); - NodeOutput *outputSocket = this->getOutputSocket(0); - - CombineChannelsOperation *operation = new CombineChannelsOperation(); - if (inputRSocket->isLinked()) { - operation->setResolutionInputSocketIndex(0); - } - else if (inputGSocket->isLinked()) { - operation->setResolutionInputSocketIndex(1); - } - else if (inputBSocket->isLinked()) { - operation->setResolutionInputSocketIndex(2); - } - else { - operation->setResolutionInputSocketIndex(3); - } - converter.addOperation(operation); - - converter.mapInputSocket(inputRSocket, operation->getInputSocket(0)); - converter.mapInputSocket(inputGSocket, operation->getInputSocket(1)); - converter.mapInputSocket(inputBSocket, operation->getInputSocket(2)); - converter.mapInputSocket(inputASocket, operation->getInputSocket(3)); - - NodeOperation *color_conv = getColorConverter(context); - if (color_conv) { - converter.addOperation(color_conv); - - converter.addLink(operation->getOutputSocket(), color_conv->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, color_conv->getOutputSocket()); - } - else { - converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); - } -} - -NodeOperation *CombineRGBANode::getColorConverter(const CompositorContext & /*context*/) const -{ - return nullptr; /* no conversion needed */ -} - -NodeOperation *CombineHSVANode::getColorConverter(const CompositorContext & /*context*/) const -{ - return new ConvertHSVToRGBOperation(); -} - -NodeOperation *CombineYCCANode::getColorConverter(const CompositorContext & /*context*/) const -{ - ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation(); - bNode *editorNode = this->getbNode(); - operation->setMode(editorNode->custom1); - return operation; -} - -NodeOperation *CombineYUVANode::getColorConverter(const CompositorContext & /*context*/) const -{ - return new ConvertYUVToRGBOperation(); -} diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cc b/source/blender/compositor/nodes/COM_CompositorNode.cc new file mode 100644 index 00000000000..32ac1fccec9 --- /dev/null +++ b/source/blender/compositor/nodes/COM_CompositorNode.cc @@ -0,0 +1,61 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_CompositorNode.h" +#include "COM_CompositorOperation.h" +#include "COM_ExecutionSystem.h" + +CompositorNode::CompositorNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void CompositorNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *editorNode = this->getbNode(); + bool is_active = (editorNode->flag & NODE_DO_OUTPUT_RECALC) || context.isRendering(); + bool ignore_alpha = (editorNode->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA) != 0; + + NodeInput *imageSocket = this->getInputSocket(0); + NodeInput *alphaSocket = this->getInputSocket(1); + NodeInput *depthSocket = this->getInputSocket(2); + + CompositorOperation *compositorOperation = new CompositorOperation(); + compositorOperation->setScene(context.getScene()); + 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()); + compositorOperation->setActive(is_active); + + converter.addOperation(compositorOperation); + converter.mapInputSocket(imageSocket, compositorOperation->getInputSocket(0)); + /* only use alpha link if "use alpha" is enabled */ + if (ignore_alpha) { + converter.addInputValue(compositorOperation->getInputSocket(1), 1.0f); + } + else { + converter.mapInputSocket(alphaSocket, compositorOperation->getInputSocket(1)); + } + converter.mapInputSocket(depthSocket, compositorOperation->getInputSocket(2)); + + converter.addNodeInputPreview(imageSocket); +} diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cpp deleted file mode 100644 index 32ac1fccec9..00000000000 --- a/source/blender/compositor/nodes/COM_CompositorNode.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_CompositorNode.h" -#include "COM_CompositorOperation.h" -#include "COM_ExecutionSystem.h" - -CompositorNode::CompositorNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void CompositorNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *editorNode = this->getbNode(); - bool is_active = (editorNode->flag & NODE_DO_OUTPUT_RECALC) || context.isRendering(); - bool ignore_alpha = (editorNode->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA) != 0; - - NodeInput *imageSocket = this->getInputSocket(0); - NodeInput *alphaSocket = this->getInputSocket(1); - NodeInput *depthSocket = this->getInputSocket(2); - - CompositorOperation *compositorOperation = new CompositorOperation(); - compositorOperation->setScene(context.getScene()); - 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()); - compositorOperation->setActive(is_active); - - converter.addOperation(compositorOperation); - converter.mapInputSocket(imageSocket, compositorOperation->getInputSocket(0)); - /* only use alpha link if "use alpha" is enabled */ - if (ignore_alpha) { - converter.addInputValue(compositorOperation->getInputSocket(1), 1.0f); - } - else { - converter.mapInputSocket(alphaSocket, compositorOperation->getInputSocket(1)); - } - converter.mapInputSocket(depthSocket, compositorOperation->getInputSocket(2)); - - converter.addNodeInputPreview(imageSocket); -} diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc new file mode 100644 index 00000000000..2921b44c95b --- /dev/null +++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc @@ -0,0 +1,41 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_ConvertAlphaNode.h" +#include "COM_ConvertOperation.h" +#include "COM_ExecutionSystem.h" + +void ConvertAlphaNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeOperation *operation = nullptr; + bNode *node = this->getbNode(); + + /* value hardcoded in rna_nodetree.c */ + if (node->custom1 == 1) { + operation = new ConvertPremulToStraightOperation(); + } + else { + operation = new ConvertStraightToPremulOperation(); + } + + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp deleted file mode 100644 index 2921b44c95b..00000000000 --- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_ConvertAlphaNode.h" -#include "COM_ConvertOperation.h" -#include "COM_ExecutionSystem.h" - -void ConvertAlphaNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeOperation *operation = nullptr; - bNode *node = this->getbNode(); - - /* value hardcoded in rna_nodetree.c */ - if (node->custom1 == 1) { - operation = new ConvertPremulToStraightOperation(); - } - else { - operation = new ConvertStraightToPremulOperation(); - } - - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cc b/source/blender/compositor/nodes/COM_CornerPinNode.cc new file mode 100644 index 00000000000..efe847bbfbf --- /dev/null +++ b/source/blender/compositor/nodes/COM_CornerPinNode.cc @@ -0,0 +1,55 @@ +/* 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. + * + * Copyright 2014, Blender Foundation. + */ + +#include "COM_CornerPinNode.h" +#include "COM_ExecutionSystem.h" + +#include "COM_PlaneCornerPinOperation.h" + +CornerPinNode::CornerPinNode(bNode *editorNode) : Node(editorNode) +{ +} + +void CornerPinNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *input_image = this->getInputSocket(0); + /* note: socket order differs between UI node and operations: + * bNode uses intuitive order following top-down layout: + * upper-left, upper-right, lower-left, lower-right + * Operations use same order as the tracking blenkernel functions expect: + * lower-left, lower-right, upper-right, upper-left + */ + const int node_corner_index[4] = {3, 4, 2, 1}; + + NodeOutput *output_warped_image = this->getOutputSocket(0); + NodeOutput *output_plane = this->getOutputSocket(1); + + PlaneCornerPinWarpImageOperation *warp_image_operation = new PlaneCornerPinWarpImageOperation(); + converter.addOperation(warp_image_operation); + PlaneCornerPinMaskOperation *plane_mask_operation = new PlaneCornerPinMaskOperation(); + converter.addOperation(plane_mask_operation); + + converter.mapInputSocket(input_image, warp_image_operation->getInputSocket(0)); + for (int i = 0; i < 4; i++) { + NodeInput *corner_input = getInputSocket(node_corner_index[i]); + converter.mapInputSocket(corner_input, warp_image_operation->getInputSocket(i + 1)); + converter.mapInputSocket(corner_input, plane_mask_operation->getInputSocket(i)); + } + converter.mapOutputSocket(output_warped_image, warp_image_operation->getOutputSocket()); + converter.mapOutputSocket(output_plane, plane_mask_operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cpp b/source/blender/compositor/nodes/COM_CornerPinNode.cpp deleted file mode 100644 index efe847bbfbf..00000000000 --- a/source/blender/compositor/nodes/COM_CornerPinNode.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* 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. - * - * Copyright 2014, Blender Foundation. - */ - -#include "COM_CornerPinNode.h" -#include "COM_ExecutionSystem.h" - -#include "COM_PlaneCornerPinOperation.h" - -CornerPinNode::CornerPinNode(bNode *editorNode) : Node(editorNode) -{ -} - -void CornerPinNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *input_image = this->getInputSocket(0); - /* note: socket order differs between UI node and operations: - * bNode uses intuitive order following top-down layout: - * upper-left, upper-right, lower-left, lower-right - * Operations use same order as the tracking blenkernel functions expect: - * lower-left, lower-right, upper-right, upper-left - */ - const int node_corner_index[4] = {3, 4, 2, 1}; - - NodeOutput *output_warped_image = this->getOutputSocket(0); - NodeOutput *output_plane = this->getOutputSocket(1); - - PlaneCornerPinWarpImageOperation *warp_image_operation = new PlaneCornerPinWarpImageOperation(); - converter.addOperation(warp_image_operation); - PlaneCornerPinMaskOperation *plane_mask_operation = new PlaneCornerPinMaskOperation(); - converter.addOperation(plane_mask_operation); - - converter.mapInputSocket(input_image, warp_image_operation->getInputSocket(0)); - for (int i = 0; i < 4; i++) { - NodeInput *corner_input = getInputSocket(node_corner_index[i]); - converter.mapInputSocket(corner_input, warp_image_operation->getInputSocket(i + 1)); - converter.mapInputSocket(corner_input, plane_mask_operation->getInputSocket(i)); - } - converter.mapOutputSocket(output_warped_image, warp_image_operation->getOutputSocket()); - converter.mapOutputSocket(output_plane, plane_mask_operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_CropNode.cc b/source/blender/compositor/nodes/COM_CropNode.cc new file mode 100644 index 00000000000..0f0883b0151 --- /dev/null +++ b/source/blender/compositor/nodes/COM_CropNode.cc @@ -0,0 +1,47 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_CropNode.h" +#include "COM_CropOperation.h" + +CropNode::CropNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void CropNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *node = getbNode(); + NodeTwoXYs *cropSettings = (NodeTwoXYs *)node->storage; + bool relative = (bool)node->custom2; + bool cropImage = (bool)node->custom1; + CropBaseOperation *operation; + if (cropImage) { + operation = new CropImageOperation(); + } + else { + operation = new CropOperation(); + } + operation->setCropSettings(cropSettings); + operation->setRelative(relative); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_CropNode.cpp b/source/blender/compositor/nodes/COM_CropNode.cpp deleted file mode 100644 index 0f0883b0151..00000000000 --- a/source/blender/compositor/nodes/COM_CropNode.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_CropNode.h" -#include "COM_CropOperation.h" - -CropNode::CropNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void CropNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *node = getbNode(); - NodeTwoXYs *cropSettings = (NodeTwoXYs *)node->storage; - bool relative = (bool)node->custom2; - bool cropImage = (bool)node->custom1; - CropBaseOperation *operation; - if (cropImage) { - operation = new CropImageOperation(); - } - else { - operation = new CropOperation(); - } - operation->setCropSettings(cropSettings); - operation->setRelative(relative); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc new file mode 100644 index 00000000000..27ef98af8f3 --- /dev/null +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc @@ -0,0 +1,80 @@ +/* + * 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. + * + * Copyright 2018, Blender Foundation. + */ + +#include "COM_CryptomatteNode.h" +#include "COM_ConvertOperation.h" +#include "COM_CryptomatteOperation.h" + +#include "BLI_assert.h" +#include "BLI_hash_mm3.h" +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "COM_SetAlphaMultiplyOperation.h" +#include + +CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void CryptomatteNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *inputSocketImage = this->getInputSocket(0); + NodeOutput *outputSocketImage = this->getOutputSocket(0); + NodeOutput *outputSocketMatte = this->getOutputSocket(1); + NodeOutput *outputSocketPick = this->getOutputSocket(2); + + bNode *node = this->getbNode(); + NodeCryptomatte *cryptoMatteSettings = (NodeCryptomatte *)node->storage; + + CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets() - 1); + if (cryptoMatteSettings) { + LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptoMatteSettings->entries) { + operation->addObjectIndex(cryptomatte_entry->encoded_hash); + } + } + + converter.addOperation(operation); + + for (int i = 0; i < getNumberOfInputSockets() - 1; i++) { + converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i)); + } + + SeparateChannelOperation *separateOperation = new SeparateChannelOperation; + separateOperation->setChannel(3); + converter.addOperation(separateOperation); + + SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation(); + converter.addOperation(operationAlpha); + + converter.addLink(operation->getOutputSocket(0), separateOperation->getInputSocket(0)); + converter.addLink(separateOperation->getOutputSocket(0), operationAlpha->getInputSocket(1)); + + SetAlphaMultiplyOperation *clearAlphaOperation = new SetAlphaMultiplyOperation(); + converter.addOperation(clearAlphaOperation); + converter.addInputValue(clearAlphaOperation->getInputSocket(1), 1.0f); + + converter.addLink(operation->getOutputSocket(0), clearAlphaOperation->getInputSocket(0)); + + converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); + converter.mapOutputSocket(outputSocketMatte, separateOperation->getOutputSocket(0)); + converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket(0)); + converter.mapOutputSocket(outputSocketPick, clearAlphaOperation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp deleted file mode 100644 index 27ef98af8f3..00000000000 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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. - * - * Copyright 2018, Blender Foundation. - */ - -#include "COM_CryptomatteNode.h" -#include "COM_ConvertOperation.h" -#include "COM_CryptomatteOperation.h" - -#include "BLI_assert.h" -#include "BLI_hash_mm3.h" -#include "BLI_listbase.h" -#include "BLI_string.h" - -#include "COM_SetAlphaMultiplyOperation.h" -#include - -CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void CryptomatteNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *inputSocketImage = this->getInputSocket(0); - NodeOutput *outputSocketImage = this->getOutputSocket(0); - NodeOutput *outputSocketMatte = this->getOutputSocket(1); - NodeOutput *outputSocketPick = this->getOutputSocket(2); - - bNode *node = this->getbNode(); - NodeCryptomatte *cryptoMatteSettings = (NodeCryptomatte *)node->storage; - - CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets() - 1); - if (cryptoMatteSettings) { - LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptoMatteSettings->entries) { - operation->addObjectIndex(cryptomatte_entry->encoded_hash); - } - } - - converter.addOperation(operation); - - for (int i = 0; i < getNumberOfInputSockets() - 1; i++) { - converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i)); - } - - SeparateChannelOperation *separateOperation = new SeparateChannelOperation; - separateOperation->setChannel(3); - converter.addOperation(separateOperation); - - SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation(); - converter.addOperation(operationAlpha); - - converter.addLink(operation->getOutputSocket(0), separateOperation->getInputSocket(0)); - converter.addLink(separateOperation->getOutputSocket(0), operationAlpha->getInputSocket(1)); - - SetAlphaMultiplyOperation *clearAlphaOperation = new SetAlphaMultiplyOperation(); - converter.addOperation(clearAlphaOperation); - converter.addInputValue(clearAlphaOperation->getInputSocket(1), 1.0f); - - converter.addLink(operation->getOutputSocket(0), clearAlphaOperation->getInputSocket(0)); - - converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); - converter.mapOutputSocket(outputSocketMatte, separateOperation->getOutputSocket(0)); - converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket(0)); - converter.mapOutputSocket(outputSocketPick, clearAlphaOperation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_DefocusNode.cc b/source/blender/compositor/nodes/COM_DefocusNode.cc new file mode 100644 index 00000000000..393b1f2dabb --- /dev/null +++ b/source/blender/compositor/nodes/COM_DefocusNode.cc @@ -0,0 +1,143 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DefocusNode.h" +#include "COM_BokehImageOperation.h" +#include "COM_ConvertDepthToRadiusOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_FastGaussianBlurOperation.h" +#include "COM_GammaCorrectOperation.h" +#include "COM_MathBaseOperation.h" +#include "COM_SetValueOperation.h" +#include "COM_VariableSizeBokehBlurOperation.h" +#include "DNA_camera_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +DefocusNode::DefocusNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void DefocusNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *node = this->getbNode(); + NodeDefocus *data = (NodeDefocus *)node->storage; + Scene *scene = node->id ? (Scene *)node->id : context.getScene(); + Object *camob = scene ? scene->camera : nullptr; + + NodeOperation *radiusOperation; + if (data->no_zbuf) { + MathMultiplyOperation *multiply = new MathMultiplyOperation(); + SetValueOperation *multiplier = new SetValueOperation(); + multiplier->setValue(data->scale); + SetValueOperation *maxRadius = new SetValueOperation(); + maxRadius->setValue(data->maxblur); + MathMinimumOperation *minimize = new MathMinimumOperation(); + + converter.addOperation(multiply); + converter.addOperation(multiplier); + converter.addOperation(maxRadius); + converter.addOperation(minimize); + + converter.mapInputSocket(getInputSocket(1), multiply->getInputSocket(0)); + converter.addLink(multiplier->getOutputSocket(), multiply->getInputSocket(1)); + converter.addLink(multiply->getOutputSocket(), minimize->getInputSocket(0)); + converter.addLink(maxRadius->getOutputSocket(), minimize->getInputSocket(1)); + + radiusOperation = minimize; + } + else { + ConvertDepthToRadiusOperation *radius_op = new ConvertDepthToRadiusOperation(); + radius_op->setCameraObject(camob); + radius_op->setfStop(data->fstop); + radius_op->setMaxRadius(data->maxblur); + converter.addOperation(radius_op); + + converter.mapInputSocket(getInputSocket(1), radius_op->getInputSocket(0)); + + FastGaussianBlurValueOperation *blur = new FastGaussianBlurValueOperation(); + /* maintain close pixels so far Z values don't bleed into the foreground */ + blur->setOverlay(FAST_GAUSS_OVERLAY_MIN); + converter.addOperation(blur); + + converter.addLink(radius_op->getOutputSocket(0), blur->getInputSocket(0)); + radius_op->setPostBlur(blur); + + radiusOperation = blur; + } + + NodeBokehImage *bokehdata = new NodeBokehImage(); + bokehdata->angle = data->rotation; + bokehdata->rounding = 0.0f; + bokehdata->flaps = data->bktype; + if (data->bktype < 3) { + bokehdata->flaps = 5; + bokehdata->rounding = 1.0f; + } + bokehdata->catadioptric = 0.0f; + bokehdata->lensshift = 0.0f; + + BokehImageOperation *bokeh = new BokehImageOperation(); + bokeh->setData(bokehdata); + bokeh->deleteDataOnFinish(); + converter.addOperation(bokeh); + +#ifdef COM_DEFOCUS_SEARCH + InverseSearchRadiusOperation *search = new InverseSearchRadiusOperation(); + search->setMaxBlur(data->maxblur); + converter.addOperation(search); + + converter.addLink(radiusOperation->getOutputSocket(0), search->getInputSocket(0)); +#endif + + VariableSizeBokehBlurOperation *operation = new VariableSizeBokehBlurOperation(); + if (data->preview) { + operation->setQuality(COM_QUALITY_LOW); + } + else { + operation->setQuality(context.getQuality()); + } + operation->setMaxBlur(data->maxblur); + operation->setThreshold(data->bthresh); + converter.addOperation(operation); + + converter.addLink(bokeh->getOutputSocket(), operation->getInputSocket(1)); + converter.addLink(radiusOperation->getOutputSocket(), operation->getInputSocket(2)); +#ifdef COM_DEFOCUS_SEARCH + converter.addLink(search->getOutputSocket(), operation->getInputSocket(3)); +#endif + + if (data->gamco) { + GammaCorrectOperation *correct = new GammaCorrectOperation(); + converter.addOperation(correct); + GammaUncorrectOperation *inverse = new GammaUncorrectOperation(); + converter.addOperation(inverse); + + converter.mapInputSocket(getInputSocket(0), correct->getInputSocket(0)); + converter.addLink(correct->getOutputSocket(), operation->getInputSocket(0)); + converter.addLink(operation->getOutputSocket(), inverse->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(), inverse->getOutputSocket()); + } + else { + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket()); + } +} diff --git a/source/blender/compositor/nodes/COM_DefocusNode.cpp b/source/blender/compositor/nodes/COM_DefocusNode.cpp deleted file mode 100644 index 393b1f2dabb..00000000000 --- a/source/blender/compositor/nodes/COM_DefocusNode.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DefocusNode.h" -#include "COM_BokehImageOperation.h" -#include "COM_ConvertDepthToRadiusOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_FastGaussianBlurOperation.h" -#include "COM_GammaCorrectOperation.h" -#include "COM_MathBaseOperation.h" -#include "COM_SetValueOperation.h" -#include "COM_VariableSizeBokehBlurOperation.h" -#include "DNA_camera_types.h" -#include "DNA_node_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -DefocusNode::DefocusNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void DefocusNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *node = this->getbNode(); - NodeDefocus *data = (NodeDefocus *)node->storage; - Scene *scene = node->id ? (Scene *)node->id : context.getScene(); - Object *camob = scene ? scene->camera : nullptr; - - NodeOperation *radiusOperation; - if (data->no_zbuf) { - MathMultiplyOperation *multiply = new MathMultiplyOperation(); - SetValueOperation *multiplier = new SetValueOperation(); - multiplier->setValue(data->scale); - SetValueOperation *maxRadius = new SetValueOperation(); - maxRadius->setValue(data->maxblur); - MathMinimumOperation *minimize = new MathMinimumOperation(); - - converter.addOperation(multiply); - converter.addOperation(multiplier); - converter.addOperation(maxRadius); - converter.addOperation(minimize); - - converter.mapInputSocket(getInputSocket(1), multiply->getInputSocket(0)); - converter.addLink(multiplier->getOutputSocket(), multiply->getInputSocket(1)); - converter.addLink(multiply->getOutputSocket(), minimize->getInputSocket(0)); - converter.addLink(maxRadius->getOutputSocket(), minimize->getInputSocket(1)); - - radiusOperation = minimize; - } - else { - ConvertDepthToRadiusOperation *radius_op = new ConvertDepthToRadiusOperation(); - radius_op->setCameraObject(camob); - radius_op->setfStop(data->fstop); - radius_op->setMaxRadius(data->maxblur); - converter.addOperation(radius_op); - - converter.mapInputSocket(getInputSocket(1), radius_op->getInputSocket(0)); - - FastGaussianBlurValueOperation *blur = new FastGaussianBlurValueOperation(); - /* maintain close pixels so far Z values don't bleed into the foreground */ - blur->setOverlay(FAST_GAUSS_OVERLAY_MIN); - converter.addOperation(blur); - - converter.addLink(radius_op->getOutputSocket(0), blur->getInputSocket(0)); - radius_op->setPostBlur(blur); - - radiusOperation = blur; - } - - NodeBokehImage *bokehdata = new NodeBokehImage(); - bokehdata->angle = data->rotation; - bokehdata->rounding = 0.0f; - bokehdata->flaps = data->bktype; - if (data->bktype < 3) { - bokehdata->flaps = 5; - bokehdata->rounding = 1.0f; - } - bokehdata->catadioptric = 0.0f; - bokehdata->lensshift = 0.0f; - - BokehImageOperation *bokeh = new BokehImageOperation(); - bokeh->setData(bokehdata); - bokeh->deleteDataOnFinish(); - converter.addOperation(bokeh); - -#ifdef COM_DEFOCUS_SEARCH - InverseSearchRadiusOperation *search = new InverseSearchRadiusOperation(); - search->setMaxBlur(data->maxblur); - converter.addOperation(search); - - converter.addLink(radiusOperation->getOutputSocket(0), search->getInputSocket(0)); -#endif - - VariableSizeBokehBlurOperation *operation = new VariableSizeBokehBlurOperation(); - if (data->preview) { - operation->setQuality(COM_QUALITY_LOW); - } - else { - operation->setQuality(context.getQuality()); - } - operation->setMaxBlur(data->maxblur); - operation->setThreshold(data->bthresh); - converter.addOperation(operation); - - converter.addLink(bokeh->getOutputSocket(), operation->getInputSocket(1)); - converter.addLink(radiusOperation->getOutputSocket(), operation->getInputSocket(2)); -#ifdef COM_DEFOCUS_SEARCH - converter.addLink(search->getOutputSocket(), operation->getInputSocket(3)); -#endif - - if (data->gamco) { - GammaCorrectOperation *correct = new GammaCorrectOperation(); - converter.addOperation(correct); - GammaUncorrectOperation *inverse = new GammaUncorrectOperation(); - converter.addOperation(inverse); - - converter.mapInputSocket(getInputSocket(0), correct->getInputSocket(0)); - converter.addLink(correct->getOutputSocket(), operation->getInputSocket(0)); - converter.addLink(operation->getOutputSocket(), inverse->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(), inverse->getOutputSocket()); - } - else { - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket()); - } -} diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.cc b/source/blender/compositor/nodes/COM_DenoiseNode.cc new file mode 100644 index 00000000000..1aae81e1e7b --- /dev/null +++ b/source/blender/compositor/nodes/COM_DenoiseNode.cc @@ -0,0 +1,43 @@ +/* + * 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. + * + * Copyright 2019, Blender Foundation. + */ +#include "COM_DenoiseNode.h" +#include "COM_DenoiseOperation.h" +#include "COM_MixOperation.h" +#include "COM_SetValueOperation.h" +#include "DNA_node_types.h" + +DenoiseNode::DenoiseNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void DenoiseNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *node = this->getbNode(); + NodeDenoise *denoise = (NodeDenoise *)node->storage; + + DenoiseOperation *operation = new DenoiseOperation(); + converter.addOperation(operation); + operation->setDenoiseSettings(denoise); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.cpp b/source/blender/compositor/nodes/COM_DenoiseNode.cpp deleted file mode 100644 index 1aae81e1e7b..00000000000 --- a/source/blender/compositor/nodes/COM_DenoiseNode.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - * - * Copyright 2019, Blender Foundation. - */ -#include "COM_DenoiseNode.h" -#include "COM_DenoiseOperation.h" -#include "COM_MixOperation.h" -#include "COM_SetValueOperation.h" -#include "DNA_node_types.h" - -DenoiseNode::DenoiseNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void DenoiseNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *node = this->getbNode(); - NodeDenoise *denoise = (NodeDenoise *)node->storage; - - DenoiseOperation *operation = new DenoiseOperation(); - converter.addOperation(operation); - operation->setDenoiseSettings(denoise); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_DespeckleNode.cc b/source/blender/compositor/nodes/COM_DespeckleNode.cc new file mode 100644 index 00000000000..58734917831 --- /dev/null +++ b/source/blender/compositor/nodes/COM_DespeckleNode.cc @@ -0,0 +1,48 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DespeckleNode.h" +#include "BLI_math.h" +#include "COM_DespeckleOperation.h" +#include "COM_ExecutionSystem.h" +#include "DNA_scene_types.h" + +DespeckleNode::DespeckleNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void DespeckleNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *editorNode = this->getbNode(); + NodeInput *inputSocket = this->getInputSocket(0); + NodeInput *inputImageSocket = this->getInputSocket(1); + NodeOutput *outputSocket = this->getOutputSocket(0); + + DespeckleOperation *operation = new DespeckleOperation(); + operation->setThreshold(editorNode->custom3); + operation->setThresholdNeighbor(editorNode->custom4); + converter.addOperation(operation); + + converter.mapInputSocket(inputImageSocket, operation->getInputSocket(0)); + converter.mapInputSocket(inputSocket, operation->getInputSocket(1)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); + + converter.addPreview(operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_DespeckleNode.cpp b/source/blender/compositor/nodes/COM_DespeckleNode.cpp deleted file mode 100644 index 58734917831..00000000000 --- a/source/blender/compositor/nodes/COM_DespeckleNode.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DespeckleNode.h" -#include "BLI_math.h" -#include "COM_DespeckleOperation.h" -#include "COM_ExecutionSystem.h" -#include "DNA_scene_types.h" - -DespeckleNode::DespeckleNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void DespeckleNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *editorNode = this->getbNode(); - NodeInput *inputSocket = this->getInputSocket(0); - NodeInput *inputImageSocket = this->getInputSocket(1); - NodeOutput *outputSocket = this->getOutputSocket(0); - - DespeckleOperation *operation = new DespeckleOperation(); - operation->setThreshold(editorNode->custom3); - operation->setThresholdNeighbor(editorNode->custom4); - converter.addOperation(operation); - - converter.mapInputSocket(inputImageSocket, operation->getInputSocket(0)); - converter.mapInputSocket(inputSocket, operation->getInputSocket(1)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); - - converter.addPreview(operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc new file mode 100644 index 00000000000..3d538e9b4a0 --- /dev/null +++ b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc @@ -0,0 +1,54 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DifferenceMatteNode.h" +#include "BKE_node.h" +#include "COM_DifferenceMatteOperation.h" +#include "COM_SetAlphaMultiplyOperation.h" + +DifferenceMatteNode::DifferenceMatteNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void DifferenceMatteNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeInput *inputSocket2 = this->getInputSocket(1); + NodeOutput *outputSocketImage = this->getOutputSocket(0); + NodeOutput *outputSocketMatte = this->getOutputSocket(1); + bNode *editorNode = this->getbNode(); + + DifferenceMatteOperation *operationSet = new DifferenceMatteOperation(); + operationSet->setSettings((NodeChroma *)editorNode->storage); + converter.addOperation(operationSet); + + converter.mapInputSocket(inputSocket, operationSet->getInputSocket(0)); + converter.mapInputSocket(inputSocket2, operationSet->getInputSocket(1)); + converter.mapOutputSocket(outputSocketMatte, operationSet->getOutputSocket(0)); + + SetAlphaMultiplyOperation *operation = new SetAlphaMultiplyOperation(); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.addLink(operationSet->getOutputSocket(), operation->getInputSocket(1)); + converter.mapOutputSocket(outputSocketImage, operation->getOutputSocket()); + + converter.addPreview(operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp deleted file mode 100644 index 3d538e9b4a0..00000000000 --- a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DifferenceMatteNode.h" -#include "BKE_node.h" -#include "COM_DifferenceMatteOperation.h" -#include "COM_SetAlphaMultiplyOperation.h" - -DifferenceMatteNode::DifferenceMatteNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void DifferenceMatteNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *inputSocket = this->getInputSocket(0); - NodeInput *inputSocket2 = this->getInputSocket(1); - NodeOutput *outputSocketImage = this->getOutputSocket(0); - NodeOutput *outputSocketMatte = this->getOutputSocket(1); - bNode *editorNode = this->getbNode(); - - DifferenceMatteOperation *operationSet = new DifferenceMatteOperation(); - operationSet->setSettings((NodeChroma *)editorNode->storage); - converter.addOperation(operationSet); - - converter.mapInputSocket(inputSocket, operationSet->getInputSocket(0)); - converter.mapInputSocket(inputSocket2, operationSet->getInputSocket(1)); - converter.mapOutputSocket(outputSocketMatte, operationSet->getOutputSocket(0)); - - SetAlphaMultiplyOperation *operation = new SetAlphaMultiplyOperation(); - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.addLink(operationSet->getOutputSocket(), operation->getInputSocket(1)); - converter.mapOutputSocket(outputSocketImage, operation->getOutputSocket()); - - converter.addPreview(operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_DilateErodeNode.cc b/source/blender/compositor/nodes/COM_DilateErodeNode.cc new file mode 100644 index 00000000000..e90707618e5 --- /dev/null +++ b/source/blender/compositor/nodes/COM_DilateErodeNode.cc @@ -0,0 +1,149 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DilateErodeNode.h" +#include "BLI_math.h" +#include "COM_AntiAliasOperation.h" +#include "COM_DilateErodeOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_GaussianAlphaXBlurOperation.h" +#include "COM_GaussianAlphaYBlurOperation.h" + +DilateErodeNode::DilateErodeNode(bNode *editorNode) : Node(editorNode) +{ + /* initialize node data */ + NodeBlurData *data = &m_alpha_blur; + memset(data, 0, sizeof(NodeBlurData)); + data->filtertype = R_FILTER_GAUSS; + + if (editorNode->custom2 > 0) { + data->sizex = data->sizey = editorNode->custom2; + } + else { + data->sizex = data->sizey = -editorNode->custom2; + } +} + +void DilateErodeNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + + bNode *editorNode = this->getbNode(); + if (editorNode->custom1 == CMP_NODE_DILATEERODE_DISTANCE_THRESH) { + DilateErodeThresholdOperation *operation = new DilateErodeThresholdOperation(); + operation->setDistance(editorNode->custom2); + operation->setInset(editorNode->custom3); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + + if (editorNode->custom3 < 2.0f) { + AntiAliasOperation *antiAlias = new AntiAliasOperation(); + converter.addOperation(antiAlias); + + converter.addLink(operation->getOutputSocket(), antiAlias->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), antiAlias->getOutputSocket(0)); + } + else { + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); + } + } + else if (editorNode->custom1 == CMP_NODE_DILATEERODE_DISTANCE) { + if (editorNode->custom2 > 0) { + DilateDistanceOperation *operation = new DilateDistanceOperation(); + operation->setDistance(editorNode->custom2); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); + } + else { + ErodeDistanceOperation *operation = new ErodeDistanceOperation(); + operation->setDistance(-editorNode->custom2); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); + } + } + else if (editorNode->custom1 == CMP_NODE_DILATEERODE_DISTANCE_FEATHER) { + /* this uses a modified gaussian blur function otherwise its far too slow */ + CompositorQuality quality = context.getQuality(); + + GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation(); + operationx->setData(&m_alpha_blur); + operationx->setQuality(quality); + operationx->setFalloff(PROP_SMOOTH); + converter.addOperation(operationx); + + converter.mapInputSocket(getInputSocket(0), operationx->getInputSocket(0)); + // converter.mapInputSocket(getInputSocket(1), operationx->getInputSocket(1)); // no size input + // yet + + GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation(); + operationy->setData(&m_alpha_blur); + operationy->setQuality(quality); + operationy->setFalloff(PROP_SMOOTH); + converter.addOperation(operationy); + + converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0)); + // converter.mapInputSocket(getInputSocket(1), operationy->getInputSocket(1)); // no size input + // yet + converter.mapOutputSocket(getOutputSocket(0), operationy->getOutputSocket()); + + converter.addPreview(operationy->getOutputSocket()); + + /* TODO? */ + /* see gaussian blue node for original usage */ +#if 0 + if (!connectedSizeSocket) { + operationx->setSize(size); + operationy->setSize(size); + } +#else + operationx->setSize(1.0f); + operationy->setSize(1.0f); +#endif + operationx->setSubtract(editorNode->custom2 < 0); + operationy->setSubtract(editorNode->custom2 < 0); + + if (editorNode->storage) { + NodeDilateErode *data_storage = (NodeDilateErode *)editorNode->storage; + operationx->setFalloff(data_storage->falloff); + operationy->setFalloff(data_storage->falloff); + } + } + else { + if (editorNode->custom2 > 0) { + DilateStepOperation *operation = new DilateStepOperation(); + operation->setIterations(editorNode->custom2); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); + } + else { + ErodeStepOperation *operation = new ErodeStepOperation(); + operation->setIterations(-editorNode->custom2); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); + } + } +} diff --git a/source/blender/compositor/nodes/COM_DilateErodeNode.cpp b/source/blender/compositor/nodes/COM_DilateErodeNode.cpp deleted file mode 100644 index e90707618e5..00000000000 --- a/source/blender/compositor/nodes/COM_DilateErodeNode.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DilateErodeNode.h" -#include "BLI_math.h" -#include "COM_AntiAliasOperation.h" -#include "COM_DilateErodeOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_GaussianAlphaXBlurOperation.h" -#include "COM_GaussianAlphaYBlurOperation.h" - -DilateErodeNode::DilateErodeNode(bNode *editorNode) : Node(editorNode) -{ - /* initialize node data */ - NodeBlurData *data = &m_alpha_blur; - memset(data, 0, sizeof(NodeBlurData)); - data->filtertype = R_FILTER_GAUSS; - - if (editorNode->custom2 > 0) { - data->sizex = data->sizey = editorNode->custom2; - } - else { - data->sizex = data->sizey = -editorNode->custom2; - } -} - -void DilateErodeNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - - bNode *editorNode = this->getbNode(); - if (editorNode->custom1 == CMP_NODE_DILATEERODE_DISTANCE_THRESH) { - DilateErodeThresholdOperation *operation = new DilateErodeThresholdOperation(); - operation->setDistance(editorNode->custom2); - operation->setInset(editorNode->custom3); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - - if (editorNode->custom3 < 2.0f) { - AntiAliasOperation *antiAlias = new AntiAliasOperation(); - converter.addOperation(antiAlias); - - converter.addLink(operation->getOutputSocket(), antiAlias->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), antiAlias->getOutputSocket(0)); - } - else { - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); - } - } - else if (editorNode->custom1 == CMP_NODE_DILATEERODE_DISTANCE) { - if (editorNode->custom2 > 0) { - DilateDistanceOperation *operation = new DilateDistanceOperation(); - operation->setDistance(editorNode->custom2); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); - } - else { - ErodeDistanceOperation *operation = new ErodeDistanceOperation(); - operation->setDistance(-editorNode->custom2); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); - } - } - else if (editorNode->custom1 == CMP_NODE_DILATEERODE_DISTANCE_FEATHER) { - /* this uses a modified gaussian blur function otherwise its far too slow */ - CompositorQuality quality = context.getQuality(); - - GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation(); - operationx->setData(&m_alpha_blur); - operationx->setQuality(quality); - operationx->setFalloff(PROP_SMOOTH); - converter.addOperation(operationx); - - converter.mapInputSocket(getInputSocket(0), operationx->getInputSocket(0)); - // converter.mapInputSocket(getInputSocket(1), operationx->getInputSocket(1)); // no size input - // yet - - GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation(); - operationy->setData(&m_alpha_blur); - operationy->setQuality(quality); - operationy->setFalloff(PROP_SMOOTH); - converter.addOperation(operationy); - - converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0)); - // converter.mapInputSocket(getInputSocket(1), operationy->getInputSocket(1)); // no size input - // yet - converter.mapOutputSocket(getOutputSocket(0), operationy->getOutputSocket()); - - converter.addPreview(operationy->getOutputSocket()); - - /* TODO? */ - /* see gaussian blue node for original usage */ -#if 0 - if (!connectedSizeSocket) { - operationx->setSize(size); - operationy->setSize(size); - } -#else - operationx->setSize(1.0f); - operationy->setSize(1.0f); -#endif - operationx->setSubtract(editorNode->custom2 < 0); - operationy->setSubtract(editorNode->custom2 < 0); - - if (editorNode->storage) { - NodeDilateErode *data_storage = (NodeDilateErode *)editorNode->storage; - operationx->setFalloff(data_storage->falloff); - operationy->setFalloff(data_storage->falloff); - } - } - else { - if (editorNode->custom2 > 0) { - DilateStepOperation *operation = new DilateStepOperation(); - operation->setIterations(editorNode->custom2); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); - } - else { - ErodeStepOperation *operation = new ErodeStepOperation(); - operation->setIterations(-editorNode->custom2); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); - } - } -} diff --git a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc new file mode 100644 index 00000000000..f8d0eaf4675 --- /dev/null +++ b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc @@ -0,0 +1,40 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DirectionalBlurNode.h" +#include "COM_DirectionalBlurOperation.h" +#include "COM_ExecutionSystem.h" +#include "DNA_node_types.h" + +DirectionalBlurNode::DirectionalBlurNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void DirectionalBlurNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + NodeDBlurData *data = (NodeDBlurData *)this->getbNode()->storage; + DirectionalBlurOperation *operation = new DirectionalBlurOperation(); + operation->setQuality(context.getQuality()); + operation->setData(data); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp deleted file mode 100644 index f8d0eaf4675..00000000000 --- a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DirectionalBlurNode.h" -#include "COM_DirectionalBlurOperation.h" -#include "COM_ExecutionSystem.h" -#include "DNA_node_types.h" - -DirectionalBlurNode::DirectionalBlurNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void DirectionalBlurNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - NodeDBlurData *data = (NodeDBlurData *)this->getbNode()->storage; - DirectionalBlurOperation *operation = new DirectionalBlurOperation(); - operation->setQuality(context.getQuality()); - operation->setData(data); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_DisplaceNode.cc b/source/blender/compositor/nodes/COM_DisplaceNode.cc new file mode 100644 index 00000000000..0c0c3aad646 --- /dev/null +++ b/source/blender/compositor/nodes/COM_DisplaceNode.cc @@ -0,0 +1,46 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DisplaceNode.h" +#include "COM_DisplaceOperation.h" +#include "COM_DisplaceSimpleOperation.h" +#include "COM_ExecutionSystem.h" + +DisplaceNode::DisplaceNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void DisplaceNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + NodeOperation *operation; + if (context.getQuality() == COM_QUALITY_LOW) { + operation = new DisplaceSimpleOperation(); + } + else { + operation = new DisplaceOperation(); + } + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); + converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(3)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_DisplaceNode.cpp b/source/blender/compositor/nodes/COM_DisplaceNode.cpp deleted file mode 100644 index 0c0c3aad646..00000000000 --- a/source/blender/compositor/nodes/COM_DisplaceNode.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DisplaceNode.h" -#include "COM_DisplaceOperation.h" -#include "COM_DisplaceSimpleOperation.h" -#include "COM_ExecutionSystem.h" - -DisplaceNode::DisplaceNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void DisplaceNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - NodeOperation *operation; - if (context.getQuality() == COM_QUALITY_LOW) { - operation = new DisplaceSimpleOperation(); - } - else { - operation = new DisplaceOperation(); - } - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); - converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(3)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.cc b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc new file mode 100644 index 00000000000..37aeb5c8504 --- /dev/null +++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc @@ -0,0 +1,98 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DistanceMatteNode.h" +#include "BKE_node.h" +#include "COM_ConvertOperation.h" +#include "COM_DistanceRGBMatteOperation.h" +#include "COM_DistanceYCCMatteOperation.h" +#include "COM_SetAlphaMultiplyOperation.h" + +DistanceMatteNode::DistanceMatteNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void DistanceMatteNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *editorsnode = getbNode(); + NodeChroma *storage = (NodeChroma *)editorsnode->storage; + + NodeInput *inputSocketImage = this->getInputSocket(0); + NodeInput *inputSocketKey = this->getInputSocket(1); + NodeOutput *outputSocketImage = this->getOutputSocket(0); + NodeOutput *outputSocketMatte = this->getOutputSocket(1); + + SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation(); + converter.addOperation(operationAlpha); + + /* work in RGB color space */ + NodeOperation *operation; + if (storage->channel == 1) { + DistanceRGBMatteOperation *matte = new DistanceRGBMatteOperation(); + matte->setSettings(storage); + converter.addOperation(matte); + + converter.mapInputSocket(inputSocketImage, matte->getInputSocket(0)); + converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); + + converter.mapInputSocket(inputSocketKey, matte->getInputSocket(1)); + + operation = matte; + } + /* work in YCbCr color space */ + else { + DistanceYCCMatteOperation *matte = new DistanceYCCMatteOperation(); + matte->setSettings(storage); + converter.addOperation(matte); + + ConvertRGBToYCCOperation *operationYCCImage = new ConvertRGBToYCCOperation(); + ConvertRGBToYCCOperation *operationYCCMatte = new ConvertRGBToYCCOperation(); + operationYCCImage->setMode(BLI_YCC_ITU_BT709); + operationYCCMatte->setMode(BLI_YCC_ITU_BT709); + converter.addOperation(operationYCCImage); + converter.addOperation(operationYCCMatte); + + converter.mapInputSocket(inputSocketImage, operationYCCImage->getInputSocket(0)); + converter.addLink(operationYCCImage->getOutputSocket(), matte->getInputSocket(0)); + converter.addLink(operationYCCImage->getOutputSocket(), operationAlpha->getInputSocket(0)); + + converter.mapInputSocket(inputSocketKey, operationYCCMatte->getInputSocket(0)); + converter.addLink(operationYCCMatte->getOutputSocket(), matte->getInputSocket(1)); + + operation = matte; + } + + converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0)); + converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1)); + + if (storage->channel != 1) { + ConvertYCCToRGBOperation *inv_convert = new ConvertYCCToRGBOperation(); + inv_convert->setMode(BLI_YCC_ITU_BT709); + + converter.addOperation(inv_convert); + converter.addLink(operationAlpha->getOutputSocket(0), inv_convert->getInputSocket(0)); + converter.mapOutputSocket(outputSocketImage, inv_convert->getOutputSocket()); + converter.addPreview(inv_convert->getOutputSocket()); + } + else { + converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); + converter.addPreview(operationAlpha->getOutputSocket()); + } +} diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp b/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp deleted file mode 100644 index 37aeb5c8504..00000000000 --- a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DistanceMatteNode.h" -#include "BKE_node.h" -#include "COM_ConvertOperation.h" -#include "COM_DistanceRGBMatteOperation.h" -#include "COM_DistanceYCCMatteOperation.h" -#include "COM_SetAlphaMultiplyOperation.h" - -DistanceMatteNode::DistanceMatteNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void DistanceMatteNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *editorsnode = getbNode(); - NodeChroma *storage = (NodeChroma *)editorsnode->storage; - - NodeInput *inputSocketImage = this->getInputSocket(0); - NodeInput *inputSocketKey = this->getInputSocket(1); - NodeOutput *outputSocketImage = this->getOutputSocket(0); - NodeOutput *outputSocketMatte = this->getOutputSocket(1); - - SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation(); - converter.addOperation(operationAlpha); - - /* work in RGB color space */ - NodeOperation *operation; - if (storage->channel == 1) { - DistanceRGBMatteOperation *matte = new DistanceRGBMatteOperation(); - matte->setSettings(storage); - converter.addOperation(matte); - - converter.mapInputSocket(inputSocketImage, matte->getInputSocket(0)); - converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); - - converter.mapInputSocket(inputSocketKey, matte->getInputSocket(1)); - - operation = matte; - } - /* work in YCbCr color space */ - else { - DistanceYCCMatteOperation *matte = new DistanceYCCMatteOperation(); - matte->setSettings(storage); - converter.addOperation(matte); - - ConvertRGBToYCCOperation *operationYCCImage = new ConvertRGBToYCCOperation(); - ConvertRGBToYCCOperation *operationYCCMatte = new ConvertRGBToYCCOperation(); - operationYCCImage->setMode(BLI_YCC_ITU_BT709); - operationYCCMatte->setMode(BLI_YCC_ITU_BT709); - converter.addOperation(operationYCCImage); - converter.addOperation(operationYCCMatte); - - converter.mapInputSocket(inputSocketImage, operationYCCImage->getInputSocket(0)); - converter.addLink(operationYCCImage->getOutputSocket(), matte->getInputSocket(0)); - converter.addLink(operationYCCImage->getOutputSocket(), operationAlpha->getInputSocket(0)); - - converter.mapInputSocket(inputSocketKey, operationYCCMatte->getInputSocket(0)); - converter.addLink(operationYCCMatte->getOutputSocket(), matte->getInputSocket(1)); - - operation = matte; - } - - converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0)); - converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1)); - - if (storage->channel != 1) { - ConvertYCCToRGBOperation *inv_convert = new ConvertYCCToRGBOperation(); - inv_convert->setMode(BLI_YCC_ITU_BT709); - - converter.addOperation(inv_convert); - converter.addLink(operationAlpha->getOutputSocket(0), inv_convert->getInputSocket(0)); - converter.mapOutputSocket(outputSocketImage, inv_convert->getOutputSocket()); - converter.addPreview(inv_convert->getOutputSocket()); - } - else { - converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket()); - converter.addPreview(operationAlpha->getOutputSocket()); - } -} diff --git a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc new file mode 100644 index 00000000000..907a9f49353 --- /dev/null +++ b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc @@ -0,0 +1,42 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DoubleEdgeMaskNode.h" +#include "COM_DoubleEdgeMaskOperation.h" +#include "COM_ExecutionSystem.h" + +DoubleEdgeMaskNode::DoubleEdgeMaskNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void DoubleEdgeMaskNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + DoubleEdgeMaskOperation *operation; + bNode *bnode = this->getbNode(); + + operation = new DoubleEdgeMaskOperation(); + operation->setAdjecentOnly(bnode->custom1); + operation->setKeepInside(bnode->custom2); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp deleted file mode 100644 index 907a9f49353..00000000000 --- a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DoubleEdgeMaskNode.h" -#include "COM_DoubleEdgeMaskOperation.h" -#include "COM_ExecutionSystem.h" - -DoubleEdgeMaskNode::DoubleEdgeMaskNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void DoubleEdgeMaskNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - DoubleEdgeMaskOperation *operation; - bNode *bnode = this->getbNode(); - - operation = new DoubleEdgeMaskOperation(); - operation->setAdjecentOnly(bnode->custom1); - operation->setKeepInside(bnode->custom2); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_EllipseMaskNode.cc b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc new file mode 100644 index 00000000000..1ae855c0f1d --- /dev/null +++ b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc @@ -0,0 +1,72 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_EllipseMaskNode.h" +#include "COM_EllipseMaskOperation.h" +#include "COM_ExecutionSystem.h" + +#include "COM_ScaleOperation.h" +#include "COM_SetValueOperation.h" + +EllipseMaskNode::EllipseMaskNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void EllipseMaskNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeOutput *outputSocket = this->getOutputSocket(0); + + EllipseMaskOperation *operation; + operation = new EllipseMaskOperation(); + operation->setData((NodeEllipseMask *)this->getbNode()->storage); + operation->setMaskType(this->getbNode()->custom1); + converter.addOperation(operation); + + if (inputSocket->isLinked()) { + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); + } + else { + /* Value operation to produce original transparent image */ + SetValueOperation *valueOperation = new SetValueOperation(); + valueOperation->setValue(0.0f); + converter.addOperation(valueOperation); + + /* Scale that image up to render resolution */ + const RenderData *rd = context.getRenderData(); + const float render_size_factor = context.getRenderPercentageAsFactor(); + ScaleFixedSizeOperation *scaleOperation = new ScaleFixedSizeOperation(); + + scaleOperation->setIsAspect(false); + scaleOperation->setIsCrop(false); + scaleOperation->setOffset(0.0f, 0.0f); + scaleOperation->setNewWidth(rd->xsch * render_size_factor); + scaleOperation->setNewHeight(rd->ysch * render_size_factor); + scaleOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); + converter.addOperation(scaleOperation); + + converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); + converter.addLink(scaleOperation->getOutputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + } + + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); +} diff --git a/source/blender/compositor/nodes/COM_EllipseMaskNode.cpp b/source/blender/compositor/nodes/COM_EllipseMaskNode.cpp deleted file mode 100644 index 1ae855c0f1d..00000000000 --- a/source/blender/compositor/nodes/COM_EllipseMaskNode.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_EllipseMaskNode.h" -#include "COM_EllipseMaskOperation.h" -#include "COM_ExecutionSystem.h" - -#include "COM_ScaleOperation.h" -#include "COM_SetValueOperation.h" - -EllipseMaskNode::EllipseMaskNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void EllipseMaskNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - NodeInput *inputSocket = this->getInputSocket(0); - NodeOutput *outputSocket = this->getOutputSocket(0); - - EllipseMaskOperation *operation; - operation = new EllipseMaskOperation(); - operation->setData((NodeEllipseMask *)this->getbNode()->storage); - operation->setMaskType(this->getbNode()->custom1); - converter.addOperation(operation); - - if (inputSocket->isLinked()) { - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); - } - else { - /* Value operation to produce original transparent image */ - SetValueOperation *valueOperation = new SetValueOperation(); - valueOperation->setValue(0.0f); - converter.addOperation(valueOperation); - - /* Scale that image up to render resolution */ - const RenderData *rd = context.getRenderData(); - const float render_size_factor = context.getRenderPercentageAsFactor(); - ScaleFixedSizeOperation *scaleOperation = new ScaleFixedSizeOperation(); - - scaleOperation->setIsAspect(false); - scaleOperation->setIsCrop(false); - scaleOperation->setOffset(0.0f, 0.0f); - scaleOperation->setNewWidth(rd->xsch * render_size_factor); - scaleOperation->setNewHeight(rd->ysch * render_size_factor); - scaleOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); - converter.addOperation(scaleOperation); - - converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); - converter.addLink(scaleOperation->getOutputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); - } - - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); -} diff --git a/source/blender/compositor/nodes/COM_FilterNode.cc b/source/blender/compositor/nodes/COM_FilterNode.cc new file mode 100644 index 00000000000..1147c11794f --- /dev/null +++ b/source/blender/compositor/nodes/COM_FilterNode.cc @@ -0,0 +1,96 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_FilterNode.h" +#include "BKE_node.h" +#include "COM_ConvolutionEdgeFilterOperation.h" +#include "COM_ConvolutionFilterOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_MixOperation.h" + +FilterNode::FilterNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void FilterNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeInput *inputImageSocket = this->getInputSocket(1); + NodeOutput *outputSocket = this->getOutputSocket(0); + ConvolutionFilterOperation *operation = nullptr; + + switch (this->getbNode()->custom1) { + case CMP_FILT_SOFT: + operation = new ConvolutionFilterOperation(); + operation->set3x3Filter(1 / 16.0f, + 2 / 16.0f, + 1 / 16.0f, + 2 / 16.0f, + 4 / 16.0f, + 2 / 16.0f, + 1 / 16.0f, + 2 / 16.0f, + 1 / 16.0f); + break; + case CMP_FILT_SHARP: + operation = new ConvolutionFilterOperation(); + operation->set3x3Filter(-1, -1, -1, -1, 9, -1, -1, -1, -1); + break; + case CMP_FILT_LAPLACE: + operation = new ConvolutionEdgeFilterOperation(); + operation->set3x3Filter(-1 / 8.0f, + -1 / 8.0f, + -1 / 8.0f, + -1 / 8.0f, + 1.0f, + -1 / 8.0f, + -1 / 8.0f, + -1 / 8.0f, + -1 / 8.0f); + break; + case CMP_FILT_SOBEL: + operation = new ConvolutionEdgeFilterOperation(); + operation->set3x3Filter(1, 2, 1, 0, 0, 0, -1, -2, -1); + break; + case CMP_FILT_PREWITT: + operation = new ConvolutionEdgeFilterOperation(); + operation->set3x3Filter(1, 1, 1, 0, 0, 0, -1, -1, -1); + break; + case CMP_FILT_KIRSCH: + operation = new ConvolutionEdgeFilterOperation(); + operation->set3x3Filter(5, 5, 5, -3, -3, -3, -2, -2, -2); + break; + case CMP_FILT_SHADOW: + operation = new ConvolutionFilterOperation(); + operation->set3x3Filter(1, 2, 1, 0, 1, 0, -1, -2, -1); + break; + default: + operation = new ConvolutionFilterOperation(); + operation->set3x3Filter(0, 0, 0, 0, 1, 0, 0, 0, 0); + break; + } + converter.addOperation(operation); + + converter.mapInputSocket(inputImageSocket, operation->getInputSocket(0)); + converter.mapInputSocket(inputSocket, operation->getInputSocket(1)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); + + converter.addPreview(operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_FilterNode.cpp b/source/blender/compositor/nodes/COM_FilterNode.cpp deleted file mode 100644 index 1147c11794f..00000000000 --- a/source/blender/compositor/nodes/COM_FilterNode.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_FilterNode.h" -#include "BKE_node.h" -#include "COM_ConvolutionEdgeFilterOperation.h" -#include "COM_ConvolutionFilterOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_MixOperation.h" - -FilterNode::FilterNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void FilterNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *inputSocket = this->getInputSocket(0); - NodeInput *inputImageSocket = this->getInputSocket(1); - NodeOutput *outputSocket = this->getOutputSocket(0); - ConvolutionFilterOperation *operation = nullptr; - - switch (this->getbNode()->custom1) { - case CMP_FILT_SOFT: - operation = new ConvolutionFilterOperation(); - operation->set3x3Filter(1 / 16.0f, - 2 / 16.0f, - 1 / 16.0f, - 2 / 16.0f, - 4 / 16.0f, - 2 / 16.0f, - 1 / 16.0f, - 2 / 16.0f, - 1 / 16.0f); - break; - case CMP_FILT_SHARP: - operation = new ConvolutionFilterOperation(); - operation->set3x3Filter(-1, -1, -1, -1, 9, -1, -1, -1, -1); - break; - case CMP_FILT_LAPLACE: - operation = new ConvolutionEdgeFilterOperation(); - operation->set3x3Filter(-1 / 8.0f, - -1 / 8.0f, - -1 / 8.0f, - -1 / 8.0f, - 1.0f, - -1 / 8.0f, - -1 / 8.0f, - -1 / 8.0f, - -1 / 8.0f); - break; - case CMP_FILT_SOBEL: - operation = new ConvolutionEdgeFilterOperation(); - operation->set3x3Filter(1, 2, 1, 0, 0, 0, -1, -2, -1); - break; - case CMP_FILT_PREWITT: - operation = new ConvolutionEdgeFilterOperation(); - operation->set3x3Filter(1, 1, 1, 0, 0, 0, -1, -1, -1); - break; - case CMP_FILT_KIRSCH: - operation = new ConvolutionEdgeFilterOperation(); - operation->set3x3Filter(5, 5, 5, -3, -3, -3, -2, -2, -2); - break; - case CMP_FILT_SHADOW: - operation = new ConvolutionFilterOperation(); - operation->set3x3Filter(1, 2, 1, 0, 1, 0, -1, -2, -1); - break; - default: - operation = new ConvolutionFilterOperation(); - operation->set3x3Filter(0, 0, 0, 0, 1, 0, 0, 0, 0); - break; - } - converter.addOperation(operation); - - converter.mapInputSocket(inputImageSocket, operation->getInputSocket(0)); - converter.mapInputSocket(inputSocket, operation->getInputSocket(1)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); - - converter.addPreview(operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_FlipNode.cc b/source/blender/compositor/nodes/COM_FlipNode.cc new file mode 100644 index 00000000000..d89e6b7b844 --- /dev/null +++ b/source/blender/compositor/nodes/COM_FlipNode.cc @@ -0,0 +1,54 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_FlipNode.h" + +#include "COM_ExecutionSystem.h" +#include "COM_FlipOperation.h" + +FlipNode::FlipNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void FlipNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeOutput *outputSocket = this->getOutputSocket(0); + FlipOperation *operation = new FlipOperation(); + switch (this->getbNode()->custom1) { + case 0: /* TODO: I didn't find any constants in the old implementation, + * should I introduce them. */ + operation->setFlipX(true); + operation->setFlipY(false); + break; + case 1: + operation->setFlipX(false); + operation->setFlipY(true); + break; + case 2: + operation->setFlipX(true); + operation->setFlipY(true); + break; + } + + converter.addOperation(operation); + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_FlipNode.cpp b/source/blender/compositor/nodes/COM_FlipNode.cpp deleted file mode 100644 index d89e6b7b844..00000000000 --- a/source/blender/compositor/nodes/COM_FlipNode.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_FlipNode.h" - -#include "COM_ExecutionSystem.h" -#include "COM_FlipOperation.h" - -FlipNode::FlipNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void FlipNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *inputSocket = this->getInputSocket(0); - NodeOutput *outputSocket = this->getOutputSocket(0); - FlipOperation *operation = new FlipOperation(); - switch (this->getbNode()->custom1) { - case 0: /* TODO: I didn't find any constants in the old implementation, - * should I introduce them. */ - operation->setFlipX(true); - operation->setFlipY(false); - break; - case 1: - operation->setFlipX(false); - operation->setFlipY(true); - break; - case 2: - operation->setFlipX(true); - operation->setFlipY(true); - break; - } - - converter.addOperation(operation); - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_GammaNode.cc b/source/blender/compositor/nodes/COM_GammaNode.cc new file mode 100644 index 00000000000..1ce17faa0dc --- /dev/null +++ b/source/blender/compositor/nodes/COM_GammaNode.cc @@ -0,0 +1,37 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GammaNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_GammaOperation.h" + +GammaNode::GammaNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void GammaNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + GammaOperation *operation = new GammaOperation(); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_GammaNode.cpp b/source/blender/compositor/nodes/COM_GammaNode.cpp deleted file mode 100644 index 1ce17faa0dc..00000000000 --- a/source/blender/compositor/nodes/COM_GammaNode.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GammaNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_GammaOperation.h" - -GammaNode::GammaNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void GammaNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - GammaOperation *operation = new GammaOperation(); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_GlareNode.cc b/source/blender/compositor/nodes/COM_GlareNode.cc new file mode 100644 index 00000000000..ef088e42205 --- /dev/null +++ b/source/blender/compositor/nodes/COM_GlareNode.cc @@ -0,0 +1,82 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GlareNode.h" +#include "COM_FastGaussianBlurOperation.h" +#include "COM_GlareFogGlowOperation.h" +#include "COM_GlareGhostOperation.h" +#include "COM_GlareSimpleStarOperation.h" +#include "COM_GlareStreaksOperation.h" +#include "COM_GlareThresholdOperation.h" +#include "COM_MixOperation.h" +#include "COM_SetValueOperation.h" +#include "DNA_node_types.h" + +GlareNode::GlareNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void GlareNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *node = this->getbNode(); + NodeGlare *glare = (NodeGlare *)node->storage; + + GlareBaseOperation *glareoperation = nullptr; + switch (glare->type) { + default: + case 3: + glareoperation = new GlareGhostOperation(); + break; + case 2: // streaks + glareoperation = new GlareStreaksOperation(); + break; + case 1: // fog glow + glareoperation = new GlareFogGlowOperation(); + break; + case 0: // simple star + glareoperation = new GlareSimpleStarOperation(); + break; + } + BLI_assert(glareoperation); + glareoperation->setGlareSettings(glare); + + GlareThresholdOperation *thresholdOperation = new GlareThresholdOperation(); + thresholdOperation->setGlareSettings(glare); + + SetValueOperation *mixvalueoperation = new SetValueOperation(); + mixvalueoperation->setValue(0.5f + glare->mix * 0.5f); + + MixGlareOperation *mixoperation = new MixGlareOperation(); + mixoperation->setResolutionInputSocketIndex(1); + mixoperation->getInputSocket(2)->setResizeMode(COM_SC_FIT); + + converter.addOperation(glareoperation); + converter.addOperation(thresholdOperation); + converter.addOperation(mixvalueoperation); + converter.addOperation(mixoperation); + + converter.mapInputSocket(getInputSocket(0), thresholdOperation->getInputSocket(0)); + converter.addLink(thresholdOperation->getOutputSocket(), glareoperation->getInputSocket(0)); + + converter.addLink(mixvalueoperation->getOutputSocket(), mixoperation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(0), mixoperation->getInputSocket(1)); + converter.addLink(glareoperation->getOutputSocket(), mixoperation->getInputSocket(2)); + converter.mapOutputSocket(getOutputSocket(), mixoperation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_GlareNode.cpp b/source/blender/compositor/nodes/COM_GlareNode.cpp deleted file mode 100644 index ef088e42205..00000000000 --- a/source/blender/compositor/nodes/COM_GlareNode.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GlareNode.h" -#include "COM_FastGaussianBlurOperation.h" -#include "COM_GlareFogGlowOperation.h" -#include "COM_GlareGhostOperation.h" -#include "COM_GlareSimpleStarOperation.h" -#include "COM_GlareStreaksOperation.h" -#include "COM_GlareThresholdOperation.h" -#include "COM_MixOperation.h" -#include "COM_SetValueOperation.h" -#include "DNA_node_types.h" - -GlareNode::GlareNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void GlareNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *node = this->getbNode(); - NodeGlare *glare = (NodeGlare *)node->storage; - - GlareBaseOperation *glareoperation = nullptr; - switch (glare->type) { - default: - case 3: - glareoperation = new GlareGhostOperation(); - break; - case 2: // streaks - glareoperation = new GlareStreaksOperation(); - break; - case 1: // fog glow - glareoperation = new GlareFogGlowOperation(); - break; - case 0: // simple star - glareoperation = new GlareSimpleStarOperation(); - break; - } - BLI_assert(glareoperation); - glareoperation->setGlareSettings(glare); - - GlareThresholdOperation *thresholdOperation = new GlareThresholdOperation(); - thresholdOperation->setGlareSettings(glare); - - SetValueOperation *mixvalueoperation = new SetValueOperation(); - mixvalueoperation->setValue(0.5f + glare->mix * 0.5f); - - MixGlareOperation *mixoperation = new MixGlareOperation(); - mixoperation->setResolutionInputSocketIndex(1); - mixoperation->getInputSocket(2)->setResizeMode(COM_SC_FIT); - - converter.addOperation(glareoperation); - converter.addOperation(thresholdOperation); - converter.addOperation(mixvalueoperation); - converter.addOperation(mixoperation); - - converter.mapInputSocket(getInputSocket(0), thresholdOperation->getInputSocket(0)); - converter.addLink(thresholdOperation->getOutputSocket(), glareoperation->getInputSocket(0)); - - converter.addLink(mixvalueoperation->getOutputSocket(), mixoperation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(0), mixoperation->getInputSocket(1)); - converter.addLink(glareoperation->getOutputSocket(), mixoperation->getInputSocket(2)); - converter.mapOutputSocket(getOutputSocket(), mixoperation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc new file mode 100644 index 00000000000..00125ba2ea5 --- /dev/null +++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc @@ -0,0 +1,64 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_HueSaturationValueCorrectNode.h" + +#include "COM_ConvertOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_HueSaturationValueCorrectOperation.h" +#include "COM_MixOperation.h" +#include "COM_SetColorOperation.h" +#include "COM_SetValueOperation.h" +#include "DNA_node_types.h" + +HueSaturationValueCorrectNode::HueSaturationValueCorrectNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void HueSaturationValueCorrectNode::convertToOperations( + NodeConverter &converter, const CompositorContext & /*context*/) const +{ + NodeInput *valueSocket = this->getInputSocket(0); + NodeInput *colorSocket = this->getInputSocket(1); + NodeOutput *outputSocket = this->getOutputSocket(0); + bNode *editorsnode = getbNode(); + CurveMapping *storage = (CurveMapping *)editorsnode->storage; + + ConvertRGBToHSVOperation *rgbToHSV = new ConvertRGBToHSVOperation(); + converter.addOperation(rgbToHSV); + + ConvertHSVToRGBOperation *hsvToRGB = new ConvertHSVToRGBOperation(); + converter.addOperation(hsvToRGB); + + HueSaturationValueCorrectOperation *changeHSV = new HueSaturationValueCorrectOperation(); + changeHSV->setCurveMapping(storage); + converter.addOperation(changeHSV); + + MixBlendOperation *blend = new MixBlendOperation(); + blend->setResolutionInputSocketIndex(1); + converter.addOperation(blend); + + converter.mapInputSocket(colorSocket, rgbToHSV->getInputSocket(0)); + converter.addLink(rgbToHSV->getOutputSocket(), changeHSV->getInputSocket(0)); + converter.addLink(changeHSV->getOutputSocket(), hsvToRGB->getInputSocket(0)); + converter.addLink(hsvToRGB->getOutputSocket(), blend->getInputSocket(2)); + converter.mapInputSocket(colorSocket, blend->getInputSocket(1)); + converter.mapInputSocket(valueSocket, blend->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, blend->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp deleted file mode 100644 index 00125ba2ea5..00000000000 --- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_HueSaturationValueCorrectNode.h" - -#include "COM_ConvertOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_HueSaturationValueCorrectOperation.h" -#include "COM_MixOperation.h" -#include "COM_SetColorOperation.h" -#include "COM_SetValueOperation.h" -#include "DNA_node_types.h" - -HueSaturationValueCorrectNode::HueSaturationValueCorrectNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void HueSaturationValueCorrectNode::convertToOperations( - NodeConverter &converter, const CompositorContext & /*context*/) const -{ - NodeInput *valueSocket = this->getInputSocket(0); - NodeInput *colorSocket = this->getInputSocket(1); - NodeOutput *outputSocket = this->getOutputSocket(0); - bNode *editorsnode = getbNode(); - CurveMapping *storage = (CurveMapping *)editorsnode->storage; - - ConvertRGBToHSVOperation *rgbToHSV = new ConvertRGBToHSVOperation(); - converter.addOperation(rgbToHSV); - - ConvertHSVToRGBOperation *hsvToRGB = new ConvertHSVToRGBOperation(); - converter.addOperation(hsvToRGB); - - HueSaturationValueCorrectOperation *changeHSV = new HueSaturationValueCorrectOperation(); - changeHSV->setCurveMapping(storage); - converter.addOperation(changeHSV); - - MixBlendOperation *blend = new MixBlendOperation(); - blend->setResolutionInputSocketIndex(1); - converter.addOperation(blend); - - converter.mapInputSocket(colorSocket, rgbToHSV->getInputSocket(0)); - converter.addLink(rgbToHSV->getOutputSocket(), changeHSV->getInputSocket(0)); - converter.addLink(changeHSV->getOutputSocket(), hsvToRGB->getInputSocket(0)); - converter.addLink(hsvToRGB->getOutputSocket(), blend->getInputSocket(2)); - converter.mapInputSocket(colorSocket, blend->getInputSocket(1)); - converter.mapInputSocket(valueSocket, blend->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, blend->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc new file mode 100644 index 00000000000..dc2e5187e8f --- /dev/null +++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc @@ -0,0 +1,67 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_HueSaturationValueNode.h" + +#include "COM_ChangeHSVOperation.h" +#include "COM_ConvertOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_MixOperation.h" +#include "COM_SetColorOperation.h" +#include "COM_SetValueOperation.h" +#include "DNA_node_types.h" + +HueSaturationValueNode::HueSaturationValueNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void HueSaturationValueNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *colorSocket = this->getInputSocket(0); + NodeInput *hueSocket = this->getInputSocket(1); + NodeInput *saturationSocket = this->getInputSocket(2); + NodeInput *valueSocket = this->getInputSocket(3); + NodeInput *facSocket = this->getInputSocket(4); + NodeOutput *outputSocket = this->getOutputSocket(0); + + ConvertRGBToHSVOperation *rgbToHSV = new ConvertRGBToHSVOperation(); + converter.addOperation(rgbToHSV); + + ConvertHSVToRGBOperation *hsvToRGB = new ConvertHSVToRGBOperation(); + converter.addOperation(hsvToRGB); + + ChangeHSVOperation *changeHSV = new ChangeHSVOperation(); + converter.mapInputSocket(hueSocket, changeHSV->getInputSocket(1)); + converter.mapInputSocket(saturationSocket, changeHSV->getInputSocket(2)); + converter.mapInputSocket(valueSocket, changeHSV->getInputSocket(3)); + converter.addOperation(changeHSV); + + MixBlendOperation *blend = new MixBlendOperation(); + blend->setResolutionInputSocketIndex(1); + converter.addOperation(blend); + + converter.mapInputSocket(colorSocket, rgbToHSV->getInputSocket(0)); + converter.addLink(rgbToHSV->getOutputSocket(), changeHSV->getInputSocket(0)); + converter.addLink(changeHSV->getOutputSocket(), hsvToRGB->getInputSocket(0)); + converter.addLink(hsvToRGB->getOutputSocket(), blend->getInputSocket(2)); + converter.mapInputSocket(colorSocket, blend->getInputSocket(1)); + converter.mapInputSocket(facSocket, blend->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, blend->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp deleted file mode 100644 index dc2e5187e8f..00000000000 --- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_HueSaturationValueNode.h" - -#include "COM_ChangeHSVOperation.h" -#include "COM_ConvertOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_MixOperation.h" -#include "COM_SetColorOperation.h" -#include "COM_SetValueOperation.h" -#include "DNA_node_types.h" - -HueSaturationValueNode::HueSaturationValueNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void HueSaturationValueNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *colorSocket = this->getInputSocket(0); - NodeInput *hueSocket = this->getInputSocket(1); - NodeInput *saturationSocket = this->getInputSocket(2); - NodeInput *valueSocket = this->getInputSocket(3); - NodeInput *facSocket = this->getInputSocket(4); - NodeOutput *outputSocket = this->getOutputSocket(0); - - ConvertRGBToHSVOperation *rgbToHSV = new ConvertRGBToHSVOperation(); - converter.addOperation(rgbToHSV); - - ConvertHSVToRGBOperation *hsvToRGB = new ConvertHSVToRGBOperation(); - converter.addOperation(hsvToRGB); - - ChangeHSVOperation *changeHSV = new ChangeHSVOperation(); - converter.mapInputSocket(hueSocket, changeHSV->getInputSocket(1)); - converter.mapInputSocket(saturationSocket, changeHSV->getInputSocket(2)); - converter.mapInputSocket(valueSocket, changeHSV->getInputSocket(3)); - converter.addOperation(changeHSV); - - MixBlendOperation *blend = new MixBlendOperation(); - blend->setResolutionInputSocketIndex(1); - converter.addOperation(blend); - - converter.mapInputSocket(colorSocket, rgbToHSV->getInputSocket(0)); - converter.addLink(rgbToHSV->getOutputSocket(), changeHSV->getInputSocket(0)); - converter.addLink(changeHSV->getOutputSocket(), hsvToRGB->getInputSocket(0)); - converter.addLink(hsvToRGB->getOutputSocket(), blend->getInputSocket(2)); - converter.mapInputSocket(colorSocket, blend->getInputSocket(1)); - converter.mapInputSocket(facSocket, blend->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, blend->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_IDMaskNode.cc b/source/blender/compositor/nodes/COM_IDMaskNode.cc new file mode 100644 index 00000000000..5ba54d75bcd --- /dev/null +++ b/source/blender/compositor/nodes/COM_IDMaskNode.cc @@ -0,0 +1,49 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_IDMaskNode.h" +#include "COM_AntiAliasOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_IDMaskOperation.h" + +IDMaskNode::IDMaskNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} +void IDMaskNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *bnode = this->getbNode(); + + IDMaskOperation *operation; + operation = new IDMaskOperation(); + operation->setObjectIndex(bnode->custom1); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + if (bnode->custom2 == 0 || context.getRenderData()->scemode & R_FULL_SAMPLE) { + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); + } + else { + AntiAliasOperation *antiAliasOperation = new AntiAliasOperation(); + converter.addOperation(antiAliasOperation); + + converter.addLink(operation->getOutputSocket(), antiAliasOperation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), antiAliasOperation->getOutputSocket(0)); + } +} diff --git a/source/blender/compositor/nodes/COM_IDMaskNode.cpp b/source/blender/compositor/nodes/COM_IDMaskNode.cpp deleted file mode 100644 index 5ba54d75bcd..00000000000 --- a/source/blender/compositor/nodes/COM_IDMaskNode.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_IDMaskNode.h" -#include "COM_AntiAliasOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_IDMaskOperation.h" - -IDMaskNode::IDMaskNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} -void IDMaskNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *bnode = this->getbNode(); - - IDMaskOperation *operation; - operation = new IDMaskOperation(); - operation->setObjectIndex(bnode->custom1); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - if (bnode->custom2 == 0 || context.getRenderData()->scemode & R_FULL_SAMPLE) { - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); - } - else { - AntiAliasOperation *antiAliasOperation = new AntiAliasOperation(); - converter.addOperation(antiAliasOperation); - - converter.addLink(operation->getOutputSocket(), antiAliasOperation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), antiAliasOperation->getOutputSocket(0)); - } -} diff --git a/source/blender/compositor/nodes/COM_ImageNode.cc b/source/blender/compositor/nodes/COM_ImageNode.cc new file mode 100644 index 00000000000..69729e018d7 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ImageNode.cc @@ -0,0 +1,299 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ImageNode.h" +#include "BKE_node.h" +#include "BLI_utildefines.h" +#include "COM_ConvertOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_ImageOperation.h" +#include "COM_MultilayerImageOperation.h" + +#include "COM_SeparateColorNode.h" +#include "COM_SetColorOperation.h" +#include "COM_SetValueOperation.h" +#include "COM_SetVectorOperation.h" + +ImageNode::ImageNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} +NodeOperation *ImageNode::doMultilayerCheck(NodeConverter &converter, + RenderLayer *render_layer, + RenderPass *render_pass, + Image *image, + ImageUser *user, + int framenumber, + int outputsocketIndex, + int view, + DataType datatype) const +{ + NodeOutput *outputSocket = this->getOutputSocket(outputsocketIndex); + MultilayerBaseOperation *operation = nullptr; + switch (datatype) { + case COM_DT_VALUE: + operation = new MultilayerValueOperation(render_layer, render_pass, view); + break; + case COM_DT_VECTOR: + operation = new MultilayerVectorOperation(render_layer, render_pass, view); + break; + case COM_DT_COLOR: + operation = new MultilayerColorOperation(render_layer, render_pass, view); + break; + default: + break; + } + operation->setImage(image); + operation->setImageUser(user); + operation->setFramenumber(framenumber); + + converter.addOperation(operation); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); + + return operation; +} + +void ImageNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + /** Image output */ + NodeOutput *outputImage = this->getOutputSocket(0); + bNode *editorNode = this->getbNode(); + Image *image = (Image *)editorNode->id; + ImageUser *imageuser = (ImageUser *)editorNode->storage; + int framenumber = context.getFramenumber(); + int numberOfOutputs = this->getNumberOfOutputSockets(); + bool outputStraightAlpha = (editorNode->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT) != 0; + BKE_image_user_frame_calc(image, imageuser, context.getFramenumber()); + /* force a load, we assume iuser index will be set OK anyway */ + if (image && image->type == IMA_TYPE_MULTILAYER) { + bool is_multilayer_ok = false; + ImBuf *ibuf = BKE_image_acquire_ibuf(image, imageuser, nullptr); + if (image->rr) { + RenderLayer *rl = (RenderLayer *)BLI_findlink(&image->rr->layers, imageuser->layer); + if (rl) { + NodeOutput *socket; + int index; + + is_multilayer_ok = true; + + for (index = 0; index < numberOfOutputs; index++) { + NodeOperation *operation = nullptr; + socket = this->getOutputSocket(index); + bNodeSocket *bnodeSocket = socket->getbNodeSocket(); + NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage; + RenderPass *rpass = (RenderPass *)BLI_findstring( + &rl->passes, storage->pass_name, offsetof(RenderPass, name)); + int view = 0; + + if (STREQ(storage->pass_name, RE_PASSNAME_COMBINED) && + STREQ(bnodeSocket->name, "Alpha")) { + /* Alpha output is already handled with the associated combined output. */ + continue; + } + + /* returns the image view to use for the current active view */ + if (BLI_listbase_count_at_most(&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)); + if (view == -1) { + view = 0; + } + } + else { + view = view_image - 1; + } + } + + if (rpass) { + switch (rpass->channels) { + case 1: + operation = doMultilayerCheck(converter, + rl, + rpass, + image, + imageuser, + framenumber, + index, + 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, + rpass, + image, + imageuser, + framenumber, + index, + view, + COM_DT_VECTOR); + break; + case 4: + operation = doMultilayerCheck(converter, + rl, + rpass, + image, + imageuser, + framenumber, + index, + view, + COM_DT_COLOR); + break; + default: + /* dummy operation is added below */ + break; + } + if (index == 0 && operation) { + converter.addPreview(operation->getOutputSocket()); + } + if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) { + for (int alphaIndex = 0; alphaIndex < numberOfOutputs; alphaIndex++) { + NodeOutput *alphaSocket = this->getOutputSocket(alphaIndex); + bNodeSocket *bnodeAlphaSocket = alphaSocket->getbNodeSocket(); + if (!STREQ(bnodeAlphaSocket->name, "Alpha")) { + continue; + } + NodeImageLayer *alphaStorage = (NodeImageLayer *)bnodeSocket->storage; + if (!STREQ(alphaStorage->pass_name, RE_PASSNAME_COMBINED)) { + continue; + } + SeparateChannelOperation *separate_operation; + separate_operation = new SeparateChannelOperation(); + separate_operation->setChannel(3); + converter.addOperation(separate_operation); + converter.addLink(operation->getOutputSocket(), + separate_operation->getInputSocket(0)); + converter.mapOutputSocket(alphaSocket, separate_operation->getOutputSocket()); + break; + } + } + } + + /* In case we can't load the layer. */ + if (operation == nullptr) { + converter.setInvalidOutput(getOutputSocket(index)); + } + } + } + } + BKE_image_release_ibuf(image, ibuf, nullptr); + + /* without this, multilayer that fail to load will crash blender T32490. */ + if (is_multilayer_ok == false) { + for (int i = 0; i < getNumberOfOutputSockets(); i++) { + converter.setInvalidOutput(getOutputSocket(i)); + } + } + } + else { + if (numberOfOutputs > 0) { + ImageOperation *operation = new ImageOperation(); + operation->setImage(image); + operation->setImageUser(imageuser); + operation->setFramenumber(framenumber); + operation->setRenderData(context.getRenderData()); + operation->setViewName(context.getViewName()); + converter.addOperation(operation); + + if (outputStraightAlpha) { + NodeOperation *alphaConvertOperation = new ConvertPremulToStraightOperation(); + + converter.addOperation(alphaConvertOperation); + converter.mapOutputSocket(outputImage, alphaConvertOperation->getOutputSocket()); + converter.addLink(operation->getOutputSocket(0), alphaConvertOperation->getInputSocket(0)); + } + else { + converter.mapOutputSocket(outputImage, operation->getOutputSocket()); + } + + converter.addPreview(operation->getOutputSocket()); + } + + if (numberOfOutputs > 1) { + NodeOutput *alphaImage = this->getOutputSocket(1); + ImageAlphaOperation *alphaOperation = new ImageAlphaOperation(); + 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()); + } + if (numberOfOutputs > 2) { + NodeOutput *depthImage = this->getOutputSocket(2); + ImageDepthOperation *depthOperation = new ImageDepthOperation(); + 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()); + } + if (numberOfOutputs > 3) { + /* happens when unlinking image datablock from multilayer node */ + for (int i = 3; i < numberOfOutputs; i++) { + NodeOutput *output = this->getOutputSocket(i); + NodeOperation *operation = nullptr; + switch (output->getDataType()) { + case COM_DT_VALUE: { + SetValueOperation *valueoperation = new SetValueOperation(); + valueoperation->setValue(0.0f); + operation = valueoperation; + break; + } + case COM_DT_VECTOR: { + SetVectorOperation *vectoroperation = new SetVectorOperation(); + vectoroperation->setX(0.0f); + vectoroperation->setY(0.0f); + vectoroperation->setW(0.0f); + operation = vectoroperation; + break; + } + case COM_DT_COLOR: { + SetColorOperation *coloroperation = new SetColorOperation(); + coloroperation->setChannel1(0.0f); + coloroperation->setChannel2(0.0f); + coloroperation->setChannel3(0.0f); + coloroperation->setChannel4(0.0f); + operation = coloroperation; + break; + } + } + + 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.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp deleted file mode 100644 index 69729e018d7..00000000000 --- a/source/blender/compositor/nodes/COM_ImageNode.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ImageNode.h" -#include "BKE_node.h" -#include "BLI_utildefines.h" -#include "COM_ConvertOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_ImageOperation.h" -#include "COM_MultilayerImageOperation.h" - -#include "COM_SeparateColorNode.h" -#include "COM_SetColorOperation.h" -#include "COM_SetValueOperation.h" -#include "COM_SetVectorOperation.h" - -ImageNode::ImageNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} -NodeOperation *ImageNode::doMultilayerCheck(NodeConverter &converter, - RenderLayer *render_layer, - RenderPass *render_pass, - Image *image, - ImageUser *user, - int framenumber, - int outputsocketIndex, - int view, - DataType datatype) const -{ - NodeOutput *outputSocket = this->getOutputSocket(outputsocketIndex); - MultilayerBaseOperation *operation = nullptr; - switch (datatype) { - case COM_DT_VALUE: - operation = new MultilayerValueOperation(render_layer, render_pass, view); - break; - case COM_DT_VECTOR: - operation = new MultilayerVectorOperation(render_layer, render_pass, view); - break; - case COM_DT_COLOR: - operation = new MultilayerColorOperation(render_layer, render_pass, view); - break; - default: - break; - } - operation->setImage(image); - operation->setImageUser(user); - operation->setFramenumber(framenumber); - - converter.addOperation(operation); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); - - return operation; -} - -void ImageNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - /** Image output */ - NodeOutput *outputImage = this->getOutputSocket(0); - bNode *editorNode = this->getbNode(); - Image *image = (Image *)editorNode->id; - ImageUser *imageuser = (ImageUser *)editorNode->storage; - int framenumber = context.getFramenumber(); - int numberOfOutputs = this->getNumberOfOutputSockets(); - bool outputStraightAlpha = (editorNode->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT) != 0; - BKE_image_user_frame_calc(image, imageuser, context.getFramenumber()); - /* force a load, we assume iuser index will be set OK anyway */ - if (image && image->type == IMA_TYPE_MULTILAYER) { - bool is_multilayer_ok = false; - ImBuf *ibuf = BKE_image_acquire_ibuf(image, imageuser, nullptr); - if (image->rr) { - RenderLayer *rl = (RenderLayer *)BLI_findlink(&image->rr->layers, imageuser->layer); - if (rl) { - NodeOutput *socket; - int index; - - is_multilayer_ok = true; - - for (index = 0; index < numberOfOutputs; index++) { - NodeOperation *operation = nullptr; - socket = this->getOutputSocket(index); - bNodeSocket *bnodeSocket = socket->getbNodeSocket(); - NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage; - RenderPass *rpass = (RenderPass *)BLI_findstring( - &rl->passes, storage->pass_name, offsetof(RenderPass, name)); - int view = 0; - - if (STREQ(storage->pass_name, RE_PASSNAME_COMBINED) && - STREQ(bnodeSocket->name, "Alpha")) { - /* Alpha output is already handled with the associated combined output. */ - continue; - } - - /* returns the image view to use for the current active view */ - if (BLI_listbase_count_at_most(&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)); - if (view == -1) { - view = 0; - } - } - else { - view = view_image - 1; - } - } - - if (rpass) { - switch (rpass->channels) { - case 1: - operation = doMultilayerCheck(converter, - rl, - rpass, - image, - imageuser, - framenumber, - index, - 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, - rpass, - image, - imageuser, - framenumber, - index, - view, - COM_DT_VECTOR); - break; - case 4: - operation = doMultilayerCheck(converter, - rl, - rpass, - image, - imageuser, - framenumber, - index, - view, - COM_DT_COLOR); - break; - default: - /* dummy operation is added below */ - break; - } - if (index == 0 && operation) { - converter.addPreview(operation->getOutputSocket()); - } - if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) { - for (int alphaIndex = 0; alphaIndex < numberOfOutputs; alphaIndex++) { - NodeOutput *alphaSocket = this->getOutputSocket(alphaIndex); - bNodeSocket *bnodeAlphaSocket = alphaSocket->getbNodeSocket(); - if (!STREQ(bnodeAlphaSocket->name, "Alpha")) { - continue; - } - NodeImageLayer *alphaStorage = (NodeImageLayer *)bnodeSocket->storage; - if (!STREQ(alphaStorage->pass_name, RE_PASSNAME_COMBINED)) { - continue; - } - SeparateChannelOperation *separate_operation; - separate_operation = new SeparateChannelOperation(); - separate_operation->setChannel(3); - converter.addOperation(separate_operation); - converter.addLink(operation->getOutputSocket(), - separate_operation->getInputSocket(0)); - converter.mapOutputSocket(alphaSocket, separate_operation->getOutputSocket()); - break; - } - } - } - - /* In case we can't load the layer. */ - if (operation == nullptr) { - converter.setInvalidOutput(getOutputSocket(index)); - } - } - } - } - BKE_image_release_ibuf(image, ibuf, nullptr); - - /* without this, multilayer that fail to load will crash blender T32490. */ - if (is_multilayer_ok == false) { - for (int i = 0; i < getNumberOfOutputSockets(); i++) { - converter.setInvalidOutput(getOutputSocket(i)); - } - } - } - else { - if (numberOfOutputs > 0) { - ImageOperation *operation = new ImageOperation(); - operation->setImage(image); - operation->setImageUser(imageuser); - operation->setFramenumber(framenumber); - operation->setRenderData(context.getRenderData()); - operation->setViewName(context.getViewName()); - converter.addOperation(operation); - - if (outputStraightAlpha) { - NodeOperation *alphaConvertOperation = new ConvertPremulToStraightOperation(); - - converter.addOperation(alphaConvertOperation); - converter.mapOutputSocket(outputImage, alphaConvertOperation->getOutputSocket()); - converter.addLink(operation->getOutputSocket(0), alphaConvertOperation->getInputSocket(0)); - } - else { - converter.mapOutputSocket(outputImage, operation->getOutputSocket()); - } - - converter.addPreview(operation->getOutputSocket()); - } - - if (numberOfOutputs > 1) { - NodeOutput *alphaImage = this->getOutputSocket(1); - ImageAlphaOperation *alphaOperation = new ImageAlphaOperation(); - 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()); - } - if (numberOfOutputs > 2) { - NodeOutput *depthImage = this->getOutputSocket(2); - ImageDepthOperation *depthOperation = new ImageDepthOperation(); - 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()); - } - if (numberOfOutputs > 3) { - /* happens when unlinking image datablock from multilayer node */ - for (int i = 3; i < numberOfOutputs; i++) { - NodeOutput *output = this->getOutputSocket(i); - NodeOperation *operation = nullptr; - switch (output->getDataType()) { - case COM_DT_VALUE: { - SetValueOperation *valueoperation = new SetValueOperation(); - valueoperation->setValue(0.0f); - operation = valueoperation; - break; - } - case COM_DT_VECTOR: { - SetVectorOperation *vectoroperation = new SetVectorOperation(); - vectoroperation->setX(0.0f); - vectoroperation->setY(0.0f); - vectoroperation->setW(0.0f); - operation = vectoroperation; - break; - } - case COM_DT_COLOR: { - SetColorOperation *coloroperation = new SetColorOperation(); - coloroperation->setChannel1(0.0f); - coloroperation->setChannel2(0.0f); - coloroperation->setChannel3(0.0f); - coloroperation->setChannel4(0.0f); - operation = coloroperation; - break; - } - } - - 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_InpaintNode.cc b/source/blender/compositor/nodes/COM_InpaintNode.cc new file mode 100644 index 00000000000..40fe63ec9f3 --- /dev/null +++ b/source/blender/compositor/nodes/COM_InpaintNode.cc @@ -0,0 +1,45 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_InpaintNode.h" +#include "BLI_math.h" +#include "COM_ExecutionSystem.h" +#include "COM_InpaintOperation.h" +#include "DNA_scene_types.h" + +InpaintNode::InpaintNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void InpaintNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + + bNode *editorNode = this->getbNode(); + + /* if (editorNode->custom1 == CMP_NODE_INPAINT_SIMPLE) { */ + if (true) { + InpaintSimpleOperation *operation = new InpaintSimpleOperation(); + operation->setIterations(editorNode->custom2); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); + } +} diff --git a/source/blender/compositor/nodes/COM_InpaintNode.cpp b/source/blender/compositor/nodes/COM_InpaintNode.cpp deleted file mode 100644 index 40fe63ec9f3..00000000000 --- a/source/blender/compositor/nodes/COM_InpaintNode.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_InpaintNode.h" -#include "BLI_math.h" -#include "COM_ExecutionSystem.h" -#include "COM_InpaintOperation.h" -#include "DNA_scene_types.h" - -InpaintNode::InpaintNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void InpaintNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - - bNode *editorNode = this->getbNode(); - - /* if (editorNode->custom1 == CMP_NODE_INPAINT_SIMPLE) { */ - if (true) { - InpaintSimpleOperation *operation = new InpaintSimpleOperation(); - operation->setIterations(editorNode->custom2); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); - } -} diff --git a/source/blender/compositor/nodes/COM_InvertNode.cc b/source/blender/compositor/nodes/COM_InvertNode.cc new file mode 100644 index 00000000000..913452c42c8 --- /dev/null +++ b/source/blender/compositor/nodes/COM_InvertNode.cc @@ -0,0 +1,41 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_InvertNode.h" +#include "BKE_node.h" +#include "COM_ExecutionSystem.h" +#include "COM_InvertOperation.h" + +InvertNode::InvertNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void InvertNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + InvertOperation *operation = new InvertOperation(); + bNode *node = this->getbNode(); + operation->setColor(node->custom1 & CMP_CHAN_RGB); + operation->setAlpha(node->custom1 & CMP_CHAN_A); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_InvertNode.cpp b/source/blender/compositor/nodes/COM_InvertNode.cpp deleted file mode 100644 index 913452c42c8..00000000000 --- a/source/blender/compositor/nodes/COM_InvertNode.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_InvertNode.h" -#include "BKE_node.h" -#include "COM_ExecutionSystem.h" -#include "COM_InvertOperation.h" - -InvertNode::InvertNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void InvertNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - InvertOperation *operation = new InvertOperation(); - bNode *node = this->getbNode(); - operation->setColor(node->custom1 & CMP_CHAN_RGB); - operation->setAlpha(node->custom1 & CMP_CHAN_A); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_KeyingNode.cc b/source/blender/compositor/nodes/COM_KeyingNode.cc new file mode 100644 index 00000000000..9b493d3f332 --- /dev/null +++ b/source/blender/compositor/nodes/COM_KeyingNode.cc @@ -0,0 +1,350 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_KeyingNode.h" + +#include "COM_ExecutionSystem.h" + +#include "COM_KeyingBlurOperation.h" +#include "COM_KeyingClipOperation.h" +#include "COM_KeyingDespillOperation.h" +#include "COM_KeyingOperation.h" + +#include "COM_MathBaseOperation.h" + +#include "COM_ConvertOperation.h" +#include "COM_SetValueOperation.h" + +#include "COM_DilateErodeOperation.h" + +#include "COM_SetAlphaMultiplyOperation.h" + +#include "COM_GaussianAlphaXBlurOperation.h" +#include "COM_GaussianAlphaYBlurOperation.h" + +KeyingNode::KeyingNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +NodeOperationOutput *KeyingNode::setupPreBlur(NodeConverter &converter, + NodeInput *inputImage, + int size) const +{ + ConvertRGBToYCCOperation *convertRGBToYCCOperation = new ConvertRGBToYCCOperation(); + convertRGBToYCCOperation->setMode(BLI_YCC_ITU_BT709); + converter.addOperation(convertRGBToYCCOperation); + + converter.mapInputSocket(inputImage, convertRGBToYCCOperation->getInputSocket(0)); + + CombineChannelsOperation *combineOperation = new CombineChannelsOperation(); + converter.addOperation(combineOperation); + + for (int channel = 0; channel < 4; channel++) { + SeparateChannelOperation *separateOperation = new SeparateChannelOperation(); + separateOperation->setChannel(channel); + converter.addOperation(separateOperation); + + converter.addLink(convertRGBToYCCOperation->getOutputSocket(0), + separateOperation->getInputSocket(0)); + + if (ELEM(channel, 0, 3)) { + converter.addLink(separateOperation->getOutputSocket(0), + combineOperation->getInputSocket(channel)); + } + else { + KeyingBlurOperation *blurXOperation = new KeyingBlurOperation(); + blurXOperation->setSize(size); + blurXOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_X); + converter.addOperation(blurXOperation); + + KeyingBlurOperation *blurYOperation = new KeyingBlurOperation(); + blurYOperation->setSize(size); + blurYOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_Y); + converter.addOperation(blurYOperation); + + converter.addLink(separateOperation->getOutputSocket(), blurXOperation->getInputSocket(0)); + converter.addLink(blurXOperation->getOutputSocket(), blurYOperation->getInputSocket(0)); + converter.addLink(blurYOperation->getOutputSocket(0), + combineOperation->getInputSocket(channel)); + } + } + + ConvertYCCToRGBOperation *convertYCCToRGBOperation = new ConvertYCCToRGBOperation(); + convertYCCToRGBOperation->setMode(BLI_YCC_ITU_BT709); + converter.addOperation(convertYCCToRGBOperation); + + converter.addLink(combineOperation->getOutputSocket(0), + convertYCCToRGBOperation->getInputSocket(0)); + + return convertYCCToRGBOperation->getOutputSocket(0); +} + +NodeOperationOutput *KeyingNode::setupPostBlur(NodeConverter &converter, + NodeOperationOutput *postBlurInput, + int size) const +{ + KeyingBlurOperation *blurXOperation = new KeyingBlurOperation(); + blurXOperation->setSize(size); + blurXOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_X); + converter.addOperation(blurXOperation); + + KeyingBlurOperation *blurYOperation = new KeyingBlurOperation(); + blurYOperation->setSize(size); + blurYOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_Y); + converter.addOperation(blurYOperation); + + converter.addLink(postBlurInput, blurXOperation->getInputSocket(0)); + converter.addLink(blurXOperation->getOutputSocket(), blurYOperation->getInputSocket(0)); + + return blurYOperation->getOutputSocket(); +} + +NodeOperationOutput *KeyingNode::setupDilateErode(NodeConverter &converter, + NodeOperationOutput *dilateErodeInput, + int distance) const +{ + DilateDistanceOperation *dilateErodeOperation; + if (distance > 0) { + dilateErodeOperation = new DilateDistanceOperation(); + dilateErodeOperation->setDistance(distance); + } + else { + dilateErodeOperation = new ErodeDistanceOperation(); + dilateErodeOperation->setDistance(-distance); + } + converter.addOperation(dilateErodeOperation); + + converter.addLink(dilateErodeInput, dilateErodeOperation->getInputSocket(0)); + + return dilateErodeOperation->getOutputSocket(0); +} + +NodeOperationOutput *KeyingNode::setupFeather(NodeConverter &converter, + const CompositorContext &context, + NodeOperationOutput *featherInput, + int falloff, + int distance) const +{ + /* this uses a modified gaussian blur function otherwise its far too slow */ + CompositorQuality quality = context.getQuality(); + + /* initialize node data */ + NodeBlurData data; + memset(&data, 0, sizeof(NodeBlurData)); + data.filtertype = R_FILTER_GAUSS; + if (distance > 0) { + data.sizex = data.sizey = distance; + } + else { + data.sizex = data.sizey = -distance; + } + + GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation(); + operationx->setData(&data); + operationx->setQuality(quality); + operationx->setSize(1.0f); + operationx->setSubtract(distance < 0); + operationx->setFalloff(falloff); + converter.addOperation(operationx); + + GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation(); + operationy->setData(&data); + operationy->setQuality(quality); + operationy->setSize(1.0f); + operationy->setSubtract(distance < 0); + operationy->setFalloff(falloff); + converter.addOperation(operationy); + + converter.addLink(featherInput, operationx->getInputSocket(0)); + converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0)); + + return operationy->getOutputSocket(); +} + +NodeOperationOutput *KeyingNode::setupDespill(NodeConverter &converter, + NodeOperationOutput *despillInput, + NodeInput *inputScreen, + float factor, + float colorBalance) const +{ + KeyingDespillOperation *despillOperation = new KeyingDespillOperation(); + despillOperation->setDespillFactor(factor); + despillOperation->setColorBalance(colorBalance); + converter.addOperation(despillOperation); + + converter.addLink(despillInput, despillOperation->getInputSocket(0)); + converter.mapInputSocket(inputScreen, despillOperation->getInputSocket(1)); + + return despillOperation->getOutputSocket(0); +} + +NodeOperationOutput *KeyingNode::setupClip(NodeConverter &converter, + NodeOperationOutput *clipInput, + int kernelRadius, + float kernelTolerance, + float clipBlack, + float clipWhite, + bool edgeMatte) const +{ + KeyingClipOperation *clipOperation = new KeyingClipOperation(); + clipOperation->setKernelRadius(kernelRadius); + clipOperation->setKernelTolerance(kernelTolerance); + clipOperation->setClipBlack(clipBlack); + clipOperation->setClipWhite(clipWhite); + clipOperation->setIsEdgeMatte(edgeMatte); + converter.addOperation(clipOperation); + + converter.addLink(clipInput, clipOperation->getInputSocket(0)); + + return clipOperation->getOutputSocket(0); +} + +void KeyingNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *editorNode = this->getbNode(); + NodeKeyingData *keying_data = (NodeKeyingData *)editorNode->storage; + + NodeInput *inputImage = this->getInputSocket(0); + NodeInput *inputScreen = this->getInputSocket(1); + NodeInput *inputGarbageMatte = this->getInputSocket(2); + NodeInput *inputCoreMatte = this->getInputSocket(3); + NodeOutput *outputImage = this->getOutputSocket(0); + NodeOutput *outputMatte = this->getOutputSocket(1); + NodeOutput *outputEdges = this->getOutputSocket(2); + NodeOperationOutput *postprocessedMatte = nullptr, *postprocessedImage = nullptr, + *edgesMatte = nullptr; + + /* keying operation */ + KeyingOperation *keyingOperation = new KeyingOperation(); + keyingOperation->setScreenBalance(keying_data->screen_balance); + converter.addOperation(keyingOperation); + + converter.mapInputSocket(inputScreen, keyingOperation->getInputSocket(1)); + + if (keying_data->blur_pre) { + /* Chroma pre-blur operation for input of keying operation. */ + NodeOperationOutput *preBlurredImage = setupPreBlur( + converter, inputImage, keying_data->blur_pre); + converter.addLink(preBlurredImage, keyingOperation->getInputSocket(0)); + } + else { + converter.mapInputSocket(inputImage, keyingOperation->getInputSocket(0)); + } + + postprocessedMatte = keyingOperation->getOutputSocket(); + + /* black / white clipping */ + if (keying_data->clip_black > 0.0f || keying_data->clip_white < 1.0f) { + postprocessedMatte = setupClip(converter, + postprocessedMatte, + keying_data->edge_kernel_radius, + keying_data->edge_kernel_tolerance, + keying_data->clip_black, + keying_data->clip_white, + false); + } + + /* output edge matte */ + edgesMatte = setupClip(converter, + postprocessedMatte, + keying_data->edge_kernel_radius, + keying_data->edge_kernel_tolerance, + keying_data->clip_black, + keying_data->clip_white, + true); + + /* apply garbage matte */ + if (inputGarbageMatte->isLinked()) { + SetValueOperation *valueOperation = new SetValueOperation(); + valueOperation->setValue(1.0f); + converter.addOperation(valueOperation); + + MathSubtractOperation *subtractOperation = new MathSubtractOperation(); + converter.addOperation(subtractOperation); + + MathMinimumOperation *minOperation = new MathMinimumOperation(); + converter.addOperation(minOperation); + + converter.addLink(valueOperation->getOutputSocket(), subtractOperation->getInputSocket(0)); + converter.mapInputSocket(inputGarbageMatte, subtractOperation->getInputSocket(1)); + + converter.addLink(subtractOperation->getOutputSocket(), minOperation->getInputSocket(0)); + converter.addLink(postprocessedMatte, minOperation->getInputSocket(1)); + + postprocessedMatte = minOperation->getOutputSocket(); + } + + /* apply core matte */ + if (inputCoreMatte->isLinked()) { + MathMaximumOperation *maxOperation = new MathMaximumOperation(); + converter.addOperation(maxOperation); + + converter.mapInputSocket(inputCoreMatte, maxOperation->getInputSocket(0)); + converter.addLink(postprocessedMatte, maxOperation->getInputSocket(1)); + + postprocessedMatte = maxOperation->getOutputSocket(); + } + + /* apply blur on matte if needed */ + if (keying_data->blur_post) { + postprocessedMatte = setupPostBlur(converter, postprocessedMatte, keying_data->blur_post); + } + + /* matte dilate/erode */ + if (keying_data->dilate_distance != 0) { + postprocessedMatte = setupDilateErode( + converter, postprocessedMatte, keying_data->dilate_distance); + } + + /* matte feather */ + if (keying_data->feather_distance != 0) { + postprocessedMatte = setupFeather(converter, + context, + postprocessedMatte, + keying_data->feather_falloff, + keying_data->feather_distance); + } + + /* set alpha channel to output image */ + SetAlphaMultiplyOperation *alphaOperation = new SetAlphaMultiplyOperation(); + converter.addOperation(alphaOperation); + + converter.mapInputSocket(inputImage, alphaOperation->getInputSocket(0)); + converter.addLink(postprocessedMatte, alphaOperation->getInputSocket(1)); + + postprocessedImage = alphaOperation->getOutputSocket(); + + /* despill output image */ + if (keying_data->despill_factor > 0.0f) { + postprocessedImage = setupDespill(converter, + postprocessedImage, + inputScreen, + keying_data->despill_factor, + keying_data->despill_balance); + } + + /* connect result to output sockets */ + converter.mapOutputSocket(outputImage, postprocessedImage); + converter.mapOutputSocket(outputMatte, postprocessedMatte); + + if (edgesMatte) { + converter.mapOutputSocket(outputEdges, edgesMatte); + } +} diff --git a/source/blender/compositor/nodes/COM_KeyingNode.cpp b/source/blender/compositor/nodes/COM_KeyingNode.cpp deleted file mode 100644 index 9b493d3f332..00000000000 --- a/source/blender/compositor/nodes/COM_KeyingNode.cpp +++ /dev/null @@ -1,350 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_KeyingNode.h" - -#include "COM_ExecutionSystem.h" - -#include "COM_KeyingBlurOperation.h" -#include "COM_KeyingClipOperation.h" -#include "COM_KeyingDespillOperation.h" -#include "COM_KeyingOperation.h" - -#include "COM_MathBaseOperation.h" - -#include "COM_ConvertOperation.h" -#include "COM_SetValueOperation.h" - -#include "COM_DilateErodeOperation.h" - -#include "COM_SetAlphaMultiplyOperation.h" - -#include "COM_GaussianAlphaXBlurOperation.h" -#include "COM_GaussianAlphaYBlurOperation.h" - -KeyingNode::KeyingNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -NodeOperationOutput *KeyingNode::setupPreBlur(NodeConverter &converter, - NodeInput *inputImage, - int size) const -{ - ConvertRGBToYCCOperation *convertRGBToYCCOperation = new ConvertRGBToYCCOperation(); - convertRGBToYCCOperation->setMode(BLI_YCC_ITU_BT709); - converter.addOperation(convertRGBToYCCOperation); - - converter.mapInputSocket(inputImage, convertRGBToYCCOperation->getInputSocket(0)); - - CombineChannelsOperation *combineOperation = new CombineChannelsOperation(); - converter.addOperation(combineOperation); - - for (int channel = 0; channel < 4; channel++) { - SeparateChannelOperation *separateOperation = new SeparateChannelOperation(); - separateOperation->setChannel(channel); - converter.addOperation(separateOperation); - - converter.addLink(convertRGBToYCCOperation->getOutputSocket(0), - separateOperation->getInputSocket(0)); - - if (ELEM(channel, 0, 3)) { - converter.addLink(separateOperation->getOutputSocket(0), - combineOperation->getInputSocket(channel)); - } - else { - KeyingBlurOperation *blurXOperation = new KeyingBlurOperation(); - blurXOperation->setSize(size); - blurXOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_X); - converter.addOperation(blurXOperation); - - KeyingBlurOperation *blurYOperation = new KeyingBlurOperation(); - blurYOperation->setSize(size); - blurYOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_Y); - converter.addOperation(blurYOperation); - - converter.addLink(separateOperation->getOutputSocket(), blurXOperation->getInputSocket(0)); - converter.addLink(blurXOperation->getOutputSocket(), blurYOperation->getInputSocket(0)); - converter.addLink(blurYOperation->getOutputSocket(0), - combineOperation->getInputSocket(channel)); - } - } - - ConvertYCCToRGBOperation *convertYCCToRGBOperation = new ConvertYCCToRGBOperation(); - convertYCCToRGBOperation->setMode(BLI_YCC_ITU_BT709); - converter.addOperation(convertYCCToRGBOperation); - - converter.addLink(combineOperation->getOutputSocket(0), - convertYCCToRGBOperation->getInputSocket(0)); - - return convertYCCToRGBOperation->getOutputSocket(0); -} - -NodeOperationOutput *KeyingNode::setupPostBlur(NodeConverter &converter, - NodeOperationOutput *postBlurInput, - int size) const -{ - KeyingBlurOperation *blurXOperation = new KeyingBlurOperation(); - blurXOperation->setSize(size); - blurXOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_X); - converter.addOperation(blurXOperation); - - KeyingBlurOperation *blurYOperation = new KeyingBlurOperation(); - blurYOperation->setSize(size); - blurYOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_Y); - converter.addOperation(blurYOperation); - - converter.addLink(postBlurInput, blurXOperation->getInputSocket(0)); - converter.addLink(blurXOperation->getOutputSocket(), blurYOperation->getInputSocket(0)); - - return blurYOperation->getOutputSocket(); -} - -NodeOperationOutput *KeyingNode::setupDilateErode(NodeConverter &converter, - NodeOperationOutput *dilateErodeInput, - int distance) const -{ - DilateDistanceOperation *dilateErodeOperation; - if (distance > 0) { - dilateErodeOperation = new DilateDistanceOperation(); - dilateErodeOperation->setDistance(distance); - } - else { - dilateErodeOperation = new ErodeDistanceOperation(); - dilateErodeOperation->setDistance(-distance); - } - converter.addOperation(dilateErodeOperation); - - converter.addLink(dilateErodeInput, dilateErodeOperation->getInputSocket(0)); - - return dilateErodeOperation->getOutputSocket(0); -} - -NodeOperationOutput *KeyingNode::setupFeather(NodeConverter &converter, - const CompositorContext &context, - NodeOperationOutput *featherInput, - int falloff, - int distance) const -{ - /* this uses a modified gaussian blur function otherwise its far too slow */ - CompositorQuality quality = context.getQuality(); - - /* initialize node data */ - NodeBlurData data; - memset(&data, 0, sizeof(NodeBlurData)); - data.filtertype = R_FILTER_GAUSS; - if (distance > 0) { - data.sizex = data.sizey = distance; - } - else { - data.sizex = data.sizey = -distance; - } - - GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation(); - operationx->setData(&data); - operationx->setQuality(quality); - operationx->setSize(1.0f); - operationx->setSubtract(distance < 0); - operationx->setFalloff(falloff); - converter.addOperation(operationx); - - GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation(); - operationy->setData(&data); - operationy->setQuality(quality); - operationy->setSize(1.0f); - operationy->setSubtract(distance < 0); - operationy->setFalloff(falloff); - converter.addOperation(operationy); - - converter.addLink(featherInput, operationx->getInputSocket(0)); - converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0)); - - return operationy->getOutputSocket(); -} - -NodeOperationOutput *KeyingNode::setupDespill(NodeConverter &converter, - NodeOperationOutput *despillInput, - NodeInput *inputScreen, - float factor, - float colorBalance) const -{ - KeyingDespillOperation *despillOperation = new KeyingDespillOperation(); - despillOperation->setDespillFactor(factor); - despillOperation->setColorBalance(colorBalance); - converter.addOperation(despillOperation); - - converter.addLink(despillInput, despillOperation->getInputSocket(0)); - converter.mapInputSocket(inputScreen, despillOperation->getInputSocket(1)); - - return despillOperation->getOutputSocket(0); -} - -NodeOperationOutput *KeyingNode::setupClip(NodeConverter &converter, - NodeOperationOutput *clipInput, - int kernelRadius, - float kernelTolerance, - float clipBlack, - float clipWhite, - bool edgeMatte) const -{ - KeyingClipOperation *clipOperation = new KeyingClipOperation(); - clipOperation->setKernelRadius(kernelRadius); - clipOperation->setKernelTolerance(kernelTolerance); - clipOperation->setClipBlack(clipBlack); - clipOperation->setClipWhite(clipWhite); - clipOperation->setIsEdgeMatte(edgeMatte); - converter.addOperation(clipOperation); - - converter.addLink(clipInput, clipOperation->getInputSocket(0)); - - return clipOperation->getOutputSocket(0); -} - -void KeyingNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *editorNode = this->getbNode(); - NodeKeyingData *keying_data = (NodeKeyingData *)editorNode->storage; - - NodeInput *inputImage = this->getInputSocket(0); - NodeInput *inputScreen = this->getInputSocket(1); - NodeInput *inputGarbageMatte = this->getInputSocket(2); - NodeInput *inputCoreMatte = this->getInputSocket(3); - NodeOutput *outputImage = this->getOutputSocket(0); - NodeOutput *outputMatte = this->getOutputSocket(1); - NodeOutput *outputEdges = this->getOutputSocket(2); - NodeOperationOutput *postprocessedMatte = nullptr, *postprocessedImage = nullptr, - *edgesMatte = nullptr; - - /* keying operation */ - KeyingOperation *keyingOperation = new KeyingOperation(); - keyingOperation->setScreenBalance(keying_data->screen_balance); - converter.addOperation(keyingOperation); - - converter.mapInputSocket(inputScreen, keyingOperation->getInputSocket(1)); - - if (keying_data->blur_pre) { - /* Chroma pre-blur operation for input of keying operation. */ - NodeOperationOutput *preBlurredImage = setupPreBlur( - converter, inputImage, keying_data->blur_pre); - converter.addLink(preBlurredImage, keyingOperation->getInputSocket(0)); - } - else { - converter.mapInputSocket(inputImage, keyingOperation->getInputSocket(0)); - } - - postprocessedMatte = keyingOperation->getOutputSocket(); - - /* black / white clipping */ - if (keying_data->clip_black > 0.0f || keying_data->clip_white < 1.0f) { - postprocessedMatte = setupClip(converter, - postprocessedMatte, - keying_data->edge_kernel_radius, - keying_data->edge_kernel_tolerance, - keying_data->clip_black, - keying_data->clip_white, - false); - } - - /* output edge matte */ - edgesMatte = setupClip(converter, - postprocessedMatte, - keying_data->edge_kernel_radius, - keying_data->edge_kernel_tolerance, - keying_data->clip_black, - keying_data->clip_white, - true); - - /* apply garbage matte */ - if (inputGarbageMatte->isLinked()) { - SetValueOperation *valueOperation = new SetValueOperation(); - valueOperation->setValue(1.0f); - converter.addOperation(valueOperation); - - MathSubtractOperation *subtractOperation = new MathSubtractOperation(); - converter.addOperation(subtractOperation); - - MathMinimumOperation *minOperation = new MathMinimumOperation(); - converter.addOperation(minOperation); - - converter.addLink(valueOperation->getOutputSocket(), subtractOperation->getInputSocket(0)); - converter.mapInputSocket(inputGarbageMatte, subtractOperation->getInputSocket(1)); - - converter.addLink(subtractOperation->getOutputSocket(), minOperation->getInputSocket(0)); - converter.addLink(postprocessedMatte, minOperation->getInputSocket(1)); - - postprocessedMatte = minOperation->getOutputSocket(); - } - - /* apply core matte */ - if (inputCoreMatte->isLinked()) { - MathMaximumOperation *maxOperation = new MathMaximumOperation(); - converter.addOperation(maxOperation); - - converter.mapInputSocket(inputCoreMatte, maxOperation->getInputSocket(0)); - converter.addLink(postprocessedMatte, maxOperation->getInputSocket(1)); - - postprocessedMatte = maxOperation->getOutputSocket(); - } - - /* apply blur on matte if needed */ - if (keying_data->blur_post) { - postprocessedMatte = setupPostBlur(converter, postprocessedMatte, keying_data->blur_post); - } - - /* matte dilate/erode */ - if (keying_data->dilate_distance != 0) { - postprocessedMatte = setupDilateErode( - converter, postprocessedMatte, keying_data->dilate_distance); - } - - /* matte feather */ - if (keying_data->feather_distance != 0) { - postprocessedMatte = setupFeather(converter, - context, - postprocessedMatte, - keying_data->feather_falloff, - keying_data->feather_distance); - } - - /* set alpha channel to output image */ - SetAlphaMultiplyOperation *alphaOperation = new SetAlphaMultiplyOperation(); - converter.addOperation(alphaOperation); - - converter.mapInputSocket(inputImage, alphaOperation->getInputSocket(0)); - converter.addLink(postprocessedMatte, alphaOperation->getInputSocket(1)); - - postprocessedImage = alphaOperation->getOutputSocket(); - - /* despill output image */ - if (keying_data->despill_factor > 0.0f) { - postprocessedImage = setupDespill(converter, - postprocessedImage, - inputScreen, - keying_data->despill_factor, - keying_data->despill_balance); - } - - /* connect result to output sockets */ - converter.mapOutputSocket(outputImage, postprocessedImage); - converter.mapOutputSocket(outputMatte, postprocessedMatte); - - if (edgesMatte) { - converter.mapOutputSocket(outputEdges, edgesMatte); - } -} diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.cc b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc new file mode 100644 index 00000000000..93a9a071226 --- /dev/null +++ b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc @@ -0,0 +1,47 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_KeyingScreenNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_KeyingScreenOperation.h" + +#include "DNA_movieclip_types.h" + +KeyingScreenNode::KeyingScreenNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void KeyingScreenNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *editorNode = this->getbNode(); + MovieClip *clip = (MovieClip *)editorNode->id; + NodeKeyingScreenData *keyingscreen_data = (NodeKeyingScreenData *)editorNode->storage; + + NodeOutput *outputScreen = this->getOutputSocket(0); + + // always connect the output image + KeyingScreenOperation *operation = new KeyingScreenOperation(); + operation->setMovieClip(clip); + operation->setTrackingObject(keyingscreen_data->tracking_object); + operation->setFramenumber(context.getFramenumber()); + converter.addOperation(operation); + + converter.mapOutputSocket(outputScreen, operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp b/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp deleted file mode 100644 index 93a9a071226..00000000000 --- a/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_KeyingScreenNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_KeyingScreenOperation.h" - -#include "DNA_movieclip_types.h" - -KeyingScreenNode::KeyingScreenNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void KeyingScreenNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *editorNode = this->getbNode(); - MovieClip *clip = (MovieClip *)editorNode->id; - NodeKeyingScreenData *keyingscreen_data = (NodeKeyingScreenData *)editorNode->storage; - - NodeOutput *outputScreen = this->getOutputSocket(0); - - // always connect the output image - KeyingScreenOperation *operation = new KeyingScreenOperation(); - operation->setMovieClip(clip); - operation->setTrackingObject(keyingscreen_data->tracking_object); - operation->setFramenumber(context.getFramenumber()); - converter.addOperation(operation); - - converter.mapOutputSocket(outputScreen, operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_LensDistortionNode.cc b/source/blender/compositor/nodes/COM_LensDistortionNode.cc new file mode 100644 index 00000000000..34d2fba6433 --- /dev/null +++ b/source/blender/compositor/nodes/COM_LensDistortionNode.cc @@ -0,0 +1,61 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_LensDistortionNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_ProjectorLensDistortionOperation.h" +#include "COM_ScreenLensDistortionOperation.h" + +LensDistortionNode::LensDistortionNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void LensDistortionNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *editorNode = this->getbNode(); + NodeLensDist *data = (NodeLensDist *)editorNode->storage; + if (data->proj) { + ProjectorLensDistortionOperation *operation = new ProjectorLensDistortionOperation(); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); + } + else { + ScreenLensDistortionOperation *operation = new ScreenLensDistortionOperation(); + operation->setFit(data->fit); + operation->setJitter(data->jit); + + if (!getInputSocket(1)->isLinked()) { + operation->setDistortion(getInputSocket(1)->getEditorValueFloat()); + } + if (!getInputSocket(2)->isLinked()) { + operation->setDispersion(getInputSocket(2)->getEditorValueFloat()); + } + + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); + } +} diff --git a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp b/source/blender/compositor/nodes/COM_LensDistortionNode.cpp deleted file mode 100644 index 34d2fba6433..00000000000 --- a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_LensDistortionNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_ProjectorLensDistortionOperation.h" -#include "COM_ScreenLensDistortionOperation.h" - -LensDistortionNode::LensDistortionNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void LensDistortionNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *editorNode = this->getbNode(); - NodeLensDist *data = (NodeLensDist *)editorNode->storage; - if (data->proj) { - ProjectorLensDistortionOperation *operation = new ProjectorLensDistortionOperation(); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); - } - else { - ScreenLensDistortionOperation *operation = new ScreenLensDistortionOperation(); - operation->setFit(data->fit); - operation->setJitter(data->jit); - - if (!getInputSocket(1)->isLinked()) { - operation->setDistortion(getInputSocket(1)->getEditorValueFloat()); - } - if (!getInputSocket(2)->isLinked()) { - operation->setDispersion(getInputSocket(2)->getEditorValueFloat()); - } - - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); - } -} diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc new file mode 100644 index 00000000000..8bfea1eff49 --- /dev/null +++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc @@ -0,0 +1,53 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_LuminanceMatteNode.h" +#include "BKE_node.h" +#include "COM_ConvertOperation.h" +#include "COM_LuminanceMatteOperation.h" +#include "COM_SetAlphaMultiplyOperation.h" + +LuminanceMatteNode::LuminanceMatteNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void LuminanceMatteNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *editorsnode = getbNode(); + NodeInput *inputSocket = this->getInputSocket(0); + NodeOutput *outputSocketImage = this->getOutputSocket(0); + NodeOutput *outputSocketMatte = this->getOutputSocket(1); + + LuminanceMatteOperation *operationSet = new LuminanceMatteOperation(); + operationSet->setSettings((NodeChroma *)editorsnode->storage); + converter.addOperation(operationSet); + + converter.mapInputSocket(inputSocket, operationSet->getInputSocket(0)); + converter.mapOutputSocket(outputSocketMatte, operationSet->getOutputSocket(0)); + + SetAlphaMultiplyOperation *operation = new SetAlphaMultiplyOperation(); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.addLink(operationSet->getOutputSocket(), operation->getInputSocket(1)); + converter.mapOutputSocket(outputSocketImage, operation->getOutputSocket()); + + converter.addPreview(operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp deleted file mode 100644 index 8bfea1eff49..00000000000 --- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_LuminanceMatteNode.h" -#include "BKE_node.h" -#include "COM_ConvertOperation.h" -#include "COM_LuminanceMatteOperation.h" -#include "COM_SetAlphaMultiplyOperation.h" - -LuminanceMatteNode::LuminanceMatteNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void LuminanceMatteNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *editorsnode = getbNode(); - NodeInput *inputSocket = this->getInputSocket(0); - NodeOutput *outputSocketImage = this->getOutputSocket(0); - NodeOutput *outputSocketMatte = this->getOutputSocket(1); - - LuminanceMatteOperation *operationSet = new LuminanceMatteOperation(); - operationSet->setSettings((NodeChroma *)editorsnode->storage); - converter.addOperation(operationSet); - - converter.mapInputSocket(inputSocket, operationSet->getInputSocket(0)); - converter.mapOutputSocket(outputSocketMatte, operationSet->getOutputSocket(0)); - - SetAlphaMultiplyOperation *operation = new SetAlphaMultiplyOperation(); - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.addLink(operationSet->getOutputSocket(), operation->getInputSocket(1)); - converter.mapOutputSocket(outputSocketImage, operation->getOutputSocket()); - - converter.addPreview(operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_MapRangeNode.cc b/source/blender/compositor/nodes/COM_MapRangeNode.cc new file mode 100644 index 00000000000..352bc0dd48d --- /dev/null +++ b/source/blender/compositor/nodes/COM_MapRangeNode.cc @@ -0,0 +1,49 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_MapRangeNode.h" + +#include "COM_ExecutionSystem.h" +#include "COM_MapRangeOperation.h" + +MapRangeNode::MapRangeNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void MapRangeNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *valueSocket = this->getInputSocket(0); + NodeInput *sourceMinSocket = this->getInputSocket(1); + NodeInput *sourceMaxSocket = this->getInputSocket(2); + NodeInput *destMinSocket = this->getInputSocket(3); + NodeInput *destMaxSocket = this->getInputSocket(4); + NodeOutput *outputSocket = this->getOutputSocket(0); + + MapRangeOperation *operation = new MapRangeOperation(); + operation->setUseClamp(this->getbNode()->custom1); + converter.addOperation(operation); + + converter.mapInputSocket(valueSocket, operation->getInputSocket(0)); + converter.mapInputSocket(sourceMinSocket, operation->getInputSocket(1)); + converter.mapInputSocket(sourceMaxSocket, operation->getInputSocket(2)); + converter.mapInputSocket(destMinSocket, operation->getInputSocket(3)); + converter.mapInputSocket(destMaxSocket, operation->getInputSocket(4)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_MapRangeNode.cpp b/source/blender/compositor/nodes/COM_MapRangeNode.cpp deleted file mode 100644 index 352bc0dd48d..00000000000 --- a/source/blender/compositor/nodes/COM_MapRangeNode.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_MapRangeNode.h" - -#include "COM_ExecutionSystem.h" -#include "COM_MapRangeOperation.h" - -MapRangeNode::MapRangeNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void MapRangeNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *valueSocket = this->getInputSocket(0); - NodeInput *sourceMinSocket = this->getInputSocket(1); - NodeInput *sourceMaxSocket = this->getInputSocket(2); - NodeInput *destMinSocket = this->getInputSocket(3); - NodeInput *destMaxSocket = this->getInputSocket(4); - NodeOutput *outputSocket = this->getOutputSocket(0); - - MapRangeOperation *operation = new MapRangeOperation(); - operation->setUseClamp(this->getbNode()->custom1); - converter.addOperation(operation); - - converter.mapInputSocket(valueSocket, operation->getInputSocket(0)); - converter.mapInputSocket(sourceMinSocket, operation->getInputSocket(1)); - converter.mapInputSocket(sourceMaxSocket, operation->getInputSocket(2)); - converter.mapInputSocket(destMinSocket, operation->getInputSocket(3)); - converter.mapInputSocket(destMaxSocket, operation->getInputSocket(4)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_MapUVNode.cc b/source/blender/compositor/nodes/COM_MapUVNode.cc new file mode 100644 index 00000000000..feb9c75ec56 --- /dev/null +++ b/source/blender/compositor/nodes/COM_MapUVNode.cc @@ -0,0 +1,41 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MapUVNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_MapUVOperation.h" + +MapUVNode::MapUVNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void MapUVNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *node = this->getbNode(); + + MapUVOperation *operation = new MapUVOperation(); + operation->setAlpha((float)node->custom1); + operation->setResolutionInputSocketIndex(1); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_MapUVNode.cpp b/source/blender/compositor/nodes/COM_MapUVNode.cpp deleted file mode 100644 index feb9c75ec56..00000000000 --- a/source/blender/compositor/nodes/COM_MapUVNode.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MapUVNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_MapUVOperation.h" - -MapUVNode::MapUVNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void MapUVNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bNode *node = this->getbNode(); - - MapUVOperation *operation = new MapUVOperation(); - operation->setAlpha((float)node->custom1); - operation->setResolutionInputSocketIndex(1); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_MapValueNode.cc b/source/blender/compositor/nodes/COM_MapValueNode.cc new file mode 100644 index 00000000000..e07df8ad367 --- /dev/null +++ b/source/blender/compositor/nodes/COM_MapValueNode.cc @@ -0,0 +1,43 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MapValueNode.h" + +#include "COM_ExecutionSystem.h" +#include "COM_MapValueOperation.h" + +MapValueNode::MapValueNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void MapValueNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + TexMapping *storage = (TexMapping *)this->getbNode()->storage; + + NodeInput *colorSocket = this->getInputSocket(0); + NodeOutput *valueSocket = this->getOutputSocket(0); + + MapValueOperation *convertProg = new MapValueOperation(); + convertProg->setSettings(storage); + converter.addOperation(convertProg); + + converter.mapInputSocket(colorSocket, convertProg->getInputSocket(0)); + converter.mapOutputSocket(valueSocket, convertProg->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_MapValueNode.cpp b/source/blender/compositor/nodes/COM_MapValueNode.cpp deleted file mode 100644 index e07df8ad367..00000000000 --- a/source/blender/compositor/nodes/COM_MapValueNode.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MapValueNode.h" - -#include "COM_ExecutionSystem.h" -#include "COM_MapValueOperation.h" - -MapValueNode::MapValueNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void MapValueNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - TexMapping *storage = (TexMapping *)this->getbNode()->storage; - - NodeInput *colorSocket = this->getInputSocket(0); - NodeOutput *valueSocket = this->getOutputSocket(0); - - MapValueOperation *convertProg = new MapValueOperation(); - convertProg->setSettings(storage); - converter.addOperation(convertProg); - - converter.mapInputSocket(colorSocket, convertProg->getInputSocket(0)); - converter.mapOutputSocket(valueSocket, convertProg->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_MaskNode.cc b/source/blender/compositor/nodes/COM_MaskNode.cc new file mode 100644 index 00000000000..a6415a3992e --- /dev/null +++ b/source/blender/compositor/nodes/COM_MaskNode.cc @@ -0,0 +1,70 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_MaskNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_MaskOperation.h" + +#include "DNA_mask_types.h" + +MaskNode::MaskNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void MaskNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + const RenderData *rd = context.getRenderData(); + const float render_size_factor = context.getRenderPercentageAsFactor(); + + NodeOutput *outputMask = this->getOutputSocket(0); + + bNode *editorNode = this->getbNode(); + NodeMask *data = (NodeMask *)editorNode->storage; + Mask *mask = (Mask *)editorNode->id; + + // always connect the output image + MaskOperation *operation = new MaskOperation(); + + if (editorNode->custom1 & CMP_NODEFLAG_MASK_FIXED) { + operation->setMaskWidth(data->size_x); + operation->setMaskHeight(data->size_y); + } + else if (editorNode->custom1 & CMP_NODEFLAG_MASK_FIXED_SCENE) { + operation->setMaskWidth(data->size_x * render_size_factor); + operation->setMaskHeight(data->size_y * render_size_factor); + } + else { + operation->setMaskWidth(rd->xsch * render_size_factor); + operation->setMaskHeight(rd->ysch * render_size_factor); + } + + operation->setMask(mask); + operation->setFramenumber(context.getFramenumber()); + operation->setFeather((bool)(editorNode->custom1 & CMP_NODEFLAG_MASK_NO_FEATHER) == 0); + + if ((editorNode->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) && (editorNode->custom2 > 1) && + (editorNode->custom3 > FLT_EPSILON)) { + operation->setMotionBlurSamples(editorNode->custom2); + operation->setMotionBlurShutter(editorNode->custom3); + } + + converter.addOperation(operation); + converter.mapOutputSocket(outputMask, operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_MaskNode.cpp b/source/blender/compositor/nodes/COM_MaskNode.cpp deleted file mode 100644 index a6415a3992e..00000000000 --- a/source/blender/compositor/nodes/COM_MaskNode.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_MaskNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_MaskOperation.h" - -#include "DNA_mask_types.h" - -MaskNode::MaskNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void MaskNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - const RenderData *rd = context.getRenderData(); - const float render_size_factor = context.getRenderPercentageAsFactor(); - - NodeOutput *outputMask = this->getOutputSocket(0); - - bNode *editorNode = this->getbNode(); - NodeMask *data = (NodeMask *)editorNode->storage; - Mask *mask = (Mask *)editorNode->id; - - // always connect the output image - MaskOperation *operation = new MaskOperation(); - - if (editorNode->custom1 & CMP_NODEFLAG_MASK_FIXED) { - operation->setMaskWidth(data->size_x); - operation->setMaskHeight(data->size_y); - } - else if (editorNode->custom1 & CMP_NODEFLAG_MASK_FIXED_SCENE) { - operation->setMaskWidth(data->size_x * render_size_factor); - operation->setMaskHeight(data->size_y * render_size_factor); - } - else { - operation->setMaskWidth(rd->xsch * render_size_factor); - operation->setMaskHeight(rd->ysch * render_size_factor); - } - - operation->setMask(mask); - operation->setFramenumber(context.getFramenumber()); - operation->setFeather((bool)(editorNode->custom1 & CMP_NODEFLAG_MASK_NO_FEATHER) == 0); - - if ((editorNode->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) && (editorNode->custom2 > 1) && - (editorNode->custom3 > FLT_EPSILON)) { - operation->setMotionBlurSamples(editorNode->custom2); - operation->setMotionBlurShutter(editorNode->custom3); - } - - converter.addOperation(operation); - converter.mapOutputSocket(outputMask, operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_MathNode.cc b/source/blender/compositor/nodes/COM_MathNode.cc new file mode 100644 index 00000000000..0edf880400f --- /dev/null +++ b/source/blender/compositor/nodes/COM_MathNode.cc @@ -0,0 +1,161 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MathNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_MathBaseOperation.h" + +void MathNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + MathBaseOperation *operation = nullptr; + + switch (this->getbNode()->custom1) { + case NODE_MATH_ADD: + operation = new MathAddOperation(); + break; + case NODE_MATH_SUBTRACT: + operation = new MathSubtractOperation(); + break; + case NODE_MATH_MULTIPLY: + operation = new MathMultiplyOperation(); + break; + case NODE_MATH_DIVIDE: + operation = new MathDivideOperation(); + break; + case NODE_MATH_SINE: + operation = new MathSineOperation(); + break; + case NODE_MATH_COSINE: + operation = new MathCosineOperation(); + break; + case NODE_MATH_TANGENT: + operation = new MathTangentOperation(); + break; + case NODE_MATH_ARCSINE: + operation = new MathArcSineOperation(); + break; + case NODE_MATH_ARCCOSINE: + operation = new MathArcCosineOperation(); + break; + case NODE_MATH_ARCTANGENT: + operation = new MathArcTangentOperation(); + break; + case NODE_MATH_SINH: + operation = new MathHyperbolicSineOperation(); + break; + case NODE_MATH_COSH: + operation = new MathHyperbolicCosineOperation(); + break; + case NODE_MATH_TANH: + operation = new MathHyperbolicTangentOperation(); + break; + case NODE_MATH_POWER: + operation = new MathPowerOperation(); + break; + case NODE_MATH_LOGARITHM: + operation = new MathLogarithmOperation(); + break; + case NODE_MATH_MINIMUM: + operation = new MathMinimumOperation(); + break; + case NODE_MATH_MAXIMUM: + operation = new MathMaximumOperation(); + break; + case NODE_MATH_ROUND: + operation = new MathRoundOperation(); + break; + case NODE_MATH_LESS_THAN: + operation = new MathLessThanOperation(); + break; + case NODE_MATH_GREATER_THAN: + operation = new MathGreaterThanOperation(); + break; + case NODE_MATH_MODULO: + operation = new MathModuloOperation(); + break; + case NODE_MATH_ABSOLUTE: + operation = new MathAbsoluteOperation(); + break; + case NODE_MATH_RADIANS: + operation = new MathRadiansOperation(); + break; + case NODE_MATH_DEGREES: + operation = new MathDegreesOperation(); + break; + case NODE_MATH_ARCTAN2: + operation = new MathArcTan2Operation(); + break; + case NODE_MATH_FLOOR: + operation = new MathFloorOperation(); + break; + case NODE_MATH_CEIL: + operation = new MathCeilOperation(); + break; + case NODE_MATH_FRACTION: + operation = new MathFractOperation(); + break; + case NODE_MATH_SQRT: + operation = new MathSqrtOperation(); + break; + case NODE_MATH_INV_SQRT: + operation = new MathInverseSqrtOperation(); + break; + case NODE_MATH_SIGN: + operation = new MathSignOperation(); + break; + case NODE_MATH_EXPONENT: + operation = new MathExponentOperation(); + break; + case NODE_MATH_TRUNC: + operation = new MathTruncOperation(); + break; + case NODE_MATH_SNAP: + operation = new MathSnapOperation(); + break; + case NODE_MATH_WRAP: + operation = new MathWrapOperation(); + break; + case NODE_MATH_PINGPONG: + operation = new MathPingpongOperation(); + break; + case NODE_MATH_COMPARE: + operation = new MathCompareOperation(); + break; + case NODE_MATH_MULTIPLY_ADD: + operation = new MathMultiplyAddOperation(); + break; + case NODE_MATH_SMOOTH_MIN: + operation = new MathSmoothMinOperation(); + break; + case NODE_MATH_SMOOTH_MAX: + operation = new MathSmoothMaxOperation(); + break; + } + + if (operation) { + bool useClamp = getbNode()->custom2; + operation->setUseClamp(useClamp); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); + } +} diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cpp deleted file mode 100644 index 0edf880400f..00000000000 --- a/source/blender/compositor/nodes/COM_MathNode.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MathNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_MathBaseOperation.h" - -void MathNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - MathBaseOperation *operation = nullptr; - - switch (this->getbNode()->custom1) { - case NODE_MATH_ADD: - operation = new MathAddOperation(); - break; - case NODE_MATH_SUBTRACT: - operation = new MathSubtractOperation(); - break; - case NODE_MATH_MULTIPLY: - operation = new MathMultiplyOperation(); - break; - case NODE_MATH_DIVIDE: - operation = new MathDivideOperation(); - break; - case NODE_MATH_SINE: - operation = new MathSineOperation(); - break; - case NODE_MATH_COSINE: - operation = new MathCosineOperation(); - break; - case NODE_MATH_TANGENT: - operation = new MathTangentOperation(); - break; - case NODE_MATH_ARCSINE: - operation = new MathArcSineOperation(); - break; - case NODE_MATH_ARCCOSINE: - operation = new MathArcCosineOperation(); - break; - case NODE_MATH_ARCTANGENT: - operation = new MathArcTangentOperation(); - break; - case NODE_MATH_SINH: - operation = new MathHyperbolicSineOperation(); - break; - case NODE_MATH_COSH: - operation = new MathHyperbolicCosineOperation(); - break; - case NODE_MATH_TANH: - operation = new MathHyperbolicTangentOperation(); - break; - case NODE_MATH_POWER: - operation = new MathPowerOperation(); - break; - case NODE_MATH_LOGARITHM: - operation = new MathLogarithmOperation(); - break; - case NODE_MATH_MINIMUM: - operation = new MathMinimumOperation(); - break; - case NODE_MATH_MAXIMUM: - operation = new MathMaximumOperation(); - break; - case NODE_MATH_ROUND: - operation = new MathRoundOperation(); - break; - case NODE_MATH_LESS_THAN: - operation = new MathLessThanOperation(); - break; - case NODE_MATH_GREATER_THAN: - operation = new MathGreaterThanOperation(); - break; - case NODE_MATH_MODULO: - operation = new MathModuloOperation(); - break; - case NODE_MATH_ABSOLUTE: - operation = new MathAbsoluteOperation(); - break; - case NODE_MATH_RADIANS: - operation = new MathRadiansOperation(); - break; - case NODE_MATH_DEGREES: - operation = new MathDegreesOperation(); - break; - case NODE_MATH_ARCTAN2: - operation = new MathArcTan2Operation(); - break; - case NODE_MATH_FLOOR: - operation = new MathFloorOperation(); - break; - case NODE_MATH_CEIL: - operation = new MathCeilOperation(); - break; - case NODE_MATH_FRACTION: - operation = new MathFractOperation(); - break; - case NODE_MATH_SQRT: - operation = new MathSqrtOperation(); - break; - case NODE_MATH_INV_SQRT: - operation = new MathInverseSqrtOperation(); - break; - case NODE_MATH_SIGN: - operation = new MathSignOperation(); - break; - case NODE_MATH_EXPONENT: - operation = new MathExponentOperation(); - break; - case NODE_MATH_TRUNC: - operation = new MathTruncOperation(); - break; - case NODE_MATH_SNAP: - operation = new MathSnapOperation(); - break; - case NODE_MATH_WRAP: - operation = new MathWrapOperation(); - break; - case NODE_MATH_PINGPONG: - operation = new MathPingpongOperation(); - break; - case NODE_MATH_COMPARE: - operation = new MathCompareOperation(); - break; - case NODE_MATH_MULTIPLY_ADD: - operation = new MathMultiplyAddOperation(); - break; - case NODE_MATH_SMOOTH_MIN: - operation = new MathSmoothMinOperation(); - break; - case NODE_MATH_SMOOTH_MAX: - operation = new MathSmoothMaxOperation(); - break; - } - - if (operation) { - bool useClamp = getbNode()->custom2; - operation->setUseClamp(useClamp); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); - } -} diff --git a/source/blender/compositor/nodes/COM_MixNode.cc b/source/blender/compositor/nodes/COM_MixNode.cc new file mode 100644 index 00000000000..d082590d21b --- /dev/null +++ b/source/blender/compositor/nodes/COM_MixNode.cc @@ -0,0 +1,112 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MixNode.h" + +#include "COM_MixOperation.h" + +#include "COM_ExecutionSystem.h" +#include "COM_SetValueOperation.h" +#include "DNA_material_types.h" /* the ramp types */ + +MixNode::MixNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void MixNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *valueSocket = this->getInputSocket(0); + NodeInput *color1Socket = this->getInputSocket(1); + NodeInput *color2Socket = this->getInputSocket(2); + NodeOutput *outputSocket = this->getOutputSocket(0); + bNode *editorNode = this->getbNode(); + bool useAlphaPremultiply = (this->getbNode()->custom2 & 1) != 0; + bool useClamp = (this->getbNode()->custom2 & 2) != 0; + + MixBaseOperation *convertProg; + switch (editorNode->custom1) { + case MA_RAMP_ADD: + convertProg = new MixAddOperation(); + break; + case MA_RAMP_MULT: + convertProg = new MixMultiplyOperation(); + break; + case MA_RAMP_LIGHT: + convertProg = new MixLightenOperation(); + break; + case MA_RAMP_BURN: + convertProg = new MixColorBurnOperation(); + break; + case MA_RAMP_HUE: + convertProg = new MixHueOperation(); + break; + case MA_RAMP_COLOR: + convertProg = new MixColorOperation(); + break; + case MA_RAMP_SOFT: + convertProg = new MixSoftLightOperation(); + break; + case MA_RAMP_SCREEN: + convertProg = new MixScreenOperation(); + break; + case MA_RAMP_LINEAR: + convertProg = new MixLinearLightOperation(); + break; + case MA_RAMP_DIFF: + convertProg = new MixDifferenceOperation(); + break; + case MA_RAMP_SAT: + convertProg = new MixSaturationOperation(); + break; + case MA_RAMP_DIV: + convertProg = new MixDivideOperation(); + break; + case MA_RAMP_SUB: + convertProg = new MixSubtractOperation(); + break; + case MA_RAMP_DARK: + convertProg = new MixDarkenOperation(); + break; + case MA_RAMP_OVERLAY: + convertProg = new MixOverlayOperation(); + break; + case MA_RAMP_VAL: + convertProg = new MixValueOperation(); + break; + case MA_RAMP_DODGE: + convertProg = new MixDodgeOperation(); + break; + + case MA_RAMP_BLEND: + default: + convertProg = new MixBlendOperation(); + break; + } + convertProg->setUseValueAlphaMultiply(useAlphaPremultiply); + convertProg->setUseClamp(useClamp); + converter.addOperation(convertProg); + + converter.mapInputSocket(valueSocket, convertProg->getInputSocket(0)); + converter.mapInputSocket(color1Socket, convertProg->getInputSocket(1)); + converter.mapInputSocket(color2Socket, convertProg->getInputSocket(2)); + converter.mapOutputSocket(outputSocket, convertProg->getOutputSocket(0)); + + converter.addPreview(convertProg->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_MixNode.cpp b/source/blender/compositor/nodes/COM_MixNode.cpp deleted file mode 100644 index d082590d21b..00000000000 --- a/source/blender/compositor/nodes/COM_MixNode.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MixNode.h" - -#include "COM_MixOperation.h" - -#include "COM_ExecutionSystem.h" -#include "COM_SetValueOperation.h" -#include "DNA_material_types.h" /* the ramp types */ - -MixNode::MixNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void MixNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *valueSocket = this->getInputSocket(0); - NodeInput *color1Socket = this->getInputSocket(1); - NodeInput *color2Socket = this->getInputSocket(2); - NodeOutput *outputSocket = this->getOutputSocket(0); - bNode *editorNode = this->getbNode(); - bool useAlphaPremultiply = (this->getbNode()->custom2 & 1) != 0; - bool useClamp = (this->getbNode()->custom2 & 2) != 0; - - MixBaseOperation *convertProg; - switch (editorNode->custom1) { - case MA_RAMP_ADD: - convertProg = new MixAddOperation(); - break; - case MA_RAMP_MULT: - convertProg = new MixMultiplyOperation(); - break; - case MA_RAMP_LIGHT: - convertProg = new MixLightenOperation(); - break; - case MA_RAMP_BURN: - convertProg = new MixColorBurnOperation(); - break; - case MA_RAMP_HUE: - convertProg = new MixHueOperation(); - break; - case MA_RAMP_COLOR: - convertProg = new MixColorOperation(); - break; - case MA_RAMP_SOFT: - convertProg = new MixSoftLightOperation(); - break; - case MA_RAMP_SCREEN: - convertProg = new MixScreenOperation(); - break; - case MA_RAMP_LINEAR: - convertProg = new MixLinearLightOperation(); - break; - case MA_RAMP_DIFF: - convertProg = new MixDifferenceOperation(); - break; - case MA_RAMP_SAT: - convertProg = new MixSaturationOperation(); - break; - case MA_RAMP_DIV: - convertProg = new MixDivideOperation(); - break; - case MA_RAMP_SUB: - convertProg = new MixSubtractOperation(); - break; - case MA_RAMP_DARK: - convertProg = new MixDarkenOperation(); - break; - case MA_RAMP_OVERLAY: - convertProg = new MixOverlayOperation(); - break; - case MA_RAMP_VAL: - convertProg = new MixValueOperation(); - break; - case MA_RAMP_DODGE: - convertProg = new MixDodgeOperation(); - break; - - case MA_RAMP_BLEND: - default: - convertProg = new MixBlendOperation(); - break; - } - convertProg->setUseValueAlphaMultiply(useAlphaPremultiply); - convertProg->setUseClamp(useClamp); - converter.addOperation(convertProg); - - converter.mapInputSocket(valueSocket, convertProg->getInputSocket(0)); - converter.mapInputSocket(color1Socket, convertProg->getInputSocket(1)); - converter.mapInputSocket(color2Socket, convertProg->getInputSocket(2)); - converter.mapOutputSocket(outputSocket, convertProg->getOutputSocket(0)); - - converter.addPreview(convertProg->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.cc b/source/blender/compositor/nodes/COM_MovieClipNode.cc new file mode 100644 index 00000000000..7cc8f2ea19c --- /dev/null +++ b/source/blender/compositor/nodes/COM_MovieClipNode.cc @@ -0,0 +1,108 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MovieClipNode.h" +#include "COM_ConvertColorProfileOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_MovieClipOperation.h" +#include "COM_SetValueOperation.h" + +#include "BKE_movieclip.h" +#include "BKE_tracking.h" + +#include "DNA_movieclip_types.h" + +#include "IMB_imbuf.h" + +MovieClipNode::MovieClipNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void MovieClipNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + NodeOutput *outputMovieClip = this->getOutputSocket(0); + NodeOutput *alphaMovieClip = this->getOutputSocket(1); + NodeOutput *offsetXMovieClip = this->getOutputSocket(2); + NodeOutput *offsetYMovieClip = this->getOutputSocket(3); + NodeOutput *scaleMovieClip = this->getOutputSocket(4); + NodeOutput *angleMovieClip = this->getOutputSocket(5); + + bNode *editorNode = this->getbNode(); + MovieClip *movieClip = (MovieClip *)editorNode->id; + MovieClipUser *movieClipUser = (MovieClipUser *)editorNode->storage; + bool cacheFrame = !context.isRendering(); + + ImBuf *ibuf = nullptr; + if (movieClip) { + if (cacheFrame) { + ibuf = BKE_movieclip_get_ibuf(movieClip, movieClipUser); + } + else { + ibuf = BKE_movieclip_get_ibuf_flag( + movieClip, movieClipUser, movieClip->flag, MOVIECLIP_CACHE_SKIP); + } + } + + // always connect the output image + MovieClipOperation *operation = new MovieClipOperation(); + operation->setMovieClip(movieClip); + operation->setMovieClipUser(movieClipUser); + operation->setFramenumber(context.getFramenumber()); + operation->setCacheFrame(cacheFrame); + + converter.addOperation(operation); + converter.mapOutputSocket(outputMovieClip, operation->getOutputSocket()); + converter.addPreview(operation->getOutputSocket()); + + MovieClipAlphaOperation *alphaOperation = new MovieClipAlphaOperation(); + alphaOperation->setMovieClip(movieClip); + alphaOperation->setMovieClipUser(movieClipUser); + alphaOperation->setFramenumber(context.getFramenumber()); + alphaOperation->setCacheFrame(cacheFrame); + + converter.addOperation(alphaOperation); + converter.mapOutputSocket(alphaMovieClip, alphaOperation->getOutputSocket()); + + MovieTrackingStabilization *stab = &movieClip->tracking.stabilization; + float loc[2], scale, angle; + loc[0] = 0.0f; + loc[1] = 0.0f; + scale = 1.0f; + angle = 0.0f; + + if (ibuf) { + if (stab->flag & TRACKING_2D_STABILIZATION) { + int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movieClip, + context.getFramenumber()); + + BKE_tracking_stabilization_data_get( + movieClip, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle); + } + } + + converter.addOutputValue(offsetXMovieClip, loc[0]); + converter.addOutputValue(offsetYMovieClip, loc[1]); + converter.addOutputValue(scaleMovieClip, scale); + converter.addOutputValue(angleMovieClip, angle); + + if (ibuf) { + IMB_freeImBuf(ibuf); + } +} diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.cpp b/source/blender/compositor/nodes/COM_MovieClipNode.cpp deleted file mode 100644 index 7cc8f2ea19c..00000000000 --- a/source/blender/compositor/nodes/COM_MovieClipNode.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MovieClipNode.h" -#include "COM_ConvertColorProfileOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_MovieClipOperation.h" -#include "COM_SetValueOperation.h" - -#include "BKE_movieclip.h" -#include "BKE_tracking.h" - -#include "DNA_movieclip_types.h" - -#include "IMB_imbuf.h" - -MovieClipNode::MovieClipNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void MovieClipNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - NodeOutput *outputMovieClip = this->getOutputSocket(0); - NodeOutput *alphaMovieClip = this->getOutputSocket(1); - NodeOutput *offsetXMovieClip = this->getOutputSocket(2); - NodeOutput *offsetYMovieClip = this->getOutputSocket(3); - NodeOutput *scaleMovieClip = this->getOutputSocket(4); - NodeOutput *angleMovieClip = this->getOutputSocket(5); - - bNode *editorNode = this->getbNode(); - MovieClip *movieClip = (MovieClip *)editorNode->id; - MovieClipUser *movieClipUser = (MovieClipUser *)editorNode->storage; - bool cacheFrame = !context.isRendering(); - - ImBuf *ibuf = nullptr; - if (movieClip) { - if (cacheFrame) { - ibuf = BKE_movieclip_get_ibuf(movieClip, movieClipUser); - } - else { - ibuf = BKE_movieclip_get_ibuf_flag( - movieClip, movieClipUser, movieClip->flag, MOVIECLIP_CACHE_SKIP); - } - } - - // always connect the output image - MovieClipOperation *operation = new MovieClipOperation(); - operation->setMovieClip(movieClip); - operation->setMovieClipUser(movieClipUser); - operation->setFramenumber(context.getFramenumber()); - operation->setCacheFrame(cacheFrame); - - converter.addOperation(operation); - converter.mapOutputSocket(outputMovieClip, operation->getOutputSocket()); - converter.addPreview(operation->getOutputSocket()); - - MovieClipAlphaOperation *alphaOperation = new MovieClipAlphaOperation(); - alphaOperation->setMovieClip(movieClip); - alphaOperation->setMovieClipUser(movieClipUser); - alphaOperation->setFramenumber(context.getFramenumber()); - alphaOperation->setCacheFrame(cacheFrame); - - converter.addOperation(alphaOperation); - converter.mapOutputSocket(alphaMovieClip, alphaOperation->getOutputSocket()); - - MovieTrackingStabilization *stab = &movieClip->tracking.stabilization; - float loc[2], scale, angle; - loc[0] = 0.0f; - loc[1] = 0.0f; - scale = 1.0f; - angle = 0.0f; - - if (ibuf) { - if (stab->flag & TRACKING_2D_STABILIZATION) { - int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movieClip, - context.getFramenumber()); - - BKE_tracking_stabilization_data_get( - movieClip, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle); - } - } - - converter.addOutputValue(offsetXMovieClip, loc[0]); - converter.addOutputValue(offsetYMovieClip, loc[1]); - converter.addOutputValue(scaleMovieClip, scale); - converter.addOutputValue(angleMovieClip, angle); - - if (ibuf) { - IMB_freeImBuf(ibuf); - } -} diff --git a/source/blender/compositor/nodes/COM_MovieDistortionNode.cc b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc new file mode 100644 index 00000000000..ebace6d5fff --- /dev/null +++ b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc @@ -0,0 +1,46 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MovieDistortionNode.h" + +#include "COM_ExecutionSystem.h" +#include "COM_MovieDistortionOperation.h" +#include "DNA_movieclip_types.h" + +MovieDistortionNode::MovieDistortionNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void MovieDistortionNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *bnode = this->getbNode(); + MovieClip *clip = (MovieClip *)bnode->id; + + NodeInput *inputSocket = this->getInputSocket(0); + NodeOutput *outputSocket = this->getOutputSocket(0); + + MovieDistortionOperation *operation = new MovieDistortionOperation(bnode->custom1 == 1); + operation->setMovieClip(clip); + operation->setFramenumber(context.getFramenumber()); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_MovieDistortionNode.cpp b/source/blender/compositor/nodes/COM_MovieDistortionNode.cpp deleted file mode 100644 index ebace6d5fff..00000000000 --- a/source/blender/compositor/nodes/COM_MovieDistortionNode.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MovieDistortionNode.h" - -#include "COM_ExecutionSystem.h" -#include "COM_MovieDistortionOperation.h" -#include "DNA_movieclip_types.h" - -MovieDistortionNode::MovieDistortionNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void MovieDistortionNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *bnode = this->getbNode(); - MovieClip *clip = (MovieClip *)bnode->id; - - NodeInput *inputSocket = this->getInputSocket(0); - NodeOutput *outputSocket = this->getOutputSocket(0); - - MovieDistortionOperation *operation = new MovieDistortionOperation(bnode->custom1 == 1); - operation->setMovieClip(clip); - operation->setFramenumber(context.getFramenumber()); - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_NormalNode.cc b/source/blender/compositor/nodes/COM_NormalNode.cc new file mode 100644 index 00000000000..1f48a26fd75 --- /dev/null +++ b/source/blender/compositor/nodes/COM_NormalNode.cc @@ -0,0 +1,56 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_NormalNode.h" +#include "BKE_node.h" +#include "COM_DotproductOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_SetVectorOperation.h" + +NormalNode::NormalNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void NormalNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeOutput *outputSocket = this->getOutputSocket(0); + NodeOutput *outputSocketDotproduct = this->getOutputSocket(1); + + SetVectorOperation *operationSet = new SetVectorOperation(); + float normal[3]; + outputSocket->getEditorValueVector(normal); + /* animation can break normalization, this restores it */ + normalize_v3(normal); + operationSet->setX(normal[0]); + operationSet->setY(normal[1]); + operationSet->setZ(normal[2]); + operationSet->setW(0.0f); + converter.addOperation(operationSet); + + converter.mapOutputSocket(outputSocket, operationSet->getOutputSocket(0)); + + DotproductOperation *operation = new DotproductOperation(); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.addLink(operationSet->getOutputSocket(0), operation->getInputSocket(1)); + converter.mapOutputSocket(outputSocketDotproduct, operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_NormalNode.cpp b/source/blender/compositor/nodes/COM_NormalNode.cpp deleted file mode 100644 index 1f48a26fd75..00000000000 --- a/source/blender/compositor/nodes/COM_NormalNode.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_NormalNode.h" -#include "BKE_node.h" -#include "COM_DotproductOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_SetVectorOperation.h" - -NormalNode::NormalNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void NormalNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *inputSocket = this->getInputSocket(0); - NodeOutput *outputSocket = this->getOutputSocket(0); - NodeOutput *outputSocketDotproduct = this->getOutputSocket(1); - - SetVectorOperation *operationSet = new SetVectorOperation(); - float normal[3]; - outputSocket->getEditorValueVector(normal); - /* animation can break normalization, this restores it */ - normalize_v3(normal); - operationSet->setX(normal[0]); - operationSet->setY(normal[1]); - operationSet->setZ(normal[2]); - operationSet->setW(0.0f); - converter.addOperation(operationSet); - - converter.mapOutputSocket(outputSocket, operationSet->getOutputSocket(0)); - - DotproductOperation *operation = new DotproductOperation(); - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.addLink(operationSet->getOutputSocket(0), operation->getInputSocket(1)); - converter.mapOutputSocket(outputSocketDotproduct, operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_NormalizeNode.cc b/source/blender/compositor/nodes/COM_NormalizeNode.cc new file mode 100644 index 00000000000..72459fd477c --- /dev/null +++ b/source/blender/compositor/nodes/COM_NormalizeNode.cc @@ -0,0 +1,36 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_NormalizeNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_NormalizeOperation.h" + +NormalizeNode::NormalizeNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void NormalizeNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NormalizeOperation *operation = new NormalizeOperation(); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_NormalizeNode.cpp b/source/blender/compositor/nodes/COM_NormalizeNode.cpp deleted file mode 100644 index 72459fd477c..00000000000 --- a/source/blender/compositor/nodes/COM_NormalizeNode.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_NormalizeNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_NormalizeOperation.h" - -NormalizeNode::NormalizeNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void NormalizeNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NormalizeOperation *operation = new NormalizeOperation(); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cc b/source/blender/compositor/nodes/COM_OutputFileNode.cc new file mode 100644 index 00000000000..dcc1fbdec67 --- /dev/null +++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc @@ -0,0 +1,153 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_OutputFileNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_OutputFileMultiViewOperation.h" +#include "COM_OutputFileOperation.h" + +#include "BKE_scene.h" + +#include "BLI_path_util.h" + +OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +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 - + * otherwise, it overwrites the output files just + * scrubbing through the timeline when the compositor updates. + */ + return; + } + + if (storage->format.imtype == R_IMF_IMTYPE_MULTILAYER) { + const bool use_half_float = (storage->format.depth == R_IMF_CHAN_DEPTH_16); + /* single output operation for the multilayer file */ + OutputOpenExrMultiLayerOperation *outputOperation; + + if (is_multiview && storage->format.views_format == R_IMF_VIEWS_MULTIVIEW) { + outputOperation = new OutputOpenExrMultiLayerMultiViewOperation(context.getScene(), + context.getRenderData(), + context.getbNodeTree(), + storage->base_path, + storage->format.exr_codec, + use_half_float, + context.getViewName()); + } + else { + outputOperation = new OutputOpenExrMultiLayerOperation(context.getScene(), + context.getRenderData(), + context.getbNodeTree(), + storage->base_path, + storage->format.exr_codec, + use_half_float, + context.getViewName()); + } + converter.addOperation(outputOperation); + + int num_inputs = getNumberOfInputSockets(); + bool previewAdded = false; + for (int i = 0; i < num_inputs; i++) { + NodeInput *input = getInputSocket(i); + NodeImageMultiFileSocket *sockdata = + (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage; + + /* note: layer becomes an empty placeholder if the input is not linked */ + outputOperation->add_layer(sockdata->layer, input->getDataType(), input->isLinked()); + + converter.mapInputSocket(input, outputOperation->getInputSocket(i)); + + if (!previewAdded) { + converter.addNodeInputPreview(input); + previewAdded = true; + } + } + } + else { /* single layer format */ + int num_inputs = getNumberOfInputSockets(); + bool previewAdded = false; + for (int i = 0; i < num_inputs; i++) { + NodeInput *input = getInputSocket(i); + if (input->isLinked()) { + 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); + + NodeOperation *outputOperation = nullptr; + + 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(), + sockdata->save_as_render); + } + 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(), + sockdata->save_as_render); + } + 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(), + sockdata->save_as_render); + } + + converter.addOperation(outputOperation); + converter.mapInputSocket(input, outputOperation->getInputSocket(0)); + + if (!previewAdded) { + converter.addNodeInputPreview(input); + previewAdded = true; + } + } + } + } +} diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cpp b/source/blender/compositor/nodes/COM_OutputFileNode.cpp deleted file mode 100644 index dcc1fbdec67..00000000000 --- a/source/blender/compositor/nodes/COM_OutputFileNode.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_OutputFileNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_OutputFileMultiViewOperation.h" -#include "COM_OutputFileOperation.h" - -#include "BKE_scene.h" - -#include "BLI_path_util.h" - -OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -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 - - * otherwise, it overwrites the output files just - * scrubbing through the timeline when the compositor updates. - */ - return; - } - - if (storage->format.imtype == R_IMF_IMTYPE_MULTILAYER) { - const bool use_half_float = (storage->format.depth == R_IMF_CHAN_DEPTH_16); - /* single output operation for the multilayer file */ - OutputOpenExrMultiLayerOperation *outputOperation; - - if (is_multiview && storage->format.views_format == R_IMF_VIEWS_MULTIVIEW) { - outputOperation = new OutputOpenExrMultiLayerMultiViewOperation(context.getScene(), - context.getRenderData(), - context.getbNodeTree(), - storage->base_path, - storage->format.exr_codec, - use_half_float, - context.getViewName()); - } - else { - outputOperation = new OutputOpenExrMultiLayerOperation(context.getScene(), - context.getRenderData(), - context.getbNodeTree(), - storage->base_path, - storage->format.exr_codec, - use_half_float, - context.getViewName()); - } - converter.addOperation(outputOperation); - - int num_inputs = getNumberOfInputSockets(); - bool previewAdded = false; - for (int i = 0; i < num_inputs; i++) { - NodeInput *input = getInputSocket(i); - NodeImageMultiFileSocket *sockdata = - (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage; - - /* note: layer becomes an empty placeholder if the input is not linked */ - outputOperation->add_layer(sockdata->layer, input->getDataType(), input->isLinked()); - - converter.mapInputSocket(input, outputOperation->getInputSocket(i)); - - if (!previewAdded) { - converter.addNodeInputPreview(input); - previewAdded = true; - } - } - } - else { /* single layer format */ - int num_inputs = getNumberOfInputSockets(); - bool previewAdded = false; - for (int i = 0; i < num_inputs; i++) { - NodeInput *input = getInputSocket(i); - if (input->isLinked()) { - 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); - - NodeOperation *outputOperation = nullptr; - - 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(), - sockdata->save_as_render); - } - 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(), - sockdata->save_as_render); - } - 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(), - sockdata->save_as_render); - } - - converter.addOperation(outputOperation); - converter.mapInputSocket(input, outputOperation->getInputSocket(0)); - - if (!previewAdded) { - converter.addNodeInputPreview(input); - previewAdded = true; - } - } - } - } -} diff --git a/source/blender/compositor/nodes/COM_PixelateNode.cc b/source/blender/compositor/nodes/COM_PixelateNode.cc new file mode 100644 index 00000000000..f238f68727e --- /dev/null +++ b/source/blender/compositor/nodes/COM_PixelateNode.cc @@ -0,0 +1,46 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_PixelateNode.h" + +#include "COM_ExecutionSystem.h" +#include "COM_PixelateOperation.h" + +PixelateNode::PixelateNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void PixelateNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeOutput *outputSocket = this->getOutputSocket(0); + DataType datatype = inputSocket->getDataType(); + + if (inputSocket->isLinked()) { + NodeOutput *link = inputSocket->getLink(); + datatype = link->getDataType(); + } + + PixelateOperation *operation = new PixelateOperation(datatype); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_PixelateNode.cpp b/source/blender/compositor/nodes/COM_PixelateNode.cpp deleted file mode 100644 index f238f68727e..00000000000 --- a/source/blender/compositor/nodes/COM_PixelateNode.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_PixelateNode.h" - -#include "COM_ExecutionSystem.h" -#include "COM_PixelateOperation.h" - -PixelateNode::PixelateNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void PixelateNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *inputSocket = this->getInputSocket(0); - NodeOutput *outputSocket = this->getOutputSocket(0); - DataType datatype = inputSocket->getDataType(); - - if (inputSocket->isLinked()) { - NodeOutput *link = inputSocket->getLink(); - datatype = link->getDataType(); - } - - PixelateOperation *operation = new PixelateOperation(datatype); - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc new file mode 100644 index 00000000000..6b9b51631ec --- /dev/null +++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc @@ -0,0 +1,72 @@ +/* + * 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. + * + * Copyright 2013, Blender Foundation. + */ + +#include "COM_PlaneTrackDeformNode.h" +#include "COM_ExecutionSystem.h" + +#include "COM_PlaneTrackOperation.h" + +#include "BKE_movieclip.h" +#include "BKE_node.h" +#include "BKE_tracking.h" + +PlaneTrackDeformNode::PlaneTrackDeformNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void PlaneTrackDeformNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *editorNode = this->getbNode(); + MovieClip *clip = (MovieClip *)editorNode->id; + NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)editorNode->storage; + + int frame_number = context.getFramenumber(); + + NodeInput *input_image = this->getInputSocket(0); + NodeOutput *output_warped_image = this->getOutputSocket(0); + NodeOutput *output_plane = this->getOutputSocket(1); + + PlaneTrackWarpImageOperation *warp_image_operation = new PlaneTrackWarpImageOperation(); + warp_image_operation->setMovieClip(clip); + warp_image_operation->setTrackingObject(data->tracking_object); + warp_image_operation->setPlaneTrackName(data->plane_track_name); + warp_image_operation->setFramenumber(frame_number); + if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) { + warp_image_operation->setMotionBlurSamples(data->motion_blur_samples); + warp_image_operation->setMotionBlurShutter(data->motion_blur_shutter); + } + converter.addOperation(warp_image_operation); + + converter.mapInputSocket(input_image, warp_image_operation->getInputSocket(0)); + converter.mapOutputSocket(output_warped_image, warp_image_operation->getOutputSocket()); + + PlaneTrackMaskOperation *plane_mask_operation = new PlaneTrackMaskOperation(); + plane_mask_operation->setMovieClip(clip); + plane_mask_operation->setTrackingObject(data->tracking_object); + plane_mask_operation->setPlaneTrackName(data->plane_track_name); + plane_mask_operation->setFramenumber(frame_number); + if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) { + plane_mask_operation->setMotionBlurSamples(data->motion_blur_samples); + plane_mask_operation->setMotionBlurShutter(data->motion_blur_shutter); + } + converter.addOperation(plane_mask_operation); + + converter.mapOutputSocket(output_plane, plane_mask_operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp deleted file mode 100644 index 6b9b51631ec..00000000000 --- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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. - * - * Copyright 2013, Blender Foundation. - */ - -#include "COM_PlaneTrackDeformNode.h" -#include "COM_ExecutionSystem.h" - -#include "COM_PlaneTrackOperation.h" - -#include "BKE_movieclip.h" -#include "BKE_node.h" -#include "BKE_tracking.h" - -PlaneTrackDeformNode::PlaneTrackDeformNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void PlaneTrackDeformNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *editorNode = this->getbNode(); - MovieClip *clip = (MovieClip *)editorNode->id; - NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)editorNode->storage; - - int frame_number = context.getFramenumber(); - - NodeInput *input_image = this->getInputSocket(0); - NodeOutput *output_warped_image = this->getOutputSocket(0); - NodeOutput *output_plane = this->getOutputSocket(1); - - PlaneTrackWarpImageOperation *warp_image_operation = new PlaneTrackWarpImageOperation(); - warp_image_operation->setMovieClip(clip); - warp_image_operation->setTrackingObject(data->tracking_object); - warp_image_operation->setPlaneTrackName(data->plane_track_name); - warp_image_operation->setFramenumber(frame_number); - if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) { - warp_image_operation->setMotionBlurSamples(data->motion_blur_samples); - warp_image_operation->setMotionBlurShutter(data->motion_blur_shutter); - } - converter.addOperation(warp_image_operation); - - converter.mapInputSocket(input_image, warp_image_operation->getInputSocket(0)); - converter.mapOutputSocket(output_warped_image, warp_image_operation->getOutputSocket()); - - PlaneTrackMaskOperation *plane_mask_operation = new PlaneTrackMaskOperation(); - plane_mask_operation->setMovieClip(clip); - plane_mask_operation->setTrackingObject(data->tracking_object); - plane_mask_operation->setPlaneTrackName(data->plane_track_name); - plane_mask_operation->setFramenumber(frame_number); - if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) { - plane_mask_operation->setMotionBlurSamples(data->motion_blur_samples); - plane_mask_operation->setMotionBlurShutter(data->motion_blur_shutter); - } - converter.addOperation(plane_mask_operation); - - converter.mapOutputSocket(output_plane, plane_mask_operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cc b/source/blender/compositor/nodes/COM_RenderLayersNode.cc new file mode 100644 index 00000000000..6be86c04c4d --- /dev/null +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cc @@ -0,0 +1,176 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_RenderLayersNode.h" +#include "COM_RenderLayersProg.h" +#include "COM_RotateOperation.h" +#include "COM_ScaleOperation.h" +#include "COM_SetColorOperation.h" +#include "COM_SetValueOperation.h" +#include "COM_SetVectorOperation.h" +#include "COM_TranslateOperation.h" + +RenderLayersNode::RenderLayersNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void RenderLayersNode::testSocketLink(NodeConverter &converter, + const CompositorContext &context, + NodeOutput *output, + RenderLayersProg *operation, + Scene *scene, + int layerId, + bool is_preview) const +{ + operation->setScene(scene); + operation->setLayerId(layerId); + operation->setRenderData(context.getRenderData()); + operation->setViewName(context.getViewName()); + + converter.mapOutputSocket(output, operation->getOutputSocket()); + converter.addOperation(operation); + + if (is_preview) { /* only for image socket */ + converter.addPreview(operation->getOutputSocket()); + } +} + +void RenderLayersNode::testRenderLink(NodeConverter &converter, + const CompositorContext &context, + Render *re) const +{ + Scene *scene = (Scene *)this->getbNode()->id; + const short layerId = this->getbNode()->custom1; + RenderResult *rr = RE_AcquireResultRead(re); + if (rr == nullptr) { + missingRenderLink(converter); + return; + } + ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, layerId); + if (view_layer == nullptr) { + missingRenderLink(converter); + return; + } + RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name); + if (rl == nullptr) { + missingRenderLink(converter); + return; + } + const int num_outputs = this->getNumberOfOutputSockets(); + for (int i = 0; i < num_outputs; i++) { + NodeOutput *output = this->getOutputSocket(i); + NodeImageLayer *storage = (NodeImageLayer *)output->getbNodeSocket()->storage; + RenderPass *rpass = (RenderPass *)BLI_findstring( + &rl->passes, storage->pass_name, offsetof(RenderPass, name)); + if (rpass == nullptr) { + missingSocketLink(converter, output); + continue; + } + RenderLayersProg *operation; + bool is_preview; + if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && + STREQ(output->getbNodeSocket()->name, "Alpha")) { + operation = new RenderLayersAlphaProg(rpass->name, COM_DT_VALUE, rpass->channels); + is_preview = false; + } + else if (STREQ(rpass->name, RE_PASSNAME_Z)) { + operation = new RenderLayersDepthProg(rpass->name, COM_DT_VALUE, rpass->channels); + is_preview = false; + } + else { + DataType type; + switch (rpass->channels) { + case 4: + type = COM_DT_COLOR; + break; + case 3: + type = COM_DT_VECTOR; + break; + case 1: + type = COM_DT_VALUE; + break; + default: + BLI_assert(!"Unexpected number of channels for pass"); + type = COM_DT_VALUE; + break; + } + operation = new RenderLayersProg(rpass->name, type, rpass->channels); + is_preview = STREQ(output->getbNodeSocket()->name, "Image"); + } + testSocketLink(converter, context, output, operation, scene, layerId, is_preview); + } +} + +void RenderLayersNode::missingSocketLink(NodeConverter &converter, NodeOutput *output) const +{ + NodeOperation *operation; + switch (output->getDataType()) { + case COM_DT_COLOR: { + const float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + SetColorOperation *color_operation = new SetColorOperation(); + color_operation->setChannels(color); + operation = color_operation; + break; + } + case COM_DT_VECTOR: { + const float vector[3] = {0.0f, 0.0f, 0.0f}; + SetVectorOperation *vector_operation = new SetVectorOperation(); + vector_operation->setVector(vector); + operation = vector_operation; + break; + } + case COM_DT_VALUE: { + SetValueOperation *value_operation = new SetValueOperation(); + value_operation->setValue(0.0f); + operation = value_operation; + break; + } + default: { + BLI_assert("!Unexpected data type"); + return; + } + } + + converter.mapOutputSocket(output, operation->getOutputSocket()); + converter.addOperation(operation); +} + +void RenderLayersNode::missingRenderLink(NodeConverter &converter) const +{ + const int num_outputs = this->getNumberOfOutputSockets(); + for (int i = 0; i < num_outputs; i++) { + NodeOutput *output = this->getOutputSocket(i); + missingSocketLink(converter, output); + } +} + +void RenderLayersNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + Scene *scene = (Scene *)this->getbNode()->id; + Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr; + + if (re != nullptr) { + testRenderLink(converter, context, re); + RE_ReleaseResult(re); + } + else { + missingRenderLink(converter); + } +} diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp deleted file mode 100644 index 6be86c04c4d..00000000000 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_RenderLayersNode.h" -#include "COM_RenderLayersProg.h" -#include "COM_RotateOperation.h" -#include "COM_ScaleOperation.h" -#include "COM_SetColorOperation.h" -#include "COM_SetValueOperation.h" -#include "COM_SetVectorOperation.h" -#include "COM_TranslateOperation.h" - -RenderLayersNode::RenderLayersNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void RenderLayersNode::testSocketLink(NodeConverter &converter, - const CompositorContext &context, - NodeOutput *output, - RenderLayersProg *operation, - Scene *scene, - int layerId, - bool is_preview) const -{ - operation->setScene(scene); - operation->setLayerId(layerId); - operation->setRenderData(context.getRenderData()); - operation->setViewName(context.getViewName()); - - converter.mapOutputSocket(output, operation->getOutputSocket()); - converter.addOperation(operation); - - if (is_preview) { /* only for image socket */ - converter.addPreview(operation->getOutputSocket()); - } -} - -void RenderLayersNode::testRenderLink(NodeConverter &converter, - const CompositorContext &context, - Render *re) const -{ - Scene *scene = (Scene *)this->getbNode()->id; - const short layerId = this->getbNode()->custom1; - RenderResult *rr = RE_AcquireResultRead(re); - if (rr == nullptr) { - missingRenderLink(converter); - return; - } - ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, layerId); - if (view_layer == nullptr) { - missingRenderLink(converter); - return; - } - RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name); - if (rl == nullptr) { - missingRenderLink(converter); - return; - } - const int num_outputs = this->getNumberOfOutputSockets(); - for (int i = 0; i < num_outputs; i++) { - NodeOutput *output = this->getOutputSocket(i); - NodeImageLayer *storage = (NodeImageLayer *)output->getbNodeSocket()->storage; - RenderPass *rpass = (RenderPass *)BLI_findstring( - &rl->passes, storage->pass_name, offsetof(RenderPass, name)); - if (rpass == nullptr) { - missingSocketLink(converter, output); - continue; - } - RenderLayersProg *operation; - bool is_preview; - if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && - STREQ(output->getbNodeSocket()->name, "Alpha")) { - operation = new RenderLayersAlphaProg(rpass->name, COM_DT_VALUE, rpass->channels); - is_preview = false; - } - else if (STREQ(rpass->name, RE_PASSNAME_Z)) { - operation = new RenderLayersDepthProg(rpass->name, COM_DT_VALUE, rpass->channels); - is_preview = false; - } - else { - DataType type; - switch (rpass->channels) { - case 4: - type = COM_DT_COLOR; - break; - case 3: - type = COM_DT_VECTOR; - break; - case 1: - type = COM_DT_VALUE; - break; - default: - BLI_assert(!"Unexpected number of channels for pass"); - type = COM_DT_VALUE; - break; - } - operation = new RenderLayersProg(rpass->name, type, rpass->channels); - is_preview = STREQ(output->getbNodeSocket()->name, "Image"); - } - testSocketLink(converter, context, output, operation, scene, layerId, is_preview); - } -} - -void RenderLayersNode::missingSocketLink(NodeConverter &converter, NodeOutput *output) const -{ - NodeOperation *operation; - switch (output->getDataType()) { - case COM_DT_COLOR: { - const float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - SetColorOperation *color_operation = new SetColorOperation(); - color_operation->setChannels(color); - operation = color_operation; - break; - } - case COM_DT_VECTOR: { - const float vector[3] = {0.0f, 0.0f, 0.0f}; - SetVectorOperation *vector_operation = new SetVectorOperation(); - vector_operation->setVector(vector); - operation = vector_operation; - break; - } - case COM_DT_VALUE: { - SetValueOperation *value_operation = new SetValueOperation(); - value_operation->setValue(0.0f); - operation = value_operation; - break; - } - default: { - BLI_assert("!Unexpected data type"); - return; - } - } - - converter.mapOutputSocket(output, operation->getOutputSocket()); - converter.addOperation(operation); -} - -void RenderLayersNode::missingRenderLink(NodeConverter &converter) const -{ - const int num_outputs = this->getNumberOfOutputSockets(); - for (int i = 0; i < num_outputs; i++) { - NodeOutput *output = this->getOutputSocket(i); - missingSocketLink(converter, output); - } -} - -void RenderLayersNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - Scene *scene = (Scene *)this->getbNode()->id; - Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr; - - if (re != nullptr) { - testRenderLink(converter, context, re); - RE_ReleaseResult(re); - } - else { - missingRenderLink(converter); - } -} diff --git a/source/blender/compositor/nodes/COM_RotateNode.cc b/source/blender/compositor/nodes/COM_RotateNode.cc new file mode 100644 index 00000000000..cbade778bcb --- /dev/null +++ b/source/blender/compositor/nodes/COM_RotateNode.cc @@ -0,0 +1,47 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_RotateNode.h" + +#include "COM_ExecutionSystem.h" +#include "COM_RotateOperation.h" +#include "COM_SetSamplerOperation.h" + +RotateNode::RotateNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void RotateNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeInput *inputDegreeSocket = this->getInputSocket(1); + NodeOutput *outputSocket = this->getOutputSocket(0); + RotateOperation *operation = new RotateOperation(); + SetSamplerOperation *sampler = new SetSamplerOperation(); + sampler->setSampler((PixelSampler)this->getbNode()->custom1); + + converter.addOperation(sampler); + converter.addOperation(operation); + + converter.addLink(sampler->getOutputSocket(), operation->getInputSocket(0)); + converter.mapInputSocket(inputSocket, sampler->getInputSocket(0)); + converter.mapInputSocket(inputDegreeSocket, operation->getInputSocket(1)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_RotateNode.cpp b/source/blender/compositor/nodes/COM_RotateNode.cpp deleted file mode 100644 index cbade778bcb..00000000000 --- a/source/blender/compositor/nodes/COM_RotateNode.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_RotateNode.h" - -#include "COM_ExecutionSystem.h" -#include "COM_RotateOperation.h" -#include "COM_SetSamplerOperation.h" - -RotateNode::RotateNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void RotateNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *inputSocket = this->getInputSocket(0); - NodeInput *inputDegreeSocket = this->getInputSocket(1); - NodeOutput *outputSocket = this->getOutputSocket(0); - RotateOperation *operation = new RotateOperation(); - SetSamplerOperation *sampler = new SetSamplerOperation(); - sampler->setSampler((PixelSampler)this->getbNode()->custom1); - - converter.addOperation(sampler); - converter.addOperation(operation); - - converter.addLink(sampler->getOutputSocket(), operation->getInputSocket(0)); - converter.mapInputSocket(inputSocket, sampler->getInputSocket(0)); - converter.mapInputSocket(inputDegreeSocket, operation->getInputSocket(1)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cc b/source/blender/compositor/nodes/COM_ScaleNode.cc new file mode 100644 index 00000000000..9ffcd5306b0 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ScaleNode.cc @@ -0,0 +1,107 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ScaleNode.h" + +#include "BKE_node.h" +#include "COM_ExecutionSystem.h" +#include "COM_ScaleOperation.h" +#include "COM_SetSamplerOperation.h" +#include "COM_SetValueOperation.h" + +ScaleNode::ScaleNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ScaleNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *bnode = this->getbNode(); + + NodeInput *inputSocket = this->getInputSocket(0); + NodeInput *inputXSocket = this->getInputSocket(1); + NodeInput *inputYSocket = this->getInputSocket(2); + NodeOutput *outputSocket = this->getOutputSocket(0); + + switch (bnode->custom1) { + case CMP_SCALE_RELATIVE: { + ScaleOperation *operation = new ScaleOperation(); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapInputSocket(inputXSocket, operation->getInputSocket(1)); + converter.mapInputSocket(inputYSocket, operation->getInputSocket(2)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + + operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked()); + break; + } + case CMP_SCALE_SCENEPERCENT: { + SetValueOperation *scaleFactorOperation = new SetValueOperation(); + scaleFactorOperation->setValue(context.getRenderPercentageAsFactor()); + converter.addOperation(scaleFactorOperation); + + ScaleOperation *operation = new ScaleOperation(); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.addLink(scaleFactorOperation->getOutputSocket(), operation->getInputSocket(1)); + converter.addLink(scaleFactorOperation->getOutputSocket(), operation->getInputSocket(2)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + + operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked()); + + break; + } + case CMP_SCALE_RENDERPERCENT: { + const RenderData *rd = context.getRenderData(); + const float render_size_factor = context.getRenderPercentageAsFactor(); + ScaleFixedSizeOperation *operation = new ScaleFixedSizeOperation(); + /* framing options */ + operation->setIsAspect((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_ASPECT) != 0); + operation->setIsCrop((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_CROP) != 0); + operation->setOffset(bnode->custom3, bnode->custom4); + operation->setNewWidth(rd->xsch * render_size_factor); + operation->setNewHeight(rd->ysch * render_size_factor); + operation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + + operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked()); + + break; + } + case CMP_SCALE_ABSOLUTE: { + /* TODO: what is the use of this one.... perhaps some issues when the ui was updated... */ + ScaleAbsoluteOperation *operation = new ScaleAbsoluteOperation(); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapInputSocket(inputXSocket, operation->getInputSocket(1)); + converter.mapInputSocket(inputYSocket, operation->getInputSocket(2)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + + operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked()); + + break; + } + } +} diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cpp b/source/blender/compositor/nodes/COM_ScaleNode.cpp deleted file mode 100644 index 9ffcd5306b0..00000000000 --- a/source/blender/compositor/nodes/COM_ScaleNode.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ScaleNode.h" - -#include "BKE_node.h" -#include "COM_ExecutionSystem.h" -#include "COM_ScaleOperation.h" -#include "COM_SetSamplerOperation.h" -#include "COM_SetValueOperation.h" - -ScaleNode::ScaleNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ScaleNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *bnode = this->getbNode(); - - NodeInput *inputSocket = this->getInputSocket(0); - NodeInput *inputXSocket = this->getInputSocket(1); - NodeInput *inputYSocket = this->getInputSocket(2); - NodeOutput *outputSocket = this->getOutputSocket(0); - - switch (bnode->custom1) { - case CMP_SCALE_RELATIVE: { - ScaleOperation *operation = new ScaleOperation(); - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.mapInputSocket(inputXSocket, operation->getInputSocket(1)); - converter.mapInputSocket(inputYSocket, operation->getInputSocket(2)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); - - operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked()); - break; - } - case CMP_SCALE_SCENEPERCENT: { - SetValueOperation *scaleFactorOperation = new SetValueOperation(); - scaleFactorOperation->setValue(context.getRenderPercentageAsFactor()); - converter.addOperation(scaleFactorOperation); - - ScaleOperation *operation = new ScaleOperation(); - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.addLink(scaleFactorOperation->getOutputSocket(), operation->getInputSocket(1)); - converter.addLink(scaleFactorOperation->getOutputSocket(), operation->getInputSocket(2)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); - - operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked()); - - break; - } - case CMP_SCALE_RENDERPERCENT: { - const RenderData *rd = context.getRenderData(); - const float render_size_factor = context.getRenderPercentageAsFactor(); - ScaleFixedSizeOperation *operation = new ScaleFixedSizeOperation(); - /* framing options */ - operation->setIsAspect((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_ASPECT) != 0); - operation->setIsCrop((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_CROP) != 0); - operation->setOffset(bnode->custom3, bnode->custom4); - operation->setNewWidth(rd->xsch * render_size_factor); - operation->setNewHeight(rd->ysch * render_size_factor); - operation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); - - operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked()); - - break; - } - case CMP_SCALE_ABSOLUTE: { - /* TODO: what is the use of this one.... perhaps some issues when the ui was updated... */ - ScaleAbsoluteOperation *operation = new ScaleAbsoluteOperation(); - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.mapInputSocket(inputXSocket, operation->getInputSocket(1)); - converter.mapInputSocket(inputYSocket, operation->getInputSocket(2)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); - - operation->setVariableSize(inputXSocket->isLinked() || inputYSocket->isLinked()); - - break; - } - } -} diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cc b/source/blender/compositor/nodes/COM_SeparateColorNode.cc new file mode 100644 index 00000000000..203aa25c9e9 --- /dev/null +++ b/source/blender/compositor/nodes/COM_SeparateColorNode.cc @@ -0,0 +1,121 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SeparateColorNode.h" + +#include "COM_ConvertOperation.h" + +SeparateColorNode::SeparateColorNode(bNode *editorNode) : Node(editorNode) +{ +} + +void SeparateColorNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + NodeInput *imageSocket = this->getInputSocket(0); + NodeOutput *outputRSocket = this->getOutputSocket(0); + NodeOutput *outputGSocket = this->getOutputSocket(1); + NodeOutput *outputBSocket = this->getOutputSocket(2); + NodeOutput *outputASocket = this->getOutputSocket(3); + + NodeOperation *color_conv = getColorConverter(context); + if (color_conv) { + converter.addOperation(color_conv); + + converter.mapInputSocket(imageSocket, color_conv->getInputSocket(0)); + } + + { + SeparateChannelOperation *operation = new SeparateChannelOperation(); + operation->setChannel(0); + converter.addOperation(operation); + + if (color_conv) { + converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0)); + } + else { + converter.mapInputSocket(imageSocket, operation->getInputSocket(0)); + } + converter.mapOutputSocket(outputRSocket, operation->getOutputSocket(0)); + } + + { + SeparateChannelOperation *operation = new SeparateChannelOperation(); + operation->setChannel(1); + converter.addOperation(operation); + + if (color_conv) { + converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0)); + } + else { + converter.mapInputSocket(imageSocket, operation->getInputSocket(0)); + } + converter.mapOutputSocket(outputGSocket, operation->getOutputSocket(0)); + } + + { + SeparateChannelOperation *operation = new SeparateChannelOperation(); + operation->setChannel(2); + converter.addOperation(operation); + + if (color_conv) { + converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0)); + } + else { + converter.mapInputSocket(imageSocket, operation->getInputSocket(0)); + } + converter.mapOutputSocket(outputBSocket, operation->getOutputSocket(0)); + } + + { + SeparateChannelOperation *operation = new SeparateChannelOperation(); + operation->setChannel(3); + converter.addOperation(operation); + + if (color_conv) { + converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0)); + } + else { + converter.mapInputSocket(imageSocket, operation->getInputSocket(0)); + } + converter.mapOutputSocket(outputASocket, operation->getOutputSocket(0)); + } +} + +NodeOperation *SeparateRGBANode::getColorConverter(const CompositorContext & /*context*/) const +{ + return nullptr; /* no conversion needed */ +} + +NodeOperation *SeparateHSVANode::getColorConverter(const CompositorContext & /*context*/) const +{ + return new ConvertRGBToHSVOperation(); +} + +NodeOperation *SeparateYCCANode::getColorConverter(const CompositorContext & /*context*/) const +{ + ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation(); + bNode *editorNode = this->getbNode(); + operation->setMode(editorNode->custom1); + return operation; +} + +NodeOperation *SeparateYUVANode::getColorConverter(const CompositorContext & /*context*/) const +{ + return new ConvertRGBToYUVOperation(); +} diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp b/source/blender/compositor/nodes/COM_SeparateColorNode.cpp deleted file mode 100644 index 203aa25c9e9..00000000000 --- a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SeparateColorNode.h" - -#include "COM_ConvertOperation.h" - -SeparateColorNode::SeparateColorNode(bNode *editorNode) : Node(editorNode) -{ -} - -void SeparateColorNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - NodeInput *imageSocket = this->getInputSocket(0); - NodeOutput *outputRSocket = this->getOutputSocket(0); - NodeOutput *outputGSocket = this->getOutputSocket(1); - NodeOutput *outputBSocket = this->getOutputSocket(2); - NodeOutput *outputASocket = this->getOutputSocket(3); - - NodeOperation *color_conv = getColorConverter(context); - if (color_conv) { - converter.addOperation(color_conv); - - converter.mapInputSocket(imageSocket, color_conv->getInputSocket(0)); - } - - { - SeparateChannelOperation *operation = new SeparateChannelOperation(); - operation->setChannel(0); - converter.addOperation(operation); - - if (color_conv) { - converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0)); - } - else { - converter.mapInputSocket(imageSocket, operation->getInputSocket(0)); - } - converter.mapOutputSocket(outputRSocket, operation->getOutputSocket(0)); - } - - { - SeparateChannelOperation *operation = new SeparateChannelOperation(); - operation->setChannel(1); - converter.addOperation(operation); - - if (color_conv) { - converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0)); - } - else { - converter.mapInputSocket(imageSocket, operation->getInputSocket(0)); - } - converter.mapOutputSocket(outputGSocket, operation->getOutputSocket(0)); - } - - { - SeparateChannelOperation *operation = new SeparateChannelOperation(); - operation->setChannel(2); - converter.addOperation(operation); - - if (color_conv) { - converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0)); - } - else { - converter.mapInputSocket(imageSocket, operation->getInputSocket(0)); - } - converter.mapOutputSocket(outputBSocket, operation->getOutputSocket(0)); - } - - { - SeparateChannelOperation *operation = new SeparateChannelOperation(); - operation->setChannel(3); - converter.addOperation(operation); - - if (color_conv) { - converter.addLink(color_conv->getOutputSocket(), operation->getInputSocket(0)); - } - else { - converter.mapInputSocket(imageSocket, operation->getInputSocket(0)); - } - converter.mapOutputSocket(outputASocket, operation->getOutputSocket(0)); - } -} - -NodeOperation *SeparateRGBANode::getColorConverter(const CompositorContext & /*context*/) const -{ - return nullptr; /* no conversion needed */ -} - -NodeOperation *SeparateHSVANode::getColorConverter(const CompositorContext & /*context*/) const -{ - return new ConvertRGBToHSVOperation(); -} - -NodeOperation *SeparateYCCANode::getColorConverter(const CompositorContext & /*context*/) const -{ - ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation(); - bNode *editorNode = this->getbNode(); - operation->setMode(editorNode->custom1); - return operation; -} - -NodeOperation *SeparateYUVANode::getColorConverter(const CompositorContext & /*context*/) const -{ - return new ConvertRGBToYUVOperation(); -} diff --git a/source/blender/compositor/nodes/COM_SetAlphaNode.cc b/source/blender/compositor/nodes/COM_SetAlphaNode.cc new file mode 100644 index 00000000000..233a5e96ff4 --- /dev/null +++ b/source/blender/compositor/nodes/COM_SetAlphaNode.cc @@ -0,0 +1,48 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SetAlphaNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_SetAlphaMultiplyOperation.h" +#include "COM_SetAlphaReplaceOperation.h" + +void SetAlphaNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + const bNode *editorNode = this->getbNode(); + const NodeSetAlpha *storage = static_cast(editorNode->storage); + NodeOperation *operation = nullptr; + switch (storage->mode) { + case CMP_NODE_SETALPHA_MODE_APPLY: + operation = new SetAlphaMultiplyOperation(); + break; + case CMP_NODE_SETALPHA_MODE_REPLACE_ALPHA: + operation = new SetAlphaReplaceOperation(); + break; + } + + if (!this->getInputSocket(0)->isLinked() && this->getInputSocket(1)->isLinked()) { + operation->setResolutionInputSocketIndex(1); + } + + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp b/source/blender/compositor/nodes/COM_SetAlphaNode.cpp deleted file mode 100644 index 233a5e96ff4..00000000000 --- a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SetAlphaNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_SetAlphaMultiplyOperation.h" -#include "COM_SetAlphaReplaceOperation.h" - -void SetAlphaNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - const bNode *editorNode = this->getbNode(); - const NodeSetAlpha *storage = static_cast(editorNode->storage); - NodeOperation *operation = nullptr; - switch (storage->mode) { - case CMP_NODE_SETALPHA_MODE_APPLY: - operation = new SetAlphaMultiplyOperation(); - break; - case CMP_NODE_SETALPHA_MODE_REPLACE_ALPHA: - operation = new SetAlphaReplaceOperation(); - break; - } - - if (!this->getInputSocket(0)->isLinked() && this->getInputSocket(1)->isLinked()) { - operation->setResolutionInputSocketIndex(1); - } - - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cc b/source/blender/compositor/nodes/COM_SocketProxyNode.cc new file mode 100644 index 00000000000..a84dbf680fe --- /dev/null +++ b/source/blender/compositor/nodes/COM_SocketProxyNode.cc @@ -0,0 +1,103 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SocketProxyNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_ReadBufferOperation.h" +#include "COM_SetColorOperation.h" +#include "COM_SetValueOperation.h" +#include "COM_SetVectorOperation.h" +#include "COM_SocketProxyOperation.h" +#include "COM_WriteBufferOperation.h" + +SocketProxyNode::SocketProxyNode(bNode *editorNode, + bNodeSocket *editorInput, + bNodeSocket *editorOutput, + bool use_conversion) + : Node(editorNode, false), m_use_conversion(use_conversion) +{ + DataType dt; + + dt = COM_DT_VALUE; + if (editorInput->type == SOCK_RGBA) { + dt = COM_DT_COLOR; + } + if (editorInput->type == SOCK_VECTOR) { + dt = COM_DT_VECTOR; + } + this->addInputSocket(dt, editorInput); + + dt = COM_DT_VALUE; + if (editorOutput->type == SOCK_RGBA) { + dt = COM_DT_COLOR; + } + if (editorOutput->type == SOCK_VECTOR) { + dt = COM_DT_VECTOR; + } + this->addOutputSocket(dt, editorOutput); +} + +void SocketProxyNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeOperationOutput *proxy_output = converter.addInputProxy(getInputSocket(0), m_use_conversion); + converter.mapOutputSocket(getOutputSocket(), proxy_output); +} + +SocketBufferNode::SocketBufferNode(bNode *editorNode, + bNodeSocket *editorInput, + bNodeSocket *editorOutput) + : Node(editorNode, false) +{ + DataType dt; + + dt = COM_DT_VALUE; + if (editorInput->type == SOCK_RGBA) { + dt = COM_DT_COLOR; + } + if (editorInput->type == SOCK_VECTOR) { + dt = COM_DT_VECTOR; + } + this->addInputSocket(dt, editorInput); + + dt = COM_DT_VALUE; + if (editorOutput->type == SOCK_RGBA) { + dt = COM_DT_COLOR; + } + if (editorOutput->type == SOCK_VECTOR) { + dt = COM_DT_VECTOR; + } + this->addOutputSocket(dt, editorOutput); +} + +void SocketBufferNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeOutput *output = this->getOutputSocket(0); + NodeInput *input = this->getInputSocket(0); + + DataType datatype = output->getDataType(); + WriteBufferOperation *writeOperation = new WriteBufferOperation(datatype); + ReadBufferOperation *readOperation = new ReadBufferOperation(datatype); + readOperation->setMemoryProxy(writeOperation->getMemoryProxy()); + converter.addOperation(writeOperation); + converter.addOperation(readOperation); + + converter.mapInputSocket(input, writeOperation->getInputSocket(0)); + converter.mapOutputSocket(output, readOperation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp b/source/blender/compositor/nodes/COM_SocketProxyNode.cpp deleted file mode 100644 index a84dbf680fe..00000000000 --- a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SocketProxyNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_ReadBufferOperation.h" -#include "COM_SetColorOperation.h" -#include "COM_SetValueOperation.h" -#include "COM_SetVectorOperation.h" -#include "COM_SocketProxyOperation.h" -#include "COM_WriteBufferOperation.h" - -SocketProxyNode::SocketProxyNode(bNode *editorNode, - bNodeSocket *editorInput, - bNodeSocket *editorOutput, - bool use_conversion) - : Node(editorNode, false), m_use_conversion(use_conversion) -{ - DataType dt; - - dt = COM_DT_VALUE; - if (editorInput->type == SOCK_RGBA) { - dt = COM_DT_COLOR; - } - if (editorInput->type == SOCK_VECTOR) { - dt = COM_DT_VECTOR; - } - this->addInputSocket(dt, editorInput); - - dt = COM_DT_VALUE; - if (editorOutput->type == SOCK_RGBA) { - dt = COM_DT_COLOR; - } - if (editorOutput->type == SOCK_VECTOR) { - dt = COM_DT_VECTOR; - } - this->addOutputSocket(dt, editorOutput); -} - -void SocketProxyNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeOperationOutput *proxy_output = converter.addInputProxy(getInputSocket(0), m_use_conversion); - converter.mapOutputSocket(getOutputSocket(), proxy_output); -} - -SocketBufferNode::SocketBufferNode(bNode *editorNode, - bNodeSocket *editorInput, - bNodeSocket *editorOutput) - : Node(editorNode, false) -{ - DataType dt; - - dt = COM_DT_VALUE; - if (editorInput->type == SOCK_RGBA) { - dt = COM_DT_COLOR; - } - if (editorInput->type == SOCK_VECTOR) { - dt = COM_DT_VECTOR; - } - this->addInputSocket(dt, editorInput); - - dt = COM_DT_VALUE; - if (editorOutput->type == SOCK_RGBA) { - dt = COM_DT_COLOR; - } - if (editorOutput->type == SOCK_VECTOR) { - dt = COM_DT_VECTOR; - } - this->addOutputSocket(dt, editorOutput); -} - -void SocketBufferNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeOutput *output = this->getOutputSocket(0); - NodeInput *input = this->getInputSocket(0); - - DataType datatype = output->getDataType(); - WriteBufferOperation *writeOperation = new WriteBufferOperation(datatype); - ReadBufferOperation *readOperation = new ReadBufferOperation(datatype); - readOperation->setMemoryProxy(writeOperation->getMemoryProxy()); - converter.addOperation(writeOperation); - converter.addOperation(readOperation); - - converter.mapInputSocket(input, writeOperation->getInputSocket(0)); - converter.mapOutputSocket(output, readOperation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cc b/source/blender/compositor/nodes/COM_SplitViewerNode.cc new file mode 100644 index 00000000000..75703876d9e --- /dev/null +++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cc @@ -0,0 +1,75 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SplitViewerNode.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_scene.h" + +#include "COM_ExecutionSystem.h" +#include "COM_SplitOperation.h" +#include "COM_ViewerOperation.h" + +SplitViewerNode::SplitViewerNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void SplitViewerNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *editorNode = this->getbNode(); + bool do_output = (editorNode->flag & NODE_DO_OUTPUT_RECALC || context.isRendering()) && + (editorNode->flag & NODE_DO_OUTPUT); + + NodeInput *image1Socket = this->getInputSocket(0); + NodeInput *image2Socket = this->getInputSocket(1); + Image *image = (Image *)this->getbNode()->id; + ImageUser *imageUser = (ImageUser *)this->getbNode()->storage; + + SplitOperation *splitViewerOperation = new SplitOperation(); + splitViewerOperation->setSplitPercentage(this->getbNode()->custom1); + splitViewerOperation->setXSplit(!this->getbNode()->custom2); + + converter.addOperation(splitViewerOperation); + converter.mapInputSocket(image1Socket, splitViewerOperation->getInputSocket(0)); + converter.mapInputSocket(image2Socket, splitViewerOperation->getInputSocket(1)); + + ViewerOperation *viewerOperation = new ViewerOperation(); + viewerOperation->setImage(image); + 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 */ + viewerOperation->setChunkOrder(COM_ORDER_OF_CHUNKS_DEFAULT); + viewerOperation->setCenterX(0.5f); + viewerOperation->setCenterY(0.5f); + + converter.addOperation(viewerOperation); + converter.addLink(splitViewerOperation->getOutputSocket(), viewerOperation->getInputSocket(0)); + + converter.addPreview(splitViewerOperation->getOutputSocket()); + + if (do_output) { + converter.registerViewer(viewerOperation); + } +} diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp b/source/blender/compositor/nodes/COM_SplitViewerNode.cpp deleted file mode 100644 index 75703876d9e..00000000000 --- a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SplitViewerNode.h" -#include "BKE_global.h" -#include "BKE_image.h" -#include "BKE_scene.h" - -#include "COM_ExecutionSystem.h" -#include "COM_SplitOperation.h" -#include "COM_ViewerOperation.h" - -SplitViewerNode::SplitViewerNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void SplitViewerNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *editorNode = this->getbNode(); - bool do_output = (editorNode->flag & NODE_DO_OUTPUT_RECALC || context.isRendering()) && - (editorNode->flag & NODE_DO_OUTPUT); - - NodeInput *image1Socket = this->getInputSocket(0); - NodeInput *image2Socket = this->getInputSocket(1); - Image *image = (Image *)this->getbNode()->id; - ImageUser *imageUser = (ImageUser *)this->getbNode()->storage; - - SplitOperation *splitViewerOperation = new SplitOperation(); - splitViewerOperation->setSplitPercentage(this->getbNode()->custom1); - splitViewerOperation->setXSplit(!this->getbNode()->custom2); - - converter.addOperation(splitViewerOperation); - converter.mapInputSocket(image1Socket, splitViewerOperation->getInputSocket(0)); - converter.mapInputSocket(image2Socket, splitViewerOperation->getInputSocket(1)); - - ViewerOperation *viewerOperation = new ViewerOperation(); - viewerOperation->setImage(image); - 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 */ - viewerOperation->setChunkOrder(COM_ORDER_OF_CHUNKS_DEFAULT); - viewerOperation->setCenterX(0.5f); - viewerOperation->setCenterY(0.5f); - - converter.addOperation(viewerOperation); - converter.addLink(splitViewerOperation->getOutputSocket(), viewerOperation->getInputSocket(0)); - - converter.addPreview(splitViewerOperation->getOutputSocket()); - - if (do_output) { - converter.registerViewer(viewerOperation); - } -} diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cc b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc new file mode 100644 index 00000000000..38db080a154 --- /dev/null +++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc @@ -0,0 +1,113 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_Stabilize2dNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_MovieClipAttributeOperation.h" +#include "COM_RotateOperation.h" +#include "COM_ScaleOperation.h" +#include "COM_SetSamplerOperation.h" +#include "COM_TranslateOperation.h" + +#include "BKE_tracking.h" + +#include "DNA_movieclip_types.h" + +Stabilize2dNode::Stabilize2dNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void Stabilize2dNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *editorNode = this->getbNode(); + NodeInput *imageInput = this->getInputSocket(0); + MovieClip *clip = (MovieClip *)editorNode->id; + bool invert = (editorNode->custom2 & CMP_NODEFLAG_STABILIZE_INVERSE) != 0; + + ScaleOperation *scaleOperation = new ScaleOperation(); + scaleOperation->setSampler((PixelSampler)editorNode->custom1); + RotateOperation *rotateOperation = new RotateOperation(); + rotateOperation->setDoDegree2RadConversion(false); + TranslateOperation *translateOperation = new TranslateOperation(); + MovieClipAttributeOperation *scaleAttribute = new MovieClipAttributeOperation(); + MovieClipAttributeOperation *angleAttribute = new MovieClipAttributeOperation(); + MovieClipAttributeOperation *xAttribute = new MovieClipAttributeOperation(); + MovieClipAttributeOperation *yAttribute = new MovieClipAttributeOperation(); + SetSamplerOperation *psoperation = new SetSamplerOperation(); + psoperation->setSampler((PixelSampler)editorNode->custom1); + + scaleAttribute->setAttribute(MCA_SCALE); + scaleAttribute->setFramenumber(context.getFramenumber()); + scaleAttribute->setMovieClip(clip); + scaleAttribute->setInvert(invert); + + angleAttribute->setAttribute(MCA_ANGLE); + angleAttribute->setFramenumber(context.getFramenumber()); + angleAttribute->setMovieClip(clip); + angleAttribute->setInvert(invert); + + xAttribute->setAttribute(MCA_X); + xAttribute->setFramenumber(context.getFramenumber()); + xAttribute->setMovieClip(clip); + xAttribute->setInvert(invert); + + yAttribute->setAttribute(MCA_Y); + yAttribute->setFramenumber(context.getFramenumber()); + yAttribute->setMovieClip(clip); + yAttribute->setInvert(invert); + + converter.addOperation(scaleAttribute); + converter.addOperation(angleAttribute); + converter.addOperation(xAttribute); + converter.addOperation(yAttribute); + converter.addOperation(scaleOperation); + converter.addOperation(translateOperation); + converter.addOperation(rotateOperation); + converter.addOperation(psoperation); + + converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(1)); + converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(2)); + + converter.addLink(angleAttribute->getOutputSocket(), rotateOperation->getInputSocket(1)); + + converter.addLink(xAttribute->getOutputSocket(), translateOperation->getInputSocket(1)); + converter.addLink(yAttribute->getOutputSocket(), translateOperation->getInputSocket(2)); + + converter.mapOutputSocket(getOutputSocket(), psoperation->getOutputSocket()); + + if (invert) { + // Translate -> Rotate -> Scale. + converter.mapInputSocket(imageInput, translateOperation->getInputSocket(0)); + + converter.addLink(translateOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); + converter.addLink(rotateOperation->getOutputSocket(), scaleOperation->getInputSocket(0)); + + converter.addLink(scaleOperation->getOutputSocket(), psoperation->getInputSocket(0)); + } + else { + // Scale -> Rotate -> Translate. + converter.mapInputSocket(imageInput, scaleOperation->getInputSocket(0)); + + converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); + converter.addLink(rotateOperation->getOutputSocket(), translateOperation->getInputSocket(0)); + + converter.addLink(translateOperation->getOutputSocket(), psoperation->getInputSocket(0)); + } +} diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp b/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp deleted file mode 100644 index 38db080a154..00000000000 --- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_Stabilize2dNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_MovieClipAttributeOperation.h" -#include "COM_RotateOperation.h" -#include "COM_ScaleOperation.h" -#include "COM_SetSamplerOperation.h" -#include "COM_TranslateOperation.h" - -#include "BKE_tracking.h" - -#include "DNA_movieclip_types.h" - -Stabilize2dNode::Stabilize2dNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void Stabilize2dNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *editorNode = this->getbNode(); - NodeInput *imageInput = this->getInputSocket(0); - MovieClip *clip = (MovieClip *)editorNode->id; - bool invert = (editorNode->custom2 & CMP_NODEFLAG_STABILIZE_INVERSE) != 0; - - ScaleOperation *scaleOperation = new ScaleOperation(); - scaleOperation->setSampler((PixelSampler)editorNode->custom1); - RotateOperation *rotateOperation = new RotateOperation(); - rotateOperation->setDoDegree2RadConversion(false); - TranslateOperation *translateOperation = new TranslateOperation(); - MovieClipAttributeOperation *scaleAttribute = new MovieClipAttributeOperation(); - MovieClipAttributeOperation *angleAttribute = new MovieClipAttributeOperation(); - MovieClipAttributeOperation *xAttribute = new MovieClipAttributeOperation(); - MovieClipAttributeOperation *yAttribute = new MovieClipAttributeOperation(); - SetSamplerOperation *psoperation = new SetSamplerOperation(); - psoperation->setSampler((PixelSampler)editorNode->custom1); - - scaleAttribute->setAttribute(MCA_SCALE); - scaleAttribute->setFramenumber(context.getFramenumber()); - scaleAttribute->setMovieClip(clip); - scaleAttribute->setInvert(invert); - - angleAttribute->setAttribute(MCA_ANGLE); - angleAttribute->setFramenumber(context.getFramenumber()); - angleAttribute->setMovieClip(clip); - angleAttribute->setInvert(invert); - - xAttribute->setAttribute(MCA_X); - xAttribute->setFramenumber(context.getFramenumber()); - xAttribute->setMovieClip(clip); - xAttribute->setInvert(invert); - - yAttribute->setAttribute(MCA_Y); - yAttribute->setFramenumber(context.getFramenumber()); - yAttribute->setMovieClip(clip); - yAttribute->setInvert(invert); - - converter.addOperation(scaleAttribute); - converter.addOperation(angleAttribute); - converter.addOperation(xAttribute); - converter.addOperation(yAttribute); - converter.addOperation(scaleOperation); - converter.addOperation(translateOperation); - converter.addOperation(rotateOperation); - converter.addOperation(psoperation); - - converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(1)); - converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(2)); - - converter.addLink(angleAttribute->getOutputSocket(), rotateOperation->getInputSocket(1)); - - converter.addLink(xAttribute->getOutputSocket(), translateOperation->getInputSocket(1)); - converter.addLink(yAttribute->getOutputSocket(), translateOperation->getInputSocket(2)); - - converter.mapOutputSocket(getOutputSocket(), psoperation->getOutputSocket()); - - if (invert) { - // Translate -> Rotate -> Scale. - converter.mapInputSocket(imageInput, translateOperation->getInputSocket(0)); - - converter.addLink(translateOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); - converter.addLink(rotateOperation->getOutputSocket(), scaleOperation->getInputSocket(0)); - - converter.addLink(scaleOperation->getOutputSocket(), psoperation->getInputSocket(0)); - } - else { - // Scale -> Rotate -> Translate. - converter.mapInputSocket(imageInput, scaleOperation->getInputSocket(0)); - - converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); - converter.addLink(rotateOperation->getOutputSocket(), translateOperation->getInputSocket(0)); - - converter.addLink(translateOperation->getOutputSocket(), psoperation->getInputSocket(0)); - } -} diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cc b/source/blender/compositor/nodes/COM_SunBeamsNode.cc new file mode 100644 index 00000000000..d899a54c03c --- /dev/null +++ b/source/blender/compositor/nodes/COM_SunBeamsNode.cc @@ -0,0 +1,39 @@ +/* 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. + * + * Copyright 2014, Blender Foundation. + */ + +#include "COM_SunBeamsNode.h" +#include "COM_SunBeamsOperation.h" + +SunBeamsNode::SunBeamsNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void SunBeamsNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeOutput *outputSocket = this->getOutputSocket(0); + NodeSunBeams *data = (NodeSunBeams *)getbNode()->storage; + + SunBeamsOperation *operation = new SunBeamsOperation(); + operation->setData(*data); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp b/source/blender/compositor/nodes/COM_SunBeamsNode.cpp deleted file mode 100644 index d899a54c03c..00000000000 --- a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* 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. - * - * Copyright 2014, Blender Foundation. - */ - -#include "COM_SunBeamsNode.h" -#include "COM_SunBeamsOperation.h" - -SunBeamsNode::SunBeamsNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void SunBeamsNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *inputSocket = this->getInputSocket(0); - NodeOutput *outputSocket = this->getOutputSocket(0); - NodeSunBeams *data = (NodeSunBeams *)getbNode()->storage; - - SunBeamsOperation *operation = new SunBeamsOperation(); - operation->setData(*data); - converter.addOperation(operation); - - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_SwitchNode.cc b/source/blender/compositor/nodes/COM_SwitchNode.cc new file mode 100644 index 00000000000..947774e98ae --- /dev/null +++ b/source/blender/compositor/nodes/COM_SwitchNode.cc @@ -0,0 +1,40 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SwitchNode.h" + +SwitchNode::SwitchNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void SwitchNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bool condition = this->getbNode()->custom1; + + NodeOperationOutput *result; + if (!condition) { + result = converter.addInputProxy(getInputSocket(0), false); + } + else { + result = converter.addInputProxy(getInputSocket(1), false); + } + + converter.mapOutputSocket(getOutputSocket(0), result); +} diff --git a/source/blender/compositor/nodes/COM_SwitchNode.cpp b/source/blender/compositor/nodes/COM_SwitchNode.cpp deleted file mode 100644 index 947774e98ae..00000000000 --- a/source/blender/compositor/nodes/COM_SwitchNode.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SwitchNode.h" - -SwitchNode::SwitchNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void SwitchNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - bool condition = this->getbNode()->custom1; - - NodeOperationOutput *result; - if (!condition) { - result = converter.addInputProxy(getInputSocket(0), false); - } - else { - result = converter.addInputProxy(getInputSocket(1), false); - } - - converter.mapOutputSocket(getOutputSocket(0), result); -} diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cc b/source/blender/compositor/nodes/COM_SwitchViewNode.cc new file mode 100644 index 00000000000..e534ebfac9a --- /dev/null +++ b/source/blender/compositor/nodes/COM_SwitchViewNode.cc @@ -0,0 +1,40 @@ +/* + * 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. + * + * Copyright 2015, Blender Foundation. + */ + +#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 = MAX2(nr, 0); + + result = converter.addInputProxy(getInputSocket(nr), false); + converter.mapOutputSocket(getOutputSocket(0), result); +} diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp b/source/blender/compositor/nodes/COM_SwitchViewNode.cpp deleted file mode 100644 index e534ebfac9a..00000000000 --- a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * - * Copyright 2015, Blender Foundation. - */ - -#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 = MAX2(nr, 0); - - result = converter.addInputProxy(getInputSocket(nr), false); - converter.mapOutputSocket(getOutputSocket(0), result); -} diff --git a/source/blender/compositor/nodes/COM_TextureNode.cc b/source/blender/compositor/nodes/COM_TextureNode.cc new file mode 100644 index 00000000000..3381b5098d7 --- /dev/null +++ b/source/blender/compositor/nodes/COM_TextureNode.cc @@ -0,0 +1,56 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_TextureNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_TextureOperation.h" + +TextureNode::TextureNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void TextureNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *editorNode = this->getbNode(); + Tex *texture = (Tex *)editorNode->id; + TextureOperation *operation = new TextureOperation(); + const ColorManagedDisplaySettings *displaySettings = context.getDisplaySettings(); + bool sceneColorManage = !STREQ(displaySettings->display_device, "None"); + operation->setTexture(texture); + operation->setRenderData(context.getRenderData()); + operation->setSceneColorManage(sceneColorManage); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(1), operation->getOutputSocket()); + + converter.addPreview(operation->getOutputSocket()); + + TextureAlphaOperation *alphaOperation = new TextureAlphaOperation(); + alphaOperation->setTexture(texture); + alphaOperation->setRenderData(context.getRenderData()); + alphaOperation->setSceneColorManage(sceneColorManage); + converter.addOperation(alphaOperation); + + converter.mapInputSocket(getInputSocket(0), alphaOperation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), alphaOperation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), alphaOperation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_TextureNode.cpp b/source/blender/compositor/nodes/COM_TextureNode.cpp deleted file mode 100644 index 3381b5098d7..00000000000 --- a/source/blender/compositor/nodes/COM_TextureNode.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_TextureNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_TextureOperation.h" - -TextureNode::TextureNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void TextureNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *editorNode = this->getbNode(); - Tex *texture = (Tex *)editorNode->id; - TextureOperation *operation = new TextureOperation(); - const ColorManagedDisplaySettings *displaySettings = context.getDisplaySettings(); - bool sceneColorManage = !STREQ(displaySettings->display_device, "None"); - operation->setTexture(texture); - operation->setRenderData(context.getRenderData()); - operation->setSceneColorManage(sceneColorManage); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(1), operation->getOutputSocket()); - - converter.addPreview(operation->getOutputSocket()); - - TextureAlphaOperation *alphaOperation = new TextureAlphaOperation(); - alphaOperation->setTexture(texture); - alphaOperation->setRenderData(context.getRenderData()); - alphaOperation->setSceneColorManage(sceneColorManage); - converter.addOperation(alphaOperation); - - converter.mapInputSocket(getInputSocket(0), alphaOperation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), alphaOperation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(0), alphaOperation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_TimeNode.cc b/source/blender/compositor/nodes/COM_TimeNode.cc new file mode 100644 index 00000000000..247e0d11df6 --- /dev/null +++ b/source/blender/compositor/nodes/COM_TimeNode.cc @@ -0,0 +1,58 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_TimeNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_SetValueOperation.h" + +#include "BKE_colortools.h" + +#include "BLI_utildefines.h" + +TimeNode::TimeNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void TimeNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + SetValueOperation *operation = new SetValueOperation(); + bNode *node = this->getbNode(); + + /* stack order output: fac */ + float fac = 0.0f; + const int framenumber = context.getFramenumber(); + + if (framenumber < node->custom1) { + fac = 0.0f; + } + else if (framenumber > node->custom2) { + fac = 1.0f; + } + else if (node->custom1 < node->custom2) { + fac = (context.getFramenumber() - node->custom1) / (float)(node->custom2 - node->custom1); + } + + BKE_curvemapping_init((CurveMapping *)node->storage); + fac = BKE_curvemapping_evaluateF((CurveMapping *)node->storage, 0, fac); + operation->setValue(clamp_f(fac, 0.0f, 1.0f)); + converter.addOperation(operation); + + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_TimeNode.cpp b/source/blender/compositor/nodes/COM_TimeNode.cpp deleted file mode 100644 index 247e0d11df6..00000000000 --- a/source/blender/compositor/nodes/COM_TimeNode.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_TimeNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_SetValueOperation.h" - -#include "BKE_colortools.h" - -#include "BLI_utildefines.h" - -TimeNode::TimeNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void TimeNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - SetValueOperation *operation = new SetValueOperation(); - bNode *node = this->getbNode(); - - /* stack order output: fac */ - float fac = 0.0f; - const int framenumber = context.getFramenumber(); - - if (framenumber < node->custom1) { - fac = 0.0f; - } - else if (framenumber > node->custom2) { - fac = 1.0f; - } - else if (node->custom1 < node->custom2) { - fac = (context.getFramenumber() - node->custom1) / (float)(node->custom2 - node->custom1); - } - - BKE_curvemapping_init((CurveMapping *)node->storage); - fac = BKE_curvemapping_evaluateF((CurveMapping *)node->storage, 0, fac); - operation->setValue(clamp_f(fac, 0.0f, 1.0f)); - converter.addOperation(operation); - - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_TonemapNode.cc b/source/blender/compositor/nodes/COM_TonemapNode.cc new file mode 100644 index 00000000000..db329e56f9b --- /dev/null +++ b/source/blender/compositor/nodes/COM_TonemapNode.cc @@ -0,0 +1,40 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_TonemapNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_TonemapOperation.h" + +TonemapNode::TonemapNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void TonemapNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeTonemap *data = (NodeTonemap *)this->getbNode()->storage; + + TonemapOperation *operation = data->type == 1 ? new PhotoreceptorTonemapOperation() : + new TonemapOperation(); + operation->setData(data); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_TonemapNode.cpp b/source/blender/compositor/nodes/COM_TonemapNode.cpp deleted file mode 100644 index db329e56f9b..00000000000 --- a/source/blender/compositor/nodes/COM_TonemapNode.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_TonemapNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_TonemapOperation.h" - -TonemapNode::TonemapNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void TonemapNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeTonemap *data = (NodeTonemap *)this->getbNode()->storage; - - TonemapOperation *operation = data->type == 1 ? new PhotoreceptorTonemapOperation() : - new TonemapOperation(); - operation->setData(data); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); -} diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.cc b/source/blender/compositor/nodes/COM_TrackPositionNode.cc new file mode 100644 index 00000000000..52e7f7d832b --- /dev/null +++ b/source/blender/compositor/nodes/COM_TrackPositionNode.cc @@ -0,0 +1,111 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_TrackPositionNode.h" + +#include "COM_ConvertOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_TrackPositionOperation.h" + +#include "DNA_movieclip_types.h" + +#include "BKE_node.h" + +TrackPositionNode::TrackPositionNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +static TrackPositionOperation *create_motion_operation(NodeConverter &converter, + MovieClip *clip, + NodeTrackPosData *trackpos_data, + int axis, + int frame_number, + int delta) +{ + TrackPositionOperation *operation = new TrackPositionOperation(); + operation->setMovieClip(clip); + operation->setTrackingObject(trackpos_data->tracking_object); + operation->setTrackName(trackpos_data->track_name); + operation->setFramenumber(frame_number); + operation->setAxis(axis); + operation->setPosition(CMP_TRACKPOS_ABSOLUTE); + operation->setRelativeFrame(frame_number + delta); + operation->setSpeedOutput(true); + converter.addOperation(operation); + return operation; +} + +void TrackPositionNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *editorNode = this->getbNode(); + MovieClip *clip = (MovieClip *)editorNode->id; + NodeTrackPosData *trackpos_data = (NodeTrackPosData *)editorNode->storage; + + NodeOutput *outputX = this->getOutputSocket(0); + NodeOutput *outputY = this->getOutputSocket(1); + NodeOutput *outputSpeed = this->getOutputSocket(2); + + int frame_number; + if (editorNode->custom1 == CMP_TRACKPOS_ABSOLUTE_FRAME) { + frame_number = editorNode->custom2; + } + else { + frame_number = context.getFramenumber(); + } + + TrackPositionOperation *operationX = new TrackPositionOperation(); + operationX->setMovieClip(clip); + operationX->setTrackingObject(trackpos_data->tracking_object); + operationX->setTrackName(trackpos_data->track_name); + operationX->setFramenumber(frame_number); + operationX->setAxis(0); + operationX->setPosition(editorNode->custom1); + operationX->setRelativeFrame(editorNode->custom2); + converter.addOperation(operationX); + converter.mapOutputSocket(outputX, operationX->getOutputSocket()); + + TrackPositionOperation *operationY = new TrackPositionOperation(); + operationY->setMovieClip(clip); + operationY->setTrackingObject(trackpos_data->tracking_object); + operationY->setTrackName(trackpos_data->track_name); + operationY->setFramenumber(frame_number); + operationY->setAxis(1); + operationY->setPosition(editorNode->custom1); + operationY->setRelativeFrame(editorNode->custom2); + converter.addOperation(operationY); + converter.mapOutputSocket(outputY, operationY->getOutputSocket()); + + TrackPositionOperation *operationMotionPreX = create_motion_operation( + converter, clip, trackpos_data, 0, frame_number, -1); + TrackPositionOperation *operationMotionPreY = create_motion_operation( + converter, clip, trackpos_data, 1, frame_number, -1); + TrackPositionOperation *operationMotionPostX = create_motion_operation( + converter, clip, trackpos_data, 0, frame_number, 1); + TrackPositionOperation *operationMotionPostY = create_motion_operation( + converter, clip, trackpos_data, 1, frame_number, 1); + + CombineChannelsOperation *combine_operation = new CombineChannelsOperation(); + converter.addOperation(combine_operation); + converter.addLink(operationMotionPreX->getOutputSocket(), combine_operation->getInputSocket(0)); + converter.addLink(operationMotionPreY->getOutputSocket(), combine_operation->getInputSocket(1)); + converter.addLink(operationMotionPostX->getOutputSocket(), combine_operation->getInputSocket(2)); + converter.addLink(operationMotionPostY->getOutputSocket(), combine_operation->getInputSocket(3)); + converter.mapOutputSocket(outputSpeed, combine_operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp b/source/blender/compositor/nodes/COM_TrackPositionNode.cpp deleted file mode 100644 index 52e7f7d832b..00000000000 --- a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_TrackPositionNode.h" - -#include "COM_ConvertOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_TrackPositionOperation.h" - -#include "DNA_movieclip_types.h" - -#include "BKE_node.h" - -TrackPositionNode::TrackPositionNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -static TrackPositionOperation *create_motion_operation(NodeConverter &converter, - MovieClip *clip, - NodeTrackPosData *trackpos_data, - int axis, - int frame_number, - int delta) -{ - TrackPositionOperation *operation = new TrackPositionOperation(); - operation->setMovieClip(clip); - operation->setTrackingObject(trackpos_data->tracking_object); - operation->setTrackName(trackpos_data->track_name); - operation->setFramenumber(frame_number); - operation->setAxis(axis); - operation->setPosition(CMP_TRACKPOS_ABSOLUTE); - operation->setRelativeFrame(frame_number + delta); - operation->setSpeedOutput(true); - converter.addOperation(operation); - return operation; -} - -void TrackPositionNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *editorNode = this->getbNode(); - MovieClip *clip = (MovieClip *)editorNode->id; - NodeTrackPosData *trackpos_data = (NodeTrackPosData *)editorNode->storage; - - NodeOutput *outputX = this->getOutputSocket(0); - NodeOutput *outputY = this->getOutputSocket(1); - NodeOutput *outputSpeed = this->getOutputSocket(2); - - int frame_number; - if (editorNode->custom1 == CMP_TRACKPOS_ABSOLUTE_FRAME) { - frame_number = editorNode->custom2; - } - else { - frame_number = context.getFramenumber(); - } - - TrackPositionOperation *operationX = new TrackPositionOperation(); - operationX->setMovieClip(clip); - operationX->setTrackingObject(trackpos_data->tracking_object); - operationX->setTrackName(trackpos_data->track_name); - operationX->setFramenumber(frame_number); - operationX->setAxis(0); - operationX->setPosition(editorNode->custom1); - operationX->setRelativeFrame(editorNode->custom2); - converter.addOperation(operationX); - converter.mapOutputSocket(outputX, operationX->getOutputSocket()); - - TrackPositionOperation *operationY = new TrackPositionOperation(); - operationY->setMovieClip(clip); - operationY->setTrackingObject(trackpos_data->tracking_object); - operationY->setTrackName(trackpos_data->track_name); - operationY->setFramenumber(frame_number); - operationY->setAxis(1); - operationY->setPosition(editorNode->custom1); - operationY->setRelativeFrame(editorNode->custom2); - converter.addOperation(operationY); - converter.mapOutputSocket(outputY, operationY->getOutputSocket()); - - TrackPositionOperation *operationMotionPreX = create_motion_operation( - converter, clip, trackpos_data, 0, frame_number, -1); - TrackPositionOperation *operationMotionPreY = create_motion_operation( - converter, clip, trackpos_data, 1, frame_number, -1); - TrackPositionOperation *operationMotionPostX = create_motion_operation( - converter, clip, trackpos_data, 0, frame_number, 1); - TrackPositionOperation *operationMotionPostY = create_motion_operation( - converter, clip, trackpos_data, 1, frame_number, 1); - - CombineChannelsOperation *combine_operation = new CombineChannelsOperation(); - converter.addOperation(combine_operation); - converter.addLink(operationMotionPreX->getOutputSocket(), combine_operation->getInputSocket(0)); - converter.addLink(operationMotionPreY->getOutputSocket(), combine_operation->getInputSocket(1)); - converter.addLink(operationMotionPostX->getOutputSocket(), combine_operation->getInputSocket(2)); - converter.addLink(operationMotionPostY->getOutputSocket(), combine_operation->getInputSocket(3)); - converter.mapOutputSocket(outputSpeed, combine_operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_TransformNode.cc b/source/blender/compositor/nodes/COM_TransformNode.cc new file mode 100644 index 00000000000..cd5ba8ba201 --- /dev/null +++ b/source/blender/compositor/nodes/COM_TransformNode.cc @@ -0,0 +1,68 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_TransformNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_RotateOperation.h" +#include "COM_ScaleOperation.h" +#include "COM_SetSamplerOperation.h" +#include "COM_SetValueOperation.h" +#include "COM_TranslateOperation.h" + +TransformNode::TransformNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void TransformNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *imageInput = this->getInputSocket(0); + NodeInput *xInput = this->getInputSocket(1); + NodeInput *yInput = this->getInputSocket(2); + NodeInput *angleInput = this->getInputSocket(3); + NodeInput *scaleInput = this->getInputSocket(4); + + ScaleOperation *scaleOperation = new ScaleOperation(); + converter.addOperation(scaleOperation); + + RotateOperation *rotateOperation = new RotateOperation(); + rotateOperation->setDoDegree2RadConversion(false); + converter.addOperation(rotateOperation); + + TranslateOperation *translateOperation = new TranslateOperation(); + converter.addOperation(translateOperation); + + SetSamplerOperation *sampler = new SetSamplerOperation(); + sampler->setSampler((PixelSampler)this->getbNode()->custom1); + converter.addOperation(sampler); + + converter.mapInputSocket(imageInput, sampler->getInputSocket(0)); + converter.addLink(sampler->getOutputSocket(), scaleOperation->getInputSocket(0)); + converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(1)); + converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(2)); // xscale = yscale + + converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); + converter.mapInputSocket(angleInput, rotateOperation->getInputSocket(1)); + + converter.addLink(rotateOperation->getOutputSocket(), translateOperation->getInputSocket(0)); + converter.mapInputSocket(xInput, translateOperation->getInputSocket(1)); + converter.mapInputSocket(yInput, translateOperation->getInputSocket(2)); + + converter.mapOutputSocket(getOutputSocket(), translateOperation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_TransformNode.cpp b/source/blender/compositor/nodes/COM_TransformNode.cpp deleted file mode 100644 index cd5ba8ba201..00000000000 --- a/source/blender/compositor/nodes/COM_TransformNode.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_TransformNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_RotateOperation.h" -#include "COM_ScaleOperation.h" -#include "COM_SetSamplerOperation.h" -#include "COM_SetValueOperation.h" -#include "COM_TranslateOperation.h" - -TransformNode::TransformNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void TransformNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *imageInput = this->getInputSocket(0); - NodeInput *xInput = this->getInputSocket(1); - NodeInput *yInput = this->getInputSocket(2); - NodeInput *angleInput = this->getInputSocket(3); - NodeInput *scaleInput = this->getInputSocket(4); - - ScaleOperation *scaleOperation = new ScaleOperation(); - converter.addOperation(scaleOperation); - - RotateOperation *rotateOperation = new RotateOperation(); - rotateOperation->setDoDegree2RadConversion(false); - converter.addOperation(rotateOperation); - - TranslateOperation *translateOperation = new TranslateOperation(); - converter.addOperation(translateOperation); - - SetSamplerOperation *sampler = new SetSamplerOperation(); - sampler->setSampler((PixelSampler)this->getbNode()->custom1); - converter.addOperation(sampler); - - converter.mapInputSocket(imageInput, sampler->getInputSocket(0)); - converter.addLink(sampler->getOutputSocket(), scaleOperation->getInputSocket(0)); - converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(1)); - converter.mapInputSocket(scaleInput, scaleOperation->getInputSocket(2)); // xscale = yscale - - converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); - converter.mapInputSocket(angleInput, rotateOperation->getInputSocket(1)); - - converter.addLink(rotateOperation->getOutputSocket(), translateOperation->getInputSocket(0)); - converter.mapInputSocket(xInput, translateOperation->getInputSocket(1)); - converter.mapInputSocket(yInput, translateOperation->getInputSocket(2)); - - converter.mapOutputSocket(getOutputSocket(), translateOperation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cc b/source/blender/compositor/nodes/COM_TranslateNode.cc new file mode 100644 index 00000000000..0e9bf825787 --- /dev/null +++ b/source/blender/compositor/nodes/COM_TranslateNode.cc @@ -0,0 +1,71 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_TranslateNode.h" + +#include "COM_ExecutionSystem.h" +#include "COM_TranslateOperation.h" +#include "COM_WrapOperation.h" +#include "COM_WriteBufferOperation.h" + +TranslateNode::TranslateNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void TranslateNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *bnode = this->getbNode(); + NodeTranslateData *data = (NodeTranslateData *)bnode->storage; + + NodeInput *inputSocket = this->getInputSocket(0); + NodeInput *inputXSocket = this->getInputSocket(1); + NodeInput *inputYSocket = this->getInputSocket(2); + NodeOutput *outputSocket = this->getOutputSocket(0); + + TranslateOperation *operation = new TranslateOperation(); + if (data->relative) { + const RenderData *rd = context.getRenderData(); + const float render_size_factor = context.getRenderPercentageAsFactor(); + float fx = rd->xsch * render_size_factor; + float fy = rd->ysch * render_size_factor; + + operation->setFactorXY(fx, fy); + } + + converter.addOperation(operation); + converter.mapInputSocket(inputXSocket, operation->getInputSocket(1)); + converter.mapInputSocket(inputYSocket, operation->getInputSocket(2)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); + + if (data->wrap_axis) { + WriteBufferOperation *writeOperation = new WriteBufferOperation(COM_DT_COLOR); + WrapOperation *wrapOperation = new WrapOperation(COM_DT_COLOR); + wrapOperation->setMemoryProxy(writeOperation->getMemoryProxy()); + wrapOperation->setWrapping(data->wrap_axis); + + converter.addOperation(writeOperation); + converter.addOperation(wrapOperation); + converter.mapInputSocket(inputSocket, writeOperation->getInputSocket(0)); + converter.addLink(wrapOperation->getOutputSocket(), operation->getInputSocket(0)); + } + else { + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + } +} diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cpp b/source/blender/compositor/nodes/COM_TranslateNode.cpp deleted file mode 100644 index 0e9bf825787..00000000000 --- a/source/blender/compositor/nodes/COM_TranslateNode.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_TranslateNode.h" - -#include "COM_ExecutionSystem.h" -#include "COM_TranslateOperation.h" -#include "COM_WrapOperation.h" -#include "COM_WriteBufferOperation.h" - -TranslateNode::TranslateNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void TranslateNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *bnode = this->getbNode(); - NodeTranslateData *data = (NodeTranslateData *)bnode->storage; - - NodeInput *inputSocket = this->getInputSocket(0); - NodeInput *inputXSocket = this->getInputSocket(1); - NodeInput *inputYSocket = this->getInputSocket(2); - NodeOutput *outputSocket = this->getOutputSocket(0); - - TranslateOperation *operation = new TranslateOperation(); - if (data->relative) { - const RenderData *rd = context.getRenderData(); - const float render_size_factor = context.getRenderPercentageAsFactor(); - float fx = rd->xsch * render_size_factor; - float fy = rd->ysch * render_size_factor; - - operation->setFactorXY(fx, fy); - } - - converter.addOperation(operation); - converter.mapInputSocket(inputXSocket, operation->getInputSocket(1)); - converter.mapInputSocket(inputYSocket, operation->getInputSocket(2)); - converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); - - if (data->wrap_axis) { - WriteBufferOperation *writeOperation = new WriteBufferOperation(COM_DT_COLOR); - WrapOperation *wrapOperation = new WrapOperation(COM_DT_COLOR); - wrapOperation->setMemoryProxy(writeOperation->getMemoryProxy()); - wrapOperation->setWrapping(data->wrap_axis); - - converter.addOperation(writeOperation); - converter.addOperation(wrapOperation); - converter.mapInputSocket(inputSocket, writeOperation->getInputSocket(0)); - converter.addLink(wrapOperation->getOutputSocket(), operation->getInputSocket(0)); - } - else { - converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); - } -} diff --git a/source/blender/compositor/nodes/COM_ValueNode.cc b/source/blender/compositor/nodes/COM_ValueNode.cc new file mode 100644 index 00000000000..4227db0d10e --- /dev/null +++ b/source/blender/compositor/nodes/COM_ValueNode.cc @@ -0,0 +1,37 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ValueNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_SetValueOperation.h" + +ValueNode::ValueNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ValueNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + SetValueOperation *operation = new SetValueOperation(); + NodeOutput *output = this->getOutputSocket(0); + operation->setValue(output->getEditorValueFloat()); + converter.addOperation(operation); + + converter.mapOutputSocket(output, operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_ValueNode.cpp b/source/blender/compositor/nodes/COM_ValueNode.cpp deleted file mode 100644 index 4227db0d10e..00000000000 --- a/source/blender/compositor/nodes/COM_ValueNode.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ValueNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_SetValueOperation.h" - -ValueNode::ValueNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ValueNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - SetValueOperation *operation = new SetValueOperation(); - NodeOutput *output = this->getOutputSocket(0); - operation->setValue(output->getEditorValueFloat()); - converter.addOperation(operation); - - converter.mapOutputSocket(output, operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_VectorBlurNode.cc b/source/blender/compositor/nodes/COM_VectorBlurNode.cc new file mode 100644 index 00000000000..a92991c8b49 --- /dev/null +++ b/source/blender/compositor/nodes/COM_VectorBlurNode.cc @@ -0,0 +1,43 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_VectorBlurNode.h" +#include "COM_VectorBlurOperation.h" +#include "DNA_node_types.h" + +VectorBlurNode::VectorBlurNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void VectorBlurNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *node = this->getbNode(); + NodeBlurData *vectorBlurSettings = (NodeBlurData *)node->storage; + + VectorBlurOperation *operation = new VectorBlurOperation(); + operation->setVectorBlurSettings(vectorBlurSettings); + operation->setQuality(context.getQuality()); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); + converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_VectorBlurNode.cpp b/source/blender/compositor/nodes/COM_VectorBlurNode.cpp deleted file mode 100644 index a92991c8b49..00000000000 --- a/source/blender/compositor/nodes/COM_VectorBlurNode.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_VectorBlurNode.h" -#include "COM_VectorBlurOperation.h" -#include "DNA_node_types.h" - -VectorBlurNode::VectorBlurNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void VectorBlurNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *node = this->getbNode(); - NodeBlurData *vectorBlurSettings = (NodeBlurData *)node->storage; - - VectorBlurOperation *operation = new VectorBlurOperation(); - operation->setVectorBlurSettings(vectorBlurSettings); - operation->setQuality(context.getQuality()); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); - converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_VectorCurveNode.cc b/source/blender/compositor/nodes/COM_VectorCurveNode.cc new file mode 100644 index 00000000000..1201a9f9613 --- /dev/null +++ b/source/blender/compositor/nodes/COM_VectorCurveNode.cc @@ -0,0 +1,37 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_VectorCurveNode.h" +#include "COM_ExecutionSystem.h" +#include "COM_VectorCurveOperation.h" + +VectorCurveNode::VectorCurveNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void VectorCurveNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + VectorCurveOperation *operation = new VectorCurveOperation(); + operation->setCurveMapping((CurveMapping *)this->getbNode()->storage); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); +} diff --git a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp b/source/blender/compositor/nodes/COM_VectorCurveNode.cpp deleted file mode 100644 index 1201a9f9613..00000000000 --- a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_VectorCurveNode.h" -#include "COM_ExecutionSystem.h" -#include "COM_VectorCurveOperation.h" - -VectorCurveNode::VectorCurveNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void VectorCurveNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - VectorCurveOperation *operation = new VectorCurveOperation(); - operation->setCurveMapping((CurveMapping *)this->getbNode()->storage); - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); -} diff --git a/source/blender/compositor/nodes/COM_ViewLevelsNode.cc b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc new file mode 100644 index 00000000000..7b86fb1d64d --- /dev/null +++ b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc @@ -0,0 +1,61 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ViewLevelsNode.h" +#include "COM_CalculateMeanOperation.h" +#include "COM_CalculateStandardDeviationOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_SetValueOperation.h" + +ViewLevelsNode::ViewLevelsNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ViewLevelsNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + NodeInput *input = this->getInputSocket(0); + if (input->isLinked()) { + // add preview to inputSocket; + + /* calculate mean operation */ + { + CalculateMeanOperation *operation = new CalculateMeanOperation(); + operation->setSetting(this->getbNode()->custom1); + + converter.addOperation(operation); + converter.mapInputSocket(input, operation->getInputSocket(0)); + converter.mapOutputSocket(this->getOutputSocket(0), operation->getOutputSocket()); + } + + /* calculate standard deviation operation */ + { + CalculateStandardDeviationOperation *operation = new CalculateStandardDeviationOperation(); + operation->setSetting(this->getbNode()->custom1); + + converter.addOperation(operation); + converter.mapInputSocket(input, operation->getInputSocket(0)); + converter.mapOutputSocket(this->getOutputSocket(1), operation->getOutputSocket()); + } + } + else { + converter.addOutputValue(getOutputSocket(0), 0.0f); + converter.addOutputValue(getOutputSocket(1), 0.0f); + } +} diff --git a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp b/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp deleted file mode 100644 index 7b86fb1d64d..00000000000 --- a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ViewLevelsNode.h" -#include "COM_CalculateMeanOperation.h" -#include "COM_CalculateStandardDeviationOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_SetValueOperation.h" - -ViewLevelsNode::ViewLevelsNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ViewLevelsNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const -{ - NodeInput *input = this->getInputSocket(0); - if (input->isLinked()) { - // add preview to inputSocket; - - /* calculate mean operation */ - { - CalculateMeanOperation *operation = new CalculateMeanOperation(); - operation->setSetting(this->getbNode()->custom1); - - converter.addOperation(operation); - converter.mapInputSocket(input, operation->getInputSocket(0)); - converter.mapOutputSocket(this->getOutputSocket(0), operation->getOutputSocket()); - } - - /* calculate standard deviation operation */ - { - CalculateStandardDeviationOperation *operation = new CalculateStandardDeviationOperation(); - operation->setSetting(this->getbNode()->custom1); - - converter.addOperation(operation); - converter.mapInputSocket(input, operation->getInputSocket(0)); - converter.mapOutputSocket(this->getOutputSocket(1), operation->getOutputSocket()); - } - } - else { - converter.addOutputValue(getOutputSocket(0), 0.0f); - converter.addOutputValue(getOutputSocket(1), 0.0f); - } -} diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cc b/source/blender/compositor/nodes/COM_ViewerNode.cc new file mode 100644 index 00000000000..fa6c1bc3c28 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ViewerNode.cc @@ -0,0 +1,84 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ViewerNode.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_scene.h" +#include "BLI_listbase.h" + +#include "COM_ExecutionSystem.h" +#include "COM_ViewerOperation.h" + +ViewerNode::ViewerNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ViewerNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + bNode *editorNode = this->getbNode(); + bool do_output = (editorNode->flag & NODE_DO_OUTPUT_RECALC || context.isRendering()) && + (editorNode->flag & NODE_DO_OUTPUT); + bool ignore_alpha = (editorNode->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA) != 0; + + NodeInput *imageSocket = this->getInputSocket(0); + NodeInput *alphaSocket = this->getInputSocket(1); + NodeInput *depthSocket = this->getInputSocket(2); + Image *image = (Image *)this->getbNode()->id; + ImageUser *imageUser = (ImageUser *)this->getbNode()->storage; + ViewerOperation *viewerOperation = new ViewerOperation(); + viewerOperation->setbNodeTree(context.getbNodeTree()); + viewerOperation->setImage(image); + viewerOperation->setImageUser(imageUser); + viewerOperation->setChunkOrder((OrderOfChunks)editorNode->custom1); + viewerOperation->setCenterX(editorNode->custom3); + 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()); + + viewerOperation->setResolutionInputSocketIndex(0); + if (!imageSocket->isLinked()) { + if (alphaSocket->isLinked()) { + viewerOperation->setResolutionInputSocketIndex(1); + } + } + + converter.addOperation(viewerOperation); + converter.mapInputSocket(imageSocket, viewerOperation->getInputSocket(0)); + /* only use alpha link if "use alpha" is enabled */ + if (ignore_alpha) { + converter.addInputValue(viewerOperation->getInputSocket(1), 1.0f); + } + else { + converter.mapInputSocket(alphaSocket, viewerOperation->getInputSocket(1)); + } + converter.mapInputSocket(depthSocket, viewerOperation->getInputSocket(2)); + + converter.addNodeInputPreview(imageSocket); + + if (do_output) { + converter.registerViewer(viewerOperation); + } +} diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cpp b/source/blender/compositor/nodes/COM_ViewerNode.cpp deleted file mode 100644 index fa6c1bc3c28..00000000000 --- a/source/blender/compositor/nodes/COM_ViewerNode.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ViewerNode.h" -#include "BKE_global.h" -#include "BKE_image.h" -#include "BKE_scene.h" -#include "BLI_listbase.h" - -#include "COM_ExecutionSystem.h" -#include "COM_ViewerOperation.h" - -ViewerNode::ViewerNode(bNode *editorNode) : Node(editorNode) -{ - /* pass */ -} - -void ViewerNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - bNode *editorNode = this->getbNode(); - bool do_output = (editorNode->flag & NODE_DO_OUTPUT_RECALC || context.isRendering()) && - (editorNode->flag & NODE_DO_OUTPUT); - bool ignore_alpha = (editorNode->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA) != 0; - - NodeInput *imageSocket = this->getInputSocket(0); - NodeInput *alphaSocket = this->getInputSocket(1); - NodeInput *depthSocket = this->getInputSocket(2); - Image *image = (Image *)this->getbNode()->id; - ImageUser *imageUser = (ImageUser *)this->getbNode()->storage; - ViewerOperation *viewerOperation = new ViewerOperation(); - viewerOperation->setbNodeTree(context.getbNodeTree()); - viewerOperation->setImage(image); - viewerOperation->setImageUser(imageUser); - viewerOperation->setChunkOrder((OrderOfChunks)editorNode->custom1); - viewerOperation->setCenterX(editorNode->custom3); - 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()); - - viewerOperation->setResolutionInputSocketIndex(0); - if (!imageSocket->isLinked()) { - if (alphaSocket->isLinked()) { - viewerOperation->setResolutionInputSocketIndex(1); - } - } - - converter.addOperation(viewerOperation); - converter.mapInputSocket(imageSocket, viewerOperation->getInputSocket(0)); - /* only use alpha link if "use alpha" is enabled */ - if (ignore_alpha) { - converter.addInputValue(viewerOperation->getInputSocket(1), 1.0f); - } - else { - converter.mapInputSocket(alphaSocket, viewerOperation->getInputSocket(1)); - } - converter.mapInputSocket(depthSocket, viewerOperation->getInputSocket(2)); - - converter.addNodeInputPreview(imageSocket); - - if (do_output) { - converter.registerViewer(viewerOperation); - } -} diff --git a/source/blender/compositor/nodes/COM_ZCombineNode.cc b/source/blender/compositor/nodes/COM_ZCombineNode.cc new file mode 100644 index 00000000000..b61c018d029 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ZCombineNode.cc @@ -0,0 +1,101 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ZCombineNode.h" + +#include "COM_ZCombineOperation.h" + +#include "COM_AntiAliasOperation.h" +#include "COM_ExecutionSystem.h" +#include "COM_MathBaseOperation.h" +#include "COM_MixOperation.h" +#include "COM_SetValueOperation.h" + +#include "DNA_material_types.h" /* the ramp types */ + +void ZCombineNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const +{ + if ((context.getRenderData()->scemode & R_FULL_SAMPLE) || this->getbNode()->custom2) { + ZCombineOperation *operation = nullptr; + if (this->getbNode()->custom1) { + operation = new ZCombineAlphaOperation(); + } + else { + operation = new ZCombineOperation(); + } + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); + converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(3)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); + + MathMinimumOperation *zoperation = new MathMinimumOperation(); + converter.addOperation(zoperation); + + converter.mapInputSocket(getInputSocket(1), zoperation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(3), zoperation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(1), zoperation->getOutputSocket()); + } + else { + /* XXX custom1 is "use_alpha", what on earth is this supposed to do here?!? */ + // not full anti alias, use masking for Z combine. be aware it uses anti aliasing. + // step 1 create mask + NodeOperation *maskoperation; + if (this->getbNode()->custom1) { + maskoperation = new MathGreaterThanOperation(); + converter.addOperation(maskoperation); + + converter.mapInputSocket(getInputSocket(1), maskoperation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(3), maskoperation->getInputSocket(1)); + } + else { + maskoperation = new MathLessThanOperation(); + converter.addOperation(maskoperation); + + converter.mapInputSocket(getInputSocket(1), maskoperation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(3), maskoperation->getInputSocket(1)); + } + + // step 2 anti alias mask bit of an expensive operation, but does the trick + AntiAliasOperation *antialiasoperation = new AntiAliasOperation(); + converter.addOperation(antialiasoperation); + + converter.addLink(maskoperation->getOutputSocket(), antialiasoperation->getInputSocket(0)); + + // use mask to blend between the input colors. + ZCombineMaskOperation *zcombineoperation = this->getbNode()->custom1 ? + new ZCombineMaskAlphaOperation() : + new ZCombineMaskOperation(); + converter.addOperation(zcombineoperation); + + converter.addLink(antialiasoperation->getOutputSocket(), zcombineoperation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(0), zcombineoperation->getInputSocket(1)); + converter.mapInputSocket(getInputSocket(2), zcombineoperation->getInputSocket(2)); + converter.mapOutputSocket(getOutputSocket(0), zcombineoperation->getOutputSocket()); + + MathMinimumOperation *zoperation = new MathMinimumOperation(); + converter.addOperation(zoperation); + + converter.mapInputSocket(getInputSocket(1), zoperation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(3), zoperation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(1), zoperation->getOutputSocket()); + } +} diff --git a/source/blender/compositor/nodes/COM_ZCombineNode.cpp b/source/blender/compositor/nodes/COM_ZCombineNode.cpp deleted file mode 100644 index b61c018d029..00000000000 --- a/source/blender/compositor/nodes/COM_ZCombineNode.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ZCombineNode.h" - -#include "COM_ZCombineOperation.h" - -#include "COM_AntiAliasOperation.h" -#include "COM_ExecutionSystem.h" -#include "COM_MathBaseOperation.h" -#include "COM_MixOperation.h" -#include "COM_SetValueOperation.h" - -#include "DNA_material_types.h" /* the ramp types */ - -void ZCombineNode::convertToOperations(NodeConverter &converter, - const CompositorContext &context) const -{ - if ((context.getRenderData()->scemode & R_FULL_SAMPLE) || this->getbNode()->custom2) { - ZCombineOperation *operation = nullptr; - if (this->getbNode()->custom1) { - operation = new ZCombineAlphaOperation(); - } - else { - operation = new ZCombineOperation(); - } - converter.addOperation(operation); - - converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); - converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); - converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(3)); - converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); - - MathMinimumOperation *zoperation = new MathMinimumOperation(); - converter.addOperation(zoperation); - - converter.mapInputSocket(getInputSocket(1), zoperation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(3), zoperation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(1), zoperation->getOutputSocket()); - } - else { - /* XXX custom1 is "use_alpha", what on earth is this supposed to do here?!? */ - // not full anti alias, use masking for Z combine. be aware it uses anti aliasing. - // step 1 create mask - NodeOperation *maskoperation; - if (this->getbNode()->custom1) { - maskoperation = new MathGreaterThanOperation(); - converter.addOperation(maskoperation); - - converter.mapInputSocket(getInputSocket(1), maskoperation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(3), maskoperation->getInputSocket(1)); - } - else { - maskoperation = new MathLessThanOperation(); - converter.addOperation(maskoperation); - - converter.mapInputSocket(getInputSocket(1), maskoperation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(3), maskoperation->getInputSocket(1)); - } - - // step 2 anti alias mask bit of an expensive operation, but does the trick - AntiAliasOperation *antialiasoperation = new AntiAliasOperation(); - converter.addOperation(antialiasoperation); - - converter.addLink(maskoperation->getOutputSocket(), antialiasoperation->getInputSocket(0)); - - // use mask to blend between the input colors. - ZCombineMaskOperation *zcombineoperation = this->getbNode()->custom1 ? - new ZCombineMaskAlphaOperation() : - new ZCombineMaskOperation(); - converter.addOperation(zcombineoperation); - - converter.addLink(antialiasoperation->getOutputSocket(), zcombineoperation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(0), zcombineoperation->getInputSocket(1)); - converter.mapInputSocket(getInputSocket(2), zcombineoperation->getInputSocket(2)); - converter.mapOutputSocket(getOutputSocket(0), zcombineoperation->getOutputSocket()); - - MathMinimumOperation *zoperation = new MathMinimumOperation(); - converter.addOperation(zoperation); - - converter.mapInputSocket(getInputSocket(1), zoperation->getInputSocket(0)); - converter.mapInputSocket(getInputSocket(3), zoperation->getInputSocket(1)); - converter.mapOutputSocket(getOutputSocket(1), zoperation->getOutputSocket()); - } -} diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc new file mode 100644 index 00000000000..668d07c7c3d --- /dev/null +++ b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc @@ -0,0 +1,54 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_AlphaOverKeyOperation.h" + +AlphaOverKeyOperation::AlphaOverKeyOperation() +{ + /* pass */ +} + +void AlphaOverKeyOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputOverColor[4]; + float value[4]; + + this->m_inputValueOperation->readSampled(value, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputOverColor, x, y, sampler); + + if (inputOverColor[3] <= 0.0f) { + copy_v4_v4(output, inputColor1); + } + else if (value[0] == 1.0f && inputOverColor[3] >= 1.0f) { + copy_v4_v4(output, inputOverColor); + } + else { + float premul = value[0] * inputOverColor[3]; + float mul = 1.0f - premul; + + output[0] = (mul * inputColor1[0]) + premul * inputOverColor[0]; + output[1] = (mul * inputColor1[1]) + premul * inputOverColor[1]; + output[2] = (mul * inputColor1[2]) + premul * inputOverColor[2]; + output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3]; + } +} diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp deleted file mode 100644 index 668d07c7c3d..00000000000 --- a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_AlphaOverKeyOperation.h" - -AlphaOverKeyOperation::AlphaOverKeyOperation() -{ - /* pass */ -} - -void AlphaOverKeyOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputOverColor[4]; - float value[4]; - - this->m_inputValueOperation->readSampled(value, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputOverColor, x, y, sampler); - - if (inputOverColor[3] <= 0.0f) { - copy_v4_v4(output, inputColor1); - } - else if (value[0] == 1.0f && inputOverColor[3] >= 1.0f) { - copy_v4_v4(output, inputOverColor); - } - else { - float premul = value[0] * inputOverColor[3]; - float mul = 1.0f - premul; - - output[0] = (mul * inputColor1[0]) + premul * inputOverColor[0]; - output[1] = (mul * inputColor1[1]) + premul * inputOverColor[1]; - output[2] = (mul * inputColor1[2]) + premul * inputOverColor[2]; - output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3]; - } -} diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc new file mode 100644 index 00000000000..b8465ab7ccf --- /dev/null +++ b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc @@ -0,0 +1,55 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_AlphaOverMixedOperation.h" + +AlphaOverMixedOperation::AlphaOverMixedOperation() +{ + this->m_x = 0.0f; +} + +void AlphaOverMixedOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputOverColor[4]; + float value[4]; + + this->m_inputValueOperation->readSampled(value, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputOverColor, x, y, sampler); + + if (inputOverColor[3] <= 0.0f) { + copy_v4_v4(output, inputColor1); + } + else if (value[0] == 1.0f && inputOverColor[3] >= 1.0f) { + copy_v4_v4(output, inputOverColor); + } + else { + float addfac = 1.0f - this->m_x + inputOverColor[3] * this->m_x; + float premul = value[0] * addfac; + float mul = 1.0f - value[0] * inputOverColor[3]; + + output[0] = (mul * inputColor1[0]) + premul * inputOverColor[0]; + output[1] = (mul * inputColor1[1]) + premul * inputOverColor[1]; + output[2] = (mul * inputColor1[2]) + premul * inputOverColor[2]; + output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3]; + } +} diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp deleted file mode 100644 index b8465ab7ccf..00000000000 --- a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_AlphaOverMixedOperation.h" - -AlphaOverMixedOperation::AlphaOverMixedOperation() -{ - this->m_x = 0.0f; -} - -void AlphaOverMixedOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputOverColor[4]; - float value[4]; - - this->m_inputValueOperation->readSampled(value, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputOverColor, x, y, sampler); - - if (inputOverColor[3] <= 0.0f) { - copy_v4_v4(output, inputColor1); - } - else if (value[0] == 1.0f && inputOverColor[3] >= 1.0f) { - copy_v4_v4(output, inputOverColor); - } - else { - float addfac = 1.0f - this->m_x + inputOverColor[3] * this->m_x; - float premul = value[0] * addfac; - float mul = 1.0f - value[0] * inputOverColor[3]; - - output[0] = (mul * inputColor1[0]) + premul * inputOverColor[0]; - output[1] = (mul * inputColor1[1]) + premul * inputOverColor[1]; - output[2] = (mul * inputColor1[2]) + premul * inputOverColor[2]; - output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3]; - } -} diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc new file mode 100644 index 00000000000..4510c027d46 --- /dev/null +++ b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc @@ -0,0 +1,54 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_AlphaOverPremultiplyOperation.h" + +AlphaOverPremultiplyOperation::AlphaOverPremultiplyOperation() +{ + /* pass */ +} + +void AlphaOverPremultiplyOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputOverColor[4]; + float value[4]; + + this->m_inputValueOperation->readSampled(value, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputOverColor, x, y, sampler); + + /* Zero alpha values should still permit an add of RGB data */ + if (inputOverColor[3] < 0.0f) { + copy_v4_v4(output, inputColor1); + } + else if (value[0] == 1.0f && inputOverColor[3] >= 1.0f) { + copy_v4_v4(output, inputOverColor); + } + else { + float mul = 1.0f - value[0] * inputOverColor[3]; + + output[0] = (mul * inputColor1[0]) + value[0] * inputOverColor[0]; + output[1] = (mul * inputColor1[1]) + value[0] * inputOverColor[1]; + output[2] = (mul * inputColor1[2]) + value[0] * inputOverColor[2]; + output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3]; + } +} diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp deleted file mode 100644 index 4510c027d46..00000000000 --- a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_AlphaOverPremultiplyOperation.h" - -AlphaOverPremultiplyOperation::AlphaOverPremultiplyOperation() -{ - /* pass */ -} - -void AlphaOverPremultiplyOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputOverColor[4]; - float value[4]; - - this->m_inputValueOperation->readSampled(value, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputOverColor, x, y, sampler); - - /* Zero alpha values should still permit an add of RGB data */ - if (inputOverColor[3] < 0.0f) { - copy_v4_v4(output, inputColor1); - } - else if (value[0] == 1.0f && inputOverColor[3] >= 1.0f) { - copy_v4_v4(output, inputOverColor); - } - else { - float mul = 1.0f - value[0] * inputOverColor[3]; - - output[0] = (mul * inputColor1[0]) + value[0] * inputOverColor[0]; - output[1] = (mul * inputColor1[1]) + value[0] * inputOverColor[1]; - output[2] = (mul * inputColor1[2]) + value[0] * inputOverColor[2]; - output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3]; - } -} diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cc b/source/blender/compositor/operations/COM_AntiAliasOperation.cc new file mode 100644 index 00000000000..684485c40cb --- /dev/null +++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cc @@ -0,0 +1,201 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_AntiAliasOperation.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "MEM_guardedalloc.h" + +#include "RE_texture.h" + +/* An implementation of the Scale3X edge-extrapolation algorithm. + * + * Code from GIMP plugin, based on code from Adam D. Moss + * licensed by the MIT license. + */ +static int extrapolate9(float *E0, + float *E1, + float *E2, + float *E3, + float *E4, + float *E5, + float *E6, + float *E7, + float *E8, + const float *A, + const float *B, + const float *C, + const float *D, + const float *E, + const float *F, + const float *G, + const float *H, + const float *I) +{ +#define PEQ(X, Y) (fabsf(*X - *Y) < 1e-3f) +#define PCPY(DST, SRC) \ + do { \ + *DST = *SRC; \ + } while (0) + if ((!PEQ(B, H)) && (!PEQ(D, F))) { + if (PEQ(D, B)) { + PCPY(E0, D); + } + else { + PCPY(E0, E); + } + if ((PEQ(D, B) && !PEQ(E, C)) || (PEQ(B, F) && !PEQ(E, A))) { + PCPY(E1, B); + } + else { + PCPY(E1, E); + } + if (PEQ(B, F)) { + PCPY(E2, F); + } + else { + PCPY(E2, E); + } + if ((PEQ(D, B) && !PEQ(E, G)) || (PEQ(D, H) && !PEQ(E, A))) { + PCPY(E3, D); + } + else { + PCPY(E3, E); + } + PCPY(E4, E); + if ((PEQ(B, F) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, C))) { + PCPY(E5, F); + } + else { + PCPY(E5, E); + } + if (PEQ(D, H)) { + PCPY(E6, D); + } + else { + PCPY(E6, E); + } + if ((PEQ(D, H) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, G))) { + PCPY(E7, H); + } + else { + PCPY(E7, E); + } + if (PEQ(H, F)) { + PCPY(E8, F); + } + else { + PCPY(E8, E); + } + return 1; + } + + return 0; + +#undef PEQ +#undef PCPY +} + +AntiAliasOperation::AntiAliasOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->m_valueReader = nullptr; + this->setComplex(true); +} + +void AntiAliasOperation::initExecution() +{ + this->m_valueReader = this->getInputSocketReader(0); +} + +void AntiAliasOperation::executePixel(float output[4], int x, int y, void *data) +{ + MemoryBuffer *input_buffer = (MemoryBuffer *)data; + const int buffer_width = input_buffer->getWidth(), buffer_height = input_buffer->getHeight(); + if (y < 0 || y >= buffer_height || x < 0 || x >= buffer_width) { + output[0] = 0.0f; + } + else { + const float *buffer = input_buffer->getBuffer(); + const float *row_curr = &buffer[y * buffer_width]; + if (x == 0 || x == buffer_width - 1 || y == 0 || y == buffer_height - 1) { + output[0] = row_curr[x]; + return; + } + const float *row_prev = &buffer[(y - 1) * buffer_width], + *row_next = &buffer[(y + 1) * buffer_width]; + float ninepix[9]; + if (extrapolate9(&ninepix[0], + &ninepix[1], + &ninepix[2], + &ninepix[3], + &ninepix[4], + &ninepix[5], + &ninepix[6], + &ninepix[7], + &ninepix[8], + &row_prev[x - 1], + &row_prev[x], + &row_prev[x + 1], + &row_curr[x - 1], + &row_curr[x], + &row_curr[x + 1], + &row_next[x - 1], + &row_next[x], + &row_next[x + 1])) { + /* Some rounding magic to so make weighting correct with the + * original coefficients. + */ + unsigned char result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] + 5 * ninepix[3] + + 6 * ninepix[4] + 5 * ninepix[5] + 3 * ninepix[6] + 5 * ninepix[7] + + 3 * ninepix[8]) * + 255.0f + + 19.0f) / + 38.0f; + output[0] = result / 255.0f; + } + else { + output[0] = row_curr[x]; + } + } +} + +void AntiAliasOperation::deinitExecution() +{ + this->m_valueReader = nullptr; +} + +bool AntiAliasOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti imageInput; + NodeOperation *operation = getInputOperation(0); + imageInput.xmax = input->xmax + 1; + imageInput.xmin = input->xmin - 1; + imageInput.ymax = input->ymax + 1; + imageInput.ymin = input->ymin - 1; + return operation->determineDependingAreaOfInterest(&imageInput, readOperation, output); +} + +void *AntiAliasOperation::initializeTileData(rcti *rect) +{ + return getInputOperation(0)->initializeTileData(rect); +} diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp deleted file mode 100644 index 684485c40cb..00000000000 --- a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_AntiAliasOperation.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -#include "MEM_guardedalloc.h" - -#include "RE_texture.h" - -/* An implementation of the Scale3X edge-extrapolation algorithm. - * - * Code from GIMP plugin, based on code from Adam D. Moss - * licensed by the MIT license. - */ -static int extrapolate9(float *E0, - float *E1, - float *E2, - float *E3, - float *E4, - float *E5, - float *E6, - float *E7, - float *E8, - const float *A, - const float *B, - const float *C, - const float *D, - const float *E, - const float *F, - const float *G, - const float *H, - const float *I) -{ -#define PEQ(X, Y) (fabsf(*X - *Y) < 1e-3f) -#define PCPY(DST, SRC) \ - do { \ - *DST = *SRC; \ - } while (0) - if ((!PEQ(B, H)) && (!PEQ(D, F))) { - if (PEQ(D, B)) { - PCPY(E0, D); - } - else { - PCPY(E0, E); - } - if ((PEQ(D, B) && !PEQ(E, C)) || (PEQ(B, F) && !PEQ(E, A))) { - PCPY(E1, B); - } - else { - PCPY(E1, E); - } - if (PEQ(B, F)) { - PCPY(E2, F); - } - else { - PCPY(E2, E); - } - if ((PEQ(D, B) && !PEQ(E, G)) || (PEQ(D, H) && !PEQ(E, A))) { - PCPY(E3, D); - } - else { - PCPY(E3, E); - } - PCPY(E4, E); - if ((PEQ(B, F) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, C))) { - PCPY(E5, F); - } - else { - PCPY(E5, E); - } - if (PEQ(D, H)) { - PCPY(E6, D); - } - else { - PCPY(E6, E); - } - if ((PEQ(D, H) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, G))) { - PCPY(E7, H); - } - else { - PCPY(E7, E); - } - if (PEQ(H, F)) { - PCPY(E8, F); - } - else { - PCPY(E8, E); - } - return 1; - } - - return 0; - -#undef PEQ -#undef PCPY -} - -AntiAliasOperation::AntiAliasOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->m_valueReader = nullptr; - this->setComplex(true); -} - -void AntiAliasOperation::initExecution() -{ - this->m_valueReader = this->getInputSocketReader(0); -} - -void AntiAliasOperation::executePixel(float output[4], int x, int y, void *data) -{ - MemoryBuffer *input_buffer = (MemoryBuffer *)data; - const int buffer_width = input_buffer->getWidth(), buffer_height = input_buffer->getHeight(); - if (y < 0 || y >= buffer_height || x < 0 || x >= buffer_width) { - output[0] = 0.0f; - } - else { - const float *buffer = input_buffer->getBuffer(); - const float *row_curr = &buffer[y * buffer_width]; - if (x == 0 || x == buffer_width - 1 || y == 0 || y == buffer_height - 1) { - output[0] = row_curr[x]; - return; - } - const float *row_prev = &buffer[(y - 1) * buffer_width], - *row_next = &buffer[(y + 1) * buffer_width]; - float ninepix[9]; - if (extrapolate9(&ninepix[0], - &ninepix[1], - &ninepix[2], - &ninepix[3], - &ninepix[4], - &ninepix[5], - &ninepix[6], - &ninepix[7], - &ninepix[8], - &row_prev[x - 1], - &row_prev[x], - &row_prev[x + 1], - &row_curr[x - 1], - &row_curr[x], - &row_curr[x + 1], - &row_next[x - 1], - &row_next[x], - &row_next[x + 1])) { - /* Some rounding magic to so make weighting correct with the - * original coefficients. - */ - unsigned char result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] + 5 * ninepix[3] + - 6 * ninepix[4] + 5 * ninepix[5] + 3 * ninepix[6] + 5 * ninepix[7] + - 3 * ninepix[8]) * - 255.0f + - 19.0f) / - 38.0f; - output[0] = result / 255.0f; - } - else { - output[0] = row_curr[x]; - } - } -} - -void AntiAliasOperation::deinitExecution() -{ - this->m_valueReader = nullptr; -} - -bool AntiAliasOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti imageInput; - NodeOperation *operation = getInputOperation(0); - imageInput.xmax = input->xmax + 1; - imageInput.xmin = input->xmin - 1; - imageInput.ymax = input->ymax + 1; - imageInput.ymin = input->ymin - 1; - return operation->determineDependingAreaOfInterest(&imageInput, readOperation, output); -} - -void *AntiAliasOperation::initializeTileData(rcti *rect) -{ - return getInputOperation(0)->initializeTileData(rect); -} diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.cc b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc new file mode 100644 index 00000000000..35b0092fa5f --- /dev/null +++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc @@ -0,0 +1,114 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BilateralBlurOperation.h" +#include "BLI_math.h" + +#include "RE_pipeline.h" + +BilateralBlurOperation::BilateralBlurOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->setComplex(true); + + this->m_inputColorProgram = nullptr; + this->m_inputDeterminatorProgram = nullptr; +} + +void BilateralBlurOperation::initExecution() +{ + this->m_inputColorProgram = getInputSocketReader(0); + this->m_inputDeterminatorProgram = getInputSocketReader(1); + this->m_space = this->m_data->sigma_space + this->m_data->iter; + QualityStepHelper::initExecution(COM_QH_INCREASE); +} + +void BilateralBlurOperation::executePixel(float output[4], int x, int y, void *data) +{ + // read the determinator color at x, y, this will be used as the reference color for the + // determinator + float determinatorReferenceColor[4]; + float determinator[4]; + float tempColor[4]; + float blurColor[4]; + float blurDivider; + float space = this->m_space; + float sigmacolor = this->m_data->sigma_color; + int minx = floor(x - space); + int maxx = ceil(x + space); + int miny = floor(y - space); + int maxy = ceil(y + space); + float deltaColor; + this->m_inputDeterminatorProgram->read(determinatorReferenceColor, x, y, data); + + zero_v4(blurColor); + blurDivider = 0.0f; + /* TODO(sergey): This isn't really good bilateral filter, it should be + * using gaussian bell for weights. Also sigma_color doesn't seem to be + * used correct at all. + */ + for (int yi = miny; yi < maxy; yi += QualityStepHelper::getStep()) { + for (int xi = minx; xi < maxx; xi += QualityStepHelper::getStep()) { + // read determinator + this->m_inputDeterminatorProgram->read(determinator, xi, yi, data); + deltaColor = (fabsf(determinatorReferenceColor[0] - determinator[0]) + + fabsf(determinatorReferenceColor[1] - determinator[1]) + + fabsf(determinatorReferenceColor[2] - + determinator[2])); // do not take the alpha channel into account + if (deltaColor < sigmacolor) { + // add this to the blur + this->m_inputColorProgram->read(tempColor, xi, yi, data); + add_v4_v4(blurColor, tempColor); + blurDivider += 1.0f; + } + } + } + + if (blurDivider > 0.0f) { + mul_v4_v4fl(output, blurColor, 1.0f / blurDivider); + } + else { + output[0] = 0.0f; + output[1] = 0.0f; + output[2] = 0.0f; + output[3] = 1.0f; + } +} + +void BilateralBlurOperation::deinitExecution() +{ + this->m_inputColorProgram = nullptr; + this->m_inputDeterminatorProgram = nullptr; +} + +bool BilateralBlurOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + int add = ceil(this->m_space) + 1; + + newInput.xmax = input->xmax + (add); + newInput.xmin = input->xmin - (add); + newInput.ymax = input->ymax + (add); + newInput.ymin = input->ymin - (add); + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp b/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp deleted file mode 100644 index 35b0092fa5f..00000000000 --- a/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BilateralBlurOperation.h" -#include "BLI_math.h" - -#include "RE_pipeline.h" - -BilateralBlurOperation::BilateralBlurOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->setComplex(true); - - this->m_inputColorProgram = nullptr; - this->m_inputDeterminatorProgram = nullptr; -} - -void BilateralBlurOperation::initExecution() -{ - this->m_inputColorProgram = getInputSocketReader(0); - this->m_inputDeterminatorProgram = getInputSocketReader(1); - this->m_space = this->m_data->sigma_space + this->m_data->iter; - QualityStepHelper::initExecution(COM_QH_INCREASE); -} - -void BilateralBlurOperation::executePixel(float output[4], int x, int y, void *data) -{ - // read the determinator color at x, y, this will be used as the reference color for the - // determinator - float determinatorReferenceColor[4]; - float determinator[4]; - float tempColor[4]; - float blurColor[4]; - float blurDivider; - float space = this->m_space; - float sigmacolor = this->m_data->sigma_color; - int minx = floor(x - space); - int maxx = ceil(x + space); - int miny = floor(y - space); - int maxy = ceil(y + space); - float deltaColor; - this->m_inputDeterminatorProgram->read(determinatorReferenceColor, x, y, data); - - zero_v4(blurColor); - blurDivider = 0.0f; - /* TODO(sergey): This isn't really good bilateral filter, it should be - * using gaussian bell for weights. Also sigma_color doesn't seem to be - * used correct at all. - */ - for (int yi = miny; yi < maxy; yi += QualityStepHelper::getStep()) { - for (int xi = minx; xi < maxx; xi += QualityStepHelper::getStep()) { - // read determinator - this->m_inputDeterminatorProgram->read(determinator, xi, yi, data); - deltaColor = (fabsf(determinatorReferenceColor[0] - determinator[0]) + - fabsf(determinatorReferenceColor[1] - determinator[1]) + - fabsf(determinatorReferenceColor[2] - - determinator[2])); // do not take the alpha channel into account - if (deltaColor < sigmacolor) { - // add this to the blur - this->m_inputColorProgram->read(tempColor, xi, yi, data); - add_v4_v4(blurColor, tempColor); - blurDivider += 1.0f; - } - } - } - - if (blurDivider > 0.0f) { - mul_v4_v4fl(output, blurColor, 1.0f / blurDivider); - } - else { - output[0] = 0.0f; - output[1] = 0.0f; - output[2] = 0.0f; - output[3] = 1.0f; - } -} - -void BilateralBlurOperation::deinitExecution() -{ - this->m_inputColorProgram = nullptr; - this->m_inputDeterminatorProgram = nullptr; -} - -bool BilateralBlurOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - int add = ceil(this->m_space) + 1; - - newInput.xmax = input->xmax + (add); - newInput.xmin = input->xmin - (add); - newInput.ymax = input->ymax + (add); - newInput.ymin = input->ymin - (add); - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cc b/source/blender/compositor/operations/COM_BlurBaseOperation.cc new file mode 100644 index 00000000000..612a71037f7 --- /dev/null +++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cc @@ -0,0 +1,184 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BlurBaseOperation.h" +#include "BLI_math.h" +#include "MEM_guardedalloc.h" + +#include "RE_pipeline.h" + +BlurBaseOperation::BlurBaseOperation(DataType data_type) +{ + /* data_type is almost always COM_DT_COLOR except for alpha-blur */ + this->addInputSocket(data_type); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(data_type); + this->setComplex(true); + this->m_inputProgram = nullptr; + memset(&m_data, 0, sizeof(NodeBlurData)); + this->m_size = 1.0f; + this->m_sizeavailable = false; + this->m_extend_bounds = false; +} +void BlurBaseOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); + this->m_inputSize = this->getInputSocketReader(1); + this->m_data.image_in_width = this->getWidth(); + this->m_data.image_in_height = this->getHeight(); + if (this->m_data.relative) { + int sizex, sizey; + switch (this->m_data.aspect) { + case CMP_NODE_BLUR_ASPECT_Y: + sizex = sizey = this->m_data.image_in_width; + break; + case CMP_NODE_BLUR_ASPECT_X: + sizex = sizey = this->m_data.image_in_height; + break; + default: + BLI_assert(this->m_data.aspect == CMP_NODE_BLUR_ASPECT_NONE); + sizex = this->m_data.image_in_width; + sizey = this->m_data.image_in_height; + break; + } + this->m_data.sizex = round_fl_to_int(this->m_data.percentx * 0.01f * sizex); + this->m_data.sizey = round_fl_to_int(this->m_data.percenty * 0.01f * sizey); + } + + QualityStepHelper::initExecution(COM_QH_MULTIPLY); +} + +float *BlurBaseOperation::make_gausstab(float rad, int size) +{ + float *gausstab, sum, val; + int i, n; + + n = 2 * size + 1; + + gausstab = (float *)MEM_mallocN(sizeof(float) * n, __func__); + + sum = 0.0f; + float fac = (rad > 0.0f ? 1.0f / rad : 0.0f); + for (i = -size; i <= size; i++) { + val = RE_filter_value(this->m_data.filtertype, (float)i * fac); + sum += val; + gausstab[i + size] = val; + } + + sum = 1.0f / sum; + for (i = 0; i < n; i++) { + gausstab[i] *= sum; + } + + return gausstab; +} + +#ifdef BLI_HAVE_SSE2 +__m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, int size) +{ + int n = 2 * size + 1; + __m128 *gausstab_sse = (__m128 *)MEM_mallocN_aligned(sizeof(__m128) * n, 16, "gausstab sse"); + for (int i = 0; i < n; i++) { + gausstab_sse[i] = _mm_set1_ps(gausstab[i]); + } + return gausstab_sse; +} +#endif + +/* normalized distance from the current (inverted so 1.0 is close and 0.0 is far) + * 'ease' is applied after, looks nicer */ +float *BlurBaseOperation::make_dist_fac_inverse(float rad, int size, int falloff) +{ + float *dist_fac_invert, val; + int i, n; + + n = 2 * size + 1; + + dist_fac_invert = (float *)MEM_mallocN(sizeof(float) * n, __func__); + + float fac = (rad > 0.0f ? 1.0f / rad : 0.0f); + for (i = -size; i <= size; i++) { + val = 1.0f - fabsf((float)i * fac); + + /* keep in sync with rna_enum_proportional_falloff_curve_only_items */ + switch (falloff) { + case PROP_SMOOTH: + /* ease - gives less hard lines for dilate/erode feather */ + val = (3.0f * val * val - 2.0f * val * val * val); + break; + case PROP_SPHERE: + val = sqrtf(2.0f * val - val * val); + break; + case PROP_ROOT: + val = sqrtf(val); + break; + case PROP_SHARP: + val = val * val; + break; + case PROP_INVSQUARE: + val = val * (2.0f - val); + break; + case PROP_LIN: + /* nothing to do */ + break; +#ifndef NDEBUG + case -1: + /* uninitialized! */ + BLI_assert(0); + break; +#endif + default: + /* nothing */ + break; + } + dist_fac_invert[i + size] = val; + } + + return dist_fac_invert; +} + +void BlurBaseOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; + this->m_inputSize = nullptr; +} + +void BlurBaseOperation::setData(const NodeBlurData *data) +{ + memcpy(&m_data, data, sizeof(NodeBlurData)); +} + +void BlurBaseOperation::updateSize() +{ + if (!this->m_sizeavailable) { + float result[4]; + this->getInputSocketReader(1)->readSampled(result, 0, 0, COM_PS_NEAREST); + this->m_size = result[0]; + this->m_sizeavailable = true; + } +} + +void BlurBaseOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + NodeOperation::determineResolution(resolution, preferredResolution); + if (this->m_extend_bounds) { + resolution[0] += 2 * this->m_size * m_data.sizex; + resolution[1] += 2 * this->m_size * m_data.sizey; + } +} diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp deleted file mode 100644 index 612a71037f7..00000000000 --- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BlurBaseOperation.h" -#include "BLI_math.h" -#include "MEM_guardedalloc.h" - -#include "RE_pipeline.h" - -BlurBaseOperation::BlurBaseOperation(DataType data_type) -{ - /* data_type is almost always COM_DT_COLOR except for alpha-blur */ - this->addInputSocket(data_type); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(data_type); - this->setComplex(true); - this->m_inputProgram = nullptr; - memset(&m_data, 0, sizeof(NodeBlurData)); - this->m_size = 1.0f; - this->m_sizeavailable = false; - this->m_extend_bounds = false; -} -void BlurBaseOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); - this->m_inputSize = this->getInputSocketReader(1); - this->m_data.image_in_width = this->getWidth(); - this->m_data.image_in_height = this->getHeight(); - if (this->m_data.relative) { - int sizex, sizey; - switch (this->m_data.aspect) { - case CMP_NODE_BLUR_ASPECT_Y: - sizex = sizey = this->m_data.image_in_width; - break; - case CMP_NODE_BLUR_ASPECT_X: - sizex = sizey = this->m_data.image_in_height; - break; - default: - BLI_assert(this->m_data.aspect == CMP_NODE_BLUR_ASPECT_NONE); - sizex = this->m_data.image_in_width; - sizey = this->m_data.image_in_height; - break; - } - this->m_data.sizex = round_fl_to_int(this->m_data.percentx * 0.01f * sizex); - this->m_data.sizey = round_fl_to_int(this->m_data.percenty * 0.01f * sizey); - } - - QualityStepHelper::initExecution(COM_QH_MULTIPLY); -} - -float *BlurBaseOperation::make_gausstab(float rad, int size) -{ - float *gausstab, sum, val; - int i, n; - - n = 2 * size + 1; - - gausstab = (float *)MEM_mallocN(sizeof(float) * n, __func__); - - sum = 0.0f; - float fac = (rad > 0.0f ? 1.0f / rad : 0.0f); - for (i = -size; i <= size; i++) { - val = RE_filter_value(this->m_data.filtertype, (float)i * fac); - sum += val; - gausstab[i + size] = val; - } - - sum = 1.0f / sum; - for (i = 0; i < n; i++) { - gausstab[i] *= sum; - } - - return gausstab; -} - -#ifdef BLI_HAVE_SSE2 -__m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, int size) -{ - int n = 2 * size + 1; - __m128 *gausstab_sse = (__m128 *)MEM_mallocN_aligned(sizeof(__m128) * n, 16, "gausstab sse"); - for (int i = 0; i < n; i++) { - gausstab_sse[i] = _mm_set1_ps(gausstab[i]); - } - return gausstab_sse; -} -#endif - -/* normalized distance from the current (inverted so 1.0 is close and 0.0 is far) - * 'ease' is applied after, looks nicer */ -float *BlurBaseOperation::make_dist_fac_inverse(float rad, int size, int falloff) -{ - float *dist_fac_invert, val; - int i, n; - - n = 2 * size + 1; - - dist_fac_invert = (float *)MEM_mallocN(sizeof(float) * n, __func__); - - float fac = (rad > 0.0f ? 1.0f / rad : 0.0f); - for (i = -size; i <= size; i++) { - val = 1.0f - fabsf((float)i * fac); - - /* keep in sync with rna_enum_proportional_falloff_curve_only_items */ - switch (falloff) { - case PROP_SMOOTH: - /* ease - gives less hard lines for dilate/erode feather */ - val = (3.0f * val * val - 2.0f * val * val * val); - break; - case PROP_SPHERE: - val = sqrtf(2.0f * val - val * val); - break; - case PROP_ROOT: - val = sqrtf(val); - break; - case PROP_SHARP: - val = val * val; - break; - case PROP_INVSQUARE: - val = val * (2.0f - val); - break; - case PROP_LIN: - /* nothing to do */ - break; -#ifndef NDEBUG - case -1: - /* uninitialized! */ - BLI_assert(0); - break; -#endif - default: - /* nothing */ - break; - } - dist_fac_invert[i + size] = val; - } - - return dist_fac_invert; -} - -void BlurBaseOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; - this->m_inputSize = nullptr; -} - -void BlurBaseOperation::setData(const NodeBlurData *data) -{ - memcpy(&m_data, data, sizeof(NodeBlurData)); -} - -void BlurBaseOperation::updateSize() -{ - if (!this->m_sizeavailable) { - float result[4]; - this->getInputSocketReader(1)->readSampled(result, 0, 0, COM_PS_NEAREST); - this->m_size = result[0]; - this->m_sizeavailable = true; - } -} - -void BlurBaseOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - NodeOperation::determineResolution(resolution, preferredResolution); - if (this->m_extend_bounds) { - resolution[0] += 2 * this->m_size * m_data.sizex; - resolution[1] += 2 * this->m_size * m_data.sizey; - } -} diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cc b/source/blender/compositor/operations/COM_BokehBlurOperation.cc new file mode 100644 index 00000000000..a8ad2a11790 --- /dev/null +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cc @@ -0,0 +1,242 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BokehBlurOperation.h" +#include "BLI_math.h" +#include "COM_OpenCLDevice.h" + +#include "RE_pipeline.h" + +BokehBlurOperation::BokehBlurOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setComplex(true); + this->setOpenCL(true); + + this->m_size = 1.0f; + this->m_sizeavailable = false; + this->m_inputProgram = nullptr; + this->m_inputBokehProgram = nullptr; + this->m_inputBoundingBoxReader = nullptr; + + this->m_extend_bounds = false; +} + +void *BokehBlurOperation::initializeTileData(rcti * /*rect*/) +{ + lockMutex(); + if (!this->m_sizeavailable) { + updateSize(); + } + void *buffer = getInputOperation(0)->initializeTileData(nullptr); + unlockMutex(); + return buffer; +} + +void BokehBlurOperation::initExecution() +{ + initMutex(); + this->m_inputProgram = getInputSocketReader(0); + this->m_inputBokehProgram = getInputSocketReader(1); + this->m_inputBoundingBoxReader = getInputSocketReader(2); + + int width = this->m_inputBokehProgram->getWidth(); + int height = this->m_inputBokehProgram->getHeight(); + + float dimension = MIN2(width, height); + + this->m_bokehMidX = width / 2.0f; + this->m_bokehMidY = height / 2.0f; + this->m_bokehDimension = dimension / 2.0f; + QualityStepHelper::initExecution(COM_QH_INCREASE); +} + +void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) +{ + float color_accum[4]; + float tempBoundingBox[4]; + float bokeh[4]; + + this->m_inputBoundingBoxReader->readSampled(tempBoundingBox, x, y, COM_PS_NEAREST); + if (tempBoundingBox[0] > 0.0f) { + float multiplier_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + float *buffer = inputBuffer->getBuffer(); + int bufferwidth = inputBuffer->getWidth(); + int bufferstartx = inputBuffer->getRect()->xmin; + int bufferstarty = inputBuffer->getRect()->ymin; + const float max_dim = MAX2(this->getWidth(), this->getHeight()); + int pixelSize = this->m_size * max_dim / 100.0f; + zero_v4(color_accum); + + if (pixelSize < 2) { + this->m_inputProgram->readSampled(color_accum, x, y, COM_PS_NEAREST); + multiplier_accum[0] = 1.0f; + multiplier_accum[1] = 1.0f; + multiplier_accum[2] = 1.0f; + multiplier_accum[3] = 1.0f; + } + int miny = y - pixelSize; + int maxy = y + pixelSize; + int minx = x - pixelSize; + int maxx = x + pixelSize; + miny = MAX2(miny, inputBuffer->getRect()->ymin); + minx = MAX2(minx, inputBuffer->getRect()->xmin); + maxy = MIN2(maxy, inputBuffer->getRect()->ymax); + maxx = MIN2(maxx, inputBuffer->getRect()->xmax); + + int step = getStep(); + int offsetadd = getOffsetAdd() * COM_NUM_CHANNELS_COLOR; + + float m = this->m_bokehDimension / pixelSize; + for (int ny = miny; ny < maxy; ny += step) { + int bufferindex = ((minx - bufferstartx) * COM_NUM_CHANNELS_COLOR) + + ((ny - bufferstarty) * COM_NUM_CHANNELS_COLOR * bufferwidth); + for (int nx = minx; nx < maxx; nx += step) { + float u = this->m_bokehMidX - (nx - x) * m; + float v = this->m_bokehMidY - (ny - y) * m; + this->m_inputBokehProgram->readSampled(bokeh, u, v, COM_PS_NEAREST); + madd_v4_v4v4(color_accum, bokeh, &buffer[bufferindex]); + add_v4_v4(multiplier_accum, bokeh); + bufferindex += offsetadd; + } + } + output[0] = color_accum[0] * (1.0f / multiplier_accum[0]); + output[1] = color_accum[1] * (1.0f / multiplier_accum[1]); + output[2] = color_accum[2] * (1.0f / multiplier_accum[2]); + output[3] = color_accum[3] * (1.0f / multiplier_accum[3]); + } + else { + this->m_inputProgram->readSampled(output, x, y, COM_PS_NEAREST); + } +} + +void BokehBlurOperation::deinitExecution() +{ + deinitMutex(); + this->m_inputProgram = nullptr; + this->m_inputBokehProgram = nullptr; + this->m_inputBoundingBoxReader = nullptr; +} + +bool BokehBlurOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + rcti bokehInput; + const float max_dim = MAX2(this->getWidth(), this->getHeight()); + + if (this->m_sizeavailable) { + newInput.xmax = input->xmax + (this->m_size * max_dim / 100.0f); + newInput.xmin = input->xmin - (this->m_size * max_dim / 100.0f); + newInput.ymax = input->ymax + (this->m_size * max_dim / 100.0f); + newInput.ymin = input->ymin - (this->m_size * max_dim / 100.0f); + } + else { + newInput.xmax = input->xmax + (10.0f * max_dim / 100.0f); + newInput.xmin = input->xmin - (10.0f * max_dim / 100.0f); + newInput.ymax = input->ymax + (10.0f * max_dim / 100.0f); + newInput.ymin = input->ymin - (10.0f * max_dim / 100.0f); + } + + NodeOperation *operation = getInputOperation(1); + bokehInput.xmax = operation->getWidth(); + bokehInput.xmin = 0; + bokehInput.ymax = operation->getHeight(); + bokehInput.ymin = 0; + if (operation->determineDependingAreaOfInterest(&bokehInput, readOperation, output)) { + return true; + } + operation = getInputOperation(0); + if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) { + return true; + } + operation = getInputOperation(2); + if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { + return true; + } + if (!this->m_sizeavailable) { + rcti sizeInput; + sizeInput.xmin = 0; + sizeInput.ymin = 0; + sizeInput.xmax = 5; + sizeInput.ymax = 5; + operation = getInputOperation(3); + if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { + return true; + } + } + return false; +} + +void BokehBlurOperation::executeOpenCL(OpenCLDevice *device, + MemoryBuffer *outputMemoryBuffer, + cl_mem clOutputBuffer, + MemoryBuffer **inputMemoryBuffers, + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) +{ + cl_kernel kernel = device->COM_clCreateKernel("bokehBlurKernel", nullptr); + if (!this->m_sizeavailable) { + updateSize(); + } + const float max_dim = MAX2(this->getWidth(), this->getHeight()); + cl_int radius = this->m_size * max_dim / 100.0f; + cl_int step = this->getStep(); + + device->COM_clAttachMemoryBufferToKernelParameter( + kernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBoundingBoxReader); + device->COM_clAttachMemoryBufferToKernelParameter( + kernel, 1, 4, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram); + device->COM_clAttachMemoryBufferToKernelParameter( + kernel, 2, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBokehProgram); + device->COM_clAttachOutputMemoryBufferToKernelParameter(kernel, 3, clOutputBuffer); + device->COM_clAttachMemoryBufferOffsetToKernelParameter(kernel, 5, outputMemoryBuffer); + clSetKernelArg(kernel, 6, sizeof(cl_int), &radius); + clSetKernelArg(kernel, 7, sizeof(cl_int), &step); + device->COM_clAttachSizeToKernelParameter(kernel, 8, this); + + device->COM_clEnqueueRange(kernel, outputMemoryBuffer, 9, this); +} + +void BokehBlurOperation::updateSize() +{ + if (!this->m_sizeavailable) { + float result[4]; + this->getInputSocketReader(3)->readSampled(result, 0, 0, COM_PS_NEAREST); + this->m_size = result[0]; + CLAMP(this->m_size, 0.0f, 10.0f); + this->m_sizeavailable = true; + } +} + +void BokehBlurOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + NodeOperation::determineResolution(resolution, preferredResolution); + if (this->m_extend_bounds) { + const float max_dim = MAX2(resolution[0], resolution[1]); + resolution[0] += 2 * this->m_size * max_dim / 100.0f; + resolution[1] += 2 * this->m_size * max_dim / 100.0f; + } +} diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp deleted file mode 100644 index a8ad2a11790..00000000000 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BokehBlurOperation.h" -#include "BLI_math.h" -#include "COM_OpenCLDevice.h" - -#include "RE_pipeline.h" - -BokehBlurOperation::BokehBlurOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setComplex(true); - this->setOpenCL(true); - - this->m_size = 1.0f; - this->m_sizeavailable = false; - this->m_inputProgram = nullptr; - this->m_inputBokehProgram = nullptr; - this->m_inputBoundingBoxReader = nullptr; - - this->m_extend_bounds = false; -} - -void *BokehBlurOperation::initializeTileData(rcti * /*rect*/) -{ - lockMutex(); - if (!this->m_sizeavailable) { - updateSize(); - } - void *buffer = getInputOperation(0)->initializeTileData(nullptr); - unlockMutex(); - return buffer; -} - -void BokehBlurOperation::initExecution() -{ - initMutex(); - this->m_inputProgram = getInputSocketReader(0); - this->m_inputBokehProgram = getInputSocketReader(1); - this->m_inputBoundingBoxReader = getInputSocketReader(2); - - int width = this->m_inputBokehProgram->getWidth(); - int height = this->m_inputBokehProgram->getHeight(); - - float dimension = MIN2(width, height); - - this->m_bokehMidX = width / 2.0f; - this->m_bokehMidY = height / 2.0f; - this->m_bokehDimension = dimension / 2.0f; - QualityStepHelper::initExecution(COM_QH_INCREASE); -} - -void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) -{ - float color_accum[4]; - float tempBoundingBox[4]; - float bokeh[4]; - - this->m_inputBoundingBoxReader->readSampled(tempBoundingBox, x, y, COM_PS_NEAREST); - if (tempBoundingBox[0] > 0.0f) { - float multiplier_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - float *buffer = inputBuffer->getBuffer(); - int bufferwidth = inputBuffer->getWidth(); - int bufferstartx = inputBuffer->getRect()->xmin; - int bufferstarty = inputBuffer->getRect()->ymin; - const float max_dim = MAX2(this->getWidth(), this->getHeight()); - int pixelSize = this->m_size * max_dim / 100.0f; - zero_v4(color_accum); - - if (pixelSize < 2) { - this->m_inputProgram->readSampled(color_accum, x, y, COM_PS_NEAREST); - multiplier_accum[0] = 1.0f; - multiplier_accum[1] = 1.0f; - multiplier_accum[2] = 1.0f; - multiplier_accum[3] = 1.0f; - } - int miny = y - pixelSize; - int maxy = y + pixelSize; - int minx = x - pixelSize; - int maxx = x + pixelSize; - miny = MAX2(miny, inputBuffer->getRect()->ymin); - minx = MAX2(minx, inputBuffer->getRect()->xmin); - maxy = MIN2(maxy, inputBuffer->getRect()->ymax); - maxx = MIN2(maxx, inputBuffer->getRect()->xmax); - - int step = getStep(); - int offsetadd = getOffsetAdd() * COM_NUM_CHANNELS_COLOR; - - float m = this->m_bokehDimension / pixelSize; - for (int ny = miny; ny < maxy; ny += step) { - int bufferindex = ((minx - bufferstartx) * COM_NUM_CHANNELS_COLOR) + - ((ny - bufferstarty) * COM_NUM_CHANNELS_COLOR * bufferwidth); - for (int nx = minx; nx < maxx; nx += step) { - float u = this->m_bokehMidX - (nx - x) * m; - float v = this->m_bokehMidY - (ny - y) * m; - this->m_inputBokehProgram->readSampled(bokeh, u, v, COM_PS_NEAREST); - madd_v4_v4v4(color_accum, bokeh, &buffer[bufferindex]); - add_v4_v4(multiplier_accum, bokeh); - bufferindex += offsetadd; - } - } - output[0] = color_accum[0] * (1.0f / multiplier_accum[0]); - output[1] = color_accum[1] * (1.0f / multiplier_accum[1]); - output[2] = color_accum[2] * (1.0f / multiplier_accum[2]); - output[3] = color_accum[3] * (1.0f / multiplier_accum[3]); - } - else { - this->m_inputProgram->readSampled(output, x, y, COM_PS_NEAREST); - } -} - -void BokehBlurOperation::deinitExecution() -{ - deinitMutex(); - this->m_inputProgram = nullptr; - this->m_inputBokehProgram = nullptr; - this->m_inputBoundingBoxReader = nullptr; -} - -bool BokehBlurOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - rcti bokehInput; - const float max_dim = MAX2(this->getWidth(), this->getHeight()); - - if (this->m_sizeavailable) { - newInput.xmax = input->xmax + (this->m_size * max_dim / 100.0f); - newInput.xmin = input->xmin - (this->m_size * max_dim / 100.0f); - newInput.ymax = input->ymax + (this->m_size * max_dim / 100.0f); - newInput.ymin = input->ymin - (this->m_size * max_dim / 100.0f); - } - else { - newInput.xmax = input->xmax + (10.0f * max_dim / 100.0f); - newInput.xmin = input->xmin - (10.0f * max_dim / 100.0f); - newInput.ymax = input->ymax + (10.0f * max_dim / 100.0f); - newInput.ymin = input->ymin - (10.0f * max_dim / 100.0f); - } - - NodeOperation *operation = getInputOperation(1); - bokehInput.xmax = operation->getWidth(); - bokehInput.xmin = 0; - bokehInput.ymax = operation->getHeight(); - bokehInput.ymin = 0; - if (operation->determineDependingAreaOfInterest(&bokehInput, readOperation, output)) { - return true; - } - operation = getInputOperation(0); - if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) { - return true; - } - operation = getInputOperation(2); - if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { - return true; - } - if (!this->m_sizeavailable) { - rcti sizeInput; - sizeInput.xmin = 0; - sizeInput.ymin = 0; - sizeInput.xmax = 5; - sizeInput.ymax = 5; - operation = getInputOperation(3); - if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { - return true; - } - } - return false; -} - -void BokehBlurOperation::executeOpenCL(OpenCLDevice *device, - MemoryBuffer *outputMemoryBuffer, - cl_mem clOutputBuffer, - MemoryBuffer **inputMemoryBuffers, - std::list *clMemToCleanUp, - std::list * /*clKernelsToCleanUp*/) -{ - cl_kernel kernel = device->COM_clCreateKernel("bokehBlurKernel", nullptr); - if (!this->m_sizeavailable) { - updateSize(); - } - const float max_dim = MAX2(this->getWidth(), this->getHeight()); - cl_int radius = this->m_size * max_dim / 100.0f; - cl_int step = this->getStep(); - - device->COM_clAttachMemoryBufferToKernelParameter( - kernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBoundingBoxReader); - device->COM_clAttachMemoryBufferToKernelParameter( - kernel, 1, 4, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram); - device->COM_clAttachMemoryBufferToKernelParameter( - kernel, 2, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBokehProgram); - device->COM_clAttachOutputMemoryBufferToKernelParameter(kernel, 3, clOutputBuffer); - device->COM_clAttachMemoryBufferOffsetToKernelParameter(kernel, 5, outputMemoryBuffer); - clSetKernelArg(kernel, 6, sizeof(cl_int), &radius); - clSetKernelArg(kernel, 7, sizeof(cl_int), &step); - device->COM_clAttachSizeToKernelParameter(kernel, 8, this); - - device->COM_clEnqueueRange(kernel, outputMemoryBuffer, 9, this); -} - -void BokehBlurOperation::updateSize() -{ - if (!this->m_sizeavailable) { - float result[4]; - this->getInputSocketReader(3)->readSampled(result, 0, 0, COM_PS_NEAREST); - this->m_size = result[0]; - CLAMP(this->m_size, 0.0f, 10.0f); - this->m_sizeavailable = true; - } -} - -void BokehBlurOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - NodeOperation::determineResolution(resolution, preferredResolution); - if (this->m_extend_bounds) { - const float max_dim = MAX2(resolution[0], resolution[1]); - resolution[0] += 2 * this->m_size * max_dim / 100.0f; - resolution[1] += 2 * this->m_size * max_dim / 100.0f; - } -} diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.cc b/source/blender/compositor/operations/COM_BokehImageOperation.cc new file mode 100644 index 00000000000..473a43c1776 --- /dev/null +++ b/source/blender/compositor/operations/COM_BokehImageOperation.cc @@ -0,0 +1,126 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BokehImageOperation.h" +#include "BLI_math.h" + +BokehImageOperation::BokehImageOperation() +{ + this->addOutputSocket(COM_DT_COLOR); + this->m_deleteData = false; +} +void BokehImageOperation::initExecution() +{ + this->m_center[0] = getWidth() / 2; + this->m_center[1] = getHeight() / 2; + this->m_inverseRounding = 1.0f - this->m_data->rounding; + this->m_circularDistance = getWidth() / 2; + this->m_flapRad = (float)(M_PI * 2) / this->m_data->flaps; + this->m_flapRadAdd = this->m_data->angle; + while (this->m_flapRadAdd < 0.0f) { + this->m_flapRadAdd += (float)(M_PI * 2.0); + } + while (this->m_flapRadAdd > (float)M_PI) { + this->m_flapRadAdd -= (float)(M_PI * 2.0); + } +} +void BokehImageOperation::detemineStartPointOfFlap(float r[2], int flapNumber, float distance) +{ + r[0] = sinf(this->m_flapRad * flapNumber + this->m_flapRadAdd) * distance + this->m_center[0]; + r[1] = cosf(this->m_flapRad * flapNumber + this->m_flapRadAdd) * distance + this->m_center[1]; +} +float BokehImageOperation::isInsideBokeh(float distance, float x, float y) +{ + float insideBokeh = 0.0f; + const float deltaX = x - this->m_center[0]; + const float deltaY = y - this->m_center[1]; + float closestPoint[2]; + float lineP1[2]; + float lineP2[2]; + float point[2]; + point[0] = x; + point[1] = y; + + const float distanceToCenter = len_v2v2(point, this->m_center); + const float bearing = (atan2f(deltaX, deltaY) + (float)(M_PI * 2.0)); + int flapNumber = (int)((bearing - this->m_flapRadAdd) / this->m_flapRad); + + detemineStartPointOfFlap(lineP1, flapNumber, distance); + detemineStartPointOfFlap(lineP2, flapNumber + 1, distance); + closest_to_line_v2(closestPoint, point, lineP1, lineP2); + + const float distanceLineToCenter = len_v2v2(this->m_center, closestPoint); + const float distanceRoundingToCenter = this->m_inverseRounding * distanceLineToCenter + + this->m_data->rounding * distance; + + const float catadioptricDistanceToCenter = distanceRoundingToCenter * this->m_data->catadioptric; + if (distanceRoundingToCenter >= distanceToCenter && + catadioptricDistanceToCenter <= distanceToCenter) { + if (distanceRoundingToCenter - distanceToCenter < 1.0f) { + insideBokeh = (distanceRoundingToCenter - distanceToCenter); + } + else if (this->m_data->catadioptric != 0.0f && + distanceToCenter - catadioptricDistanceToCenter < 1.0f) { + insideBokeh = (distanceToCenter - catadioptricDistanceToCenter); + } + else { + insideBokeh = 1.0f; + } + } + return insideBokeh; +} +void BokehImageOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + float shift = this->m_data->lensshift; + float shift2 = shift / 2.0f; + float distance = this->m_circularDistance; + float insideBokehMax = isInsideBokeh(distance, x, y); + float insideBokehMed = isInsideBokeh(distance - fabsf(shift2 * distance), x, y); + float insideBokehMin = isInsideBokeh(distance - fabsf(shift * distance), x, y); + if (shift < 0) { + output[0] = insideBokehMax; + output[1] = insideBokehMed; + output[2] = insideBokehMin; + } + else { + output[0] = insideBokehMin; + output[1] = insideBokehMed; + output[2] = insideBokehMax; + } + output[3] = (insideBokehMax + insideBokehMed + insideBokehMin) / 3.0f; +} + +void BokehImageOperation::deinitExecution() +{ + if (this->m_deleteData) { + if (this->m_data) { + delete this->m_data; + this->m_data = nullptr; + } + } +} + +void BokehImageOperation::determineResolution(unsigned int resolution[2], + unsigned int /*preferredResolution*/[2]) +{ + resolution[0] = COM_BLUR_BOKEH_PIXELS; + resolution[1] = COM_BLUR_BOKEH_PIXELS; +} diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.cpp b/source/blender/compositor/operations/COM_BokehImageOperation.cpp deleted file mode 100644 index 473a43c1776..00000000000 --- a/source/blender/compositor/operations/COM_BokehImageOperation.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BokehImageOperation.h" -#include "BLI_math.h" - -BokehImageOperation::BokehImageOperation() -{ - this->addOutputSocket(COM_DT_COLOR); - this->m_deleteData = false; -} -void BokehImageOperation::initExecution() -{ - this->m_center[0] = getWidth() / 2; - this->m_center[1] = getHeight() / 2; - this->m_inverseRounding = 1.0f - this->m_data->rounding; - this->m_circularDistance = getWidth() / 2; - this->m_flapRad = (float)(M_PI * 2) / this->m_data->flaps; - this->m_flapRadAdd = this->m_data->angle; - while (this->m_flapRadAdd < 0.0f) { - this->m_flapRadAdd += (float)(M_PI * 2.0); - } - while (this->m_flapRadAdd > (float)M_PI) { - this->m_flapRadAdd -= (float)(M_PI * 2.0); - } -} -void BokehImageOperation::detemineStartPointOfFlap(float r[2], int flapNumber, float distance) -{ - r[0] = sinf(this->m_flapRad * flapNumber + this->m_flapRadAdd) * distance + this->m_center[0]; - r[1] = cosf(this->m_flapRad * flapNumber + this->m_flapRadAdd) * distance + this->m_center[1]; -} -float BokehImageOperation::isInsideBokeh(float distance, float x, float y) -{ - float insideBokeh = 0.0f; - const float deltaX = x - this->m_center[0]; - const float deltaY = y - this->m_center[1]; - float closestPoint[2]; - float lineP1[2]; - float lineP2[2]; - float point[2]; - point[0] = x; - point[1] = y; - - const float distanceToCenter = len_v2v2(point, this->m_center); - const float bearing = (atan2f(deltaX, deltaY) + (float)(M_PI * 2.0)); - int flapNumber = (int)((bearing - this->m_flapRadAdd) / this->m_flapRad); - - detemineStartPointOfFlap(lineP1, flapNumber, distance); - detemineStartPointOfFlap(lineP2, flapNumber + 1, distance); - closest_to_line_v2(closestPoint, point, lineP1, lineP2); - - const float distanceLineToCenter = len_v2v2(this->m_center, closestPoint); - const float distanceRoundingToCenter = this->m_inverseRounding * distanceLineToCenter + - this->m_data->rounding * distance; - - const float catadioptricDistanceToCenter = distanceRoundingToCenter * this->m_data->catadioptric; - if (distanceRoundingToCenter >= distanceToCenter && - catadioptricDistanceToCenter <= distanceToCenter) { - if (distanceRoundingToCenter - distanceToCenter < 1.0f) { - insideBokeh = (distanceRoundingToCenter - distanceToCenter); - } - else if (this->m_data->catadioptric != 0.0f && - distanceToCenter - catadioptricDistanceToCenter < 1.0f) { - insideBokeh = (distanceToCenter - catadioptricDistanceToCenter); - } - else { - insideBokeh = 1.0f; - } - } - return insideBokeh; -} -void BokehImageOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - float shift = this->m_data->lensshift; - float shift2 = shift / 2.0f; - float distance = this->m_circularDistance; - float insideBokehMax = isInsideBokeh(distance, x, y); - float insideBokehMed = isInsideBokeh(distance - fabsf(shift2 * distance), x, y); - float insideBokehMin = isInsideBokeh(distance - fabsf(shift * distance), x, y); - if (shift < 0) { - output[0] = insideBokehMax; - output[1] = insideBokehMed; - output[2] = insideBokehMin; - } - else { - output[0] = insideBokehMin; - output[1] = insideBokehMed; - output[2] = insideBokehMax; - } - output[3] = (insideBokehMax + insideBokehMed + insideBokehMin) / 3.0f; -} - -void BokehImageOperation::deinitExecution() -{ - if (this->m_deleteData) { - if (this->m_data) { - delete this->m_data; - this->m_data = nullptr; - } - } -} - -void BokehImageOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) -{ - resolution[0] = COM_BLUR_BOKEH_PIXELS; - resolution[1] = COM_BLUR_BOKEH_PIXELS; -} diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.cc b/source/blender/compositor/operations/COM_BoxMaskOperation.cc new file mode 100644 index 00000000000..bb10f3425e2 --- /dev/null +++ b/source/blender/compositor/operations/COM_BoxMaskOperation.cc @@ -0,0 +1,110 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BoxMaskOperation.h" +#include "BLI_math.h" +#include "DNA_node_types.h" + +BoxMaskOperation::BoxMaskOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->m_inputMask = nullptr; + this->m_inputValue = nullptr; + this->m_cosine = 0.0f; + this->m_sine = 0.0f; +} +void BoxMaskOperation::initExecution() +{ + this->m_inputMask = this->getInputSocketReader(0); + this->m_inputValue = this->getInputSocketReader(1); + const double rad = (double)this->m_data->rotation; + this->m_cosine = cos(rad); + this->m_sine = sin(rad); + this->m_aspectRatio = ((float)this->getWidth()) / this->getHeight(); +} + +void BoxMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float inputMask[4]; + float inputValue[4]; + + float rx = x / this->getWidth(); + float ry = y / this->getHeight(); + + const float dy = (ry - this->m_data->y) / this->m_aspectRatio; + const float dx = rx - this->m_data->x; + rx = this->m_data->x + (this->m_cosine * dx + this->m_sine * dy); + ry = this->m_data->y + (-this->m_sine * dx + this->m_cosine * dy); + + this->m_inputMask->readSampled(inputMask, x, y, sampler); + this->m_inputValue->readSampled(inputValue, x, y, sampler); + + float halfHeight = this->m_data->height / 2.0f; + float halfWidth = this->m_data->width / 2.0f; + bool inside = (rx > this->m_data->x - halfWidth && rx < this->m_data->x + halfWidth && + ry > this->m_data->y - halfHeight && ry < this->m_data->y + halfHeight); + + switch (this->m_maskType) { + case CMP_NODE_MASKTYPE_ADD: + if (inside) { + output[0] = MAX2(inputMask[0], inputValue[0]); + } + else { + output[0] = inputMask[0]; + } + break; + case CMP_NODE_MASKTYPE_SUBTRACT: + if (inside) { + output[0] = inputMask[0] - inputValue[0]; + CLAMP(output[0], 0, 1); + } + else { + output[0] = inputMask[0]; + } + break; + case CMP_NODE_MASKTYPE_MULTIPLY: + if (inside) { + output[0] = inputMask[0] * inputValue[0]; + } + else { + output[0] = 0; + } + break; + case CMP_NODE_MASKTYPE_NOT: + if (inside) { + if (inputMask[0] > 0.0f) { + output[0] = 0; + } + else { + output[0] = inputValue[0]; + } + } + else { + output[0] = inputMask[0]; + } + break; + } +} + +void BoxMaskOperation::deinitExecution() +{ + this->m_inputMask = nullptr; + this->m_inputValue = nullptr; +} diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp b/source/blender/compositor/operations/COM_BoxMaskOperation.cpp deleted file mode 100644 index bb10f3425e2..00000000000 --- a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BoxMaskOperation.h" -#include "BLI_math.h" -#include "DNA_node_types.h" - -BoxMaskOperation::BoxMaskOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputMask = nullptr; - this->m_inputValue = nullptr; - this->m_cosine = 0.0f; - this->m_sine = 0.0f; -} -void BoxMaskOperation::initExecution() -{ - this->m_inputMask = this->getInputSocketReader(0); - this->m_inputValue = this->getInputSocketReader(1); - const double rad = (double)this->m_data->rotation; - this->m_cosine = cos(rad); - this->m_sine = sin(rad); - this->m_aspectRatio = ((float)this->getWidth()) / this->getHeight(); -} - -void BoxMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - float inputMask[4]; - float inputValue[4]; - - float rx = x / this->getWidth(); - float ry = y / this->getHeight(); - - const float dy = (ry - this->m_data->y) / this->m_aspectRatio; - const float dx = rx - this->m_data->x; - rx = this->m_data->x + (this->m_cosine * dx + this->m_sine * dy); - ry = this->m_data->y + (-this->m_sine * dx + this->m_cosine * dy); - - this->m_inputMask->readSampled(inputMask, x, y, sampler); - this->m_inputValue->readSampled(inputValue, x, y, sampler); - - float halfHeight = this->m_data->height / 2.0f; - float halfWidth = this->m_data->width / 2.0f; - bool inside = (rx > this->m_data->x - halfWidth && rx < this->m_data->x + halfWidth && - ry > this->m_data->y - halfHeight && ry < this->m_data->y + halfHeight); - - switch (this->m_maskType) { - case CMP_NODE_MASKTYPE_ADD: - if (inside) { - output[0] = MAX2(inputMask[0], inputValue[0]); - } - else { - output[0] = inputMask[0]; - } - break; - case CMP_NODE_MASKTYPE_SUBTRACT: - if (inside) { - output[0] = inputMask[0] - inputValue[0]; - CLAMP(output[0], 0, 1); - } - else { - output[0] = inputMask[0]; - } - break; - case CMP_NODE_MASKTYPE_MULTIPLY: - if (inside) { - output[0] = inputMask[0] * inputValue[0]; - } - else { - output[0] = 0; - } - break; - case CMP_NODE_MASKTYPE_NOT: - if (inside) { - if (inputMask[0] > 0.0f) { - output[0] = 0; - } - else { - output[0] = inputValue[0]; - } - } - else { - output[0] = inputMask[0]; - } - break; - } -} - -void BoxMaskOperation::deinitExecution() -{ - this->m_inputMask = nullptr; - this->m_inputValue = nullptr; -} diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cc b/source/blender/compositor/operations/COM_BrightnessOperation.cc new file mode 100644 index 00000000000..3ae1b4aaef4 --- /dev/null +++ b/source/blender/compositor/operations/COM_BrightnessOperation.cc @@ -0,0 +1,91 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_BrightnessOperation.h" + +BrightnessOperation::BrightnessOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputProgram = nullptr; + this->m_use_premultiply = false; +} + +void BrightnessOperation::setUsePremultiply(bool use_premultiply) +{ + this->m_use_premultiply = use_premultiply; +} + +void BrightnessOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); + this->m_inputBrightnessProgram = this->getInputSocketReader(1); + this->m_inputContrastProgram = this->getInputSocketReader(2); +} + +void BrightnessOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue[4]; + float a, b; + float inputBrightness[4]; + float inputContrast[4]; + this->m_inputProgram->readSampled(inputValue, x, y, sampler); + this->m_inputBrightnessProgram->readSampled(inputBrightness, x, y, sampler); + this->m_inputContrastProgram->readSampled(inputContrast, x, y, sampler); + float brightness = inputBrightness[0]; + float contrast = inputContrast[0]; + brightness /= 100.0f; + float delta = contrast / 200.0f; + /* + * The algorithm is by Werner D. Streidt + * (http://visca.com/ffactory/archives/5-99/msg00021.html) + * Extracted of OpenCV demhist.c + */ + if (contrast > 0) { + a = 1.0f - delta * 2.0f; + a = 1.0f / max_ff(a, FLT_EPSILON); + b = a * (brightness - delta); + } + else { + delta *= -1; + a = max_ff(1.0f - delta * 2.0f, 0.0f); + b = a * brightness + delta; + } + if (this->m_use_premultiply) { + premul_to_straight_v4(inputValue); + } + output[0] = a * inputValue[0] + b; + output[1] = a * inputValue[1] + b; + output[2] = a * inputValue[2] + b; + output[3] = inputValue[3]; + if (this->m_use_premultiply) { + straight_to_premul_v4(output); + } +} + +void BrightnessOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; + this->m_inputBrightnessProgram = nullptr; + this->m_inputContrastProgram = nullptr; +} diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cpp b/source/blender/compositor/operations/COM_BrightnessOperation.cpp deleted file mode 100644 index 3ae1b4aaef4..00000000000 --- a/source/blender/compositor/operations/COM_BrightnessOperation.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_BrightnessOperation.h" - -BrightnessOperation::BrightnessOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputProgram = nullptr; - this->m_use_premultiply = false; -} - -void BrightnessOperation::setUsePremultiply(bool use_premultiply) -{ - this->m_use_premultiply = use_premultiply; -} - -void BrightnessOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); - this->m_inputBrightnessProgram = this->getInputSocketReader(1); - this->m_inputContrastProgram = this->getInputSocketReader(2); -} - -void BrightnessOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue[4]; - float a, b; - float inputBrightness[4]; - float inputContrast[4]; - this->m_inputProgram->readSampled(inputValue, x, y, sampler); - this->m_inputBrightnessProgram->readSampled(inputBrightness, x, y, sampler); - this->m_inputContrastProgram->readSampled(inputContrast, x, y, sampler); - float brightness = inputBrightness[0]; - float contrast = inputContrast[0]; - brightness /= 100.0f; - float delta = contrast / 200.0f; - /* - * The algorithm is by Werner D. Streidt - * (http://visca.com/ffactory/archives/5-99/msg00021.html) - * Extracted of OpenCV demhist.c - */ - if (contrast > 0) { - a = 1.0f - delta * 2.0f; - a = 1.0f / max_ff(a, FLT_EPSILON); - b = a * (brightness - delta); - } - else { - delta *= -1; - a = max_ff(1.0f - delta * 2.0f, 0.0f); - b = a * brightness + delta; - } - if (this->m_use_premultiply) { - premul_to_straight_v4(inputValue); - } - output[0] = a * inputValue[0] + b; - output[1] = a * inputValue[1] + b; - output[2] = a * inputValue[2] + b; - output[3] = inputValue[3]; - if (this->m_use_premultiply) { - straight_to_premul_v4(output); - } -} - -void BrightnessOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; - this->m_inputBrightnessProgram = nullptr; - this->m_inputContrastProgram = nullptr; -} diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cc b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc new file mode 100644 index 00000000000..9ccf9d7f1ef --- /dev/null +++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc @@ -0,0 +1,127 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_CalculateMeanOperation.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "IMB_colormanagement.h" + +CalculateMeanOperation::CalculateMeanOperation() +{ + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); + this->addOutputSocket(COM_DT_VALUE); + this->m_imageReader = nullptr; + this->m_iscalculated = false; + this->m_setting = 1; + this->setComplex(true); +} +void CalculateMeanOperation::initExecution() +{ + this->m_imageReader = this->getInputSocketReader(0); + this->m_iscalculated = false; + NodeOperation::initMutex(); +} + +void CalculateMeanOperation::executePixel(float output[4], int /*x*/, int /*y*/, void * /*data*/) +{ + output[0] = this->m_result; +} + +void CalculateMeanOperation::deinitExecution() +{ + this->m_imageReader = nullptr; + NodeOperation::deinitMutex(); +} + +bool CalculateMeanOperation::determineDependingAreaOfInterest(rcti * /*input*/, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti imageInput; + if (this->m_iscalculated) { + return false; + } + NodeOperation *operation = getInputOperation(0); + imageInput.xmax = operation->getWidth(); + imageInput.xmin = 0; + imageInput.ymax = operation->getHeight(); + imageInput.ymin = 0; + if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) { + return true; + } + return false; +} + +void *CalculateMeanOperation::initializeTileData(rcti *rect) +{ + lockMutex(); + if (!this->m_iscalculated) { + MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect); + calculateMean(tile); + this->m_iscalculated = true; + } + unlockMutex(); + return nullptr; +} + +void CalculateMeanOperation::calculateMean(MemoryBuffer *tile) +{ + this->m_result = 0.0f; + float *buffer = tile->getBuffer(); + int size = tile->getWidth() * tile->getHeight(); + int pixels = 0; + float sum = 0.0f; + for (int i = 0, offset = 0; i < size; i++, offset += 4) { + if (buffer[offset + 3] > 0) { + pixels++; + + switch (this->m_setting) { + case 1: { + sum += IMB_colormanagement_get_luminance(&buffer[offset]); + break; + } + case 2: { + sum += buffer[offset]; + break; + } + case 3: { + sum += buffer[offset + 1]; + break; + } + case 4: { + sum += buffer[offset + 2]; + break; + } + case 5: { + float yuv[3]; + rgb_to_yuv(buffer[offset], + buffer[offset + 1], + buffer[offset + 2], + &yuv[0], + &yuv[1], + &yuv[2], + BLI_YUV_ITU_BT709); + sum += yuv[0]; + break; + } + } + } + } + this->m_result = sum / pixels; +} diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp b/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp deleted file mode 100644 index 9ccf9d7f1ef..00000000000 --- a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_CalculateMeanOperation.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -#include "IMB_colormanagement.h" - -CalculateMeanOperation::CalculateMeanOperation() -{ - this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); - this->addOutputSocket(COM_DT_VALUE); - this->m_imageReader = nullptr; - this->m_iscalculated = false; - this->m_setting = 1; - this->setComplex(true); -} -void CalculateMeanOperation::initExecution() -{ - this->m_imageReader = this->getInputSocketReader(0); - this->m_iscalculated = false; - NodeOperation::initMutex(); -} - -void CalculateMeanOperation::executePixel(float output[4], int /*x*/, int /*y*/, void * /*data*/) -{ - output[0] = this->m_result; -} - -void CalculateMeanOperation::deinitExecution() -{ - this->m_imageReader = nullptr; - NodeOperation::deinitMutex(); -} - -bool CalculateMeanOperation::determineDependingAreaOfInterest(rcti * /*input*/, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti imageInput; - if (this->m_iscalculated) { - return false; - } - NodeOperation *operation = getInputOperation(0); - imageInput.xmax = operation->getWidth(); - imageInput.xmin = 0; - imageInput.ymax = operation->getHeight(); - imageInput.ymin = 0; - if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) { - return true; - } - return false; -} - -void *CalculateMeanOperation::initializeTileData(rcti *rect) -{ - lockMutex(); - if (!this->m_iscalculated) { - MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect); - calculateMean(tile); - this->m_iscalculated = true; - } - unlockMutex(); - return nullptr; -} - -void CalculateMeanOperation::calculateMean(MemoryBuffer *tile) -{ - this->m_result = 0.0f; - float *buffer = tile->getBuffer(); - int size = tile->getWidth() * tile->getHeight(); - int pixels = 0; - float sum = 0.0f; - for (int i = 0, offset = 0; i < size; i++, offset += 4) { - if (buffer[offset + 3] > 0) { - pixels++; - - switch (this->m_setting) { - case 1: { - sum += IMB_colormanagement_get_luminance(&buffer[offset]); - break; - } - case 2: { - sum += buffer[offset]; - break; - } - case 3: { - sum += buffer[offset + 1]; - break; - } - case 4: { - sum += buffer[offset + 2]; - break; - } - case 5: { - float yuv[3]; - rgb_to_yuv(buffer[offset], - buffer[offset + 1], - buffer[offset + 2], - &yuv[0], - &yuv[1], - &yuv[2], - BLI_YUV_ITU_BT709); - sum += yuv[0]; - break; - } - } - } - } - this->m_result = sum / pixels; -} diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc new file mode 100644 index 00000000000..9a1e48177ed --- /dev/null +++ b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc @@ -0,0 +1,100 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_CalculateStandardDeviationOperation.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "IMB_colormanagement.h" + +CalculateStandardDeviationOperation::CalculateStandardDeviationOperation() +{ + /* pass */ +} + +void CalculateStandardDeviationOperation::executePixel(float output[4], + int /*x*/, + int /*y*/, + void * /*data*/) +{ + output[0] = this->m_standardDeviation; +} + +void *CalculateStandardDeviationOperation::initializeTileData(rcti *rect) +{ + lockMutex(); + if (!this->m_iscalculated) { + MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect); + CalculateMeanOperation::calculateMean(tile); + this->m_standardDeviation = 0.0f; + float *buffer = tile->getBuffer(); + int size = tile->getWidth() * tile->getHeight(); + int pixels = 0; + float sum = 0.0f; + float mean = this->m_result; + for (int i = 0, offset = 0; i < size; i++, offset += 4) { + if (buffer[offset + 3] > 0) { + pixels++; + + switch (this->m_setting) { + case 1: /* rgb combined */ + { + float value = IMB_colormanagement_get_luminance(&buffer[offset]); + sum += (value - mean) * (value - mean); + break; + } + case 2: /* red */ + { + float value = buffer[offset]; + sum += (value - mean) * (value - mean); + break; + } + case 3: /* green */ + { + float value = buffer[offset + 1]; + sum += (value - mean) * (value - mean); + break; + } + case 4: /* blue */ + { + float value = buffer[offset + 2]; + sum += (value - mean) * (value - mean); + break; + } + case 5: /* luminance */ + { + float yuv[3]; + rgb_to_yuv(buffer[offset], + buffer[offset + 1], + buffer[offset + 2], + &yuv[0], + &yuv[1], + &yuv[2], + BLI_YUV_ITU_BT709); + sum += (yuv[0] - mean) * (yuv[0] - mean); + break; + } + } + } + } + this->m_standardDeviation = sqrt(sum / (float)(pixels - 1)); + this->m_iscalculated = true; + } + unlockMutex(); + return nullptr; +} diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp deleted file mode 100644 index 9a1e48177ed..00000000000 --- a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_CalculateStandardDeviationOperation.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -#include "IMB_colormanagement.h" - -CalculateStandardDeviationOperation::CalculateStandardDeviationOperation() -{ - /* pass */ -} - -void CalculateStandardDeviationOperation::executePixel(float output[4], - int /*x*/, - int /*y*/, - void * /*data*/) -{ - output[0] = this->m_standardDeviation; -} - -void *CalculateStandardDeviationOperation::initializeTileData(rcti *rect) -{ - lockMutex(); - if (!this->m_iscalculated) { - MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect); - CalculateMeanOperation::calculateMean(tile); - this->m_standardDeviation = 0.0f; - float *buffer = tile->getBuffer(); - int size = tile->getWidth() * tile->getHeight(); - int pixels = 0; - float sum = 0.0f; - float mean = this->m_result; - for (int i = 0, offset = 0; i < size; i++, offset += 4) { - if (buffer[offset + 3] > 0) { - pixels++; - - switch (this->m_setting) { - case 1: /* rgb combined */ - { - float value = IMB_colormanagement_get_luminance(&buffer[offset]); - sum += (value - mean) * (value - mean); - break; - } - case 2: /* red */ - { - float value = buffer[offset]; - sum += (value - mean) * (value - mean); - break; - } - case 3: /* green */ - { - float value = buffer[offset + 1]; - sum += (value - mean) * (value - mean); - break; - } - case 4: /* blue */ - { - float value = buffer[offset + 2]; - sum += (value - mean) * (value - mean); - break; - } - case 5: /* luminance */ - { - float yuv[3]; - rgb_to_yuv(buffer[offset], - buffer[offset + 1], - buffer[offset + 2], - &yuv[0], - &yuv[1], - &yuv[2], - BLI_YUV_ITU_BT709); - sum += (yuv[0] - mean) * (yuv[0] - mean); - break; - } - } - } - } - this->m_standardDeviation = sqrt(sum / (float)(pixels - 1)); - this->m_iscalculated = true; - } - unlockMutex(); - return nullptr; -} diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.cc b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc new file mode 100644 index 00000000000..6bc9fa53c31 --- /dev/null +++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc @@ -0,0 +1,70 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ChangeHSVOperation.h" + +ChangeHSVOperation::ChangeHSVOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputOperation = nullptr; +} + +void ChangeHSVOperation::initExecution() +{ + this->m_inputOperation = getInputSocketReader(0); + this->m_hueOperation = getInputSocketReader(1); + this->m_saturationOperation = getInputSocketReader(2); + this->m_valueOperation = getInputSocketReader(3); +} + +void ChangeHSVOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; + this->m_hueOperation = nullptr; + this->m_saturationOperation = nullptr; + this->m_valueOperation = nullptr; +} + +void ChangeHSVOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float hue[4], saturation[4], value[4]; + + this->m_inputOperation->readSampled(inputColor1, x, y, sampler); + this->m_hueOperation->readSampled(hue, x, y, sampler); + this->m_saturationOperation->readSampled(saturation, x, y, sampler); + this->m_valueOperation->readSampled(value, x, y, sampler); + + output[0] = inputColor1[0] + (hue[0] - 0.5f); + if (output[0] > 1.0f) { + output[0] -= 1.0f; + } + else if (output[0] < 0.0f) { + output[0] += 1.0f; + } + output[1] = inputColor1[1] * saturation[0]; + output[2] = inputColor1[2] * value[0]; + output[3] = inputColor1[3]; +} diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp b/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp deleted file mode 100644 index 6bc9fa53c31..00000000000 --- a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ChangeHSVOperation.h" - -ChangeHSVOperation::ChangeHSVOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputOperation = nullptr; -} - -void ChangeHSVOperation::initExecution() -{ - this->m_inputOperation = getInputSocketReader(0); - this->m_hueOperation = getInputSocketReader(1); - this->m_saturationOperation = getInputSocketReader(2); - this->m_valueOperation = getInputSocketReader(3); -} - -void ChangeHSVOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; - this->m_hueOperation = nullptr; - this->m_saturationOperation = nullptr; - this->m_valueOperation = nullptr; -} - -void ChangeHSVOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float hue[4], saturation[4], value[4]; - - this->m_inputOperation->readSampled(inputColor1, x, y, sampler); - this->m_hueOperation->readSampled(hue, x, y, sampler); - this->m_saturationOperation->readSampled(saturation, x, y, sampler); - this->m_valueOperation->readSampled(value, x, y, sampler); - - output[0] = inputColor1[0] + (hue[0] - 0.5f); - if (output[0] > 1.0f) { - output[0] -= 1.0f; - } - else if (output[0] < 0.0f) { - output[0] += 1.0f; - } - output[1] = inputColor1[1] * saturation[0]; - output[2] = inputColor1[2] * value[0]; - output[3] = inputColor1[3]; -} diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.cc b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc new file mode 100644 index 00000000000..15375589888 --- /dev/null +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc @@ -0,0 +1,120 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_ChannelMatteOperation.h" +#include "BLI_math.h" + +ChannelMatteOperation::ChannelMatteOperation() +{ + addInputSocket(COM_DT_COLOR); + addOutputSocket(COM_DT_VALUE); + + this->m_inputImageProgram = nullptr; +} + +void ChannelMatteOperation::initExecution() +{ + this->m_inputImageProgram = this->getInputSocketReader(0); + + this->m_limit_range = this->m_limit_max - this->m_limit_min; + + switch (this->m_limit_method) { + /* SINGLE */ + case 0: { + /* 123 / RGB / HSV / YUV / YCC */ + const int matte_channel = this->m_matte_channel - 1; + const int limit_channel = this->m_limit_channel - 1; + this->m_ids[0] = matte_channel; + this->m_ids[1] = limit_channel; + this->m_ids[2] = limit_channel; + break; + } + /* MAX */ + case 1: { + switch (this->m_matte_channel) { + case 1: { + this->m_ids[0] = 0; + this->m_ids[1] = 1; + this->m_ids[2] = 2; + break; + } + case 2: { + this->m_ids[0] = 1; + this->m_ids[1] = 0; + this->m_ids[2] = 2; + break; + } + case 3: { + this->m_ids[0] = 2; + this->m_ids[1] = 0; + this->m_ids[2] = 1; + break; + } + default: + break; + } + break; + } + default: + break; + } +} + +void ChannelMatteOperation::deinitExecution() +{ + this->m_inputImageProgram = nullptr; +} + +void ChannelMatteOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inColor[4]; + float alpha; + + const float limit_max = this->m_limit_max; + const float limit_min = this->m_limit_min; + const float limit_range = this->m_limit_range; + + this->m_inputImageProgram->readSampled(inColor, x, y, sampler); + + /* matte operation */ + alpha = inColor[this->m_ids[0]] - MAX2(inColor[this->m_ids[1]], inColor[this->m_ids[2]]); + + /* flip because 0.0 is transparent, not 1.0 */ + alpha = 1.0f - alpha; + + /* test range */ + if (alpha > limit_max) { + alpha = inColor[3]; /*whatever it was prior */ + } + else if (alpha < limit_min) { + alpha = 0.0f; + } + else { /*blend */ + alpha = (alpha - limit_min) / limit_range; + } + + /* Store matte(alpha) value in [0] to go with + * COM_SetAlphaMultiplyOperation and the Value output. + */ + + /* Don't make something that was more transparent less transparent. */ + output[0] = MIN2(alpha, inColor[3]); +} diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp b/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp deleted file mode 100644 index 15375589888..00000000000 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_ChannelMatteOperation.h" -#include "BLI_math.h" - -ChannelMatteOperation::ChannelMatteOperation() -{ - addInputSocket(COM_DT_COLOR); - addOutputSocket(COM_DT_VALUE); - - this->m_inputImageProgram = nullptr; -} - -void ChannelMatteOperation::initExecution() -{ - this->m_inputImageProgram = this->getInputSocketReader(0); - - this->m_limit_range = this->m_limit_max - this->m_limit_min; - - switch (this->m_limit_method) { - /* SINGLE */ - case 0: { - /* 123 / RGB / HSV / YUV / YCC */ - const int matte_channel = this->m_matte_channel - 1; - const int limit_channel = this->m_limit_channel - 1; - this->m_ids[0] = matte_channel; - this->m_ids[1] = limit_channel; - this->m_ids[2] = limit_channel; - break; - } - /* MAX */ - case 1: { - switch (this->m_matte_channel) { - case 1: { - this->m_ids[0] = 0; - this->m_ids[1] = 1; - this->m_ids[2] = 2; - break; - } - case 2: { - this->m_ids[0] = 1; - this->m_ids[1] = 0; - this->m_ids[2] = 2; - break; - } - case 3: { - this->m_ids[0] = 2; - this->m_ids[1] = 0; - this->m_ids[2] = 1; - break; - } - default: - break; - } - break; - } - default: - break; - } -} - -void ChannelMatteOperation::deinitExecution() -{ - this->m_inputImageProgram = nullptr; -} - -void ChannelMatteOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inColor[4]; - float alpha; - - const float limit_max = this->m_limit_max; - const float limit_min = this->m_limit_min; - const float limit_range = this->m_limit_range; - - this->m_inputImageProgram->readSampled(inColor, x, y, sampler); - - /* matte operation */ - alpha = inColor[this->m_ids[0]] - MAX2(inColor[this->m_ids[1]], inColor[this->m_ids[2]]); - - /* flip because 0.0 is transparent, not 1.0 */ - alpha = 1.0f - alpha; - - /* test range */ - if (alpha > limit_max) { - alpha = inColor[3]; /*whatever it was prior */ - } - else if (alpha < limit_min) { - alpha = 0.0f; - } - else { /*blend */ - alpha = (alpha - limit_min) / limit_range; - } - - /* Store matte(alpha) value in [0] to go with - * COM_SetAlphaMultiplyOperation and the Value output. - */ - - /* Don't make something that was more transparent less transparent. */ - output[0] = MIN2(alpha, inColor[3]); -} diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.cc b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc new file mode 100644 index 00000000000..52de0198a00 --- /dev/null +++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc @@ -0,0 +1,109 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ChromaMatteOperation.h" +#include "BLI_math.h" + +ChromaMatteOperation::ChromaMatteOperation() +{ + addInputSocket(COM_DT_COLOR); + addInputSocket(COM_DT_COLOR); + addOutputSocket(COM_DT_VALUE); + + this->m_inputImageProgram = nullptr; + this->m_inputKeyProgram = nullptr; +} + +void ChromaMatteOperation::initExecution() +{ + this->m_inputImageProgram = this->getInputSocketReader(0); + this->m_inputKeyProgram = this->getInputSocketReader(1); +} + +void ChromaMatteOperation::deinitExecution() +{ + this->m_inputImageProgram = nullptr; + this->m_inputKeyProgram = nullptr; +} + +void ChromaMatteOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inKey[4]; + float inImage[4]; + + const float acceptance = this->m_settings->t1; /* in radians */ + const float cutoff = this->m_settings->t2; /* in radians */ + const float gain = this->m_settings->fstrength; + + float x_angle, z_angle, alpha; + float theta, beta; + float kfg; + + this->m_inputKeyProgram->readSampled(inKey, x, y, sampler); + this->m_inputImageProgram->readSampled(inImage, x, y, sampler); + + /* Store matte(alpha) value in [0] to go with + * #COM_SetAlphaMultiplyOperation and the Value output. */ + + /* Algorithm from book "Video Demystified", does not include the spill reduction part. */ + /* Find theta, the angle that the color space should be rotated based on key. */ + + /* rescale to -1.0..1.0 */ + // inImage[0] = (inImage[0] * 2.0f) - 1.0f; // UNUSED + inImage[1] = (inImage[1] * 2.0f) - 1.0f; + inImage[2] = (inImage[2] * 2.0f) - 1.0f; + + // inKey[0] = (inKey[0] * 2.0f) - 1.0f; // UNUSED + inKey[1] = (inKey[1] * 2.0f) - 1.0f; + inKey[2] = (inKey[2] * 2.0f) - 1.0f; + + theta = atan2(inKey[2], inKey[1]); + + /*rotate the cb and cr into x/z space */ + x_angle = inImage[1] * cosf(theta) + inImage[2] * sinf(theta); + z_angle = inImage[2] * cosf(theta) - inImage[1] * sinf(theta); + + /*if within the acceptance angle */ + /* if kfg is <0 then the pixel is outside of the key color */ + kfg = x_angle - (fabsf(z_angle) / tanf(acceptance / 2.0f)); + + if (kfg > 0.0f) { /* found a pixel that is within key color */ + alpha = 1.0f - (kfg / gain); + + beta = atan2(z_angle, x_angle); + + /* if beta is within the cutoff angle */ + if (fabsf(beta) < (cutoff / 2.0f)) { + alpha = 0.0f; + } + + /* don't make something that was more transparent less transparent */ + if (alpha < inImage[3]) { + output[0] = alpha; + } + else { + output[0] = inImage[3]; + } + } + else { /*pixel is outside key color */ + output[0] = inImage[3]; /* make pixel just as transparent as it was before */ + } +} diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp b/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp deleted file mode 100644 index 52de0198a00..00000000000 --- a/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ChromaMatteOperation.h" -#include "BLI_math.h" - -ChromaMatteOperation::ChromaMatteOperation() -{ - addInputSocket(COM_DT_COLOR); - addInputSocket(COM_DT_COLOR); - addOutputSocket(COM_DT_VALUE); - - this->m_inputImageProgram = nullptr; - this->m_inputKeyProgram = nullptr; -} - -void ChromaMatteOperation::initExecution() -{ - this->m_inputImageProgram = this->getInputSocketReader(0); - this->m_inputKeyProgram = this->getInputSocketReader(1); -} - -void ChromaMatteOperation::deinitExecution() -{ - this->m_inputImageProgram = nullptr; - this->m_inputKeyProgram = nullptr; -} - -void ChromaMatteOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inKey[4]; - float inImage[4]; - - const float acceptance = this->m_settings->t1; /* in radians */ - const float cutoff = this->m_settings->t2; /* in radians */ - const float gain = this->m_settings->fstrength; - - float x_angle, z_angle, alpha; - float theta, beta; - float kfg; - - this->m_inputKeyProgram->readSampled(inKey, x, y, sampler); - this->m_inputImageProgram->readSampled(inImage, x, y, sampler); - - /* Store matte(alpha) value in [0] to go with - * #COM_SetAlphaMultiplyOperation and the Value output. */ - - /* Algorithm from book "Video Demystified", does not include the spill reduction part. */ - /* Find theta, the angle that the color space should be rotated based on key. */ - - /* rescale to -1.0..1.0 */ - // inImage[0] = (inImage[0] * 2.0f) - 1.0f; // UNUSED - inImage[1] = (inImage[1] * 2.0f) - 1.0f; - inImage[2] = (inImage[2] * 2.0f) - 1.0f; - - // inKey[0] = (inKey[0] * 2.0f) - 1.0f; // UNUSED - inKey[1] = (inKey[1] * 2.0f) - 1.0f; - inKey[2] = (inKey[2] * 2.0f) - 1.0f; - - theta = atan2(inKey[2], inKey[1]); - - /*rotate the cb and cr into x/z space */ - x_angle = inImage[1] * cosf(theta) + inImage[2] * sinf(theta); - z_angle = inImage[2] * cosf(theta) - inImage[1] * sinf(theta); - - /*if within the acceptance angle */ - /* if kfg is <0 then the pixel is outside of the key color */ - kfg = x_angle - (fabsf(z_angle) / tanf(acceptance / 2.0f)); - - if (kfg > 0.0f) { /* found a pixel that is within key color */ - alpha = 1.0f - (kfg / gain); - - beta = atan2(z_angle, x_angle); - - /* if beta is within the cutoff angle */ - if (fabsf(beta) < (cutoff / 2.0f)) { - alpha = 0.0f; - } - - /* don't make something that was more transparent less transparent */ - if (alpha < inImage[3]) { - output[0] = alpha; - } - else { - output[0] = inImage[3]; - } - } - else { /*pixel is outside key color */ - output[0] = inImage[3]; /* make pixel just as transparent as it was before */ - } -} diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc new file mode 100644 index 00000000000..44eef1e19cd --- /dev/null +++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc @@ -0,0 +1,81 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorBalanceASCCDLOperation.h" +#include "BLI_math.h" + +inline float colorbalance_cdl(float in, float offset, float power, float slope) +{ + float x = in * slope + offset; + + /* prevent NaN */ + if (x < 0.0f) { + x = 0.0f; + } + + return powf(x, power); +} + +ColorBalanceASCCDLOperation::ColorBalanceASCCDLOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputValueOperation = nullptr; + this->m_inputColorOperation = nullptr; + this->setResolutionInputSocketIndex(1); +} + +void ColorBalanceASCCDLOperation::initExecution() +{ + this->m_inputValueOperation = this->getInputSocketReader(0); + this->m_inputColorOperation = this->getInputSocketReader(1); +} + +void ColorBalanceASCCDLOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + float value[4]; + + this->m_inputValueOperation->readSampled(value, x, y, sampler); + this->m_inputColorOperation->readSampled(inputColor, x, y, sampler); + + float fac = value[0]; + fac = MIN2(1.0f, fac); + const float mfac = 1.0f - fac; + + output[0] = mfac * inputColor[0] + + fac * colorbalance_cdl( + inputColor[0], this->m_offset[0], this->m_power[0], this->m_slope[0]); + output[1] = mfac * inputColor[1] + + fac * colorbalance_cdl( + inputColor[1], this->m_offset[1], this->m_power[1], this->m_slope[1]); + output[2] = mfac * inputColor[2] + + fac * colorbalance_cdl( + inputColor[2], this->m_offset[2], this->m_power[2], this->m_slope[2]); + output[3] = inputColor[3]; +} + +void ColorBalanceASCCDLOperation::deinitExecution() +{ + this->m_inputValueOperation = nullptr; + this->m_inputColorOperation = nullptr; +} diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp deleted file mode 100644 index 44eef1e19cd..00000000000 --- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorBalanceASCCDLOperation.h" -#include "BLI_math.h" - -inline float colorbalance_cdl(float in, float offset, float power, float slope) -{ - float x = in * slope + offset; - - /* prevent NaN */ - if (x < 0.0f) { - x = 0.0f; - } - - return powf(x, power); -} - -ColorBalanceASCCDLOperation::ColorBalanceASCCDLOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputValueOperation = nullptr; - this->m_inputColorOperation = nullptr; - this->setResolutionInputSocketIndex(1); -} - -void ColorBalanceASCCDLOperation::initExecution() -{ - this->m_inputValueOperation = this->getInputSocketReader(0); - this->m_inputColorOperation = this->getInputSocketReader(1); -} - -void ColorBalanceASCCDLOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - float value[4]; - - this->m_inputValueOperation->readSampled(value, x, y, sampler); - this->m_inputColorOperation->readSampled(inputColor, x, y, sampler); - - float fac = value[0]; - fac = MIN2(1.0f, fac); - const float mfac = 1.0f - fac; - - output[0] = mfac * inputColor[0] + - fac * colorbalance_cdl( - inputColor[0], this->m_offset[0], this->m_power[0], this->m_slope[0]); - output[1] = mfac * inputColor[1] + - fac * colorbalance_cdl( - inputColor[1], this->m_offset[1], this->m_power[1], this->m_slope[1]); - output[2] = mfac * inputColor[2] + - fac * colorbalance_cdl( - inputColor[2], this->m_offset[2], this->m_power[2], this->m_slope[2]); - output[3] = inputColor[3]; -} - -void ColorBalanceASCCDLOperation::deinitExecution() -{ - this->m_inputValueOperation = nullptr; - this->m_inputColorOperation = nullptr; -} diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc new file mode 100644 index 00000000000..934b7e51aee --- /dev/null +++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc @@ -0,0 +1,86 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorBalanceLGGOperation.h" +#include "BLI_math.h" + +inline float colorbalance_lgg(float in, float lift_lgg, float gamma_inv, float gain) +{ + /* 1:1 match with the sequencer with linear/srgb conversions, the conversion isnt pretty + * but best keep it this way, since testing for durian shows a similar calculation + * without lin/srgb conversions gives bad results (over-saturated shadows) with colors + * slightly below 1.0. some correction can be done but it ends up looking bad for shadows or + * lighter tones - campbell */ + float x = (((linearrgb_to_srgb(in) - 1.0f) * lift_lgg) + 1.0f) * gain; + + /* prevent NaN */ + if (x < 0.0f) { + x = 0.0f; + } + + return powf(srgb_to_linearrgb(x), gamma_inv); +} + +ColorBalanceLGGOperation::ColorBalanceLGGOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputValueOperation = nullptr; + this->m_inputColorOperation = nullptr; + this->setResolutionInputSocketIndex(1); +} + +void ColorBalanceLGGOperation::initExecution() +{ + this->m_inputValueOperation = this->getInputSocketReader(0); + this->m_inputColorOperation = this->getInputSocketReader(1); +} + +void ColorBalanceLGGOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + float value[4]; + + this->m_inputValueOperation->readSampled(value, x, y, sampler); + this->m_inputColorOperation->readSampled(inputColor, x, y, sampler); + + float fac = value[0]; + fac = MIN2(1.0f, fac); + const float mfac = 1.0f - fac; + + output[0] = mfac * inputColor[0] + + fac * colorbalance_lgg( + inputColor[0], this->m_lift[0], this->m_gamma_inv[0], this->m_gain[0]); + output[1] = mfac * inputColor[1] + + fac * colorbalance_lgg( + inputColor[1], this->m_lift[1], this->m_gamma_inv[1], this->m_gain[1]); + output[2] = mfac * inputColor[2] + + fac * colorbalance_lgg( + inputColor[2], this->m_lift[2], this->m_gamma_inv[2], this->m_gain[2]); + output[3] = inputColor[3]; +} + +void ColorBalanceLGGOperation::deinitExecution() +{ + this->m_inputValueOperation = nullptr; + this->m_inputColorOperation = nullptr; +} diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp deleted file mode 100644 index 934b7e51aee..00000000000 --- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorBalanceLGGOperation.h" -#include "BLI_math.h" - -inline float colorbalance_lgg(float in, float lift_lgg, float gamma_inv, float gain) -{ - /* 1:1 match with the sequencer with linear/srgb conversions, the conversion isnt pretty - * but best keep it this way, since testing for durian shows a similar calculation - * without lin/srgb conversions gives bad results (over-saturated shadows) with colors - * slightly below 1.0. some correction can be done but it ends up looking bad for shadows or - * lighter tones - campbell */ - float x = (((linearrgb_to_srgb(in) - 1.0f) * lift_lgg) + 1.0f) * gain; - - /* prevent NaN */ - if (x < 0.0f) { - x = 0.0f; - } - - return powf(srgb_to_linearrgb(x), gamma_inv); -} - -ColorBalanceLGGOperation::ColorBalanceLGGOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputValueOperation = nullptr; - this->m_inputColorOperation = nullptr; - this->setResolutionInputSocketIndex(1); -} - -void ColorBalanceLGGOperation::initExecution() -{ - this->m_inputValueOperation = this->getInputSocketReader(0); - this->m_inputColorOperation = this->getInputSocketReader(1); -} - -void ColorBalanceLGGOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - float value[4]; - - this->m_inputValueOperation->readSampled(value, x, y, sampler); - this->m_inputColorOperation->readSampled(inputColor, x, y, sampler); - - float fac = value[0]; - fac = MIN2(1.0f, fac); - const float mfac = 1.0f - fac; - - output[0] = mfac * inputColor[0] + - fac * colorbalance_lgg( - inputColor[0], this->m_lift[0], this->m_gamma_inv[0], this->m_gain[0]); - output[1] = mfac * inputColor[1] + - fac * colorbalance_lgg( - inputColor[1], this->m_lift[1], this->m_gamma_inv[1], this->m_gain[1]); - output[2] = mfac * inputColor[2] + - fac * colorbalance_lgg( - inputColor[2], this->m_lift[2], this->m_gamma_inv[2], this->m_gain[2]); - output[3] = inputColor[3]; -} - -void ColorBalanceLGGOperation::deinitExecution() -{ - this->m_inputValueOperation = nullptr; - this->m_inputColorOperation = nullptr; -} diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc new file mode 100644 index 00000000000..02c109e8acd --- /dev/null +++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc @@ -0,0 +1,162 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorCorrectionOperation.h" +#include "BLI_math.h" + +#include "IMB_colormanagement.h" + +ColorCorrectionOperation::ColorCorrectionOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputImage = nullptr; + this->m_inputMask = nullptr; + this->m_redChannelEnabled = true; + this->m_greenChannelEnabled = true; + this->m_blueChannelEnabled = true; +} +void ColorCorrectionOperation::initExecution() +{ + this->m_inputImage = this->getInputSocketReader(0); + this->m_inputMask = this->getInputSocketReader(1); +} + +/* Calculate x^y if the function is defined. Otherwise return the given fallback value. */ +BLI_INLINE float color_correct_powf_safe(const float x, const float y, const float fallback_value) +{ + if (x < 0) { + return fallback_value; + } + return powf(x, y); +} + +void ColorCorrectionOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputImageColor[4]; + float inputMask[4]; + this->m_inputImage->readSampled(inputImageColor, x, y, sampler); + this->m_inputMask->readSampled(inputMask, x, y, sampler); + + float level = (inputImageColor[0] + inputImageColor[1] + inputImageColor[2]) / 3.0f; + float contrast = this->m_data->master.contrast; + float saturation = this->m_data->master.saturation; + float gamma = this->m_data->master.gamma; + float gain = this->m_data->master.gain; + float lift = this->m_data->master.lift; + float r, g, b; + + float value = inputMask[0]; + value = MIN2(1.0f, value); + const float mvalue = 1.0f - value; + + float levelShadows = 0.0; + float levelMidtones = 0.0; + float levelHighlights = 0.0; +#define MARGIN 0.10f +#define MARGIN_DIV (0.5f / MARGIN) + if (level < this->m_data->startmidtones - MARGIN) { + levelShadows = 1.0f; + } + else if (level < this->m_data->startmidtones + MARGIN) { + levelMidtones = ((level - this->m_data->startmidtones) * MARGIN_DIV) + 0.5f; + levelShadows = 1.0f - levelMidtones; + } + else if (level < this->m_data->endmidtones - MARGIN) { + levelMidtones = 1.0f; + } + else if (level < this->m_data->endmidtones + MARGIN) { + levelHighlights = ((level - this->m_data->endmidtones) * MARGIN_DIV) + 0.5f; + levelMidtones = 1.0f - levelHighlights; + } + else { + levelHighlights = 1.0f; + } +#undef MARGIN +#undef MARGIN_DIV + contrast *= (levelShadows * this->m_data->shadows.contrast) + + (levelMidtones * this->m_data->midtones.contrast) + + (levelHighlights * this->m_data->highlights.contrast); + saturation *= (levelShadows * this->m_data->shadows.saturation) + + (levelMidtones * this->m_data->midtones.saturation) + + (levelHighlights * this->m_data->highlights.saturation); + gamma *= (levelShadows * this->m_data->shadows.gamma) + + (levelMidtones * this->m_data->midtones.gamma) + + (levelHighlights * this->m_data->highlights.gamma); + gain *= (levelShadows * this->m_data->shadows.gain) + + (levelMidtones * this->m_data->midtones.gain) + + (levelHighlights * this->m_data->highlights.gain); + lift += (levelShadows * this->m_data->shadows.lift) + + (levelMidtones * this->m_data->midtones.lift) + + (levelHighlights * this->m_data->highlights.lift); + + float invgamma = 1.0f / gamma; + float luma = IMB_colormanagement_get_luminance(inputImageColor); + + r = inputImageColor[0]; + g = inputImageColor[1]; + b = inputImageColor[2]; + + r = (luma + saturation * (r - luma)); + g = (luma + saturation * (g - luma)); + b = (luma + saturation * (b - luma)); + + r = 0.5f + ((r - 0.5f) * contrast); + g = 0.5f + ((g - 0.5f) * contrast); + b = 0.5f + ((b - 0.5f) * contrast); + + /* Check for negative values to avoid nan. */ + r = color_correct_powf_safe(r * gain + lift, invgamma, r); + g = color_correct_powf_safe(g * gain + lift, invgamma, g); + b = color_correct_powf_safe(b * gain + lift, invgamma, b); + + // mix with mask + r = mvalue * inputImageColor[0] + value * r; + g = mvalue * inputImageColor[1] + value * g; + b = mvalue * inputImageColor[2] + value * b; + + if (this->m_redChannelEnabled) { + output[0] = r; + } + else { + output[0] = inputImageColor[0]; + } + if (this->m_greenChannelEnabled) { + output[1] = g; + } + else { + output[1] = inputImageColor[1]; + } + if (this->m_blueChannelEnabled) { + output[2] = b; + } + else { + output[2] = inputImageColor[2]; + } + output[3] = inputImageColor[3]; +} + +void ColorCorrectionOperation::deinitExecution() +{ + this->m_inputImage = nullptr; + this->m_inputMask = nullptr; +} diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp deleted file mode 100644 index 02c109e8acd..00000000000 --- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorCorrectionOperation.h" -#include "BLI_math.h" - -#include "IMB_colormanagement.h" - -ColorCorrectionOperation::ColorCorrectionOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputImage = nullptr; - this->m_inputMask = nullptr; - this->m_redChannelEnabled = true; - this->m_greenChannelEnabled = true; - this->m_blueChannelEnabled = true; -} -void ColorCorrectionOperation::initExecution() -{ - this->m_inputImage = this->getInputSocketReader(0); - this->m_inputMask = this->getInputSocketReader(1); -} - -/* Calculate x^y if the function is defined. Otherwise return the given fallback value. */ -BLI_INLINE float color_correct_powf_safe(const float x, const float y, const float fallback_value) -{ - if (x < 0) { - return fallback_value; - } - return powf(x, y); -} - -void ColorCorrectionOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputImageColor[4]; - float inputMask[4]; - this->m_inputImage->readSampled(inputImageColor, x, y, sampler); - this->m_inputMask->readSampled(inputMask, x, y, sampler); - - float level = (inputImageColor[0] + inputImageColor[1] + inputImageColor[2]) / 3.0f; - float contrast = this->m_data->master.contrast; - float saturation = this->m_data->master.saturation; - float gamma = this->m_data->master.gamma; - float gain = this->m_data->master.gain; - float lift = this->m_data->master.lift; - float r, g, b; - - float value = inputMask[0]; - value = MIN2(1.0f, value); - const float mvalue = 1.0f - value; - - float levelShadows = 0.0; - float levelMidtones = 0.0; - float levelHighlights = 0.0; -#define MARGIN 0.10f -#define MARGIN_DIV (0.5f / MARGIN) - if (level < this->m_data->startmidtones - MARGIN) { - levelShadows = 1.0f; - } - else if (level < this->m_data->startmidtones + MARGIN) { - levelMidtones = ((level - this->m_data->startmidtones) * MARGIN_DIV) + 0.5f; - levelShadows = 1.0f - levelMidtones; - } - else if (level < this->m_data->endmidtones - MARGIN) { - levelMidtones = 1.0f; - } - else if (level < this->m_data->endmidtones + MARGIN) { - levelHighlights = ((level - this->m_data->endmidtones) * MARGIN_DIV) + 0.5f; - levelMidtones = 1.0f - levelHighlights; - } - else { - levelHighlights = 1.0f; - } -#undef MARGIN -#undef MARGIN_DIV - contrast *= (levelShadows * this->m_data->shadows.contrast) + - (levelMidtones * this->m_data->midtones.contrast) + - (levelHighlights * this->m_data->highlights.contrast); - saturation *= (levelShadows * this->m_data->shadows.saturation) + - (levelMidtones * this->m_data->midtones.saturation) + - (levelHighlights * this->m_data->highlights.saturation); - gamma *= (levelShadows * this->m_data->shadows.gamma) + - (levelMidtones * this->m_data->midtones.gamma) + - (levelHighlights * this->m_data->highlights.gamma); - gain *= (levelShadows * this->m_data->shadows.gain) + - (levelMidtones * this->m_data->midtones.gain) + - (levelHighlights * this->m_data->highlights.gain); - lift += (levelShadows * this->m_data->shadows.lift) + - (levelMidtones * this->m_data->midtones.lift) + - (levelHighlights * this->m_data->highlights.lift); - - float invgamma = 1.0f / gamma; - float luma = IMB_colormanagement_get_luminance(inputImageColor); - - r = inputImageColor[0]; - g = inputImageColor[1]; - b = inputImageColor[2]; - - r = (luma + saturation * (r - luma)); - g = (luma + saturation * (g - luma)); - b = (luma + saturation * (b - luma)); - - r = 0.5f + ((r - 0.5f) * contrast); - g = 0.5f + ((g - 0.5f) * contrast); - b = 0.5f + ((b - 0.5f) * contrast); - - /* Check for negative values to avoid nan. */ - r = color_correct_powf_safe(r * gain + lift, invgamma, r); - g = color_correct_powf_safe(g * gain + lift, invgamma, g); - b = color_correct_powf_safe(b * gain + lift, invgamma, b); - - // mix with mask - r = mvalue * inputImageColor[0] + value * r; - g = mvalue * inputImageColor[1] + value * g; - b = mvalue * inputImageColor[2] + value * b; - - if (this->m_redChannelEnabled) { - output[0] = r; - } - else { - output[0] = inputImageColor[0]; - } - if (this->m_greenChannelEnabled) { - output[1] = g; - } - else { - output[1] = inputImageColor[1]; - } - if (this->m_blueChannelEnabled) { - output[2] = b; - } - else { - output[2] = inputImageColor[2]; - } - output[3] = inputImageColor[3]; -} - -void ColorCorrectionOperation::deinitExecution() -{ - this->m_inputImage = nullptr; - this->m_inputMask = nullptr; -} diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cc b/source/blender/compositor/operations/COM_ColorCurveOperation.cc new file mode 100644 index 00000000000..ed107a88953 --- /dev/null +++ b/source/blender/compositor/operations/COM_ColorCurveOperation.cc @@ -0,0 +1,153 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorCurveOperation.h" + +#include "BKE_colortools.h" + +#include "MEM_guardedalloc.h" + +ColorCurveOperation::ColorCurveOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + + this->m_inputFacProgram = nullptr; + this->m_inputImageProgram = nullptr; + this->m_inputBlackProgram = nullptr; + this->m_inputWhiteProgram = nullptr; + + this->setResolutionInputSocketIndex(1); +} +void ColorCurveOperation::initExecution() +{ + CurveBaseOperation::initExecution(); + this->m_inputFacProgram = this->getInputSocketReader(0); + this->m_inputImageProgram = this->getInputSocketReader(1); + this->m_inputBlackProgram = this->getInputSocketReader(2); + this->m_inputWhiteProgram = this->getInputSocketReader(3); + + BKE_curvemapping_premultiply(this->m_curveMapping, 0); +} + +void ColorCurveOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + CurveMapping *cumap = this->m_curveMapping; + + float fac[4]; + float image[4]; + + /* local versions of cumap->black, cumap->white, cumap->bwmul */ + float black[4]; + float white[4]; + float bwmul[3]; + + this->m_inputBlackProgram->readSampled(black, x, y, sampler); + this->m_inputWhiteProgram->readSampled(white, x, y, sampler); + + /* get our own local bwmul value, + * since we can't be threadsafe and use cumap->bwmul & friends */ + BKE_curvemapping_set_black_white_ex(black, white, bwmul); + + this->m_inputFacProgram->readSampled(fac, x, y, sampler); + this->m_inputImageProgram->readSampled(image, x, y, sampler); + + if (*fac >= 1.0f) { + BKE_curvemapping_evaluate_premulRGBF_ex(cumap, output, image, black, bwmul); + } + else if (*fac <= 0.0f) { + copy_v3_v3(output, image); + } + else { + float col[4]; + BKE_curvemapping_evaluate_premulRGBF_ex(cumap, col, image, black, bwmul); + interp_v3_v3v3(output, image, col, *fac); + } + output[3] = image[3]; +} + +void ColorCurveOperation::deinitExecution() +{ + CurveBaseOperation::deinitExecution(); + this->m_inputFacProgram = nullptr; + this->m_inputImageProgram = nullptr; + this->m_inputBlackProgram = nullptr; + this->m_inputWhiteProgram = nullptr; +} + +// Constant level curve mapping + +ConstantLevelColorCurveOperation::ConstantLevelColorCurveOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + + this->m_inputFacProgram = nullptr; + this->m_inputImageProgram = nullptr; + + this->setResolutionInputSocketIndex(1); +} +void ConstantLevelColorCurveOperation::initExecution() +{ + CurveBaseOperation::initExecution(); + this->m_inputFacProgram = this->getInputSocketReader(0); + this->m_inputImageProgram = this->getInputSocketReader(1); + + BKE_curvemapping_premultiply(this->m_curveMapping, 0); + + BKE_curvemapping_set_black_white(this->m_curveMapping, this->m_black, this->m_white); +} + +void ConstantLevelColorCurveOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float fac[4]; + float image[4]; + + this->m_inputFacProgram->readSampled(fac, x, y, sampler); + this->m_inputImageProgram->readSampled(image, x, y, sampler); + + if (*fac >= 1.0f) { + BKE_curvemapping_evaluate_premulRGBF(this->m_curveMapping, output, image); + } + else if (*fac <= 0.0f) { + copy_v3_v3(output, image); + } + else { + float col[4]; + BKE_curvemapping_evaluate_premulRGBF(this->m_curveMapping, col, image); + interp_v3_v3v3(output, image, col, *fac); + } + output[3] = image[3]; +} + +void ConstantLevelColorCurveOperation::deinitExecution() +{ + CurveBaseOperation::deinitExecution(); + this->m_inputFacProgram = nullptr; + this->m_inputImageProgram = nullptr; +} diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cpp b/source/blender/compositor/operations/COM_ColorCurveOperation.cpp deleted file mode 100644 index ed107a88953..00000000000 --- a/source/blender/compositor/operations/COM_ColorCurveOperation.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorCurveOperation.h" - -#include "BKE_colortools.h" - -#include "MEM_guardedalloc.h" - -ColorCurveOperation::ColorCurveOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - - this->m_inputFacProgram = nullptr; - this->m_inputImageProgram = nullptr; - this->m_inputBlackProgram = nullptr; - this->m_inputWhiteProgram = nullptr; - - this->setResolutionInputSocketIndex(1); -} -void ColorCurveOperation::initExecution() -{ - CurveBaseOperation::initExecution(); - this->m_inputFacProgram = this->getInputSocketReader(0); - this->m_inputImageProgram = this->getInputSocketReader(1); - this->m_inputBlackProgram = this->getInputSocketReader(2); - this->m_inputWhiteProgram = this->getInputSocketReader(3); - - BKE_curvemapping_premultiply(this->m_curveMapping, 0); -} - -void ColorCurveOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - CurveMapping *cumap = this->m_curveMapping; - - float fac[4]; - float image[4]; - - /* local versions of cumap->black, cumap->white, cumap->bwmul */ - float black[4]; - float white[4]; - float bwmul[3]; - - this->m_inputBlackProgram->readSampled(black, x, y, sampler); - this->m_inputWhiteProgram->readSampled(white, x, y, sampler); - - /* get our own local bwmul value, - * since we can't be threadsafe and use cumap->bwmul & friends */ - BKE_curvemapping_set_black_white_ex(black, white, bwmul); - - this->m_inputFacProgram->readSampled(fac, x, y, sampler); - this->m_inputImageProgram->readSampled(image, x, y, sampler); - - if (*fac >= 1.0f) { - BKE_curvemapping_evaluate_premulRGBF_ex(cumap, output, image, black, bwmul); - } - else if (*fac <= 0.0f) { - copy_v3_v3(output, image); - } - else { - float col[4]; - BKE_curvemapping_evaluate_premulRGBF_ex(cumap, col, image, black, bwmul); - interp_v3_v3v3(output, image, col, *fac); - } - output[3] = image[3]; -} - -void ColorCurveOperation::deinitExecution() -{ - CurveBaseOperation::deinitExecution(); - this->m_inputFacProgram = nullptr; - this->m_inputImageProgram = nullptr; - this->m_inputBlackProgram = nullptr; - this->m_inputWhiteProgram = nullptr; -} - -// Constant level curve mapping - -ConstantLevelColorCurveOperation::ConstantLevelColorCurveOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - - this->m_inputFacProgram = nullptr; - this->m_inputImageProgram = nullptr; - - this->setResolutionInputSocketIndex(1); -} -void ConstantLevelColorCurveOperation::initExecution() -{ - CurveBaseOperation::initExecution(); - this->m_inputFacProgram = this->getInputSocketReader(0); - this->m_inputImageProgram = this->getInputSocketReader(1); - - BKE_curvemapping_premultiply(this->m_curveMapping, 0); - - BKE_curvemapping_set_black_white(this->m_curveMapping, this->m_black, this->m_white); -} - -void ConstantLevelColorCurveOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float fac[4]; - float image[4]; - - this->m_inputFacProgram->readSampled(fac, x, y, sampler); - this->m_inputImageProgram->readSampled(image, x, y, sampler); - - if (*fac >= 1.0f) { - BKE_curvemapping_evaluate_premulRGBF(this->m_curveMapping, output, image); - } - else if (*fac <= 0.0f) { - copy_v3_v3(output, image); - } - else { - float col[4]; - BKE_curvemapping_evaluate_premulRGBF(this->m_curveMapping, col, image); - interp_v3_v3v3(output, image, col, *fac); - } - output[3] = image[3]; -} - -void ConstantLevelColorCurveOperation::deinitExecution() -{ - CurveBaseOperation::deinitExecution(); - this->m_inputFacProgram = nullptr; - this->m_inputImageProgram = nullptr; -} diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.cc b/source/blender/compositor/operations/COM_ColorExposureOperation.cc new file mode 100644 index 00000000000..a11039852a1 --- /dev/null +++ b/source/blender/compositor/operations/COM_ColorExposureOperation.cc @@ -0,0 +1,57 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +#include "COM_ColorExposureOperation.h" + +ExposureOperation::ExposureOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputProgram = nullptr; +} + +void ExposureOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); + this->m_inputExposureProgram = this->getInputSocketReader(1); +} + +void ExposureOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue[4]; + float inputExposure[4]; + this->m_inputProgram->readSampled(inputValue, x, y, sampler); + this->m_inputExposureProgram->readSampled(inputExposure, x, y, sampler); + const float exposure = pow(2, inputExposure[0]); + + output[0] = inputValue[0] * exposure; + output[1] = inputValue[1] * exposure; + output[2] = inputValue[2] * exposure; + + output[3] = inputValue[3]; +} + +void ExposureOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; + this->m_inputExposureProgram = nullptr; +} diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.cpp b/source/blender/compositor/operations/COM_ColorExposureOperation.cpp deleted file mode 100644 index a11039852a1..00000000000 --- a/source/blender/compositor/operations/COM_ColorExposureOperation.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. - * - * Copyright 2020, Blender Foundation. - */ - -#include "COM_ColorExposureOperation.h" - -ExposureOperation::ExposureOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputProgram = nullptr; -} - -void ExposureOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); - this->m_inputExposureProgram = this->getInputSocketReader(1); -} - -void ExposureOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue[4]; - float inputExposure[4]; - this->m_inputProgram->readSampled(inputValue, x, y, sampler); - this->m_inputExposureProgram->readSampled(inputExposure, x, y, sampler); - const float exposure = pow(2, inputExposure[0]); - - output[0] = inputValue[0] * exposure; - output[1] = inputValue[1] * exposure; - output[2] = inputValue[2] * exposure; - - output[3] = inputValue[3]; -} - -void ExposureOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; - this->m_inputExposureProgram = nullptr; -} diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.cc b/source/blender/compositor/operations/COM_ColorMatteOperation.cc new file mode 100644 index 00000000000..17ada8d89b2 --- /dev/null +++ b/source/blender/compositor/operations/COM_ColorMatteOperation.cc @@ -0,0 +1,81 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorMatteOperation.h" +#include "BLI_math.h" + +ColorMatteOperation::ColorMatteOperation() +{ + addInputSocket(COM_DT_COLOR); + addInputSocket(COM_DT_COLOR); + addOutputSocket(COM_DT_VALUE); + + this->m_inputImageProgram = nullptr; + this->m_inputKeyProgram = nullptr; +} + +void ColorMatteOperation::initExecution() +{ + this->m_inputImageProgram = this->getInputSocketReader(0); + this->m_inputKeyProgram = this->getInputSocketReader(1); +} + +void ColorMatteOperation::deinitExecution() +{ + this->m_inputImageProgram = nullptr; + this->m_inputKeyProgram = nullptr; +} + +void ColorMatteOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inColor[4]; + float inKey[4]; + + const float hue = this->m_settings->t1; + const float sat = this->m_settings->t2; + const float val = this->m_settings->t3; + + float h_wrap; + + this->m_inputImageProgram->readSampled(inColor, x, y, sampler); + this->m_inputKeyProgram->readSampled(inKey, x, y, sampler); + + /* Store matte(alpha) value in [0] to go with + * COM_SetAlphaMultiplyOperation and the Value output. + */ + + if ( + /* do hue last because it needs to wrap, and does some more checks */ + + /* sat */ (fabsf(inColor[1] - inKey[1]) < sat) && + /* val */ (fabsf(inColor[2] - inKey[2]) < val) && + + /* multiply by 2 because it wraps on both sides of the hue, + * otherwise 0.5 would key all hue's */ + + /* hue */ ((h_wrap = 2.0f * fabsf(inColor[0] - inKey[0])) < hue || (2.0f - h_wrap) < hue)) { + output[0] = 0.0f; /* make transparent */ + } + + else { /*pixel is outside key color */ + output[0] = inColor[3]; /* make pixel just as transparent as it was before */ + } +} diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.cpp b/source/blender/compositor/operations/COM_ColorMatteOperation.cpp deleted file mode 100644 index 17ada8d89b2..00000000000 --- a/source/blender/compositor/operations/COM_ColorMatteOperation.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorMatteOperation.h" -#include "BLI_math.h" - -ColorMatteOperation::ColorMatteOperation() -{ - addInputSocket(COM_DT_COLOR); - addInputSocket(COM_DT_COLOR); - addOutputSocket(COM_DT_VALUE); - - this->m_inputImageProgram = nullptr; - this->m_inputKeyProgram = nullptr; -} - -void ColorMatteOperation::initExecution() -{ - this->m_inputImageProgram = this->getInputSocketReader(0); - this->m_inputKeyProgram = this->getInputSocketReader(1); -} - -void ColorMatteOperation::deinitExecution() -{ - this->m_inputImageProgram = nullptr; - this->m_inputKeyProgram = nullptr; -} - -void ColorMatteOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inColor[4]; - float inKey[4]; - - const float hue = this->m_settings->t1; - const float sat = this->m_settings->t2; - const float val = this->m_settings->t3; - - float h_wrap; - - this->m_inputImageProgram->readSampled(inColor, x, y, sampler); - this->m_inputKeyProgram->readSampled(inKey, x, y, sampler); - - /* Store matte(alpha) value in [0] to go with - * COM_SetAlphaMultiplyOperation and the Value output. - */ - - if ( - /* do hue last because it needs to wrap, and does some more checks */ - - /* sat */ (fabsf(inColor[1] - inKey[1]) < sat) && - /* val */ (fabsf(inColor[2] - inKey[2]) < val) && - - /* multiply by 2 because it wraps on both sides of the hue, - * otherwise 0.5 would key all hue's */ - - /* hue */ ((h_wrap = 2.0f * fabsf(inColor[0] - inKey[0])) < hue || (2.0f - h_wrap) < hue)) { - output[0] = 0.0f; /* make transparent */ - } - - else { /*pixel is outside key color */ - output[0] = inColor[3]; /* make pixel just as transparent as it was before */ - } -} diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.cc b/source/blender/compositor/operations/COM_ColorRampOperation.cc new file mode 100644 index 00000000000..4d62a293b78 --- /dev/null +++ b/source/blender/compositor/operations/COM_ColorRampOperation.cc @@ -0,0 +1,50 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorRampOperation.h" + +#include "BKE_colorband.h" + +ColorRampOperation::ColorRampOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + + this->m_inputProgram = nullptr; + this->m_colorBand = nullptr; +} +void ColorRampOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); +} + +void ColorRampOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float values[4]; + + this->m_inputProgram->readSampled(values, x, y, sampler); + BKE_colorband_evaluate(this->m_colorBand, values[0], output); +} + +void ColorRampOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; +} diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.cpp b/source/blender/compositor/operations/COM_ColorRampOperation.cpp deleted file mode 100644 index 4d62a293b78..00000000000 --- a/source/blender/compositor/operations/COM_ColorRampOperation.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorRampOperation.h" - -#include "BKE_colorband.h" - -ColorRampOperation::ColorRampOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - - this->m_inputProgram = nullptr; - this->m_colorBand = nullptr; -} -void ColorRampOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); -} - -void ColorRampOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float values[4]; - - this->m_inputProgram->readSampled(values, x, y, sampler); - BKE_colorband_evaluate(this->m_colorBand, values[0], output); -} - -void ColorRampOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; -} diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.cc b/source/blender/compositor/operations/COM_ColorSpillOperation.cc new file mode 100644 index 00000000000..8139d71c637 --- /dev/null +++ b/source/blender/compositor/operations/COM_ColorSpillOperation.cc @@ -0,0 +1,117 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ColorSpillOperation.h" +#include "BLI_math.h" +#define AVG(a, b) ((a + b) / 2) + +ColorSpillOperation::ColorSpillOperation() +{ + addInputSocket(COM_DT_COLOR); + addInputSocket(COM_DT_VALUE); + addOutputSocket(COM_DT_COLOR); + + this->m_inputImageReader = nullptr; + this->m_inputFacReader = nullptr; + this->m_spillChannel = 1; // GREEN + this->m_spillMethod = 0; +} + +void ColorSpillOperation::initExecution() +{ + this->m_inputImageReader = this->getInputSocketReader(0); + this->m_inputFacReader = this->getInputSocketReader(1); + if (this->m_spillChannel == 0) { + this->m_rmut = -1.0f; + this->m_gmut = 1.0f; + this->m_bmut = 1.0f; + this->m_channel2 = 1; + this->m_channel3 = 2; + if (this->m_settings->unspill == 0) { + this->m_settings->uspillr = 1.0f; + this->m_settings->uspillg = 0.0f; + this->m_settings->uspillb = 0.0f; + } + } + else if (this->m_spillChannel == 1) { + this->m_rmut = 1.0f; + this->m_gmut = -1.0f; + this->m_bmut = 1.0f; + this->m_channel2 = 0; + this->m_channel3 = 2; + if (this->m_settings->unspill == 0) { + this->m_settings->uspillr = 0.0f; + this->m_settings->uspillg = 1.0f; + this->m_settings->uspillb = 0.0f; + } + } + else { + this->m_rmut = 1.0f; + this->m_gmut = 1.0f; + this->m_bmut = -1.0f; + + this->m_channel2 = 0; + this->m_channel3 = 1; + if (this->m_settings->unspill == 0) { + this->m_settings->uspillr = 0.0f; + this->m_settings->uspillg = 0.0f; + this->m_settings->uspillb = 1.0f; + } + } +} + +void ColorSpillOperation::deinitExecution() +{ + this->m_inputImageReader = nullptr; + this->m_inputFacReader = nullptr; +} + +void ColorSpillOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float fac[4]; + float input[4]; + this->m_inputFacReader->readSampled(fac, x, y, sampler); + this->m_inputImageReader->readSampled(input, x, y, sampler); + float rfac = MIN2(1.0f, fac[0]); + float map; + + switch (this->m_spillMethod) { + case 0: /* simple */ + map = rfac * (input[this->m_spillChannel] - + (this->m_settings->limscale * input[this->m_settings->limchan])); + break; + default: /* average */ + map = rfac * + (input[this->m_spillChannel] - + (this->m_settings->limscale * AVG(input[this->m_channel2], input[this->m_channel3]))); + break; + } + + if (map > 0.0f) { + output[0] = input[0] + this->m_rmut * (this->m_settings->uspillr * map); + output[1] = input[1] + this->m_gmut * (this->m_settings->uspillg * map); + output[2] = input[2] + this->m_bmut * (this->m_settings->uspillb * map); + output[3] = input[3]; + } + else { + copy_v4_v4(output, input); + } +} diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp b/source/blender/compositor/operations/COM_ColorSpillOperation.cpp deleted file mode 100644 index 8139d71c637..00000000000 --- a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ColorSpillOperation.h" -#include "BLI_math.h" -#define AVG(a, b) ((a + b) / 2) - -ColorSpillOperation::ColorSpillOperation() -{ - addInputSocket(COM_DT_COLOR); - addInputSocket(COM_DT_VALUE); - addOutputSocket(COM_DT_COLOR); - - this->m_inputImageReader = nullptr; - this->m_inputFacReader = nullptr; - this->m_spillChannel = 1; // GREEN - this->m_spillMethod = 0; -} - -void ColorSpillOperation::initExecution() -{ - this->m_inputImageReader = this->getInputSocketReader(0); - this->m_inputFacReader = this->getInputSocketReader(1); - if (this->m_spillChannel == 0) { - this->m_rmut = -1.0f; - this->m_gmut = 1.0f; - this->m_bmut = 1.0f; - this->m_channel2 = 1; - this->m_channel3 = 2; - if (this->m_settings->unspill == 0) { - this->m_settings->uspillr = 1.0f; - this->m_settings->uspillg = 0.0f; - this->m_settings->uspillb = 0.0f; - } - } - else if (this->m_spillChannel == 1) { - this->m_rmut = 1.0f; - this->m_gmut = -1.0f; - this->m_bmut = 1.0f; - this->m_channel2 = 0; - this->m_channel3 = 2; - if (this->m_settings->unspill == 0) { - this->m_settings->uspillr = 0.0f; - this->m_settings->uspillg = 1.0f; - this->m_settings->uspillb = 0.0f; - } - } - else { - this->m_rmut = 1.0f; - this->m_gmut = 1.0f; - this->m_bmut = -1.0f; - - this->m_channel2 = 0; - this->m_channel3 = 1; - if (this->m_settings->unspill == 0) { - this->m_settings->uspillr = 0.0f; - this->m_settings->uspillg = 0.0f; - this->m_settings->uspillb = 1.0f; - } - } -} - -void ColorSpillOperation::deinitExecution() -{ - this->m_inputImageReader = nullptr; - this->m_inputFacReader = nullptr; -} - -void ColorSpillOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float fac[4]; - float input[4]; - this->m_inputFacReader->readSampled(fac, x, y, sampler); - this->m_inputImageReader->readSampled(input, x, y, sampler); - float rfac = MIN2(1.0f, fac[0]); - float map; - - switch (this->m_spillMethod) { - case 0: /* simple */ - map = rfac * (input[this->m_spillChannel] - - (this->m_settings->limscale * input[this->m_settings->limchan])); - break; - default: /* average */ - map = rfac * - (input[this->m_spillChannel] - - (this->m_settings->limscale * AVG(input[this->m_channel2], input[this->m_channel3]))); - break; - } - - if (map > 0.0f) { - output[0] = input[0] + this->m_rmut * (this->m_settings->uspillr * map); - output[1] = input[1] + this->m_gmut * (this->m_settings->uspillg * map); - output[2] = input[2] + this->m_bmut * (this->m_settings->uspillb * map); - output[3] = input[3]; - } - else { - copy_v4_v4(output, input); - } -} diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cc b/source/blender/compositor/operations/COM_CompositorOperation.cc new file mode 100644 index 00000000000..6a16872cae2 --- /dev/null +++ b/source/blender/compositor/operations/COM_CompositorOperation.cc @@ -0,0 +1,244 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_CompositorOperation.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BLI_listbase.h" +#include "MEM_guardedalloc.h" + +#include "BLI_threads.h" + +#include "RE_pipeline.h" +#include "RE_texture.h" + +#include "render_types.h" + +#include "PIL_time.h" + +CompositorOperation::CompositorOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + + this->setRenderData(nullptr); + this->m_outputBuffer = nullptr; + this->m_depthBuffer = nullptr; + this->m_imageInput = nullptr; + this->m_alphaInput = nullptr; + this->m_depthInput = nullptr; + + this->m_useAlphaInput = false; + this->m_active = false; + + this->m_scene = nullptr; + this->m_sceneName[0] = '\0'; + this->m_viewName = nullptr; +} + +void CompositorOperation::initExecution() +{ + if (!this->m_active) { + return; + } + + // When initializing the tree during initial load the width and height can be zero. + this->m_imageInput = getInputSocketReader(0); + this->m_alphaInput = getInputSocketReader(1); + this->m_depthInput = getInputSocketReader(2); + if (this->getWidth() * this->getHeight() != 0) { + this->m_outputBuffer = (float *)MEM_callocN( + sizeof(float[4]) * this->getWidth() * this->getHeight(), "CompositorOperation"); + } + if (this->m_depthInput != nullptr) { + this->m_depthBuffer = (float *)MEM_callocN( + sizeof(float) * this->getWidth() * this->getHeight(), "CompositorOperation"); + } +} + +void CompositorOperation::deinitExecution() +{ + if (!this->m_active) { + return; + } + + if (!isBraked()) { + Render *re = RE_GetSceneRender(this->m_scene); + RenderResult *rr = RE_AcquireResultWrite(re); + + if (rr) { + RenderView *rv = RE_RenderViewGetByName(rr, this->m_viewName); + + if (rv->rectf != nullptr) { + MEM_freeN(rv->rectf); + } + rv->rectf = this->m_outputBuffer; + if (rv->rectz != nullptr) { + MEM_freeN(rv->rectz); + } + rv->rectz = this->m_depthBuffer; + rr->have_combined = true; + } + else { + if (this->m_outputBuffer) { + MEM_freeN(this->m_outputBuffer); + } + if (this->m_depthBuffer) { + MEM_freeN(this->m_depthBuffer); + } + } + + if (re) { + RE_ReleaseResult(re); + re = nullptr; + } + + BLI_thread_lock(LOCK_DRAW_IMAGE); + BKE_image_signal(G.main, + BKE_image_ensure_viewer(G.main, IMA_TYPE_R_RESULT, "Render Result"), + nullptr, + IMA_SIGNAL_FREE); + BLI_thread_unlock(LOCK_DRAW_IMAGE); + } + else { + if (this->m_outputBuffer) { + MEM_freeN(this->m_outputBuffer); + } + if (this->m_depthBuffer) { + MEM_freeN(this->m_depthBuffer); + } + } + + this->m_outputBuffer = nullptr; + this->m_depthBuffer = nullptr; + this->m_imageInput = nullptr; + this->m_alphaInput = nullptr; + this->m_depthInput = nullptr; +} + +void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) +{ + float color[8]; // 7 is enough + float *buffer = this->m_outputBuffer; + float *zbuffer = this->m_depthBuffer; + + if (!buffer) { + return; + } + int x1 = rect->xmin; + int y1 = rect->ymin; + int x2 = rect->xmax; + int y2 = rect->ymax; + int offset = (y1 * this->getWidth() + x1); + int add = (this->getWidth() - (x2 - x1)); + int offset4 = offset * COM_NUM_CHANNELS_COLOR; + int x; + int y; + bool breaked = false; + int dx = 0, dy = 0; + +#if 0 + const RenderData *rd = this->m_rd; + + if (rd->mode & R_BORDER && rd->mode & R_CROP) { + /** + * When using cropped render result, need to re-position area of interest, + * so it'll natch bounds of render border within frame. By default, canvas + * will be centered between full frame and cropped frame, so we use such + * scheme to map cropped coordinates to full-frame coordinates + * + * ^ Y + * | Width + * +------------------------------------------------+ + * | | + * | | + * | Centered canvas, we map coordinate from it | + * | +------------------+ | + * | | | | H + * | | | | e + * | +------------------+ . Center | | i + * | | | | | | g + * | | | | | | h + * | |....dx.... +------|-----------+ | t + * | | . dy | | + * | +------------------+ | + * | Render border, we map coordinates to it | + * | | X + * +------------------------------------------------+----> + * Full frame + */ + + int full_width = rd->xsch * rd->size / 100; + int full_height = rd->ysch * rd->size / 100; + + dx = rd->border.xmin * full_width - (full_width - this->getWidth()) / 2.0f; + dy = rd->border.ymin * full_height - (full_height - this->getHeight()) / 2.0f; + } +#endif + + for (y = y1; y < y2 && (!breaked); y++) { + for (x = x1; x < x2 && (!breaked); x++) { + int input_x = x + dx, input_y = y + dy; + + this->m_imageInput->readSampled(color, input_x, input_y, COM_PS_NEAREST); + if (this->m_useAlphaInput) { + this->m_alphaInput->readSampled(&(color[3]), input_x, input_y, COM_PS_NEAREST); + } + + copy_v4_v4(buffer + offset4, color); + + this->m_depthInput->readSampled(color, input_x, input_y, COM_PS_NEAREST); + zbuffer[offset] = color[0]; + offset4 += COM_NUM_CHANNELS_COLOR; + offset++; + if (isBraked()) { + breaked = true; + } + } + offset += add; + offset4 += add * COM_NUM_CHANNELS_COLOR; + } +} + +void CompositorOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + int width = this->m_rd->xsch * this->m_rd->size / 100; + int height = this->m_rd->ysch * this->m_rd->size / 100; + + // check actual render resolution with cropping it may differ with cropped border.rendering + // FIX for: [31777] Border Crop gives black (easy) + Render *re = RE_GetSceneRender(this->m_scene); + if (re) { + RenderResult *rr = RE_AcquireResultRead(re); + if (rr) { + width = rr->rectx; + height = rr->recty; + } + RE_ReleaseResult(re); + } + + preferredResolution[0] = width; + preferredResolution[1] = height; + + NodeOperation::determineResolution(resolution, preferredResolution); + + resolution[0] = width; + resolution[1] = height; +} diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp deleted file mode 100644 index 6a16872cae2..00000000000 --- a/source/blender/compositor/operations/COM_CompositorOperation.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_CompositorOperation.h" -#include "BKE_global.h" -#include "BKE_image.h" -#include "BLI_listbase.h" -#include "MEM_guardedalloc.h" - -#include "BLI_threads.h" - -#include "RE_pipeline.h" -#include "RE_texture.h" - -#include "render_types.h" - -#include "PIL_time.h" - -CompositorOperation::CompositorOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - - this->setRenderData(nullptr); - this->m_outputBuffer = nullptr; - this->m_depthBuffer = nullptr; - this->m_imageInput = nullptr; - this->m_alphaInput = nullptr; - this->m_depthInput = nullptr; - - this->m_useAlphaInput = false; - this->m_active = false; - - this->m_scene = nullptr; - this->m_sceneName[0] = '\0'; - this->m_viewName = nullptr; -} - -void CompositorOperation::initExecution() -{ - if (!this->m_active) { - return; - } - - // When initializing the tree during initial load the width and height can be zero. - this->m_imageInput = getInputSocketReader(0); - this->m_alphaInput = getInputSocketReader(1); - this->m_depthInput = getInputSocketReader(2); - if (this->getWidth() * this->getHeight() != 0) { - this->m_outputBuffer = (float *)MEM_callocN( - sizeof(float[4]) * this->getWidth() * this->getHeight(), "CompositorOperation"); - } - if (this->m_depthInput != nullptr) { - this->m_depthBuffer = (float *)MEM_callocN( - sizeof(float) * this->getWidth() * this->getHeight(), "CompositorOperation"); - } -} - -void CompositorOperation::deinitExecution() -{ - if (!this->m_active) { - return; - } - - if (!isBraked()) { - Render *re = RE_GetSceneRender(this->m_scene); - RenderResult *rr = RE_AcquireResultWrite(re); - - if (rr) { - RenderView *rv = RE_RenderViewGetByName(rr, this->m_viewName); - - if (rv->rectf != nullptr) { - MEM_freeN(rv->rectf); - } - rv->rectf = this->m_outputBuffer; - if (rv->rectz != nullptr) { - MEM_freeN(rv->rectz); - } - rv->rectz = this->m_depthBuffer; - rr->have_combined = true; - } - else { - if (this->m_outputBuffer) { - MEM_freeN(this->m_outputBuffer); - } - if (this->m_depthBuffer) { - MEM_freeN(this->m_depthBuffer); - } - } - - if (re) { - RE_ReleaseResult(re); - re = nullptr; - } - - BLI_thread_lock(LOCK_DRAW_IMAGE); - BKE_image_signal(G.main, - BKE_image_ensure_viewer(G.main, IMA_TYPE_R_RESULT, "Render Result"), - nullptr, - IMA_SIGNAL_FREE); - BLI_thread_unlock(LOCK_DRAW_IMAGE); - } - else { - if (this->m_outputBuffer) { - MEM_freeN(this->m_outputBuffer); - } - if (this->m_depthBuffer) { - MEM_freeN(this->m_depthBuffer); - } - } - - this->m_outputBuffer = nullptr; - this->m_depthBuffer = nullptr; - this->m_imageInput = nullptr; - this->m_alphaInput = nullptr; - this->m_depthInput = nullptr; -} - -void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) -{ - float color[8]; // 7 is enough - float *buffer = this->m_outputBuffer; - float *zbuffer = this->m_depthBuffer; - - if (!buffer) { - return; - } - int x1 = rect->xmin; - int y1 = rect->ymin; - int x2 = rect->xmax; - int y2 = rect->ymax; - int offset = (y1 * this->getWidth() + x1); - int add = (this->getWidth() - (x2 - x1)); - int offset4 = offset * COM_NUM_CHANNELS_COLOR; - int x; - int y; - bool breaked = false; - int dx = 0, dy = 0; - -#if 0 - const RenderData *rd = this->m_rd; - - if (rd->mode & R_BORDER && rd->mode & R_CROP) { - /** - * When using cropped render result, need to re-position area of interest, - * so it'll natch bounds of render border within frame. By default, canvas - * will be centered between full frame and cropped frame, so we use such - * scheme to map cropped coordinates to full-frame coordinates - * - * ^ Y - * | Width - * +------------------------------------------------+ - * | | - * | | - * | Centered canvas, we map coordinate from it | - * | +------------------+ | - * | | | | H - * | | | | e - * | +------------------+ . Center | | i - * | | | | | | g - * | | | | | | h - * | |....dx.... +------|-----------+ | t - * | | . dy | | - * | +------------------+ | - * | Render border, we map coordinates to it | - * | | X - * +------------------------------------------------+----> - * Full frame - */ - - int full_width = rd->xsch * rd->size / 100; - int full_height = rd->ysch * rd->size / 100; - - dx = rd->border.xmin * full_width - (full_width - this->getWidth()) / 2.0f; - dy = rd->border.ymin * full_height - (full_height - this->getHeight()) / 2.0f; - } -#endif - - for (y = y1; y < y2 && (!breaked); y++) { - for (x = x1; x < x2 && (!breaked); x++) { - int input_x = x + dx, input_y = y + dy; - - this->m_imageInput->readSampled(color, input_x, input_y, COM_PS_NEAREST); - if (this->m_useAlphaInput) { - this->m_alphaInput->readSampled(&(color[3]), input_x, input_y, COM_PS_NEAREST); - } - - copy_v4_v4(buffer + offset4, color); - - this->m_depthInput->readSampled(color, input_x, input_y, COM_PS_NEAREST); - zbuffer[offset] = color[0]; - offset4 += COM_NUM_CHANNELS_COLOR; - offset++; - if (isBraked()) { - breaked = true; - } - } - offset += add; - offset4 += add * COM_NUM_CHANNELS_COLOR; - } -} - -void CompositorOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - int width = this->m_rd->xsch * this->m_rd->size / 100; - int height = this->m_rd->ysch * this->m_rd->size / 100; - - // check actual render resolution with cropping it may differ with cropped border.rendering - // FIX for: [31777] Border Crop gives black (easy) - Render *re = RE_GetSceneRender(this->m_scene); - if (re) { - RenderResult *rr = RE_AcquireResultRead(re); - if (rr) { - width = rr->rectx; - height = rr->recty; - } - RE_ReleaseResult(re); - } - - preferredResolution[0] = width; - preferredResolution[1] = height; - - NodeOperation::determineResolution(resolution, preferredResolution); - - resolution[0] = width; - resolution[1] = height; -} diff --git a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc new file mode 100644 index 00000000000..44468e04ae9 --- /dev/null +++ b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc @@ -0,0 +1,50 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ConvertColorProfileOperation.h" + +#include "IMB_imbuf.h" + +ConvertColorProfileOperation::ConvertColorProfileOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputOperation = nullptr; + this->m_predivided = false; +} + +void ConvertColorProfileOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); +} + +void ConvertColorProfileOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float color[4]; + this->m_inputOperation->readSampled(color, x, y, sampler); + IMB_buffer_float_from_float( + output, color, 4, this->m_toProfile, this->m_fromProfile, this->m_predivided, 1, 1, 0, 0); +} + +void ConvertColorProfileOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; +} diff --git a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp deleted file mode 100644 index 44468e04ae9..00000000000 --- a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ConvertColorProfileOperation.h" - -#include "IMB_imbuf.h" - -ConvertColorProfileOperation::ConvertColorProfileOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputOperation = nullptr; - this->m_predivided = false; -} - -void ConvertColorProfileOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertColorProfileOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float color[4]; - this->m_inputOperation->readSampled(color, x, y, sampler); - IMB_buffer_float_from_float( - output, color, 4, this->m_toProfile, this->m_fromProfile, this->m_predivided, 1, 1, 0, 0); -} - -void ConvertColorProfileOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; -} diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc new file mode 100644 index 00000000000..abf423cc48a --- /dev/null +++ b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc @@ -0,0 +1,115 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ConvertDepthToRadiusOperation.h" +#include "BKE_camera.h" +#include "BLI_math.h" +#include "DNA_camera_types.h" + +ConvertDepthToRadiusOperation::ConvertDepthToRadiusOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->m_inputOperation = nullptr; + this->m_fStop = 128.0f; + this->m_cameraObject = nullptr; + this->m_maxRadius = 32.0f; + this->m_blurPostOperation = nullptr; +} + +float ConvertDepthToRadiusOperation::determineFocalDistance() +{ + if (this->m_cameraObject && this->m_cameraObject->type == OB_CAMERA) { + Camera *camera = (Camera *)this->m_cameraObject->data; + this->m_cam_lens = camera->lens; + return BKE_camera_object_dof_distance(this->m_cameraObject); + } + + return 10.0f; +} + +void ConvertDepthToRadiusOperation::initExecution() +{ + float cam_sensor = DEFAULT_SENSOR_WIDTH; + Camera *camera = nullptr; + + if (this->m_cameraObject && this->m_cameraObject->type == OB_CAMERA) { + camera = (Camera *)this->m_cameraObject->data; + cam_sensor = BKE_camera_sensor_size(camera->sensor_fit, camera->sensor_x, camera->sensor_y); + } + + this->m_inputOperation = this->getInputSocketReader(0); + float focalDistance = determineFocalDistance(); + if (focalDistance == 0.0f) { + focalDistance = 1e10f; /* if the dof is 0.0 then set it to be far away */ + } + this->m_inverseFocalDistance = 1.0f / focalDistance; + this->m_aspect = (this->getWidth() > this->getHeight()) ? + (this->getHeight() / (float)this->getWidth()) : + (this->getWidth() / (float)this->getHeight()); + this->m_aperture = 0.5f * (this->m_cam_lens / (this->m_aspect * cam_sensor)) / this->m_fStop; + const float minsz = MIN2(getWidth(), getHeight()); + this->m_dof_sp = minsz / + ((cam_sensor / 2.0f) / + this->m_cam_lens); // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov); + + if (this->m_blurPostOperation) { + m_blurPostOperation->setSigma(MIN2(m_aperture * 128.0f, this->m_maxRadius)); + } +} + +void ConvertDepthToRadiusOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue[4]; + float z; + float radius; + this->m_inputOperation->readSampled(inputValue, x, y, sampler); + z = inputValue[0]; + if (z != 0.0f) { + float iZ = (1.0f / z); + + /* bug T6656 part 2b, do not re-scale. */ +#if 0 + bcrad = 0.5f * fabs(aperture * (dof_sp * (cam_invfdist - iZ) - 1.0f)); + // scale crad back to original maximum and blend + crad->rect[px] = bcrad + wts->rect[px] * (scf * crad->rect[px] - bcrad); +#endif + radius = 0.5f * fabsf(this->m_aperture * + (this->m_dof_sp * (this->m_inverseFocalDistance - iZ) - 1.0f)); + /* 'bug' T6615, limit minimum radius to 1 pixel, + * not really a solution, but somewhat mitigates the problem. */ + if (radius < 0.0f) { + radius = 0.0f; + } + if (radius > this->m_maxRadius) { + radius = this->m_maxRadius; + } + output[0] = radius; + } + else { + output[0] = 0.0f; + } +} + +void ConvertDepthToRadiusOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; +} diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp deleted file mode 100644 index abf423cc48a..00000000000 --- a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ConvertDepthToRadiusOperation.h" -#include "BKE_camera.h" -#include "BLI_math.h" -#include "DNA_camera_types.h" - -ConvertDepthToRadiusOperation::ConvertDepthToRadiusOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputOperation = nullptr; - this->m_fStop = 128.0f; - this->m_cameraObject = nullptr; - this->m_maxRadius = 32.0f; - this->m_blurPostOperation = nullptr; -} - -float ConvertDepthToRadiusOperation::determineFocalDistance() -{ - if (this->m_cameraObject && this->m_cameraObject->type == OB_CAMERA) { - Camera *camera = (Camera *)this->m_cameraObject->data; - this->m_cam_lens = camera->lens; - return BKE_camera_object_dof_distance(this->m_cameraObject); - } - - return 10.0f; -} - -void ConvertDepthToRadiusOperation::initExecution() -{ - float cam_sensor = DEFAULT_SENSOR_WIDTH; - Camera *camera = nullptr; - - if (this->m_cameraObject && this->m_cameraObject->type == OB_CAMERA) { - camera = (Camera *)this->m_cameraObject->data; - cam_sensor = BKE_camera_sensor_size(camera->sensor_fit, camera->sensor_x, camera->sensor_y); - } - - this->m_inputOperation = this->getInputSocketReader(0); - float focalDistance = determineFocalDistance(); - if (focalDistance == 0.0f) { - focalDistance = 1e10f; /* if the dof is 0.0 then set it to be far away */ - } - this->m_inverseFocalDistance = 1.0f / focalDistance; - this->m_aspect = (this->getWidth() > this->getHeight()) ? - (this->getHeight() / (float)this->getWidth()) : - (this->getWidth() / (float)this->getHeight()); - this->m_aperture = 0.5f * (this->m_cam_lens / (this->m_aspect * cam_sensor)) / this->m_fStop; - const float minsz = MIN2(getWidth(), getHeight()); - this->m_dof_sp = minsz / - ((cam_sensor / 2.0f) / - this->m_cam_lens); // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov); - - if (this->m_blurPostOperation) { - m_blurPostOperation->setSigma(MIN2(m_aperture * 128.0f, this->m_maxRadius)); - } -} - -void ConvertDepthToRadiusOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue[4]; - float z; - float radius; - this->m_inputOperation->readSampled(inputValue, x, y, sampler); - z = inputValue[0]; - if (z != 0.0f) { - float iZ = (1.0f / z); - - /* bug T6656 part 2b, do not re-scale. */ -#if 0 - bcrad = 0.5f * fabs(aperture * (dof_sp * (cam_invfdist - iZ) - 1.0f)); - // scale crad back to original maximum and blend - crad->rect[px] = bcrad + wts->rect[px] * (scf * crad->rect[px] - bcrad); -#endif - radius = 0.5f * fabsf(this->m_aperture * - (this->m_dof_sp * (this->m_inverseFocalDistance - iZ) - 1.0f)); - /* 'bug' T6615, limit minimum radius to 1 pixel, - * not really a solution, but somewhat mitigates the problem. */ - if (radius < 0.0f) { - radius = 0.0f; - } - if (radius > this->m_maxRadius) { - radius = this->m_maxRadius; - } - output[0] = radius; - } - else { - output[0] = 0.0f; - } -} - -void ConvertDepthToRadiusOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; -} diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cc b/source/blender/compositor/operations/COM_ConvertOperation.cc new file mode 100644 index 00000000000..cccfd407752 --- /dev/null +++ b/source/blender/compositor/operations/COM_ConvertOperation.cc @@ -0,0 +1,480 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ConvertOperation.h" + +#include "IMB_colormanagement.h" + +ConvertBaseOperation::ConvertBaseOperation() +{ + this->m_inputOperation = nullptr; +} + +void ConvertBaseOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); +} + +void ConvertBaseOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; +} + +/* ******** Value to Color ******** */ + +ConvertValueToColorOperation::ConvertValueToColorOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertValueToColorOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float value; + this->m_inputOperation->readSampled(&value, x, y, sampler); + output[0] = output[1] = output[2] = value; + output[3] = 1.0f; +} + +/* ******** Color to Value ******** */ + +ConvertColorToValueOperation::ConvertColorToValueOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_VALUE); +} + +void ConvertColorToValueOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->readSampled(inputColor, x, y, sampler); + output[0] = (inputColor[0] + inputColor[1] + inputColor[2]) / 3.0f; +} + +/* ******** Color to BW ******** */ + +ConvertColorToBWOperation::ConvertColorToBWOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_VALUE); +} + +void ConvertColorToBWOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->readSampled(inputColor, x, y, sampler); + output[0] = IMB_colormanagement_get_luminance(inputColor); +} + +/* ******** Color to Vector ******** */ + +ConvertColorToVectorOperation::ConvertColorToVectorOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_VECTOR); +} + +void ConvertColorToVectorOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float color[4]; + this->m_inputOperation->readSampled(color, x, y, sampler); + copy_v3_v3(output, color); +} + +/* ******** Value to Vector ******** */ + +ConvertValueToVectorOperation::ConvertValueToVectorOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VECTOR); +} + +void ConvertValueToVectorOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float value; + this->m_inputOperation->readSampled(&value, x, y, sampler); + output[0] = output[1] = output[2] = value; +} + +/* ******** Vector to Color ******** */ + +ConvertVectorToColorOperation::ConvertVectorToColorOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_VECTOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertVectorToColorOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + this->m_inputOperation->readSampled(output, x, y, sampler); + output[3] = 1.0f; +} + +/* ******** Vector to Value ******** */ + +ConvertVectorToValueOperation::ConvertVectorToValueOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_VECTOR); + this->addOutputSocket(COM_DT_VALUE); +} + +void ConvertVectorToValueOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float input[4]; + this->m_inputOperation->readSampled(input, x, y, sampler); + output[0] = (input[0] + input[1] + input[2]) / 3.0f; +} + +/* ******** RGB to YCC ******** */ + +ConvertRGBToYCCOperation::ConvertRGBToYCCOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertRGBToYCCOperation::setMode(int mode) +{ + switch (mode) { + case 0: + this->m_mode = BLI_YCC_ITU_BT601; + break; + case 2: + this->m_mode = BLI_YCC_JFIF_0_255; + break; + case 1: + default: + this->m_mode = BLI_YCC_ITU_BT709; + break; + } +} + +void ConvertRGBToYCCOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + float color[3]; + + this->m_inputOperation->readSampled(inputColor, x, y, sampler); + rgb_to_ycc( + inputColor[0], inputColor[1], inputColor[2], &color[0], &color[1], &color[2], this->m_mode); + + /* divided by 255 to normalize for viewing in */ + /* R,G,B --> Y,Cb,Cr */ + mul_v3_v3fl(output, color, 1.0f / 255.0f); + output[3] = inputColor[3]; +} + +/* ******** YCC to RGB ******** */ + +ConvertYCCToRGBOperation::ConvertYCCToRGBOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertYCCToRGBOperation::setMode(int mode) +{ + switch (mode) { + case 0: + this->m_mode = BLI_YCC_ITU_BT601; + break; + case 2: + this->m_mode = BLI_YCC_JFIF_0_255; + break; + case 1: + default: + this->m_mode = BLI_YCC_ITU_BT709; + break; + } +} + +void ConvertYCCToRGBOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->readSampled(inputColor, x, y, sampler); + + /* need to un-normalize the data */ + /* R,G,B --> Y,Cb,Cr */ + mul_v3_fl(inputColor, 255.0f); + + ycc_to_rgb(inputColor[0], + inputColor[1], + inputColor[2], + &output[0], + &output[1], + &output[2], + this->m_mode); + output[3] = inputColor[3]; +} + +/* ******** RGB to YUV ******** */ + +ConvertRGBToYUVOperation::ConvertRGBToYUVOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertRGBToYUVOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->readSampled(inputColor, x, y, sampler); + rgb_to_yuv(inputColor[0], + inputColor[1], + inputColor[2], + &output[0], + &output[1], + &output[2], + BLI_YUV_ITU_BT709); + output[3] = inputColor[3]; +} + +/* ******** YUV to RGB ******** */ + +ConvertYUVToRGBOperation::ConvertYUVToRGBOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertYUVToRGBOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->readSampled(inputColor, x, y, sampler); + yuv_to_rgb(inputColor[0], + inputColor[1], + inputColor[2], + &output[0], + &output[1], + &output[2], + BLI_YUV_ITU_BT709); + output[3] = inputColor[3]; +} + +/* ******** RGB to HSV ******** */ + +ConvertRGBToHSVOperation::ConvertRGBToHSVOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertRGBToHSVOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->readSampled(inputColor, x, y, sampler); + rgb_to_hsv_v(inputColor, output); + output[3] = inputColor[3]; +} + +/* ******** HSV to RGB ******** */ + +ConvertHSVToRGBOperation::ConvertHSVToRGBOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertHSVToRGBOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->readSampled(inputColor, x, y, sampler); + hsv_to_rgb_v(inputColor, output); + output[0] = max_ff(output[0], 0.0f); + output[1] = max_ff(output[1], 0.0f); + output[2] = max_ff(output[2], 0.0f); + output[3] = inputColor[3]; +} + +/* ******** Premul to Straight ******** */ + +ConvertPremulToStraightOperation::ConvertPremulToStraightOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertPremulToStraightOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue[4]; + float alpha; + + this->m_inputOperation->readSampled(inputValue, x, y, sampler); + alpha = inputValue[3]; + + if (fabsf(alpha) < 1e-5f) { + zero_v3(output); + } + else { + mul_v3_v3fl(output, inputValue, 1.0f / alpha); + } + + /* never touches the alpha */ + output[3] = alpha; +} + +/* ******** Straight to Premul ******** */ + +ConvertStraightToPremulOperation::ConvertStraightToPremulOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertStraightToPremulOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue[4]; + float alpha; + + this->m_inputOperation->readSampled(inputValue, x, y, sampler); + alpha = inputValue[3]; + + mul_v3_v3fl(output, inputValue, alpha); + + /* never touches the alpha */ + output[3] = alpha; +} + +/* ******** Separate Channels ******** */ + +SeparateChannelOperation::SeparateChannelOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_VALUE); + this->m_inputOperation = nullptr; +} +void SeparateChannelOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); +} + +void SeparateChannelOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; +} + +void SeparateChannelOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float input[4]; + this->m_inputOperation->readSampled(input, x, y, sampler); + output[0] = input[this->m_channel]; +} + +/* ******** Combine Channels ******** */ + +CombineChannelsOperation::CombineChannelsOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + this->m_inputChannel1Operation = nullptr; + this->m_inputChannel2Operation = nullptr; + this->m_inputChannel3Operation = nullptr; + this->m_inputChannel4Operation = nullptr; +} + +void CombineChannelsOperation::initExecution() +{ + this->m_inputChannel1Operation = this->getInputSocketReader(0); + this->m_inputChannel2Operation = this->getInputSocketReader(1); + this->m_inputChannel3Operation = this->getInputSocketReader(2); + this->m_inputChannel4Operation = this->getInputSocketReader(3); +} + +void CombineChannelsOperation::deinitExecution() +{ + this->m_inputChannel1Operation = nullptr; + this->m_inputChannel2Operation = nullptr; + this->m_inputChannel3Operation = nullptr; + this->m_inputChannel4Operation = nullptr; +} + +void CombineChannelsOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float input[4]; + if (this->m_inputChannel1Operation) { + this->m_inputChannel1Operation->readSampled(input, x, y, sampler); + output[0] = input[0]; + } + if (this->m_inputChannel2Operation) { + this->m_inputChannel2Operation->readSampled(input, x, y, sampler); + output[1] = input[0]; + } + if (this->m_inputChannel3Operation) { + this->m_inputChannel3Operation->readSampled(input, x, y, sampler); + output[2] = input[0]; + } + if (this->m_inputChannel4Operation) { + this->m_inputChannel4Operation->readSampled(input, x, y, sampler); + output[3] = input[0]; + } +} diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cpp b/source/blender/compositor/operations/COM_ConvertOperation.cpp deleted file mode 100644 index cccfd407752..00000000000 --- a/source/blender/compositor/operations/COM_ConvertOperation.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ConvertOperation.h" - -#include "IMB_colormanagement.h" - -ConvertBaseOperation::ConvertBaseOperation() -{ - this->m_inputOperation = nullptr; -} - -void ConvertBaseOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertBaseOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; -} - -/* ******** Value to Color ******** */ - -ConvertValueToColorOperation::ConvertValueToColorOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); -} - -void ConvertValueToColorOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float value; - this->m_inputOperation->readSampled(&value, x, y, sampler); - output[0] = output[1] = output[2] = value; - output[3] = 1.0f; -} - -/* ******** Color to Value ******** */ - -ConvertColorToValueOperation::ConvertColorToValueOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_VALUE); -} - -void ConvertColorToValueOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->readSampled(inputColor, x, y, sampler); - output[0] = (inputColor[0] + inputColor[1] + inputColor[2]) / 3.0f; -} - -/* ******** Color to BW ******** */ - -ConvertColorToBWOperation::ConvertColorToBWOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_VALUE); -} - -void ConvertColorToBWOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->readSampled(inputColor, x, y, sampler); - output[0] = IMB_colormanagement_get_luminance(inputColor); -} - -/* ******** Color to Vector ******** */ - -ConvertColorToVectorOperation::ConvertColorToVectorOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_VECTOR); -} - -void ConvertColorToVectorOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float color[4]; - this->m_inputOperation->readSampled(color, x, y, sampler); - copy_v3_v3(output, color); -} - -/* ******** Value to Vector ******** */ - -ConvertValueToVectorOperation::ConvertValueToVectorOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VECTOR); -} - -void ConvertValueToVectorOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float value; - this->m_inputOperation->readSampled(&value, x, y, sampler); - output[0] = output[1] = output[2] = value; -} - -/* ******** Vector to Color ******** */ - -ConvertVectorToColorOperation::ConvertVectorToColorOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_VECTOR); - this->addOutputSocket(COM_DT_COLOR); -} - -void ConvertVectorToColorOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - this->m_inputOperation->readSampled(output, x, y, sampler); - output[3] = 1.0f; -} - -/* ******** Vector to Value ******** */ - -ConvertVectorToValueOperation::ConvertVectorToValueOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_VECTOR); - this->addOutputSocket(COM_DT_VALUE); -} - -void ConvertVectorToValueOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float input[4]; - this->m_inputOperation->readSampled(input, x, y, sampler); - output[0] = (input[0] + input[1] + input[2]) / 3.0f; -} - -/* ******** RGB to YCC ******** */ - -ConvertRGBToYCCOperation::ConvertRGBToYCCOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); -} - -void ConvertRGBToYCCOperation::setMode(int mode) -{ - switch (mode) { - case 0: - this->m_mode = BLI_YCC_ITU_BT601; - break; - case 2: - this->m_mode = BLI_YCC_JFIF_0_255; - break; - case 1: - default: - this->m_mode = BLI_YCC_ITU_BT709; - break; - } -} - -void ConvertRGBToYCCOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - float color[3]; - - this->m_inputOperation->readSampled(inputColor, x, y, sampler); - rgb_to_ycc( - inputColor[0], inputColor[1], inputColor[2], &color[0], &color[1], &color[2], this->m_mode); - - /* divided by 255 to normalize for viewing in */ - /* R,G,B --> Y,Cb,Cr */ - mul_v3_v3fl(output, color, 1.0f / 255.0f); - output[3] = inputColor[3]; -} - -/* ******** YCC to RGB ******** */ - -ConvertYCCToRGBOperation::ConvertYCCToRGBOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); -} - -void ConvertYCCToRGBOperation::setMode(int mode) -{ - switch (mode) { - case 0: - this->m_mode = BLI_YCC_ITU_BT601; - break; - case 2: - this->m_mode = BLI_YCC_JFIF_0_255; - break; - case 1: - default: - this->m_mode = BLI_YCC_ITU_BT709; - break; - } -} - -void ConvertYCCToRGBOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->readSampled(inputColor, x, y, sampler); - - /* need to un-normalize the data */ - /* R,G,B --> Y,Cb,Cr */ - mul_v3_fl(inputColor, 255.0f); - - ycc_to_rgb(inputColor[0], - inputColor[1], - inputColor[2], - &output[0], - &output[1], - &output[2], - this->m_mode); - output[3] = inputColor[3]; -} - -/* ******** RGB to YUV ******** */ - -ConvertRGBToYUVOperation::ConvertRGBToYUVOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); -} - -void ConvertRGBToYUVOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->readSampled(inputColor, x, y, sampler); - rgb_to_yuv(inputColor[0], - inputColor[1], - inputColor[2], - &output[0], - &output[1], - &output[2], - BLI_YUV_ITU_BT709); - output[3] = inputColor[3]; -} - -/* ******** YUV to RGB ******** */ - -ConvertYUVToRGBOperation::ConvertYUVToRGBOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); -} - -void ConvertYUVToRGBOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->readSampled(inputColor, x, y, sampler); - yuv_to_rgb(inputColor[0], - inputColor[1], - inputColor[2], - &output[0], - &output[1], - &output[2], - BLI_YUV_ITU_BT709); - output[3] = inputColor[3]; -} - -/* ******** RGB to HSV ******** */ - -ConvertRGBToHSVOperation::ConvertRGBToHSVOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); -} - -void ConvertRGBToHSVOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->readSampled(inputColor, x, y, sampler); - rgb_to_hsv_v(inputColor, output); - output[3] = inputColor[3]; -} - -/* ******** HSV to RGB ******** */ - -ConvertHSVToRGBOperation::ConvertHSVToRGBOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); -} - -void ConvertHSVToRGBOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->readSampled(inputColor, x, y, sampler); - hsv_to_rgb_v(inputColor, output); - output[0] = max_ff(output[0], 0.0f); - output[1] = max_ff(output[1], 0.0f); - output[2] = max_ff(output[2], 0.0f); - output[3] = inputColor[3]; -} - -/* ******** Premul to Straight ******** */ - -ConvertPremulToStraightOperation::ConvertPremulToStraightOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); -} - -void ConvertPremulToStraightOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue[4]; - float alpha; - - this->m_inputOperation->readSampled(inputValue, x, y, sampler); - alpha = inputValue[3]; - - if (fabsf(alpha) < 1e-5f) { - zero_v3(output); - } - else { - mul_v3_v3fl(output, inputValue, 1.0f / alpha); - } - - /* never touches the alpha */ - output[3] = alpha; -} - -/* ******** Straight to Premul ******** */ - -ConvertStraightToPremulOperation::ConvertStraightToPremulOperation() : ConvertBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); -} - -void ConvertStraightToPremulOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue[4]; - float alpha; - - this->m_inputOperation->readSampled(inputValue, x, y, sampler); - alpha = inputValue[3]; - - mul_v3_v3fl(output, inputValue, alpha); - - /* never touches the alpha */ - output[3] = alpha; -} - -/* ******** Separate Channels ******** */ - -SeparateChannelOperation::SeparateChannelOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputOperation = nullptr; -} -void SeparateChannelOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void SeparateChannelOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; -} - -void SeparateChannelOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float input[4]; - this->m_inputOperation->readSampled(input, x, y, sampler); - output[0] = input[this->m_channel]; -} - -/* ******** Combine Channels ******** */ - -CombineChannelsOperation::CombineChannelsOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_inputChannel1Operation = nullptr; - this->m_inputChannel2Operation = nullptr; - this->m_inputChannel3Operation = nullptr; - this->m_inputChannel4Operation = nullptr; -} - -void CombineChannelsOperation::initExecution() -{ - this->m_inputChannel1Operation = this->getInputSocketReader(0); - this->m_inputChannel2Operation = this->getInputSocketReader(1); - this->m_inputChannel3Operation = this->getInputSocketReader(2); - this->m_inputChannel4Operation = this->getInputSocketReader(3); -} - -void CombineChannelsOperation::deinitExecution() -{ - this->m_inputChannel1Operation = nullptr; - this->m_inputChannel2Operation = nullptr; - this->m_inputChannel3Operation = nullptr; - this->m_inputChannel4Operation = nullptr; -} - -void CombineChannelsOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float input[4]; - if (this->m_inputChannel1Operation) { - this->m_inputChannel1Operation->readSampled(input, x, y, sampler); - output[0] = input[0]; - } - if (this->m_inputChannel2Operation) { - this->m_inputChannel2Operation->readSampled(input, x, y, sampler); - output[1] = input[0]; - } - if (this->m_inputChannel3Operation) { - this->m_inputChannel3Operation->readSampled(input, x, y, sampler); - output[2] = input[0]; - } - if (this->m_inputChannel4Operation) { - this->m_inputChannel4Operation->readSampled(input, x, y, sampler); - output[3] = input[0]; - } -} diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc new file mode 100644 index 00000000000..a5f2ae404e3 --- /dev/null +++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc @@ -0,0 +1,99 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ConvolutionEdgeFilterOperation.h" +#include "BLI_math.h" + +ConvolutionEdgeFilterOperation::ConvolutionEdgeFilterOperation() +{ + /* pass */ +} + +void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/) +{ + float in1[4], in2[4], res1[4] = {0.0}, res2[4] = {0.0}; + + int x1 = x - 1; + int x2 = x; + int x3 = x + 1; + int y1 = y - 1; + int y2 = y; + int y3 = y + 1; + CLAMP(x1, 0, getWidth() - 1); + CLAMP(x2, 0, getWidth() - 1); + CLAMP(x3, 0, getWidth() - 1); + CLAMP(y1, 0, getHeight() - 1); + CLAMP(y2, 0, getHeight() - 1); + CLAMP(y3, 0, getHeight() - 1); + + float value[4]; + this->m_inputValueOperation->read(value, x2, y2, nullptr); + float mval = 1.0f - value[0]; + + this->m_inputOperation->read(in1, x1, y1, nullptr); + madd_v3_v3fl(res1, in1, this->m_filter[0]); + madd_v3_v3fl(res2, in1, this->m_filter[0]); + + this->m_inputOperation->read(in1, x2, y1, nullptr); + madd_v3_v3fl(res1, in1, this->m_filter[1]); + madd_v3_v3fl(res2, in1, this->m_filter[3]); + + this->m_inputOperation->read(in1, x3, y1, nullptr); + madd_v3_v3fl(res1, in1, this->m_filter[2]); + madd_v3_v3fl(res2, in1, this->m_filter[6]); + + this->m_inputOperation->read(in1, x1, y2, nullptr); + madd_v3_v3fl(res1, in1, this->m_filter[3]); + madd_v3_v3fl(res2, in1, this->m_filter[1]); + + this->m_inputOperation->read(in2, x2, y2, nullptr); + madd_v3_v3fl(res1, in2, this->m_filter[4]); + madd_v3_v3fl(res2, in2, this->m_filter[4]); + + this->m_inputOperation->read(in1, x3, y2, nullptr); + madd_v3_v3fl(res1, in1, this->m_filter[5]); + madd_v3_v3fl(res2, in1, this->m_filter[7]); + + this->m_inputOperation->read(in1, x1, y3, nullptr); + madd_v3_v3fl(res1, in1, this->m_filter[6]); + madd_v3_v3fl(res2, in1, this->m_filter[2]); + + this->m_inputOperation->read(in1, x2, y3, nullptr); + madd_v3_v3fl(res1, in1, this->m_filter[7]); + madd_v3_v3fl(res2, in1, this->m_filter[5]); + + this->m_inputOperation->read(in1, x3, y3, nullptr); + madd_v3_v3fl(res1, in1, this->m_filter[8]); + madd_v3_v3fl(res2, in1, this->m_filter[8]); + + output[0] = sqrt(res1[0] * res1[0] + res2[0] * res2[0]); + output[1] = sqrt(res1[1] * res1[1] + res2[1] * res2[1]); + output[2] = sqrt(res1[2] * res1[2] + res2[2] * res2[2]); + + output[0] = output[0] * value[0] + in2[0] * mval; + output[1] = output[1] * value[0] + in2[1] * mval; + output[2] = output[2] * value[0] + in2[2] * mval; + + output[3] = in2[3]; + + /* Make sure we don't return negative color. */ + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); + output[3] = MAX2(output[3], 0.0f); +} diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp deleted file mode 100644 index a5f2ae404e3..00000000000 --- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ConvolutionEdgeFilterOperation.h" -#include "BLI_math.h" - -ConvolutionEdgeFilterOperation::ConvolutionEdgeFilterOperation() -{ - /* pass */ -} - -void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/) -{ - float in1[4], in2[4], res1[4] = {0.0}, res2[4] = {0.0}; - - int x1 = x - 1; - int x2 = x; - int x3 = x + 1; - int y1 = y - 1; - int y2 = y; - int y3 = y + 1; - CLAMP(x1, 0, getWidth() - 1); - CLAMP(x2, 0, getWidth() - 1); - CLAMP(x3, 0, getWidth() - 1); - CLAMP(y1, 0, getHeight() - 1); - CLAMP(y2, 0, getHeight() - 1); - CLAMP(y3, 0, getHeight() - 1); - - float value[4]; - this->m_inputValueOperation->read(value, x2, y2, nullptr); - float mval = 1.0f - value[0]; - - this->m_inputOperation->read(in1, x1, y1, nullptr); - madd_v3_v3fl(res1, in1, this->m_filter[0]); - madd_v3_v3fl(res2, in1, this->m_filter[0]); - - this->m_inputOperation->read(in1, x2, y1, nullptr); - madd_v3_v3fl(res1, in1, this->m_filter[1]); - madd_v3_v3fl(res2, in1, this->m_filter[3]); - - this->m_inputOperation->read(in1, x3, y1, nullptr); - madd_v3_v3fl(res1, in1, this->m_filter[2]); - madd_v3_v3fl(res2, in1, this->m_filter[6]); - - this->m_inputOperation->read(in1, x1, y2, nullptr); - madd_v3_v3fl(res1, in1, this->m_filter[3]); - madd_v3_v3fl(res2, in1, this->m_filter[1]); - - this->m_inputOperation->read(in2, x2, y2, nullptr); - madd_v3_v3fl(res1, in2, this->m_filter[4]); - madd_v3_v3fl(res2, in2, this->m_filter[4]); - - this->m_inputOperation->read(in1, x3, y2, nullptr); - madd_v3_v3fl(res1, in1, this->m_filter[5]); - madd_v3_v3fl(res2, in1, this->m_filter[7]); - - this->m_inputOperation->read(in1, x1, y3, nullptr); - madd_v3_v3fl(res1, in1, this->m_filter[6]); - madd_v3_v3fl(res2, in1, this->m_filter[2]); - - this->m_inputOperation->read(in1, x2, y3, nullptr); - madd_v3_v3fl(res1, in1, this->m_filter[7]); - madd_v3_v3fl(res2, in1, this->m_filter[5]); - - this->m_inputOperation->read(in1, x3, y3, nullptr); - madd_v3_v3fl(res1, in1, this->m_filter[8]); - madd_v3_v3fl(res2, in1, this->m_filter[8]); - - output[0] = sqrt(res1[0] * res1[0] + res2[0] * res2[0]); - output[1] = sqrt(res1[1] * res1[1] + res2[1] * res2[1]); - output[2] = sqrt(res1[2] * res1[2] + res2[2] * res2[2]); - - output[0] = output[0] * value[0] + in2[0] * mval; - output[1] = output[1] * value[0] + in2[1] * mval; - output[2] = output[2] * value[0] + in2[2] * mval; - - output[3] = in2[3]; - - /* Make sure we don't return negative color. */ - output[0] = MAX2(output[0], 0.0f); - output[1] = MAX2(output[1], 0.0f); - output[2] = MAX2(output[2], 0.0f); - output[3] = MAX2(output[3], 0.0f); -} diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc new file mode 100644 index 00000000000..425e87ffa7e --- /dev/null +++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc @@ -0,0 +1,126 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ConvolutionFilterOperation.h" + +#include "BLI_utildefines.h" + +#include "MEM_guardedalloc.h" + +ConvolutionFilterOperation::ConvolutionFilterOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + this->m_inputOperation = nullptr; + this->setComplex(true); +} +void ConvolutionFilterOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); + this->m_inputValueOperation = this->getInputSocketReader(1); +} + +void ConvolutionFilterOperation::set3x3Filter( + float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9) +{ + this->m_filter[0] = f1; + this->m_filter[1] = f2; + this->m_filter[2] = f3; + this->m_filter[3] = f4; + this->m_filter[4] = f5; + this->m_filter[5] = f6; + this->m_filter[6] = f7; + this->m_filter[7] = f8; + this->m_filter[8] = f9; + this->m_filterHeight = 3; + this->m_filterWidth = 3; +} + +void ConvolutionFilterOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; + this->m_inputValueOperation = nullptr; +} + +void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/) +{ + float in1[4]; + float in2[4]; + int x1 = x - 1; + int x2 = x; + int x3 = x + 1; + int y1 = y - 1; + int y2 = y; + int y3 = y + 1; + CLAMP(x1, 0, getWidth() - 1); + CLAMP(x2, 0, getWidth() - 1); + CLAMP(x3, 0, getWidth() - 1); + CLAMP(y1, 0, getHeight() - 1); + CLAMP(y2, 0, getHeight() - 1); + CLAMP(y3, 0, getHeight() - 1); + float value[4]; + this->m_inputValueOperation->read(value, x2, y2, nullptr); + const float mval = 1.0f - value[0]; + + zero_v4(output); + this->m_inputOperation->read(in1, x1, y1, nullptr); + madd_v4_v4fl(output, in1, this->m_filter[0]); + this->m_inputOperation->read(in1, x2, y1, nullptr); + madd_v4_v4fl(output, in1, this->m_filter[1]); + this->m_inputOperation->read(in1, x3, y1, nullptr); + madd_v4_v4fl(output, in1, this->m_filter[2]); + this->m_inputOperation->read(in1, x1, y2, nullptr); + madd_v4_v4fl(output, in1, this->m_filter[3]); + this->m_inputOperation->read(in2, x2, y2, nullptr); + madd_v4_v4fl(output, in2, this->m_filter[4]); + this->m_inputOperation->read(in1, x3, y2, nullptr); + madd_v4_v4fl(output, in1, this->m_filter[5]); + this->m_inputOperation->read(in1, x1, y3, nullptr); + madd_v4_v4fl(output, in1, this->m_filter[6]); + this->m_inputOperation->read(in1, x2, y3, nullptr); + madd_v4_v4fl(output, in1, this->m_filter[7]); + this->m_inputOperation->read(in1, x3, y3, nullptr); + madd_v4_v4fl(output, in1, this->m_filter[8]); + + output[0] = output[0] * value[0] + in2[0] * mval; + output[1] = output[1] * value[0] + in2[1] * mval; + output[2] = output[2] * value[0] + in2[2] * mval; + output[3] = output[3] * value[0] + in2[3] * mval; + + /* Make sure we don't return negative color. */ + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); + output[3] = MAX2(output[3], 0.0f); +} + +bool ConvolutionFilterOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + int addx = (this->m_filterWidth - 1) / 2 + 1; + int addy = (this->m_filterHeight - 1) / 2 + 1; + newInput.xmax = input->xmax + addx; + newInput.xmin = input->xmin - addx; + newInput.ymax = input->ymax + addy; + newInput.ymin = input->ymin - addy; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp deleted file mode 100644 index 425e87ffa7e..00000000000 --- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ConvolutionFilterOperation.h" - -#include "BLI_utildefines.h" - -#include "MEM_guardedalloc.h" - -ConvolutionFilterOperation::ConvolutionFilterOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = nullptr; - this->setComplex(true); -} -void ConvolutionFilterOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); - this->m_inputValueOperation = this->getInputSocketReader(1); -} - -void ConvolutionFilterOperation::set3x3Filter( - float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9) -{ - this->m_filter[0] = f1; - this->m_filter[1] = f2; - this->m_filter[2] = f3; - this->m_filter[3] = f4; - this->m_filter[4] = f5; - this->m_filter[5] = f6; - this->m_filter[6] = f7; - this->m_filter[7] = f8; - this->m_filter[8] = f9; - this->m_filterHeight = 3; - this->m_filterWidth = 3; -} - -void ConvolutionFilterOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; - this->m_inputValueOperation = nullptr; -} - -void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/) -{ - float in1[4]; - float in2[4]; - int x1 = x - 1; - int x2 = x; - int x3 = x + 1; - int y1 = y - 1; - int y2 = y; - int y3 = y + 1; - CLAMP(x1, 0, getWidth() - 1); - CLAMP(x2, 0, getWidth() - 1); - CLAMP(x3, 0, getWidth() - 1); - CLAMP(y1, 0, getHeight() - 1); - CLAMP(y2, 0, getHeight() - 1); - CLAMP(y3, 0, getHeight() - 1); - float value[4]; - this->m_inputValueOperation->read(value, x2, y2, nullptr); - const float mval = 1.0f - value[0]; - - zero_v4(output); - this->m_inputOperation->read(in1, x1, y1, nullptr); - madd_v4_v4fl(output, in1, this->m_filter[0]); - this->m_inputOperation->read(in1, x2, y1, nullptr); - madd_v4_v4fl(output, in1, this->m_filter[1]); - this->m_inputOperation->read(in1, x3, y1, nullptr); - madd_v4_v4fl(output, in1, this->m_filter[2]); - this->m_inputOperation->read(in1, x1, y2, nullptr); - madd_v4_v4fl(output, in1, this->m_filter[3]); - this->m_inputOperation->read(in2, x2, y2, nullptr); - madd_v4_v4fl(output, in2, this->m_filter[4]); - this->m_inputOperation->read(in1, x3, y2, nullptr); - madd_v4_v4fl(output, in1, this->m_filter[5]); - this->m_inputOperation->read(in1, x1, y3, nullptr); - madd_v4_v4fl(output, in1, this->m_filter[6]); - this->m_inputOperation->read(in1, x2, y3, nullptr); - madd_v4_v4fl(output, in1, this->m_filter[7]); - this->m_inputOperation->read(in1, x3, y3, nullptr); - madd_v4_v4fl(output, in1, this->m_filter[8]); - - output[0] = output[0] * value[0] + in2[0] * mval; - output[1] = output[1] * value[0] + in2[1] * mval; - output[2] = output[2] * value[0] + in2[2] * mval; - output[3] = output[3] * value[0] + in2[3] * mval; - - /* Make sure we don't return negative color. */ - output[0] = MAX2(output[0], 0.0f); - output[1] = MAX2(output[1], 0.0f); - output[2] = MAX2(output[2], 0.0f); - output[3] = MAX2(output[3], 0.0f); -} - -bool ConvolutionFilterOperation::determineDependingAreaOfInterest( - rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInput; - int addx = (this->m_filterWidth - 1) / 2 + 1; - int addy = (this->m_filterHeight - 1) / 2 + 1; - newInput.xmax = input->xmax + addx; - newInput.xmin = input->xmin - addx; - newInput.ymax = input->ymax + addy; - newInput.ymin = input->ymin - addy; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_CropOperation.cc b/source/blender/compositor/operations/COM_CropOperation.cc new file mode 100644 index 00000000000..9364557169c --- /dev/null +++ b/source/blender/compositor/operations/COM_CropOperation.cc @@ -0,0 +1,135 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_CropOperation.h" +#include "BLI_math.h" + +CropBaseOperation::CropBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputOperation = nullptr; + this->m_settings = nullptr; +} + +void CropBaseOperation::updateArea() +{ + SocketReader *inputReference = this->getInputSocketReader(0); + float width = inputReference->getWidth(); + float height = inputReference->getHeight(); + NodeTwoXYs local_settings = *this->m_settings; + + if (width > 0.0f && height > 0.0f) { + if (this->m_relative) { + local_settings.x1 = width * local_settings.fac_x1; + local_settings.x2 = width * local_settings.fac_x2; + local_settings.y1 = height * local_settings.fac_y1; + local_settings.y2 = height * local_settings.fac_y2; + } + if (width <= local_settings.x1 + 1) { + local_settings.x1 = width - 1; + } + if (height <= local_settings.y1 + 1) { + local_settings.y1 = height - 1; + } + if (width <= local_settings.x2 + 1) { + local_settings.x2 = width - 1; + } + if (height <= local_settings.y2 + 1) { + local_settings.y2 = height - 1; + } + + this->m_xmax = MAX2(local_settings.x1, local_settings.x2) + 1; + this->m_xmin = MIN2(local_settings.x1, local_settings.x2); + this->m_ymax = MAX2(local_settings.y1, local_settings.y2) + 1; + this->m_ymin = MIN2(local_settings.y1, local_settings.y2); + } + else { + this->m_xmax = 0; + this->m_xmin = 0; + this->m_ymax = 0; + this->m_ymin = 0; + } +} + +void CropBaseOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); + updateArea(); +} + +void CropBaseOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; +} + +CropOperation::CropOperation() : CropBaseOperation() +{ + /* pass */ +} + +void CropOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + if ((x < this->m_xmax && x >= this->m_xmin) && (y < this->m_ymax && y >= this->m_ymin)) { + this->m_inputOperation->readSampled(output, x, y, sampler); + } + else { + zero_v4(output); + } +} + +CropImageOperation::CropImageOperation() : CropBaseOperation() +{ + /* pass */ +} + +bool CropImageOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + + newInput.xmax = input->xmax + this->m_xmin; + newInput.xmin = input->xmin + this->m_xmin; + newInput.ymax = input->ymax + this->m_ymin; + newInput.ymin = input->ymin + this->m_ymin; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +void CropImageOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + NodeOperation::determineResolution(resolution, preferredResolution); + updateArea(); + resolution[0] = this->m_xmax - this->m_xmin; + resolution[1] = this->m_ymax - this->m_ymin; +} + +void CropImageOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) { + this->m_inputOperation->readSampled(output, (x + this->m_xmin), (y + this->m_ymin), sampler); + } + else { + zero_v4(output); + } +} diff --git a/source/blender/compositor/operations/COM_CropOperation.cpp b/source/blender/compositor/operations/COM_CropOperation.cpp deleted file mode 100644 index 9364557169c..00000000000 --- a/source/blender/compositor/operations/COM_CropOperation.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_CropOperation.h" -#include "BLI_math.h" - -CropBaseOperation::CropBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputOperation = nullptr; - this->m_settings = nullptr; -} - -void CropBaseOperation::updateArea() -{ - SocketReader *inputReference = this->getInputSocketReader(0); - float width = inputReference->getWidth(); - float height = inputReference->getHeight(); - NodeTwoXYs local_settings = *this->m_settings; - - if (width > 0.0f && height > 0.0f) { - if (this->m_relative) { - local_settings.x1 = width * local_settings.fac_x1; - local_settings.x2 = width * local_settings.fac_x2; - local_settings.y1 = height * local_settings.fac_y1; - local_settings.y2 = height * local_settings.fac_y2; - } - if (width <= local_settings.x1 + 1) { - local_settings.x1 = width - 1; - } - if (height <= local_settings.y1 + 1) { - local_settings.y1 = height - 1; - } - if (width <= local_settings.x2 + 1) { - local_settings.x2 = width - 1; - } - if (height <= local_settings.y2 + 1) { - local_settings.y2 = height - 1; - } - - this->m_xmax = MAX2(local_settings.x1, local_settings.x2) + 1; - this->m_xmin = MIN2(local_settings.x1, local_settings.x2); - this->m_ymax = MAX2(local_settings.y1, local_settings.y2) + 1; - this->m_ymin = MIN2(local_settings.y1, local_settings.y2); - } - else { - this->m_xmax = 0; - this->m_xmin = 0; - this->m_ymax = 0; - this->m_ymin = 0; - } -} - -void CropBaseOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); - updateArea(); -} - -void CropBaseOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; -} - -CropOperation::CropOperation() : CropBaseOperation() -{ - /* pass */ -} - -void CropOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - if ((x < this->m_xmax && x >= this->m_xmin) && (y < this->m_ymax && y >= this->m_ymin)) { - this->m_inputOperation->readSampled(output, x, y, sampler); - } - else { - zero_v4(output); - } -} - -CropImageOperation::CropImageOperation() : CropBaseOperation() -{ - /* pass */ -} - -bool CropImageOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - - newInput.xmax = input->xmax + this->m_xmin; - newInput.xmin = input->xmin + this->m_xmin; - newInput.ymax = input->ymax + this->m_ymin; - newInput.ymin = input->ymin + this->m_ymin; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -void CropImageOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - NodeOperation::determineResolution(resolution, preferredResolution); - updateArea(); - resolution[0] = this->m_xmax - this->m_xmin; - resolution[1] = this->m_ymax - this->m_ymin; -} - -void CropImageOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) { - this->m_inputOperation->readSampled(output, (x + this->m_xmin), (y + this->m_ymin), sampler); - } - else { - zero_v4(output); - } -} diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.cc b/source/blender/compositor/operations/COM_CryptomatteOperation.cc new file mode 100644 index 00000000000..ccd291697cf --- /dev/null +++ b/source/blender/compositor/operations/COM_CryptomatteOperation.cc @@ -0,0 +1,70 @@ +/* + * 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. + * + * Copyright 2018, Blender Foundation. + */ + +#include "COM_CryptomatteOperation.h" + +CryptomatteOperation::CryptomatteOperation(size_t num_inputs) +{ + for (size_t i = 0; i < num_inputs; i++) { + this->addInputSocket(COM_DT_COLOR); + } + inputs.resize(num_inputs); + this->addOutputSocket(COM_DT_COLOR); + this->setComplex(true); +} + +void CryptomatteOperation::initExecution() +{ + for (size_t i = 0; i < inputs.size(); i++) { + inputs[i] = this->getInputSocketReader(i); + } +} + +void CryptomatteOperation::addObjectIndex(float objectIndex) +{ + if (objectIndex != 0.0f) { + m_objectIndex.push_back(objectIndex); + } +} + +void CryptomatteOperation::executePixel(float output[4], int x, int y, void *data) +{ + float input[4]; + output[0] = output[1] = output[2] = output[3] = 0.0f; + for (size_t i = 0; i < inputs.size(); i++) { + inputs[i]->read(input, x, y, data); + if (i == 0) { + /* Write the front-most object as false color for picking. */ + output[0] = input[0]; + uint32_t m3hash; + ::memcpy(&m3hash, &input[0], sizeof(uint32_t)); + /* Since the red channel is likely to be out of display range, + * setting green and blue gives more meaningful images. */ + output[1] = ((float)((m3hash << 8)) / (float)UINT32_MAX); + output[2] = ((float)((m3hash << 16)) / (float)UINT32_MAX); + } + for (size_t i = 0; i < m_objectIndex.size(); i++) { + if (m_objectIndex[i] == input[0]) { + output[3] += input[1]; + } + if (m_objectIndex[i] == input[2]) { + output[3] += input[3]; + } + } + } +} diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.cpp b/source/blender/compositor/operations/COM_CryptomatteOperation.cpp deleted file mode 100644 index ccd291697cf..00000000000 --- a/source/blender/compositor/operations/COM_CryptomatteOperation.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - * - * Copyright 2018, Blender Foundation. - */ - -#include "COM_CryptomatteOperation.h" - -CryptomatteOperation::CryptomatteOperation(size_t num_inputs) -{ - for (size_t i = 0; i < num_inputs; i++) { - this->addInputSocket(COM_DT_COLOR); - } - inputs.resize(num_inputs); - this->addOutputSocket(COM_DT_COLOR); - this->setComplex(true); -} - -void CryptomatteOperation::initExecution() -{ - for (size_t i = 0; i < inputs.size(); i++) { - inputs[i] = this->getInputSocketReader(i); - } -} - -void CryptomatteOperation::addObjectIndex(float objectIndex) -{ - if (objectIndex != 0.0f) { - m_objectIndex.push_back(objectIndex); - } -} - -void CryptomatteOperation::executePixel(float output[4], int x, int y, void *data) -{ - float input[4]; - output[0] = output[1] = output[2] = output[3] = 0.0f; - for (size_t i = 0; i < inputs.size(); i++) { - inputs[i]->read(input, x, y, data); - if (i == 0) { - /* Write the front-most object as false color for picking. */ - output[0] = input[0]; - uint32_t m3hash; - ::memcpy(&m3hash, &input[0], sizeof(uint32_t)); - /* Since the red channel is likely to be out of display range, - * setting green and blue gives more meaningful images. */ - output[1] = ((float)((m3hash << 8)) / (float)UINT32_MAX); - output[2] = ((float)((m3hash << 16)) / (float)UINT32_MAX); - } - for (size_t i = 0; i < m_objectIndex.size(); i++) { - if (m_objectIndex[i] == input[0]) { - output[3] += input[1]; - } - if (m_objectIndex[i] == input[2]) { - output[3] += input[3]; - } - } - } -} diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.cc b/source/blender/compositor/operations/COM_CurveBaseOperation.cc new file mode 100644 index 00000000000..b58efcf0cca --- /dev/null +++ b/source/blender/compositor/operations/COM_CurveBaseOperation.cc @@ -0,0 +1,55 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_CurveBaseOperation.h" + +#include "BKE_colortools.h" + +CurveBaseOperation::CurveBaseOperation() +{ + this->m_curveMapping = nullptr; +} + +CurveBaseOperation::~CurveBaseOperation() +{ + if (this->m_curveMapping) { + BKE_curvemapping_free(this->m_curveMapping); + this->m_curveMapping = nullptr; + } +} + +void CurveBaseOperation::initExecution() +{ + BKE_curvemapping_init(this->m_curveMapping); +} +void CurveBaseOperation::deinitExecution() +{ + if (this->m_curveMapping) { + BKE_curvemapping_free(this->m_curveMapping); + this->m_curveMapping = nullptr; + } +} + +void CurveBaseOperation::setCurveMapping(CurveMapping *mapping) +{ + /* duplicate the curve to avoid glitches while drawing, see bug T32374. */ + if (this->m_curveMapping) { + BKE_curvemapping_free(this->m_curveMapping); + } + this->m_curveMapping = BKE_curvemapping_copy(mapping); +} diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp b/source/blender/compositor/operations/COM_CurveBaseOperation.cpp deleted file mode 100644 index b58efcf0cca..00000000000 --- a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_CurveBaseOperation.h" - -#include "BKE_colortools.h" - -CurveBaseOperation::CurveBaseOperation() -{ - this->m_curveMapping = nullptr; -} - -CurveBaseOperation::~CurveBaseOperation() -{ - if (this->m_curveMapping) { - BKE_curvemapping_free(this->m_curveMapping); - this->m_curveMapping = nullptr; - } -} - -void CurveBaseOperation::initExecution() -{ - BKE_curvemapping_init(this->m_curveMapping); -} -void CurveBaseOperation::deinitExecution() -{ - if (this->m_curveMapping) { - BKE_curvemapping_free(this->m_curveMapping); - this->m_curveMapping = nullptr; - } -} - -void CurveBaseOperation::setCurveMapping(CurveMapping *mapping) -{ - /* duplicate the curve to avoid glitches while drawing, see bug T32374. */ - if (this->m_curveMapping) { - BKE_curvemapping_free(this->m_curveMapping); - } - this->m_curveMapping = BKE_curvemapping_copy(mapping); -} diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cc b/source/blender/compositor/operations/COM_DenoiseOperation.cc new file mode 100644 index 00000000000..d08f238c4c1 --- /dev/null +++ b/source/blender/compositor/operations/COM_DenoiseOperation.cc @@ -0,0 +1,166 @@ +/* + * 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. + * + * Copyright 2019, Blender Foundation. + */ + +#include "COM_DenoiseOperation.h" +#include "BLI_math.h" +#include "BLI_system.h" +#ifdef WITH_OPENIMAGEDENOISE +# include "BLI_threads.h" +# include +static pthread_mutex_t oidn_lock = BLI_MUTEX_INITIALIZER; +#endif +#include + +DenoiseOperation::DenoiseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VECTOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_settings = nullptr; +} +void DenoiseOperation::initExecution() +{ + SingleThreadedOperation::initExecution(); + this->m_inputProgramColor = getInputSocketReader(0); + this->m_inputProgramNormal = getInputSocketReader(1); + this->m_inputProgramAlbedo = getInputSocketReader(2); +} + +void DenoiseOperation::deinitExecution() +{ + this->m_inputProgramColor = nullptr; + this->m_inputProgramNormal = nullptr; + this->m_inputProgramAlbedo = nullptr; + SingleThreadedOperation::deinitExecution(); +} + +MemoryBuffer *DenoiseOperation::createMemoryBuffer(rcti *rect2) +{ + MemoryBuffer *tileColor = (MemoryBuffer *)this->m_inputProgramColor->initializeTileData(rect2); + MemoryBuffer *tileNormal = (MemoryBuffer *)this->m_inputProgramNormal->initializeTileData(rect2); + MemoryBuffer *tileAlbedo = (MemoryBuffer *)this->m_inputProgramAlbedo->initializeTileData(rect2); + rcti rect; + rect.xmin = 0; + rect.ymin = 0; + rect.xmax = getWidth(); + rect.ymax = getHeight(); + MemoryBuffer *result = new MemoryBuffer(COM_DT_COLOR, &rect); + float *data = result->getBuffer(); + this->generateDenoise(data, tileColor, tileNormal, tileAlbedo, this->m_settings); + return result; +} + +bool DenoiseOperation::determineDependingAreaOfInterest(rcti * /*input*/, + ReadBufferOperation *readOperation, + rcti *output) +{ + if (isCached()) { + return false; + } + + rcti newInput; + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +void DenoiseOperation::generateDenoise(float *data, + MemoryBuffer *inputTileColor, + MemoryBuffer *inputTileNormal, + MemoryBuffer *inputTileAlbedo, + NodeDenoise *settings) +{ + float *inputBufferColor = inputTileColor->getBuffer(); + BLI_assert(inputBufferColor); + if (!inputBufferColor) { + return; + } +#ifdef WITH_OPENIMAGEDENOISE + /* Always supported through Accelerate framework BNNS on macOS. */ +# ifndef __APPLE__ + if (BLI_cpu_support_sse41()) +# endif + { + oidn::DeviceRef device = oidn::newDevice(); + device.commit(); + + oidn::FilterRef filter = device.newFilter("RT"); + filter.setImage("color", + inputBufferColor, + oidn::Format::Float3, + inputTileColor->getWidth(), + inputTileColor->getHeight(), + 0, + sizeof(float[4])); + if (inputTileNormal && inputTileNormal->getBuffer()) { + filter.setImage("normal", + inputTileNormal->getBuffer(), + oidn::Format::Float3, + inputTileNormal->getWidth(), + inputTileNormal->getHeight(), + 0, + sizeof(float[3])); + } + if (inputTileAlbedo && inputTileAlbedo->getBuffer()) { + filter.setImage("albedo", + inputTileAlbedo->getBuffer(), + oidn::Format::Float3, + inputTileAlbedo->getWidth(), + inputTileAlbedo->getHeight(), + 0, + sizeof(float[4])); + } + filter.setImage("output", + data, + oidn::Format::Float3, + inputTileColor->getWidth(), + inputTileColor->getHeight(), + 0, + sizeof(float[4])); + + BLI_assert(settings); + if (settings) { + filter.set("hdr", settings->hdr); + filter.set("srgb", false); + } + + filter.commit(); + /* Since it's memory intensive, it's better to run only one instance of OIDN at a time. + * OpenImageDenoise is multithreaded internally and should use all available cores nonetheless. + */ + BLI_mutex_lock(&oidn_lock); + filter.execute(); + BLI_mutex_unlock(&oidn_lock); + + /* copy the alpha channel, OpenImageDenoise currently only supports RGB */ + size_t numPixels = inputTileColor->getWidth() * inputTileColor->getHeight(); + for (size_t i = 0; i < numPixels; i++) { + data[i * 4 + 3] = inputBufferColor[i * 4 + 3]; + } + return; + } +#endif + /* If built without OIDN or running on an unsupported CPU, just pass through. */ + UNUSED_VARS(inputTileAlbedo, inputTileNormal, settings); + ::memcpy(data, + inputBufferColor, + sizeof(float[4]) * inputTileColor->getWidth() * inputTileColor->getHeight()); +} diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cpp b/source/blender/compositor/operations/COM_DenoiseOperation.cpp deleted file mode 100644 index d08f238c4c1..00000000000 --- a/source/blender/compositor/operations/COM_DenoiseOperation.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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. - * - * Copyright 2019, Blender Foundation. - */ - -#include "COM_DenoiseOperation.h" -#include "BLI_math.h" -#include "BLI_system.h" -#ifdef WITH_OPENIMAGEDENOISE -# include "BLI_threads.h" -# include -static pthread_mutex_t oidn_lock = BLI_MUTEX_INITIALIZER; -#endif -#include - -DenoiseOperation::DenoiseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VECTOR); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_settings = nullptr; -} -void DenoiseOperation::initExecution() -{ - SingleThreadedOperation::initExecution(); - this->m_inputProgramColor = getInputSocketReader(0); - this->m_inputProgramNormal = getInputSocketReader(1); - this->m_inputProgramAlbedo = getInputSocketReader(2); -} - -void DenoiseOperation::deinitExecution() -{ - this->m_inputProgramColor = nullptr; - this->m_inputProgramNormal = nullptr; - this->m_inputProgramAlbedo = nullptr; - SingleThreadedOperation::deinitExecution(); -} - -MemoryBuffer *DenoiseOperation::createMemoryBuffer(rcti *rect2) -{ - MemoryBuffer *tileColor = (MemoryBuffer *)this->m_inputProgramColor->initializeTileData(rect2); - MemoryBuffer *tileNormal = (MemoryBuffer *)this->m_inputProgramNormal->initializeTileData(rect2); - MemoryBuffer *tileAlbedo = (MemoryBuffer *)this->m_inputProgramAlbedo->initializeTileData(rect2); - rcti rect; - rect.xmin = 0; - rect.ymin = 0; - rect.xmax = getWidth(); - rect.ymax = getHeight(); - MemoryBuffer *result = new MemoryBuffer(COM_DT_COLOR, &rect); - float *data = result->getBuffer(); - this->generateDenoise(data, tileColor, tileNormal, tileAlbedo, this->m_settings); - return result; -} - -bool DenoiseOperation::determineDependingAreaOfInterest(rcti * /*input*/, - ReadBufferOperation *readOperation, - rcti *output) -{ - if (isCached()) { - return false; - } - - rcti newInput; - newInput.xmax = this->getWidth(); - newInput.xmin = 0; - newInput.ymax = this->getHeight(); - newInput.ymin = 0; - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -void DenoiseOperation::generateDenoise(float *data, - MemoryBuffer *inputTileColor, - MemoryBuffer *inputTileNormal, - MemoryBuffer *inputTileAlbedo, - NodeDenoise *settings) -{ - float *inputBufferColor = inputTileColor->getBuffer(); - BLI_assert(inputBufferColor); - if (!inputBufferColor) { - return; - } -#ifdef WITH_OPENIMAGEDENOISE - /* Always supported through Accelerate framework BNNS on macOS. */ -# ifndef __APPLE__ - if (BLI_cpu_support_sse41()) -# endif - { - oidn::DeviceRef device = oidn::newDevice(); - device.commit(); - - oidn::FilterRef filter = device.newFilter("RT"); - filter.setImage("color", - inputBufferColor, - oidn::Format::Float3, - inputTileColor->getWidth(), - inputTileColor->getHeight(), - 0, - sizeof(float[4])); - if (inputTileNormal && inputTileNormal->getBuffer()) { - filter.setImage("normal", - inputTileNormal->getBuffer(), - oidn::Format::Float3, - inputTileNormal->getWidth(), - inputTileNormal->getHeight(), - 0, - sizeof(float[3])); - } - if (inputTileAlbedo && inputTileAlbedo->getBuffer()) { - filter.setImage("albedo", - inputTileAlbedo->getBuffer(), - oidn::Format::Float3, - inputTileAlbedo->getWidth(), - inputTileAlbedo->getHeight(), - 0, - sizeof(float[4])); - } - filter.setImage("output", - data, - oidn::Format::Float3, - inputTileColor->getWidth(), - inputTileColor->getHeight(), - 0, - sizeof(float[4])); - - BLI_assert(settings); - if (settings) { - filter.set("hdr", settings->hdr); - filter.set("srgb", false); - } - - filter.commit(); - /* Since it's memory intensive, it's better to run only one instance of OIDN at a time. - * OpenImageDenoise is multithreaded internally and should use all available cores nonetheless. - */ - BLI_mutex_lock(&oidn_lock); - filter.execute(); - BLI_mutex_unlock(&oidn_lock); - - /* copy the alpha channel, OpenImageDenoise currently only supports RGB */ - size_t numPixels = inputTileColor->getWidth() * inputTileColor->getHeight(); - for (size_t i = 0; i < numPixels; i++) { - data[i * 4 + 3] = inputBufferColor[i * 4 + 3]; - } - return; - } -#endif - /* If built without OIDN or running on an unsupported CPU, just pass through. */ - UNUSED_VARS(inputTileAlbedo, inputTileNormal, settings); - ::memcpy(data, - inputBufferColor, - sizeof(float[4]) * inputTileColor->getWidth() * inputTileColor->getHeight()); -} diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.cc b/source/blender/compositor/operations/COM_DespeckleOperation.cc new file mode 100644 index 00000000000..901445c6875 --- /dev/null +++ b/source/blender/compositor/operations/COM_DespeckleOperation.cc @@ -0,0 +1,143 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "MEM_guardedalloc.h" + +#include "COM_DespeckleOperation.h" + +#include "BLI_utildefines.h" + +DespeckleOperation::DespeckleOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + this->m_inputOperation = nullptr; + this->setComplex(true); +} +void DespeckleOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); + this->m_inputValueOperation = this->getInputSocketReader(1); +} + +void DespeckleOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; + this->m_inputValueOperation = nullptr; +} + +BLI_INLINE int color_diff(const float a[3], const float b[3], const float threshold) +{ + return ((fabsf(a[0] - b[0]) > threshold) || (fabsf(a[1] - b[1]) > threshold) || + (fabsf(a[2] - b[2]) > threshold)); +} + +void DespeckleOperation::executePixel(float output[4], int x, int y, void * /*data*/) +{ + float w = 0.0f; + float color_org[4]; + float color_mid[4]; + float color_mid_ok[4]; + float in1[4]; + int x1 = x - 1; + int x2 = x; + int x3 = x + 1; + int y1 = y - 1; + int y2 = y; + int y3 = y + 1; + CLAMP(x1, 0, getWidth() - 1); + CLAMP(x2, 0, getWidth() - 1); + CLAMP(x3, 0, getWidth() - 1); + CLAMP(y1, 0, getHeight() - 1); + CLAMP(y2, 0, getHeight() - 1); + CLAMP(y3, 0, getHeight() - 1); + float value[4]; + this->m_inputValueOperation->read(value, x2, y2, nullptr); + // const float mval = 1.0f - value[0]; + + this->m_inputOperation->read(color_org, x2, y2, nullptr); + +#define TOT_DIV_ONE 1.0f +#define TOT_DIV_CNR (float)M_SQRT1_2 + +#define WTOT (TOT_DIV_ONE * 4 + TOT_DIV_CNR * 4) + +#define COLOR_ADD(fac) \ + { \ + madd_v4_v4fl(color_mid, in1, fac); \ + if (color_diff(in1, color_org, this->m_threshold)) { \ + w += fac; \ + madd_v4_v4fl(color_mid_ok, in1, fac); \ + } \ + } + + zero_v4(color_mid); + zero_v4(color_mid_ok); + + this->m_inputOperation->read(in1, x1, y1, nullptr); + COLOR_ADD(TOT_DIV_CNR) + this->m_inputOperation->read(in1, x2, y1, nullptr); + COLOR_ADD(TOT_DIV_ONE) + this->m_inputOperation->read(in1, x3, y1, nullptr); + COLOR_ADD(TOT_DIV_CNR) + this->m_inputOperation->read(in1, x1, y2, nullptr); + COLOR_ADD(TOT_DIV_ONE) + +#if 0 + this->m_inputOperation->read(in2, x2, y2, NULL); + madd_v4_v4fl(color_mid, in2, this->m_filter[4]); +#endif + + this->m_inputOperation->read(in1, x3, y2, nullptr); + COLOR_ADD(TOT_DIV_ONE) + this->m_inputOperation->read(in1, x1, y3, nullptr); + COLOR_ADD(TOT_DIV_CNR) + this->m_inputOperation->read(in1, x2, y3, nullptr); + COLOR_ADD(TOT_DIV_ONE) + this->m_inputOperation->read(in1, x3, y3, nullptr); + COLOR_ADD(TOT_DIV_CNR) + + mul_v4_fl(color_mid, 1.0f / (4.0f + (4.0f * (float)M_SQRT1_2))); + // mul_v4_fl(color_mid, 1.0f / w); + + if ((w != 0.0f) && ((w / WTOT) > (this->m_threshold_neighbor)) && + color_diff(color_mid, color_org, this->m_threshold)) { + mul_v4_fl(color_mid_ok, 1.0f / w); + interp_v4_v4v4(output, color_org, color_mid_ok, value[0]); + } + else { + copy_v4_v4(output, color_org); + } +} + +bool DespeckleOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + int addx = 2; //(this->m_filterWidth - 1) / 2 + 1; + int addy = 2; //(this->m_filterHeight - 1) / 2 + 1; + newInput.xmax = input->xmax + addx; + newInput.xmin = input->xmin - addx; + newInput.ymax = input->ymax + addy; + newInput.ymin = input->ymin - addy; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.cpp b/source/blender/compositor/operations/COM_DespeckleOperation.cpp deleted file mode 100644 index 901445c6875..00000000000 --- a/source/blender/compositor/operations/COM_DespeckleOperation.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "MEM_guardedalloc.h" - -#include "COM_DespeckleOperation.h" - -#include "BLI_utildefines.h" - -DespeckleOperation::DespeckleOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = nullptr; - this->setComplex(true); -} -void DespeckleOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); - this->m_inputValueOperation = this->getInputSocketReader(1); -} - -void DespeckleOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; - this->m_inputValueOperation = nullptr; -} - -BLI_INLINE int color_diff(const float a[3], const float b[3], const float threshold) -{ - return ((fabsf(a[0] - b[0]) > threshold) || (fabsf(a[1] - b[1]) > threshold) || - (fabsf(a[2] - b[2]) > threshold)); -} - -void DespeckleOperation::executePixel(float output[4], int x, int y, void * /*data*/) -{ - float w = 0.0f; - float color_org[4]; - float color_mid[4]; - float color_mid_ok[4]; - float in1[4]; - int x1 = x - 1; - int x2 = x; - int x3 = x + 1; - int y1 = y - 1; - int y2 = y; - int y3 = y + 1; - CLAMP(x1, 0, getWidth() - 1); - CLAMP(x2, 0, getWidth() - 1); - CLAMP(x3, 0, getWidth() - 1); - CLAMP(y1, 0, getHeight() - 1); - CLAMP(y2, 0, getHeight() - 1); - CLAMP(y3, 0, getHeight() - 1); - float value[4]; - this->m_inputValueOperation->read(value, x2, y2, nullptr); - // const float mval = 1.0f - value[0]; - - this->m_inputOperation->read(color_org, x2, y2, nullptr); - -#define TOT_DIV_ONE 1.0f -#define TOT_DIV_CNR (float)M_SQRT1_2 - -#define WTOT (TOT_DIV_ONE * 4 + TOT_DIV_CNR * 4) - -#define COLOR_ADD(fac) \ - { \ - madd_v4_v4fl(color_mid, in1, fac); \ - if (color_diff(in1, color_org, this->m_threshold)) { \ - w += fac; \ - madd_v4_v4fl(color_mid_ok, in1, fac); \ - } \ - } - - zero_v4(color_mid); - zero_v4(color_mid_ok); - - this->m_inputOperation->read(in1, x1, y1, nullptr); - COLOR_ADD(TOT_DIV_CNR) - this->m_inputOperation->read(in1, x2, y1, nullptr); - COLOR_ADD(TOT_DIV_ONE) - this->m_inputOperation->read(in1, x3, y1, nullptr); - COLOR_ADD(TOT_DIV_CNR) - this->m_inputOperation->read(in1, x1, y2, nullptr); - COLOR_ADD(TOT_DIV_ONE) - -#if 0 - this->m_inputOperation->read(in2, x2, y2, NULL); - madd_v4_v4fl(color_mid, in2, this->m_filter[4]); -#endif - - this->m_inputOperation->read(in1, x3, y2, nullptr); - COLOR_ADD(TOT_DIV_ONE) - this->m_inputOperation->read(in1, x1, y3, nullptr); - COLOR_ADD(TOT_DIV_CNR) - this->m_inputOperation->read(in1, x2, y3, nullptr); - COLOR_ADD(TOT_DIV_ONE) - this->m_inputOperation->read(in1, x3, y3, nullptr); - COLOR_ADD(TOT_DIV_CNR) - - mul_v4_fl(color_mid, 1.0f / (4.0f + (4.0f * (float)M_SQRT1_2))); - // mul_v4_fl(color_mid, 1.0f / w); - - if ((w != 0.0f) && ((w / WTOT) > (this->m_threshold_neighbor)) && - color_diff(color_mid, color_org, this->m_threshold)) { - mul_v4_fl(color_mid_ok, 1.0f / w); - interp_v4_v4v4(output, color_org, color_mid_ok, value[0]); - } - else { - copy_v4_v4(output, color_org); - } -} - -bool DespeckleOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - int addx = 2; //(this->m_filterWidth - 1) / 2 + 1; - int addy = 2; //(this->m_filterHeight - 1) / 2 + 1; - newInput.xmax = input->xmax + addx; - newInput.xmin = input->xmin - addx; - newInput.ymax = input->ymax + addy; - newInput.ymin = input->ymin - addy; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc new file mode 100644 index 00000000000..cca99a42c0c --- /dev/null +++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc @@ -0,0 +1,85 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DifferenceMatteOperation.h" +#include "BLI_math.h" + +DifferenceMatteOperation::DifferenceMatteOperation() +{ + addInputSocket(COM_DT_COLOR); + addInputSocket(COM_DT_COLOR); + addOutputSocket(COM_DT_VALUE); + + this->m_inputImage1Program = nullptr; + this->m_inputImage2Program = nullptr; +} + +void DifferenceMatteOperation::initExecution() +{ + this->m_inputImage1Program = this->getInputSocketReader(0); + this->m_inputImage2Program = this->getInputSocketReader(1); +} +void DifferenceMatteOperation::deinitExecution() +{ + this->m_inputImage1Program = nullptr; + this->m_inputImage2Program = nullptr; +} + +void DifferenceMatteOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inColor1[4]; + float inColor2[4]; + + const float tolerance = this->m_settings->t1; + const float falloff = this->m_settings->t2; + float difference; + float alpha; + + this->m_inputImage1Program->readSampled(inColor1, x, y, sampler); + this->m_inputImage2Program->readSampled(inColor2, x, y, sampler); + + difference = (fabsf(inColor2[0] - inColor1[0]) + fabsf(inColor2[1] - inColor1[1]) + + fabsf(inColor2[2] - inColor1[2])); + + /* average together the distances */ + difference = difference / 3.0f; + + /* make 100% transparent */ + if (difference <= tolerance) { + output[0] = 0.0f; + } + /*in the falloff region, make partially transparent */ + else if (difference <= falloff + tolerance) { + difference = difference - tolerance; + alpha = difference / falloff; + /*only change if more transparent than before */ + if (alpha < inColor1[3]) { + output[0] = alpha; + } + else { /* leave as before */ + output[0] = inColor1[3]; + } + } + else { + /* foreground object */ + output[0] = inColor1[3]; + } +} diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp deleted file mode 100644 index cca99a42c0c..00000000000 --- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DifferenceMatteOperation.h" -#include "BLI_math.h" - -DifferenceMatteOperation::DifferenceMatteOperation() -{ - addInputSocket(COM_DT_COLOR); - addInputSocket(COM_DT_COLOR); - addOutputSocket(COM_DT_VALUE); - - this->m_inputImage1Program = nullptr; - this->m_inputImage2Program = nullptr; -} - -void DifferenceMatteOperation::initExecution() -{ - this->m_inputImage1Program = this->getInputSocketReader(0); - this->m_inputImage2Program = this->getInputSocketReader(1); -} -void DifferenceMatteOperation::deinitExecution() -{ - this->m_inputImage1Program = nullptr; - this->m_inputImage2Program = nullptr; -} - -void DifferenceMatteOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inColor1[4]; - float inColor2[4]; - - const float tolerance = this->m_settings->t1; - const float falloff = this->m_settings->t2; - float difference; - float alpha; - - this->m_inputImage1Program->readSampled(inColor1, x, y, sampler); - this->m_inputImage2Program->readSampled(inColor2, x, y, sampler); - - difference = (fabsf(inColor2[0] - inColor1[0]) + fabsf(inColor2[1] - inColor1[1]) + - fabsf(inColor2[2] - inColor1[2])); - - /* average together the distances */ - difference = difference / 3.0f; - - /* make 100% transparent */ - if (difference <= tolerance) { - output[0] = 0.0f; - } - /*in the falloff region, make partially transparent */ - else if (difference <= falloff + tolerance) { - difference = difference - tolerance; - alpha = difference / falloff; - /*only change if more transparent than before */ - if (alpha < inColor1[3]) { - output[0] = alpha; - } - else { /* leave as before */ - output[0] = inColor1[3]; - } - } - else { - /* foreground object */ - output[0] = inColor1[3]; - } -} diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cc b/source/blender/compositor/operations/COM_DilateErodeOperation.cc new file mode 100644 index 00000000000..fbe9fe8ea27 --- /dev/null +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cc @@ -0,0 +1,570 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DilateErodeOperation.h" +#include "BLI_math.h" +#include "COM_OpenCLDevice.h" + +#include "MEM_guardedalloc.h" + +// DilateErode Distance Threshold +DilateErodeThresholdOperation::DilateErodeThresholdOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->setComplex(true); + this->m_inputProgram = nullptr; + this->m_inset = 0.0f; + this->m__switch = 0.5f; + this->m_distance = 0.0f; +} +void DilateErodeThresholdOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); + if (this->m_distance < 0.0f) { + this->m_scope = -this->m_distance + this->m_inset; + } + else { + if (this->m_inset * 2 > this->m_distance) { + this->m_scope = MAX2(this->m_inset * 2 - this->m_distance, this->m_distance); + } + else { + this->m_scope = this->m_distance; + } + } + if (this->m_scope < 3) { + this->m_scope = 3; + } +} + +void *DilateErodeThresholdOperation::initializeTileData(rcti * /*rect*/) +{ + void *buffer = this->m_inputProgram->initializeTileData(nullptr); + return buffer; +} + +void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, void *data) +{ + float inputValue[4]; + const float sw = this->m__switch; + const float distance = this->m_distance; + float pixelvalue; + const float rd = this->m_scope * this->m_scope; + const float inset = this->m_inset; + float mindist = rd * 2; + + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + float *buffer = inputBuffer->getBuffer(); + rcti *rect = inputBuffer->getRect(); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); + const int bufferWidth = BLI_rcti_size_x(rect); + int offset; + + inputBuffer->read(inputValue, x, y); + if (inputValue[0] > sw) { + for (int yi = miny; yi < maxy; yi++) { + const float dy = yi - y; + offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)); + for (int xi = minx; xi < maxx; xi++) { + if (buffer[offset] < sw) { + const float dx = xi - x; + const float dis = dx * dx + dy * dy; + mindist = MIN2(mindist, dis); + } + offset++; + } + } + pixelvalue = -sqrtf(mindist); + } + else { + for (int yi = miny; yi < maxy; yi++) { + const float dy = yi - y; + offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)); + for (int xi = minx; xi < maxx; xi++) { + if (buffer[offset] > sw) { + const float dx = xi - x; + const float dis = dx * dx + dy * dy; + mindist = MIN2(mindist, dis); + } + offset++; + } + } + pixelvalue = sqrtf(mindist); + } + + if (distance > 0.0f) { + const float delta = distance - pixelvalue; + if (delta >= 0.0f) { + if (delta >= inset) { + output[0] = 1.0f; + } + else { + output[0] = delta / inset; + } + } + else { + output[0] = 0.0f; + } + } + else { + const float delta = -distance + pixelvalue; + if (delta < 0.0f) { + if (delta < -inset) { + output[0] = 1.0f; + } + else { + output[0] = (-delta) / inset; + } + } + else { + output[0] = 0.0f; + } + } +} + +void DilateErodeThresholdOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; +} + +bool DilateErodeThresholdOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + + newInput.xmax = input->xmax + this->m_scope; + newInput.xmin = input->xmin - this->m_scope; + newInput.ymax = input->ymax + this->m_scope; + newInput.ymin = input->ymin - this->m_scope; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +// Dilate Distance +DilateDistanceOperation::DilateDistanceOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->setComplex(true); + this->m_inputProgram = nullptr; + this->m_distance = 0.0f; + this->setOpenCL(true); +} +void DilateDistanceOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); + this->m_scope = this->m_distance; + if (this->m_scope < 3) { + this->m_scope = 3; + } +} + +void *DilateDistanceOperation::initializeTileData(rcti * /*rect*/) +{ + void *buffer = this->m_inputProgram->initializeTileData(nullptr); + return buffer; +} + +void DilateDistanceOperation::executePixel(float output[4], int x, int y, void *data) +{ + const float distance = this->m_distance; + const float mindist = distance * distance; + + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + float *buffer = inputBuffer->getBuffer(); + rcti *rect = inputBuffer->getRect(); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); + const int bufferWidth = BLI_rcti_size_x(rect); + int offset; + + float value = 0.0f; + + for (int yi = miny; yi < maxy; yi++) { + const float dy = yi - y; + offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)); + for (int xi = minx; xi < maxx; xi++) { + const float dx = xi - x; + const float dis = dx * dx + dy * dy; + if (dis <= mindist) { + value = MAX2(buffer[offset], value); + } + offset++; + } + } + output[0] = value; +} + +void DilateDistanceOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; +} + +bool DilateDistanceOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + + newInput.xmax = input->xmax + this->m_scope; + newInput.xmin = input->xmin - this->m_scope; + newInput.ymax = input->ymax + this->m_scope; + newInput.ymin = input->ymin - this->m_scope; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device, + MemoryBuffer *outputMemoryBuffer, + cl_mem clOutputBuffer, + MemoryBuffer **inputMemoryBuffers, + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) +{ + cl_kernel dilateKernel = device->COM_clCreateKernel("dilateKernel", nullptr); + + cl_int distanceSquared = this->m_distance * this->m_distance; + cl_int scope = this->m_scope; + + device->COM_clAttachMemoryBufferToKernelParameter( + dilateKernel, 0, 2, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram); + device->COM_clAttachOutputMemoryBufferToKernelParameter(dilateKernel, 1, clOutputBuffer); + device->COM_clAttachMemoryBufferOffsetToKernelParameter(dilateKernel, 3, outputMemoryBuffer); + clSetKernelArg(dilateKernel, 4, sizeof(cl_int), &scope); + clSetKernelArg(dilateKernel, 5, sizeof(cl_int), &distanceSquared); + device->COM_clAttachSizeToKernelParameter(dilateKernel, 6, this); + device->COM_clEnqueueRange(dilateKernel, outputMemoryBuffer, 7, this); +} + +// Erode Distance +ErodeDistanceOperation::ErodeDistanceOperation() : DilateDistanceOperation() +{ + /* pass */ +} + +void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *data) +{ + const float distance = this->m_distance; + const float mindist = distance * distance; + + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + float *buffer = inputBuffer->getBuffer(); + rcti *rect = inputBuffer->getRect(); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); + const int bufferWidth = BLI_rcti_size_x(rect); + int offset; + + float value = 1.0f; + + for (int yi = miny; yi < maxy; yi++) { + const float dy = yi - y; + offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)); + for (int xi = minx; xi < maxx; xi++) { + const float dx = xi - x; + const float dis = dx * dx + dy * dy; + if (dis <= mindist) { + value = MIN2(buffer[offset], value); + } + offset++; + } + } + output[0] = value; +} + +void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device, + MemoryBuffer *outputMemoryBuffer, + cl_mem clOutputBuffer, + MemoryBuffer **inputMemoryBuffers, + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) +{ + cl_kernel erodeKernel = device->COM_clCreateKernel("erodeKernel", nullptr); + + cl_int distanceSquared = this->m_distance * this->m_distance; + cl_int scope = this->m_scope; + + device->COM_clAttachMemoryBufferToKernelParameter( + erodeKernel, 0, 2, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram); + device->COM_clAttachOutputMemoryBufferToKernelParameter(erodeKernel, 1, clOutputBuffer); + device->COM_clAttachMemoryBufferOffsetToKernelParameter(erodeKernel, 3, outputMemoryBuffer); + clSetKernelArg(erodeKernel, 4, sizeof(cl_int), &scope); + clSetKernelArg(erodeKernel, 5, sizeof(cl_int), &distanceSquared); + device->COM_clAttachSizeToKernelParameter(erodeKernel, 6, this); + device->COM_clEnqueueRange(erodeKernel, outputMemoryBuffer, 7, this); +} + +// Dilate step +DilateStepOperation::DilateStepOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->setComplex(true); + this->m_inputProgram = nullptr; +} +void DilateStepOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); +} + +// small helper to pass data from initializeTileData to executePixel +struct tile_info { + rcti rect; + int width; + float *buffer; +}; + +static tile_info *create_cache(int xmin, int xmax, int ymin, int ymax) +{ + tile_info *result = (tile_info *)MEM_mallocN(sizeof(tile_info), "dilate erode tile"); + result->rect.xmin = xmin; + result->rect.xmax = xmax; + result->rect.ymin = ymin; + result->rect.ymax = ymax; + result->width = xmax - xmin; + result->buffer = (float *)MEM_callocN(sizeof(float) * (ymax - ymin) * result->width, + "dilate erode cache"); + return result; +} + +void *DilateStepOperation::initializeTileData(rcti *rect) +{ + MemoryBuffer *tile = (MemoryBuffer *)this->m_inputProgram->initializeTileData(nullptr); + int x, y, i; + int width = tile->getWidth(); + int height = tile->getHeight(); + float *buffer = tile->getBuffer(); + + int half_window = this->m_iterations; + int window = half_window * 2 + 1; + + int xmin = MAX2(0, rect->xmin - half_window); + int ymin = MAX2(0, rect->ymin - half_window); + int xmax = MIN2(width, rect->xmax + half_window); + int ymax = MIN2(height, rect->ymax + half_window); + + int bwidth = rect->xmax - rect->xmin; + int bheight = rect->ymax - rect->ymin; + + // Note: Cache buffer has original tilesize width, but new height. + // We have to calculate the additional rows in the first pass, + // to have valid data available for the second pass. + tile_info *result = create_cache(rect->xmin, rect->xmax, ymin, ymax); + float *rectf = result->buffer; + + // temp holds maxima for every step in the algorithm, buf holds a + // single row or column of input values, padded with FLT_MAX's to + // simplify the logic. + float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); + float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window), + "dilate erode buf"); + + // The following is based on the van Herk/Gil-Werman algorithm for morphology operations. + // first pass, horizontal dilate/erode + for (y = ymin; y < ymax; y++) { + for (x = 0; x < bwidth + 5 * half_window; x++) { + buf[x] = -FLT_MAX; + } + for (x = xmin; x < xmax; x++) { + buf[x - rect->xmin + window - 1] = buffer[(y * width + x)]; + } + + for (i = 0; i < (bwidth + 3 * half_window) / window; i++) { + int start = (i + 1) * window - 1; + + temp[window - 1] = buf[start]; + for (x = 1; x < window; x++) { + temp[window - 1 - x] = MAX2(temp[window - x], buf[start - x]); + temp[window - 1 + x] = MAX2(temp[window + x - 2], buf[start + x]); + } + + start = half_window + (i - 1) * window + 1; + for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) { + rectf[bwidth * (y - ymin) + (start + x)] = MAX2(temp[x], temp[x + window - 1]); + } + } + } + + // second pass, vertical dilate/erode + for (x = 0; x < bwidth; x++) { + for (y = 0; y < bheight + 5 * half_window; y++) { + buf[y] = -FLT_MAX; + } + for (y = ymin; y < ymax; y++) { + buf[y - rect->ymin + window - 1] = rectf[(y - ymin) * bwidth + x]; + } + + for (i = 0; i < (bheight + 3 * half_window) / window; i++) { + int start = (i + 1) * window - 1; + + temp[window - 1] = buf[start]; + for (y = 1; y < window; y++) { + temp[window - 1 - y] = MAX2(temp[window - y], buf[start - y]); + temp[window - 1 + y] = MAX2(temp[window + y - 2], buf[start + y]); + } + + start = half_window + (i - 1) * window + 1; + for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) { + rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MAX2(temp[y], + temp[y + window - 1]); + } + } + } + + MEM_freeN(temp); + MEM_freeN(buf); + + return result; +} + +void DilateStepOperation::executePixel(float output[4], int x, int y, void *data) +{ + tile_info *tile = (tile_info *)data; + int nx = x - tile->rect.xmin; + int ny = y - tile->rect.ymin; + output[0] = tile->buffer[tile->width * ny + nx]; +} + +void DilateStepOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; +} + +void DilateStepOperation::deinitializeTileData(rcti * /*rect*/, void *data) +{ + tile_info *tile = (tile_info *)data; + MEM_freeN(tile->buffer); + MEM_freeN(tile); +} + +bool DilateStepOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + int it = this->m_iterations; + newInput.xmax = input->xmax + it; + newInput.xmin = input->xmin - it; + newInput.ymax = input->ymax + it; + newInput.ymin = input->ymin - it; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +// Erode step +ErodeStepOperation::ErodeStepOperation() : DilateStepOperation() +{ + /* pass */ +} + +void *ErodeStepOperation::initializeTileData(rcti *rect) +{ + MemoryBuffer *tile = (MemoryBuffer *)this->m_inputProgram->initializeTileData(nullptr); + int x, y, i; + int width = tile->getWidth(); + int height = tile->getHeight(); + float *buffer = tile->getBuffer(); + + int half_window = this->m_iterations; + int window = half_window * 2 + 1; + + int xmin = MAX2(0, rect->xmin - half_window); + int ymin = MAX2(0, rect->ymin - half_window); + int xmax = MIN2(width, rect->xmax + half_window); + int ymax = MIN2(height, rect->ymax + half_window); + + int bwidth = rect->xmax - rect->xmin; + int bheight = rect->ymax - rect->ymin; + + // Note: Cache buffer has original tilesize width, but new height. + // We have to calculate the additional rows in the first pass, + // to have valid data available for the second pass. + tile_info *result = create_cache(rect->xmin, rect->xmax, ymin, ymax); + float *rectf = result->buffer; + + // temp holds maxima for every step in the algorithm, buf holds a + // single row or column of input values, padded with FLT_MAX's to + // simplify the logic. + float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); + float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window), + "dilate erode buf"); + + // The following is based on the van Herk/Gil-Werman algorithm for morphology operations. + // first pass, horizontal dilate/erode + for (y = ymin; y < ymax; y++) { + for (x = 0; x < bwidth + 5 * half_window; x++) { + buf[x] = FLT_MAX; + } + for (x = xmin; x < xmax; x++) { + buf[x - rect->xmin + window - 1] = buffer[(y * width + x)]; + } + + for (i = 0; i < (bwidth + 3 * half_window) / window; i++) { + int start = (i + 1) * window - 1; + + temp[window - 1] = buf[start]; + for (x = 1; x < window; x++) { + temp[window - 1 - x] = MIN2(temp[window - x], buf[start - x]); + temp[window - 1 + x] = MIN2(temp[window + x - 2], buf[start + x]); + } + + start = half_window + (i - 1) * window + 1; + for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) { + rectf[bwidth * (y - ymin) + (start + x)] = MIN2(temp[x], temp[x + window - 1]); + } + } + } + + // second pass, vertical dilate/erode + for (x = 0; x < bwidth; x++) { + for (y = 0; y < bheight + 5 * half_window; y++) { + buf[y] = FLT_MAX; + } + for (y = ymin; y < ymax; y++) { + buf[y - rect->ymin + window - 1] = rectf[(y - ymin) * bwidth + x]; + } + + for (i = 0; i < (bheight + 3 * half_window) / window; i++) { + int start = (i + 1) * window - 1; + + temp[window - 1] = buf[start]; + for (y = 1; y < window; y++) { + temp[window - 1 - y] = MIN2(temp[window - y], buf[start - y]); + temp[window - 1 + y] = MIN2(temp[window + y - 2], buf[start + y]); + } + + start = half_window + (i - 1) * window + 1; + for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) { + rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MIN2(temp[y], + temp[y + window - 1]); + } + } + } + + MEM_freeN(temp); + MEM_freeN(buf); + + return result; +} diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp deleted file mode 100644 index fbe9fe8ea27..00000000000 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp +++ /dev/null @@ -1,570 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DilateErodeOperation.h" -#include "BLI_math.h" -#include "COM_OpenCLDevice.h" - -#include "MEM_guardedalloc.h" - -// DilateErode Distance Threshold -DilateErodeThresholdOperation::DilateErodeThresholdOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->setComplex(true); - this->m_inputProgram = nullptr; - this->m_inset = 0.0f; - this->m__switch = 0.5f; - this->m_distance = 0.0f; -} -void DilateErodeThresholdOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); - if (this->m_distance < 0.0f) { - this->m_scope = -this->m_distance + this->m_inset; - } - else { - if (this->m_inset * 2 > this->m_distance) { - this->m_scope = MAX2(this->m_inset * 2 - this->m_distance, this->m_distance); - } - else { - this->m_scope = this->m_distance; - } - } - if (this->m_scope < 3) { - this->m_scope = 3; - } -} - -void *DilateErodeThresholdOperation::initializeTileData(rcti * /*rect*/) -{ - void *buffer = this->m_inputProgram->initializeTileData(nullptr); - return buffer; -} - -void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, void *data) -{ - float inputValue[4]; - const float sw = this->m__switch; - const float distance = this->m_distance; - float pixelvalue; - const float rd = this->m_scope * this->m_scope; - const float inset = this->m_inset; - float mindist = rd * 2; - - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - float *buffer = inputBuffer->getBuffer(); - rcti *rect = inputBuffer->getRect(); - const int minx = MAX2(x - this->m_scope, rect->xmin); - const int miny = MAX2(y - this->m_scope, rect->ymin); - const int maxx = MIN2(x + this->m_scope, rect->xmax); - const int maxy = MIN2(y + this->m_scope, rect->ymax); - const int bufferWidth = BLI_rcti_size_x(rect); - int offset; - - inputBuffer->read(inputValue, x, y); - if (inputValue[0] > sw) { - for (int yi = miny; yi < maxy; yi++) { - const float dy = yi - y; - offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)); - for (int xi = minx; xi < maxx; xi++) { - if (buffer[offset] < sw) { - const float dx = xi - x; - const float dis = dx * dx + dy * dy; - mindist = MIN2(mindist, dis); - } - offset++; - } - } - pixelvalue = -sqrtf(mindist); - } - else { - for (int yi = miny; yi < maxy; yi++) { - const float dy = yi - y; - offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)); - for (int xi = minx; xi < maxx; xi++) { - if (buffer[offset] > sw) { - const float dx = xi - x; - const float dis = dx * dx + dy * dy; - mindist = MIN2(mindist, dis); - } - offset++; - } - } - pixelvalue = sqrtf(mindist); - } - - if (distance > 0.0f) { - const float delta = distance - pixelvalue; - if (delta >= 0.0f) { - if (delta >= inset) { - output[0] = 1.0f; - } - else { - output[0] = delta / inset; - } - } - else { - output[0] = 0.0f; - } - } - else { - const float delta = -distance + pixelvalue; - if (delta < 0.0f) { - if (delta < -inset) { - output[0] = 1.0f; - } - else { - output[0] = (-delta) / inset; - } - } - else { - output[0] = 0.0f; - } - } -} - -void DilateErodeThresholdOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; -} - -bool DilateErodeThresholdOperation::determineDependingAreaOfInterest( - rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInput; - - newInput.xmax = input->xmax + this->m_scope; - newInput.xmin = input->xmin - this->m_scope; - newInput.ymax = input->ymax + this->m_scope; - newInput.ymin = input->ymin - this->m_scope; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -// Dilate Distance -DilateDistanceOperation::DilateDistanceOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->setComplex(true); - this->m_inputProgram = nullptr; - this->m_distance = 0.0f; - this->setOpenCL(true); -} -void DilateDistanceOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); - this->m_scope = this->m_distance; - if (this->m_scope < 3) { - this->m_scope = 3; - } -} - -void *DilateDistanceOperation::initializeTileData(rcti * /*rect*/) -{ - void *buffer = this->m_inputProgram->initializeTileData(nullptr); - return buffer; -} - -void DilateDistanceOperation::executePixel(float output[4], int x, int y, void *data) -{ - const float distance = this->m_distance; - const float mindist = distance * distance; - - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - float *buffer = inputBuffer->getBuffer(); - rcti *rect = inputBuffer->getRect(); - const int minx = MAX2(x - this->m_scope, rect->xmin); - const int miny = MAX2(y - this->m_scope, rect->ymin); - const int maxx = MIN2(x + this->m_scope, rect->xmax); - const int maxy = MIN2(y + this->m_scope, rect->ymax); - const int bufferWidth = BLI_rcti_size_x(rect); - int offset; - - float value = 0.0f; - - for (int yi = miny; yi < maxy; yi++) { - const float dy = yi - y; - offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)); - for (int xi = minx; xi < maxx; xi++) { - const float dx = xi - x; - const float dis = dx * dx + dy * dy; - if (dis <= mindist) { - value = MAX2(buffer[offset], value); - } - offset++; - } - } - output[0] = value; -} - -void DilateDistanceOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; -} - -bool DilateDistanceOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - - newInput.xmax = input->xmax + this->m_scope; - newInput.xmin = input->xmin - this->m_scope; - newInput.ymax = input->ymax + this->m_scope; - newInput.ymin = input->ymin - this->m_scope; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device, - MemoryBuffer *outputMemoryBuffer, - cl_mem clOutputBuffer, - MemoryBuffer **inputMemoryBuffers, - std::list *clMemToCleanUp, - std::list * /*clKernelsToCleanUp*/) -{ - cl_kernel dilateKernel = device->COM_clCreateKernel("dilateKernel", nullptr); - - cl_int distanceSquared = this->m_distance * this->m_distance; - cl_int scope = this->m_scope; - - device->COM_clAttachMemoryBufferToKernelParameter( - dilateKernel, 0, 2, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram); - device->COM_clAttachOutputMemoryBufferToKernelParameter(dilateKernel, 1, clOutputBuffer); - device->COM_clAttachMemoryBufferOffsetToKernelParameter(dilateKernel, 3, outputMemoryBuffer); - clSetKernelArg(dilateKernel, 4, sizeof(cl_int), &scope); - clSetKernelArg(dilateKernel, 5, sizeof(cl_int), &distanceSquared); - device->COM_clAttachSizeToKernelParameter(dilateKernel, 6, this); - device->COM_clEnqueueRange(dilateKernel, outputMemoryBuffer, 7, this); -} - -// Erode Distance -ErodeDistanceOperation::ErodeDistanceOperation() : DilateDistanceOperation() -{ - /* pass */ -} - -void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *data) -{ - const float distance = this->m_distance; - const float mindist = distance * distance; - - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - float *buffer = inputBuffer->getBuffer(); - rcti *rect = inputBuffer->getRect(); - const int minx = MAX2(x - this->m_scope, rect->xmin); - const int miny = MAX2(y - this->m_scope, rect->ymin); - const int maxx = MIN2(x + this->m_scope, rect->xmax); - const int maxy = MIN2(y + this->m_scope, rect->ymax); - const int bufferWidth = BLI_rcti_size_x(rect); - int offset; - - float value = 1.0f; - - for (int yi = miny; yi < maxy; yi++) { - const float dy = yi - y; - offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)); - for (int xi = minx; xi < maxx; xi++) { - const float dx = xi - x; - const float dis = dx * dx + dy * dy; - if (dis <= mindist) { - value = MIN2(buffer[offset], value); - } - offset++; - } - } - output[0] = value; -} - -void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device, - MemoryBuffer *outputMemoryBuffer, - cl_mem clOutputBuffer, - MemoryBuffer **inputMemoryBuffers, - std::list *clMemToCleanUp, - std::list * /*clKernelsToCleanUp*/) -{ - cl_kernel erodeKernel = device->COM_clCreateKernel("erodeKernel", nullptr); - - cl_int distanceSquared = this->m_distance * this->m_distance; - cl_int scope = this->m_scope; - - device->COM_clAttachMemoryBufferToKernelParameter( - erodeKernel, 0, 2, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram); - device->COM_clAttachOutputMemoryBufferToKernelParameter(erodeKernel, 1, clOutputBuffer); - device->COM_clAttachMemoryBufferOffsetToKernelParameter(erodeKernel, 3, outputMemoryBuffer); - clSetKernelArg(erodeKernel, 4, sizeof(cl_int), &scope); - clSetKernelArg(erodeKernel, 5, sizeof(cl_int), &distanceSquared); - device->COM_clAttachSizeToKernelParameter(erodeKernel, 6, this); - device->COM_clEnqueueRange(erodeKernel, outputMemoryBuffer, 7, this); -} - -// Dilate step -DilateStepOperation::DilateStepOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->setComplex(true); - this->m_inputProgram = nullptr; -} -void DilateStepOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); -} - -// small helper to pass data from initializeTileData to executePixel -struct tile_info { - rcti rect; - int width; - float *buffer; -}; - -static tile_info *create_cache(int xmin, int xmax, int ymin, int ymax) -{ - tile_info *result = (tile_info *)MEM_mallocN(sizeof(tile_info), "dilate erode tile"); - result->rect.xmin = xmin; - result->rect.xmax = xmax; - result->rect.ymin = ymin; - result->rect.ymax = ymax; - result->width = xmax - xmin; - result->buffer = (float *)MEM_callocN(sizeof(float) * (ymax - ymin) * result->width, - "dilate erode cache"); - return result; -} - -void *DilateStepOperation::initializeTileData(rcti *rect) -{ - MemoryBuffer *tile = (MemoryBuffer *)this->m_inputProgram->initializeTileData(nullptr); - int x, y, i; - int width = tile->getWidth(); - int height = tile->getHeight(); - float *buffer = tile->getBuffer(); - - int half_window = this->m_iterations; - int window = half_window * 2 + 1; - - int xmin = MAX2(0, rect->xmin - half_window); - int ymin = MAX2(0, rect->ymin - half_window); - int xmax = MIN2(width, rect->xmax + half_window); - int ymax = MIN2(height, rect->ymax + half_window); - - int bwidth = rect->xmax - rect->xmin; - int bheight = rect->ymax - rect->ymin; - - // Note: Cache buffer has original tilesize width, but new height. - // We have to calculate the additional rows in the first pass, - // to have valid data available for the second pass. - tile_info *result = create_cache(rect->xmin, rect->xmax, ymin, ymax); - float *rectf = result->buffer; - - // temp holds maxima for every step in the algorithm, buf holds a - // single row or column of input values, padded with FLT_MAX's to - // simplify the logic. - float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); - float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window), - "dilate erode buf"); - - // The following is based on the van Herk/Gil-Werman algorithm for morphology operations. - // first pass, horizontal dilate/erode - for (y = ymin; y < ymax; y++) { - for (x = 0; x < bwidth + 5 * half_window; x++) { - buf[x] = -FLT_MAX; - } - for (x = xmin; x < xmax; x++) { - buf[x - rect->xmin + window - 1] = buffer[(y * width + x)]; - } - - for (i = 0; i < (bwidth + 3 * half_window) / window; i++) { - int start = (i + 1) * window - 1; - - temp[window - 1] = buf[start]; - for (x = 1; x < window; x++) { - temp[window - 1 - x] = MAX2(temp[window - x], buf[start - x]); - temp[window - 1 + x] = MAX2(temp[window + x - 2], buf[start + x]); - } - - start = half_window + (i - 1) * window + 1; - for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) { - rectf[bwidth * (y - ymin) + (start + x)] = MAX2(temp[x], temp[x + window - 1]); - } - } - } - - // second pass, vertical dilate/erode - for (x = 0; x < bwidth; x++) { - for (y = 0; y < bheight + 5 * half_window; y++) { - buf[y] = -FLT_MAX; - } - for (y = ymin; y < ymax; y++) { - buf[y - rect->ymin + window - 1] = rectf[(y - ymin) * bwidth + x]; - } - - for (i = 0; i < (bheight + 3 * half_window) / window; i++) { - int start = (i + 1) * window - 1; - - temp[window - 1] = buf[start]; - for (y = 1; y < window; y++) { - temp[window - 1 - y] = MAX2(temp[window - y], buf[start - y]); - temp[window - 1 + y] = MAX2(temp[window + y - 2], buf[start + y]); - } - - start = half_window + (i - 1) * window + 1; - for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) { - rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MAX2(temp[y], - temp[y + window - 1]); - } - } - } - - MEM_freeN(temp); - MEM_freeN(buf); - - return result; -} - -void DilateStepOperation::executePixel(float output[4], int x, int y, void *data) -{ - tile_info *tile = (tile_info *)data; - int nx = x - tile->rect.xmin; - int ny = y - tile->rect.ymin; - output[0] = tile->buffer[tile->width * ny + nx]; -} - -void DilateStepOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; -} - -void DilateStepOperation::deinitializeTileData(rcti * /*rect*/, void *data) -{ - tile_info *tile = (tile_info *)data; - MEM_freeN(tile->buffer); - MEM_freeN(tile); -} - -bool DilateStepOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - int it = this->m_iterations; - newInput.xmax = input->xmax + it; - newInput.xmin = input->xmin - it; - newInput.ymax = input->ymax + it; - newInput.ymin = input->ymin - it; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -// Erode step -ErodeStepOperation::ErodeStepOperation() : DilateStepOperation() -{ - /* pass */ -} - -void *ErodeStepOperation::initializeTileData(rcti *rect) -{ - MemoryBuffer *tile = (MemoryBuffer *)this->m_inputProgram->initializeTileData(nullptr); - int x, y, i; - int width = tile->getWidth(); - int height = tile->getHeight(); - float *buffer = tile->getBuffer(); - - int half_window = this->m_iterations; - int window = half_window * 2 + 1; - - int xmin = MAX2(0, rect->xmin - half_window); - int ymin = MAX2(0, rect->ymin - half_window); - int xmax = MIN2(width, rect->xmax + half_window); - int ymax = MIN2(height, rect->ymax + half_window); - - int bwidth = rect->xmax - rect->xmin; - int bheight = rect->ymax - rect->ymin; - - // Note: Cache buffer has original tilesize width, but new height. - // We have to calculate the additional rows in the first pass, - // to have valid data available for the second pass. - tile_info *result = create_cache(rect->xmin, rect->xmax, ymin, ymax); - float *rectf = result->buffer; - - // temp holds maxima for every step in the algorithm, buf holds a - // single row or column of input values, padded with FLT_MAX's to - // simplify the logic. - float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); - float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window), - "dilate erode buf"); - - // The following is based on the van Herk/Gil-Werman algorithm for morphology operations. - // first pass, horizontal dilate/erode - for (y = ymin; y < ymax; y++) { - for (x = 0; x < bwidth + 5 * half_window; x++) { - buf[x] = FLT_MAX; - } - for (x = xmin; x < xmax; x++) { - buf[x - rect->xmin + window - 1] = buffer[(y * width + x)]; - } - - for (i = 0; i < (bwidth + 3 * half_window) / window; i++) { - int start = (i + 1) * window - 1; - - temp[window - 1] = buf[start]; - for (x = 1; x < window; x++) { - temp[window - 1 - x] = MIN2(temp[window - x], buf[start - x]); - temp[window - 1 + x] = MIN2(temp[window + x - 2], buf[start + x]); - } - - start = half_window + (i - 1) * window + 1; - for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) { - rectf[bwidth * (y - ymin) + (start + x)] = MIN2(temp[x], temp[x + window - 1]); - } - } - } - - // second pass, vertical dilate/erode - for (x = 0; x < bwidth; x++) { - for (y = 0; y < bheight + 5 * half_window; y++) { - buf[y] = FLT_MAX; - } - for (y = ymin; y < ymax; y++) { - buf[y - rect->ymin + window - 1] = rectf[(y - ymin) * bwidth + x]; - } - - for (i = 0; i < (bheight + 3 * half_window) / window; i++) { - int start = (i + 1) * window - 1; - - temp[window - 1] = buf[start]; - for (y = 1; y < window; y++) { - temp[window - 1 - y] = MIN2(temp[window - y], buf[start - y]); - temp[window - 1 + y] = MIN2(temp[window + y - 2], buf[start + y]); - } - - start = half_window + (i - 1) * window + 1; - for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) { - rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MIN2(temp[y], - temp[y + window - 1]); - } - } - } - - MEM_freeN(temp); - MEM_freeN(buf); - - return result; -} diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc new file mode 100644 index 00000000000..3f0cd4ef255 --- /dev/null +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc @@ -0,0 +1,146 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DirectionalBlurOperation.h" +#include "COM_OpenCLDevice.h" + +#include "BLI_math.h" + +#include "RE_pipeline.h" + +DirectionalBlurOperation::DirectionalBlurOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->setComplex(true); + + this->setOpenCL(true); + this->m_inputProgram = nullptr; +} + +void DirectionalBlurOperation::initExecution() +{ + this->m_inputProgram = getInputSocketReader(0); + QualityStepHelper::initExecution(COM_QH_INCREASE); + const float angle = this->m_data->angle; + const float zoom = this->m_data->zoom; + const float spin = this->m_data->spin; + const float iterations = this->m_data->iter; + const float distance = this->m_data->distance; + const float center_x = this->m_data->center_x; + const float center_y = this->m_data->center_y; + const float width = getWidth(); + const float height = getHeight(); + + const float a = angle; + const float itsc = 1.0f / powf(2.0f, (float)iterations); + float D; + + D = distance * sqrtf(width * width + height * height); + this->m_center_x_pix = center_x * width; + this->m_center_y_pix = center_y * height; + + this->m_tx = itsc * D * cosf(a); + this->m_ty = -itsc * D * sinf(a); + this->m_sc = itsc * zoom; + this->m_rot = itsc * spin; +} + +void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void * /*data*/) +{ + const int iterations = pow(2.0f, this->m_data->iter); + float col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float col2[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + this->m_inputProgram->readSampled(col2, x, y, COM_PS_BILINEAR); + float ltx = this->m_tx; + float lty = this->m_ty; + float lsc = this->m_sc; + float lrot = this->m_rot; + /* blur the image */ + for (int i = 0; i < iterations; i++) { + const float cs = cosf(lrot), ss = sinf(lrot); + const float isc = 1.0f / (1.0f + lsc); + + const float v = isc * (y - this->m_center_y_pix) + lty; + const float u = isc * (x - this->m_center_x_pix) + ltx; + + this->m_inputProgram->readSampled(col, + cs * u + ss * v + this->m_center_x_pix, + cs * v - ss * u + this->m_center_y_pix, + COM_PS_BILINEAR); + + add_v4_v4(col2, col); + + /* double transformations */ + ltx += this->m_tx; + lty += this->m_ty; + lrot += this->m_rot; + lsc += this->m_sc; + } + + mul_v4_v4fl(output, col2, 1.0f / (iterations + 1)); +} + +void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device, + MemoryBuffer *outputMemoryBuffer, + cl_mem clOutputBuffer, + MemoryBuffer **inputMemoryBuffers, + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) +{ + cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", nullptr); + + cl_int iterations = pow(2.0f, this->m_data->iter); + cl_float2 ltxy = {{this->m_tx, this->m_ty}}; + cl_float2 centerpix = {{this->m_center_x_pix, this->m_center_y_pix}}; + cl_float lsc = this->m_sc; + cl_float lrot = this->m_rot; + + device->COM_clAttachMemoryBufferToKernelParameter( + directionalBlurKernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram); + device->COM_clAttachOutputMemoryBufferToKernelParameter( + directionalBlurKernel, 1, clOutputBuffer); + device->COM_clAttachMemoryBufferOffsetToKernelParameter( + directionalBlurKernel, 2, outputMemoryBuffer); + clSetKernelArg(directionalBlurKernel, 3, sizeof(cl_int), &iterations); + clSetKernelArg(directionalBlurKernel, 4, sizeof(cl_float), &lsc); + clSetKernelArg(directionalBlurKernel, 5, sizeof(cl_float), &lrot); + clSetKernelArg(directionalBlurKernel, 6, sizeof(cl_float2), <xy); + clSetKernelArg(directionalBlurKernel, 7, sizeof(cl_float2), ¢erpix); + + device->COM_clEnqueueRange(directionalBlurKernel, outputMemoryBuffer, 8, this); +} + +void DirectionalBlurOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; +} + +bool DirectionalBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp deleted file mode 100644 index 3f0cd4ef255..00000000000 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DirectionalBlurOperation.h" -#include "COM_OpenCLDevice.h" - -#include "BLI_math.h" - -#include "RE_pipeline.h" - -DirectionalBlurOperation::DirectionalBlurOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->setComplex(true); - - this->setOpenCL(true); - this->m_inputProgram = nullptr; -} - -void DirectionalBlurOperation::initExecution() -{ - this->m_inputProgram = getInputSocketReader(0); - QualityStepHelper::initExecution(COM_QH_INCREASE); - const float angle = this->m_data->angle; - const float zoom = this->m_data->zoom; - const float spin = this->m_data->spin; - const float iterations = this->m_data->iter; - const float distance = this->m_data->distance; - const float center_x = this->m_data->center_x; - const float center_y = this->m_data->center_y; - const float width = getWidth(); - const float height = getHeight(); - - const float a = angle; - const float itsc = 1.0f / powf(2.0f, (float)iterations); - float D; - - D = distance * sqrtf(width * width + height * height); - this->m_center_x_pix = center_x * width; - this->m_center_y_pix = center_y * height; - - this->m_tx = itsc * D * cosf(a); - this->m_ty = -itsc * D * sinf(a); - this->m_sc = itsc * zoom; - this->m_rot = itsc * spin; -} - -void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void * /*data*/) -{ - const int iterations = pow(2.0f, this->m_data->iter); - float col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - float col2[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - this->m_inputProgram->readSampled(col2, x, y, COM_PS_BILINEAR); - float ltx = this->m_tx; - float lty = this->m_ty; - float lsc = this->m_sc; - float lrot = this->m_rot; - /* blur the image */ - for (int i = 0; i < iterations; i++) { - const float cs = cosf(lrot), ss = sinf(lrot); - const float isc = 1.0f / (1.0f + lsc); - - const float v = isc * (y - this->m_center_y_pix) + lty; - const float u = isc * (x - this->m_center_x_pix) + ltx; - - this->m_inputProgram->readSampled(col, - cs * u + ss * v + this->m_center_x_pix, - cs * v - ss * u + this->m_center_y_pix, - COM_PS_BILINEAR); - - add_v4_v4(col2, col); - - /* double transformations */ - ltx += this->m_tx; - lty += this->m_ty; - lrot += this->m_rot; - lsc += this->m_sc; - } - - mul_v4_v4fl(output, col2, 1.0f / (iterations + 1)); -} - -void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device, - MemoryBuffer *outputMemoryBuffer, - cl_mem clOutputBuffer, - MemoryBuffer **inputMemoryBuffers, - std::list *clMemToCleanUp, - std::list * /*clKernelsToCleanUp*/) -{ - cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", nullptr); - - cl_int iterations = pow(2.0f, this->m_data->iter); - cl_float2 ltxy = {{this->m_tx, this->m_ty}}; - cl_float2 centerpix = {{this->m_center_x_pix, this->m_center_y_pix}}; - cl_float lsc = this->m_sc; - cl_float lrot = this->m_rot; - - device->COM_clAttachMemoryBufferToKernelParameter( - directionalBlurKernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram); - device->COM_clAttachOutputMemoryBufferToKernelParameter( - directionalBlurKernel, 1, clOutputBuffer); - device->COM_clAttachMemoryBufferOffsetToKernelParameter( - directionalBlurKernel, 2, outputMemoryBuffer); - clSetKernelArg(directionalBlurKernel, 3, sizeof(cl_int), &iterations); - clSetKernelArg(directionalBlurKernel, 4, sizeof(cl_float), &lsc); - clSetKernelArg(directionalBlurKernel, 5, sizeof(cl_float), &lrot); - clSetKernelArg(directionalBlurKernel, 6, sizeof(cl_float2), <xy); - clSetKernelArg(directionalBlurKernel, 7, sizeof(cl_float2), ¢erpix); - - device->COM_clEnqueueRange(directionalBlurKernel, outputMemoryBuffer, 8, this); -} - -void DirectionalBlurOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; -} - -bool DirectionalBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - - newInput.xmax = this->getWidth(); - newInput.xmin = 0; - newInput.ymax = this->getHeight(); - newInput.ymin = 0; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cc b/source/blender/compositor/operations/COM_DisplaceOperation.cc new file mode 100644 index 00000000000..fcc8bc4670e --- /dev/null +++ b/source/blender/compositor/operations/COM_DisplaceOperation.cc @@ -0,0 +1,194 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DisplaceOperation.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +DisplaceOperation::DisplaceOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VECTOR); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setComplex(true); + + this->m_inputColorProgram = nullptr; + this->m_inputVectorProgram = nullptr; + this->m_inputScaleXProgram = nullptr; + this->m_inputScaleYProgram = nullptr; +} + +void DisplaceOperation::initExecution() +{ + this->m_inputColorProgram = this->getInputSocketReader(0); + this->m_inputVectorProgram = this->getInputSocketReader(1); + this->m_inputScaleXProgram = this->getInputSocketReader(2); + this->m_inputScaleYProgram = this->getInputSocketReader(3); + + this->m_width_x4 = this->getWidth() * 4; + this->m_height_x4 = this->getHeight() * 4; +} + +void DisplaceOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + float xy[2] = {x, y}; + float uv[2], deriv[2][2]; + + pixelTransform(xy, uv, deriv); + if (is_zero_v2(deriv[0]) && is_zero_v2(deriv[1])) { + this->m_inputColorProgram->readSampled(output, uv[0], uv[1], COM_PS_BILINEAR); + } + else { + /* EWA filtering (without nearest it gets blurry with NO distortion) */ + this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]); + } +} + +bool DisplaceOperation::read_displacement( + float x, float y, float xscale, float yscale, const float origin[2], float &r_u, float &r_v) +{ + float width = m_inputVectorProgram->getWidth(); + float height = m_inputVectorProgram->getHeight(); + if (x < 0.0f || x >= width || y < 0.0f || y >= height) { + r_u = 0.0f; + r_v = 0.0f; + return false; + } + + float col[4]; + m_inputVectorProgram->readSampled(col, x, y, COM_PS_BILINEAR); + r_u = origin[0] - col[0] * xscale; + r_v = origin[1] - col[1] * yscale; + return true; +} + +void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2]) +{ + float col[4]; + float uv[2]; /* temporary variables for derivative estimation */ + int num; + + m_inputScaleXProgram->readSampled(col, xy[0], xy[1], COM_PS_NEAREST); + float xs = col[0]; + m_inputScaleYProgram->readSampled(col, xy[0], xy[1], COM_PS_NEAREST); + float ys = col[0]; + /* clamp x and y displacement to triple image resolution - + * to prevent hangs from huge values mistakenly plugged in eg. z buffers */ + CLAMP(xs, -m_width_x4, m_width_x4); + CLAMP(ys, -m_height_x4, m_height_x4); + + /* displaced pixel in uv coords, for image sampling */ + read_displacement(xy[0], xy[1], xs, ys, xy, r_uv[0], r_uv[1]); + + /* Estimate partial derivatives using 1-pixel offsets */ + const float epsilon[2] = {1.0f, 1.0f}; + + zero_v2(r_deriv[0]); + zero_v2(r_deriv[1]); + + num = 0; + if (read_displacement(xy[0] + epsilon[0], xy[1], xs, ys, xy, uv[0], uv[1])) { + r_deriv[0][0] += uv[0] - r_uv[0]; + r_deriv[1][0] += uv[1] - r_uv[1]; + num++; + } + if (read_displacement(xy[0] - epsilon[0], xy[1], xs, ys, xy, uv[0], uv[1])) { + r_deriv[0][0] += r_uv[0] - uv[0]; + r_deriv[1][0] += r_uv[1] - uv[1]; + num++; + } + if (num > 0) { + float numinv = 1.0f / (float)num; + r_deriv[0][0] *= numinv; + r_deriv[1][0] *= numinv; + } + + num = 0; + if (read_displacement(xy[0], xy[1] + epsilon[1], xs, ys, xy, uv[0], uv[1])) { + r_deriv[0][1] += uv[0] - r_uv[0]; + r_deriv[1][1] += uv[1] - r_uv[1]; + num++; + } + if (read_displacement(xy[0], xy[1] - epsilon[1], xs, ys, xy, uv[0], uv[1])) { + r_deriv[0][1] += r_uv[0] - uv[0]; + r_deriv[1][1] += r_uv[1] - uv[1]; + num++; + } + if (num > 0) { + float numinv = 1.0f / (float)num; + r_deriv[0][1] *= numinv; + r_deriv[1][1] *= numinv; + } +} + +void DisplaceOperation::deinitExecution() +{ + this->m_inputColorProgram = nullptr; + this->m_inputVectorProgram = nullptr; + this->m_inputScaleXProgram = nullptr; + this->m_inputScaleYProgram = nullptr; +} + +bool DisplaceOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti colorInput; + rcti vectorInput; + NodeOperation *operation = nullptr; + + /* the vector buffer only needs a 2x2 buffer. The image needs whole buffer */ + /* image */ + operation = getInputOperation(0); + colorInput.xmax = operation->getWidth(); + colorInput.xmin = 0; + colorInput.ymax = operation->getHeight(); + colorInput.ymin = 0; + if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) { + return true; + } + + /* vector */ + operation = getInputOperation(1); + vectorInput.xmax = input->xmax + 1; + vectorInput.xmin = input->xmin - 1; + vectorInput.ymax = input->ymax + 1; + vectorInput.ymin = input->ymin - 1; + if (operation->determineDependingAreaOfInterest(&vectorInput, readOperation, output)) { + return true; + } + + /* scale x */ + operation = getInputOperation(2); + if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { + return true; + } + + /* scale y */ + operation = getInputOperation(3); + if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { + return true; + } + + return false; +} diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cpp b/source/blender/compositor/operations/COM_DisplaceOperation.cpp deleted file mode 100644 index fcc8bc4670e..00000000000 --- a/source/blender/compositor/operations/COM_DisplaceOperation.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DisplaceOperation.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -DisplaceOperation::DisplaceOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VECTOR); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setComplex(true); - - this->m_inputColorProgram = nullptr; - this->m_inputVectorProgram = nullptr; - this->m_inputScaleXProgram = nullptr; - this->m_inputScaleYProgram = nullptr; -} - -void DisplaceOperation::initExecution() -{ - this->m_inputColorProgram = this->getInputSocketReader(0); - this->m_inputVectorProgram = this->getInputSocketReader(1); - this->m_inputScaleXProgram = this->getInputSocketReader(2); - this->m_inputScaleYProgram = this->getInputSocketReader(3); - - this->m_width_x4 = this->getWidth() * 4; - this->m_height_x4 = this->getHeight() * 4; -} - -void DisplaceOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - float xy[2] = {x, y}; - float uv[2], deriv[2][2]; - - pixelTransform(xy, uv, deriv); - if (is_zero_v2(deriv[0]) && is_zero_v2(deriv[1])) { - this->m_inputColorProgram->readSampled(output, uv[0], uv[1], COM_PS_BILINEAR); - } - else { - /* EWA filtering (without nearest it gets blurry with NO distortion) */ - this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]); - } -} - -bool DisplaceOperation::read_displacement( - float x, float y, float xscale, float yscale, const float origin[2], float &r_u, float &r_v) -{ - float width = m_inputVectorProgram->getWidth(); - float height = m_inputVectorProgram->getHeight(); - if (x < 0.0f || x >= width || y < 0.0f || y >= height) { - r_u = 0.0f; - r_v = 0.0f; - return false; - } - - float col[4]; - m_inputVectorProgram->readSampled(col, x, y, COM_PS_BILINEAR); - r_u = origin[0] - col[0] * xscale; - r_v = origin[1] - col[1] * yscale; - return true; -} - -void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2]) -{ - float col[4]; - float uv[2]; /* temporary variables for derivative estimation */ - int num; - - m_inputScaleXProgram->readSampled(col, xy[0], xy[1], COM_PS_NEAREST); - float xs = col[0]; - m_inputScaleYProgram->readSampled(col, xy[0], xy[1], COM_PS_NEAREST); - float ys = col[0]; - /* clamp x and y displacement to triple image resolution - - * to prevent hangs from huge values mistakenly plugged in eg. z buffers */ - CLAMP(xs, -m_width_x4, m_width_x4); - CLAMP(ys, -m_height_x4, m_height_x4); - - /* displaced pixel in uv coords, for image sampling */ - read_displacement(xy[0], xy[1], xs, ys, xy, r_uv[0], r_uv[1]); - - /* Estimate partial derivatives using 1-pixel offsets */ - const float epsilon[2] = {1.0f, 1.0f}; - - zero_v2(r_deriv[0]); - zero_v2(r_deriv[1]); - - num = 0; - if (read_displacement(xy[0] + epsilon[0], xy[1], xs, ys, xy, uv[0], uv[1])) { - r_deriv[0][0] += uv[0] - r_uv[0]; - r_deriv[1][0] += uv[1] - r_uv[1]; - num++; - } - if (read_displacement(xy[0] - epsilon[0], xy[1], xs, ys, xy, uv[0], uv[1])) { - r_deriv[0][0] += r_uv[0] - uv[0]; - r_deriv[1][0] += r_uv[1] - uv[1]; - num++; - } - if (num > 0) { - float numinv = 1.0f / (float)num; - r_deriv[0][0] *= numinv; - r_deriv[1][0] *= numinv; - } - - num = 0; - if (read_displacement(xy[0], xy[1] + epsilon[1], xs, ys, xy, uv[0], uv[1])) { - r_deriv[0][1] += uv[0] - r_uv[0]; - r_deriv[1][1] += uv[1] - r_uv[1]; - num++; - } - if (read_displacement(xy[0], xy[1] - epsilon[1], xs, ys, xy, uv[0], uv[1])) { - r_deriv[0][1] += r_uv[0] - uv[0]; - r_deriv[1][1] += r_uv[1] - uv[1]; - num++; - } - if (num > 0) { - float numinv = 1.0f / (float)num; - r_deriv[0][1] *= numinv; - r_deriv[1][1] *= numinv; - } -} - -void DisplaceOperation::deinitExecution() -{ - this->m_inputColorProgram = nullptr; - this->m_inputVectorProgram = nullptr; - this->m_inputScaleXProgram = nullptr; - this->m_inputScaleYProgram = nullptr; -} - -bool DisplaceOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti colorInput; - rcti vectorInput; - NodeOperation *operation = nullptr; - - /* the vector buffer only needs a 2x2 buffer. The image needs whole buffer */ - /* image */ - operation = getInputOperation(0); - colorInput.xmax = operation->getWidth(); - colorInput.xmin = 0; - colorInput.ymax = operation->getHeight(); - colorInput.ymin = 0; - if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) { - return true; - } - - /* vector */ - operation = getInputOperation(1); - vectorInput.xmax = input->xmax + 1; - vectorInput.xmin = input->xmin - 1; - vectorInput.ymax = input->ymax + 1; - vectorInput.ymin = input->ymin - 1; - if (operation->determineDependingAreaOfInterest(&vectorInput, readOperation, output)) { - return true; - } - - /* scale x */ - operation = getInputOperation(2); - if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { - return true; - } - - /* scale y */ - operation = getInputOperation(3); - if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { - return true; - } - - return false; -} diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc new file mode 100644 index 00000000000..bbc4d63305b --- /dev/null +++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc @@ -0,0 +1,131 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_DisplaceSimpleOperation.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +DisplaceSimpleOperation::DisplaceSimpleOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VECTOR); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + + this->m_inputColorProgram = nullptr; + this->m_inputVectorProgram = nullptr; + this->m_inputScaleXProgram = nullptr; + this->m_inputScaleYProgram = nullptr; +} + +void DisplaceSimpleOperation::initExecution() +{ + this->m_inputColorProgram = this->getInputSocketReader(0); + this->m_inputVectorProgram = this->getInputSocketReader(1); + this->m_inputScaleXProgram = this->getInputSocketReader(2); + this->m_inputScaleYProgram = this->getInputSocketReader(3); + + this->m_width_x4 = this->getWidth() * 4; + this->m_height_x4 = this->getHeight() * 4; +} + +/* minimum distance (in pixels) a pixel has to be displaced + * in order to take effect */ +// #define DISPLACE_EPSILON 0.01f + +void DisplaceSimpleOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inVector[4]; + float inScale[4]; + + float p_dx, p_dy; /* main displacement in pixel space */ + float u, v; + + this->m_inputScaleXProgram->readSampled(inScale, x, y, sampler); + float xs = inScale[0]; + this->m_inputScaleYProgram->readSampled(inScale, x, y, sampler); + float ys = inScale[0]; + + /* clamp x and y displacement to triple image resolution - + * to prevent hangs from huge values mistakenly plugged in eg. z buffers */ + CLAMP(xs, -this->m_width_x4, this->m_width_x4); + CLAMP(ys, -this->m_height_x4, this->m_height_x4); + + this->m_inputVectorProgram->readSampled(inVector, x, y, sampler); + p_dx = inVector[0] * xs; + p_dy = inVector[1] * ys; + + /* displaced pixel in uv coords, for image sampling */ + /* clamp nodes to avoid glitches */ + u = x - p_dx + 0.5f; + v = y - p_dy + 0.5f; + CLAMP(u, 0.0f, this->getWidth() - 1.0f); + CLAMP(v, 0.0f, this->getHeight() - 1.0f); + + this->m_inputColorProgram->readSampled(output, u, v, sampler); +} + +void DisplaceSimpleOperation::deinitExecution() +{ + this->m_inputColorProgram = nullptr; + this->m_inputVectorProgram = nullptr; + this->m_inputScaleXProgram = nullptr; + this->m_inputScaleYProgram = nullptr; +} + +bool DisplaceSimpleOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti colorInput; + NodeOperation *operation = nullptr; + + /* the vector buffer only needs a 2x2 buffer. The image needs whole buffer */ + /* image */ + operation = getInputOperation(0); + colorInput.xmax = operation->getWidth(); + colorInput.xmin = 0; + colorInput.ymax = operation->getHeight(); + colorInput.ymin = 0; + if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) { + return true; + } + + /* vector */ + if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { + return true; + } + + /* scale x */ + operation = getInputOperation(2); + if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { + return true; + } + + /* scale y */ + operation = getInputOperation(3); + if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { + return true; + } + + return false; +} diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp deleted file mode 100644 index bbc4d63305b..00000000000 --- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_DisplaceSimpleOperation.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -DisplaceSimpleOperation::DisplaceSimpleOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VECTOR); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - - this->m_inputColorProgram = nullptr; - this->m_inputVectorProgram = nullptr; - this->m_inputScaleXProgram = nullptr; - this->m_inputScaleYProgram = nullptr; -} - -void DisplaceSimpleOperation::initExecution() -{ - this->m_inputColorProgram = this->getInputSocketReader(0); - this->m_inputVectorProgram = this->getInputSocketReader(1); - this->m_inputScaleXProgram = this->getInputSocketReader(2); - this->m_inputScaleYProgram = this->getInputSocketReader(3); - - this->m_width_x4 = this->getWidth() * 4; - this->m_height_x4 = this->getHeight() * 4; -} - -/* minimum distance (in pixels) a pixel has to be displaced - * in order to take effect */ -// #define DISPLACE_EPSILON 0.01f - -void DisplaceSimpleOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inVector[4]; - float inScale[4]; - - float p_dx, p_dy; /* main displacement in pixel space */ - float u, v; - - this->m_inputScaleXProgram->readSampled(inScale, x, y, sampler); - float xs = inScale[0]; - this->m_inputScaleYProgram->readSampled(inScale, x, y, sampler); - float ys = inScale[0]; - - /* clamp x and y displacement to triple image resolution - - * to prevent hangs from huge values mistakenly plugged in eg. z buffers */ - CLAMP(xs, -this->m_width_x4, this->m_width_x4); - CLAMP(ys, -this->m_height_x4, this->m_height_x4); - - this->m_inputVectorProgram->readSampled(inVector, x, y, sampler); - p_dx = inVector[0] * xs; - p_dy = inVector[1] * ys; - - /* displaced pixel in uv coords, for image sampling */ - /* clamp nodes to avoid glitches */ - u = x - p_dx + 0.5f; - v = y - p_dy + 0.5f; - CLAMP(u, 0.0f, this->getWidth() - 1.0f); - CLAMP(v, 0.0f, this->getHeight() - 1.0f); - - this->m_inputColorProgram->readSampled(output, u, v, sampler); -} - -void DisplaceSimpleOperation::deinitExecution() -{ - this->m_inputColorProgram = nullptr; - this->m_inputVectorProgram = nullptr; - this->m_inputScaleXProgram = nullptr; - this->m_inputScaleYProgram = nullptr; -} - -bool DisplaceSimpleOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti colorInput; - NodeOperation *operation = nullptr; - - /* the vector buffer only needs a 2x2 buffer. The image needs whole buffer */ - /* image */ - operation = getInputOperation(0); - colorInput.xmax = operation->getWidth(); - colorInput.xmin = 0; - colorInput.ymax = operation->getHeight(); - colorInput.ymin = 0; - if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) { - return true; - } - - /* vector */ - if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { - return true; - } - - /* scale x */ - operation = getInputOperation(2); - if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { - return true; - } - - /* scale y */ - operation = getInputOperation(3); - if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { - return true; - } - - return false; -} diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc new file mode 100644 index 00000000000..ecc2fc2e85f --- /dev/null +++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc @@ -0,0 +1,92 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DistanceRGBMatteOperation.h" +#include "BLI_math.h" + +DistanceRGBMatteOperation::DistanceRGBMatteOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_VALUE); + + this->m_inputImageProgram = nullptr; + this->m_inputKeyProgram = nullptr; +} + +void DistanceRGBMatteOperation::initExecution() +{ + this->m_inputImageProgram = this->getInputSocketReader(0); + this->m_inputKeyProgram = this->getInputSocketReader(1); +} + +void DistanceRGBMatteOperation::deinitExecution() +{ + this->m_inputImageProgram = nullptr; + this->m_inputKeyProgram = nullptr; +} + +float DistanceRGBMatteOperation::calculateDistance(float key[4], float image[4]) +{ + return len_v3v3(key, image); +} + +void DistanceRGBMatteOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inKey[4]; + float inImage[4]; + + const float tolerance = this->m_settings->t1; + const float falloff = this->m_settings->t2; + + float distance; + float alpha; + + this->m_inputKeyProgram->readSampled(inKey, x, y, sampler); + this->m_inputImageProgram->readSampled(inImage, x, y, sampler); + + distance = this->calculateDistance(inKey, inImage); + + /* Store matte(alpha) value in [0] to go with + * COM_SetAlphaMultiplyOperation and the Value output. + */ + + /*make 100% transparent */ + if (distance < tolerance) { + output[0] = 0.0f; + } + /*in the falloff region, make partially transparent */ + else if (distance < falloff + tolerance) { + distance = distance - tolerance; + alpha = distance / falloff; + /*only change if more transparent than before */ + if (alpha < inImage[3]) { + output[0] = alpha; + } + else { /* leave as before */ + output[0] = inImage[3]; + } + } + else { + /* leave as before */ + output[0] = inImage[3]; + } +} diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp deleted file mode 100644 index ecc2fc2e85f..00000000000 --- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DistanceRGBMatteOperation.h" -#include "BLI_math.h" - -DistanceRGBMatteOperation::DistanceRGBMatteOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_VALUE); - - this->m_inputImageProgram = nullptr; - this->m_inputKeyProgram = nullptr; -} - -void DistanceRGBMatteOperation::initExecution() -{ - this->m_inputImageProgram = this->getInputSocketReader(0); - this->m_inputKeyProgram = this->getInputSocketReader(1); -} - -void DistanceRGBMatteOperation::deinitExecution() -{ - this->m_inputImageProgram = nullptr; - this->m_inputKeyProgram = nullptr; -} - -float DistanceRGBMatteOperation::calculateDistance(float key[4], float image[4]) -{ - return len_v3v3(key, image); -} - -void DistanceRGBMatteOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inKey[4]; - float inImage[4]; - - const float tolerance = this->m_settings->t1; - const float falloff = this->m_settings->t2; - - float distance; - float alpha; - - this->m_inputKeyProgram->readSampled(inKey, x, y, sampler); - this->m_inputImageProgram->readSampled(inImage, x, y, sampler); - - distance = this->calculateDistance(inKey, inImage); - - /* Store matte(alpha) value in [0] to go with - * COM_SetAlphaMultiplyOperation and the Value output. - */ - - /*make 100% transparent */ - if (distance < tolerance) { - output[0] = 0.0f; - } - /*in the falloff region, make partially transparent */ - else if (distance < falloff + tolerance) { - distance = distance - tolerance; - alpha = distance / falloff; - /*only change if more transparent than before */ - if (alpha < inImage[3]) { - output[0] = alpha; - } - else { /* leave as before */ - output[0] = inImage[3]; - } - } - else { - /* leave as before */ - output[0] = inImage[3]; - } -} diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc new file mode 100644 index 00000000000..f333cc1ecd9 --- /dev/null +++ b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc @@ -0,0 +1,31 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DistanceYCCMatteOperation.h" +#include "BLI_math.h" + +DistanceYCCMatteOperation::DistanceYCCMatteOperation() +{ + /* pass */ +} + +float DistanceYCCMatteOperation::calculateDistance(float key[4], float image[4]) +{ + /* only measure the second 2 values */ + return len_v2v2(key + 1, image + 1); +} diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp deleted file mode 100644 index f333cc1ecd9..00000000000 --- a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DistanceYCCMatteOperation.h" -#include "BLI_math.h" - -DistanceYCCMatteOperation::DistanceYCCMatteOperation() -{ - /* pass */ -} - -float DistanceYCCMatteOperation::calculateDistance(float key[4], float image[4]) -{ - /* only measure the second 2 values */ - return len_v2v2(key + 1, image + 1); -} diff --git a/source/blender/compositor/operations/COM_DotproductOperation.cc b/source/blender/compositor/operations/COM_DotproductOperation.cc new file mode 100644 index 00000000000..5914be21453 --- /dev/null +++ b/source/blender/compositor/operations/COM_DotproductOperation.cc @@ -0,0 +1,54 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_DotproductOperation.h" + +DotproductOperation::DotproductOperation() +{ + this->addInputSocket(COM_DT_VECTOR); + this->addInputSocket(COM_DT_VECTOR); + this->addOutputSocket(COM_DT_VALUE); + this->setResolutionInputSocketIndex(0); + this->m_input1Operation = nullptr; + this->m_input2Operation = nullptr; +} +void DotproductOperation::initExecution() +{ + this->m_input1Operation = this->getInputSocketReader(0); + this->m_input2Operation = this->getInputSocketReader(1); +} + +void DotproductOperation::deinitExecution() +{ + this->m_input1Operation = nullptr; + this->m_input2Operation = nullptr; +} + +/** \todo current implementation is the inverse of a dot-product. not 'logically' correct + */ +void DotproductOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float input1[4]; + float input2[4]; + this->m_input1Operation->readSampled(input1, x, y, sampler); + this->m_input2Operation->readSampled(input2, x, y, sampler); + output[0] = -(input1[0] * input2[0] + input1[1] * input2[1] + input1[2] * input2[2]); +} diff --git a/source/blender/compositor/operations/COM_DotproductOperation.cpp b/source/blender/compositor/operations/COM_DotproductOperation.cpp deleted file mode 100644 index 5914be21453..00000000000 --- a/source/blender/compositor/operations/COM_DotproductOperation.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_DotproductOperation.h" - -DotproductOperation::DotproductOperation() -{ - this->addInputSocket(COM_DT_VECTOR); - this->addInputSocket(COM_DT_VECTOR); - this->addOutputSocket(COM_DT_VALUE); - this->setResolutionInputSocketIndex(0); - this->m_input1Operation = nullptr; - this->m_input2Operation = nullptr; -} -void DotproductOperation::initExecution() -{ - this->m_input1Operation = this->getInputSocketReader(0); - this->m_input2Operation = this->getInputSocketReader(1); -} - -void DotproductOperation::deinitExecution() -{ - this->m_input1Operation = nullptr; - this->m_input2Operation = nullptr; -} - -/** \todo current implementation is the inverse of a dot-product. not 'logically' correct - */ -void DotproductOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float input1[4]; - float input2[4]; - this->m_input1Operation->readSampled(input1, x, y, sampler); - this->m_input2Operation->readSampled(input2, x, y, sampler); - output[0] = -(input1[0] * input2[0] + input1[1] * input2[1] + input1[2] * input2[2]); -} diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc new file mode 100644 index 00000000000..b548a684ba5 --- /dev/null +++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc @@ -0,0 +1,1381 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include + +#include "BLI_math.h" +#include "COM_DoubleEdgeMaskOperation.h" +#include "DNA_node_types.h" +#include "MEM_guardedalloc.h" + +// this part has been copied from the double edge mask +static void do_adjacentKeepBorders(unsigned int t, + unsigned int rw, + const unsigned int *limask, + const unsigned int *lomask, + unsigned int *lres, + float *res, + unsigned int *rsize) +{ + int x; + unsigned int isz = 0; // inner edge size + unsigned int osz = 0; // outer edge size + unsigned int gsz = 0; // gradient fill area size + /* Test the four corners */ + /* upper left corner */ + x = t - rw + 1; + // test if inner mask is filled + if (limask[x]) { + // test if pixel underneath, or to the right, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + 1] && lomask[x + 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + /* upper right corner */ + x = t; + // test if inner mask is filled + if (limask[x]) { + // test if pixel underneath, or to the left, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x - 1] && lomask[x - 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + /* lower left corner */ + x = 0; + // test if inner mask is filled + if (limask[x]) { + // test if pixel above, or to the right, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x + 1] && lomask[x + 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + /* lower right corner */ + x = rw - 1; + // test if inner mask is filled + if (limask[x]) { + // test if pixel above, or to the left, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x - 1] && lomask[x - 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + + /* Test the TOP row of pixels in buffer, except corners */ + for (x = t - 1; x >= (t - rw) + 2; x--) { + // test if inner mask is filled + if (limask[x]) { + // test if pixel to the right, or to the left, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + } + + /* Test the BOTTOM row of pixels in buffer, except corners */ + for (x = rw - 2; x; x--) { + // test if inner mask is filled + if (limask[x]) { + // test if pixel to the right, or to the left, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + } + /* Test the LEFT edge of pixels in buffer, except corners */ + for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { + // test if inner mask is filled + if (limask[x]) { + // test if pixel underneath, or above, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + } + + /* Test the RIGHT edge of pixels in buffer, except corners */ + for (x = t - rw; x > rw; x -= rw) { + // test if inner mask is filled + if (limask[x]) { + // test if pixel underneath, or above, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + } + + rsize[0] = isz; // fill in our return sizes for edges + fill + rsize[1] = osz; + rsize[2] = gsz; +} + +static void do_adjacentBleedBorders(unsigned int t, + unsigned int rw, + const unsigned int *limask, + const unsigned int *lomask, + unsigned int *lres, + float *res, + unsigned int *rsize) +{ + int x; + unsigned int isz = 0; // inner edge size + unsigned int osz = 0; // outer edge size + unsigned int gsz = 0; // gradient fill area size + /* Test the four corners */ + /* upper left corner */ + x = t - rw + 1; + // test if inner mask is filled + if (limask[x]) { + // test if pixel underneath, or to the right, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + 1] && lomask[x + 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - rw] || + !lomask[x + 1]) { // test if outer mask is empty underneath or to the right + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + /* upper right corner */ + x = t; + // test if inner mask is filled + if (limask[x]) { + // test if pixel underneath, or to the left, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x - 1] && lomask[x - 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - rw] || + !lomask[x - 1]) { // test if outer mask is empty underneath or to the left + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + /* lower left corner */ + x = 0; + // test if inner mask is filled + if (limask[x]) { + // test if pixel above, or to the right, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x + 1] && lomask[x + 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x + rw] || !lomask[x + 1]) { // test if outer mask is empty above or to the right + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + /* lower right corner */ + x = rw - 1; + // test if inner mask is filled + if (limask[x]) { + // test if pixel above, or to the left, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x - 1] && lomask[x - 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x + rw] || !lomask[x - 1]) { // test if outer mask is empty above or to the left + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + /* Test the TOP row of pixels in buffer, except corners */ + for (x = t - 1; x >= (t - rw) + 2; x--) { + // test if inner mask is filled + if (limask[x]) { + // test if pixel to the left, or to the right, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - 1] || + !lomask[x + 1]) { // test if outer mask is empty to the left or to the right + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + } + + /* Test the BOTTOM row of pixels in buffer, except corners */ + for (x = rw - 2; x; x--) { + // test if inner mask is filled + if (limask[x]) { + // test if pixel to the left, or to the right, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - 1] || + !lomask[x + 1]) { // test if outer mask is empty to the left or to the right + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + } + /* Test the LEFT edge of pixels in buffer, except corners */ + for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { + // test if inner mask is filled + if (limask[x]) { + // test if pixel underneath, or above, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + } + + /* Test the RIGHT edge of pixels in buffer, except corners */ + for (x = t - rw; x > rw; x -= rw) { + // test if inner mask is filled + if (limask[x]) { + // test if pixel underneath, or above, are empty in the inner mask, + // but filled in the outer mask + if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + } + + rsize[0] = isz; // fill in our return sizes for edges + fill + rsize[1] = osz; + rsize[2] = gsz; +} + +static void do_allKeepBorders(unsigned int t, + unsigned int rw, + const unsigned int *limask, + const unsigned int *lomask, + unsigned int *lres, + float *res, + unsigned int *rsize) +{ + int x; + unsigned int isz = 0; // inner edge size + unsigned int osz = 0; // outer edge size + unsigned int gsz = 0; // gradient fill area size + /* Test the four corners */ + /* upper left corner */ + x = t - rw + 1; + // test if inner mask is filled + if (limask[x]) { + // test if the inner mask is empty underneath or to the right + if (!limask[x - rw] || !limask[x + 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + /* upper right corner */ + x = t; + // test if inner mask is filled + if (limask[x]) { + // test if the inner mask is empty underneath or to the left + if (!limask[x - rw] || !limask[x - 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + /* lower left corner */ + x = 0; + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty above or to the right + if (!limask[x + rw] || !limask[x + 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + /* lower right corner */ + x = rw - 1; + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty above or to the left + if (!limask[x + rw] || !limask[x - 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + + /* Test the TOP row of pixels in buffer, except corners */ + for (x = t - 1; x >= (t - rw) + 2; x--) { + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty to the left or to the right + if (!limask[x - 1] || !limask[x + 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + } + + /* Test the BOTTOM row of pixels in buffer, except corners */ + for (x = rw - 2; x; x--) { + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty to the left or to the right + if (!limask[x - 1] || !limask[x + 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + } + /* Test the LEFT edge of pixels in buffer, except corners */ + for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty underneath or above + if (!limask[x - rw] || !limask[x + rw]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + } + + /* Test the RIGHT edge of pixels in buffer, except corners */ + for (x = t - rw; x > rw; x -= rw) { + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty underneath or above + if (!limask[x - rw] || !limask[x + rw]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + } + + rsize[0] = isz; // fill in our return sizes for edges + fill + rsize[1] = osz; + rsize[2] = gsz; +} + +static void do_allBleedBorders(unsigned int t, + unsigned int rw, + const unsigned int *limask, + const unsigned int *lomask, + unsigned int *lres, + float *res, + unsigned int *rsize) +{ + int x; + unsigned int isz = 0; // inner edge size + unsigned int osz = 0; // outer edge size + unsigned int gsz = 0; // gradient fill area size + /* Test the four corners */ + /* upper left corner */ + x = t - rw + 1; + // test if inner mask is filled + if (limask[x]) { + // test if the inner mask is empty underneath or to the right + if (!limask[x - rw] || !limask[x + 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - rw] || + !lomask[x + 1]) { // test if outer mask is empty underneath or to the right + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + /* upper right corner */ + x = t; + // test if inner mask is filled + if (limask[x]) { + // test if the inner mask is empty underneath or to the left + if (!limask[x - rw] || !limask[x - 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - rw] || !lomask[x - 1]) { // test if outer mask is empty above or to the left + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + /* lower left corner */ + x = 0; + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty above or to the right + if (!limask[x + rw] || !limask[x + 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x + rw] || + !lomask[x + 1]) { // test if outer mask is empty underneath or to the right + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + /* lower right corner */ + x = rw - 1; + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty above or to the left + if (!limask[x + rw] || !limask[x - 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x + rw] || + !lomask[x - 1]) { // test if outer mask is empty underneath or to the left + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + /* Test the TOP row of pixels in buffer, except corners */ + for (x = t - 1; x >= (t - rw) + 2; x--) { + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty to the left or to the right + if (!limask[x - 1] || !limask[x + 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - 1] || + !lomask[x + 1]) { // test if outer mask is empty to the left or to the right + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + } + + /* Test the BOTTOM row of pixels in buffer, except corners */ + for (x = rw - 2; x; x--) { + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty to the left or to the right + if (!limask[x - 1] || !limask[x + 1]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - 1] || + !lomask[x + 1]) { // test if outer mask is empty to the left or to the right + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + } + /* Test the LEFT edge of pixels in buffer, except corners */ + for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty underneath or above + if (!limask[x - rw] || !limask[x + rw]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + } + + /* Test the RIGHT edge of pixels in buffer, except corners */ + for (x = t - rw; x > rw; x -= rw) { + // test if inner mask is filled + if (limask[x]) { + // test if inner mask is empty underneath or above + if (!limask[x - rw] || !limask[x + rw]) { + isz++; // increment inner edge size + lres[x] = 4; // flag pixel as inner edge + } + else { + res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge + } + } + else if (lomask[x]) { // inner mask was empty, test if outer mask is filled + if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above + osz++; // increment outer edge size + lres[x] = 3; // flag pixel as outer edge + } + else { + gsz++; // increment the gradient pixel count + lres[x] = 2; // flag pixel as gradient + } + } + } + + rsize[0] = isz; // fill in our return sizes for edges + fill + rsize[1] = osz; + rsize[2] = gsz; +} + +static void do_allEdgeDetection(unsigned int t, + unsigned int rw, + const unsigned int *limask, + const unsigned int *lomask, + unsigned int *lres, + float *res, + unsigned int *rsize, + unsigned int in_isz, + unsigned int in_osz, + unsigned int in_gsz) +{ + int x; // x = pixel loop counter + int a; // a = pixel loop counter + int dx; // dx = delta x + int pix_prevRow; // pix_prevRow = pixel one row behind the one we are testing in a loop + int pix_nextRow; // pix_nextRow = pixel one row in front of the one we are testing in a loop + int pix_prevCol; // pix_prevCol = pixel one column behind the one we are testing in a loop + int pix_nextCol; // pix_nextCol = pixel one column in front of the one we are testing in a loop + /* Test all rows between the FIRST and LAST rows, excluding left and right edges */ + for (x = (t - rw) + 1, dx = x - (rw - 2); dx > rw; x -= rw, dx -= rw) { + a = x - 2; + pix_prevRow = a + rw; + pix_nextRow = a - rw; + pix_prevCol = a + 1; + pix_nextCol = a - 1; + while (a > dx - 2) { + if (!limask[a]) { // if the inner mask is empty + if (lomask[a]) { // if the outer mask is full + /* + * Next we test all 4 directions around the current pixel: next/prev/up/down + * The test ensures that the outer mask is empty and that the inner mask + * is also empty. If both conditions are true for any one of the 4 adjacent pixels + * then the current pixel is counted as being a true outer edge pixel. + */ + if ((!lomask[pix_nextCol] && !limask[pix_nextCol]) || + (!lomask[pix_prevCol] && !limask[pix_prevCol]) || + (!lomask[pix_nextRow] && !limask[pix_nextRow]) || + (!lomask[pix_prevRow] && !limask[pix_prevRow])) { + in_osz++; // increment the outer boundary pixel count + lres[a] = 3; // flag pixel as part of outer edge + } + else { // it's not a boundary pixel, but it is a gradient pixel + in_gsz++; // increment the gradient pixel count + lres[a] = 2; // flag pixel as gradient + } + } + } + else { + if (!limask[pix_nextCol] || !limask[pix_prevCol] || !limask[pix_nextRow] || + !limask[pix_prevRow]) { + in_isz++; // increment the inner boundary pixel count + lres[a] = 4; // flag pixel as part of inner edge + } + else { + res[a] = 1.0f; // pixel is part of inner mask, but not at an edge + } + } + a--; + pix_prevRow--; + pix_nextRow--; + pix_prevCol--; + pix_nextCol--; + } + } + + rsize[0] = in_isz; // fill in our return sizes for edges + fill + rsize[1] = in_osz; + rsize[2] = in_gsz; +} + +static void do_adjacentEdgeDetection(unsigned int t, + unsigned int rw, + const unsigned int *limask, + const unsigned int *lomask, + unsigned int *lres, + float *res, + unsigned int *rsize, + unsigned int in_isz, + unsigned int in_osz, + unsigned int in_gsz) +{ + int x; // x = pixel loop counter + int a; // a = pixel loop counter + int dx; // dx = delta x + int pix_prevRow; // pix_prevRow = pixel one row behind the one we are testing in a loop + int pix_nextRow; // pix_nextRow = pixel one row in front of the one we are testing in a loop + int pix_prevCol; // pix_prevCol = pixel one column behind the one we are testing in a loop + int pix_nextCol; // pix_nextCol = pixel one column in front of the one we are testing in a loop + /* Test all rows between the FIRST and LAST rows, excluding left and right edges */ + for (x = (t - rw) + 1, dx = x - (rw - 2); dx > rw; x -= rw, dx -= rw) { + a = x - 2; + pix_prevRow = a + rw; + pix_nextRow = a - rw; + pix_prevCol = a + 1; + pix_nextCol = a - 1; + while (a > dx - 2) { + if (!limask[a]) { // if the inner mask is empty + if (lomask[a]) { // if the outer mask is full + /* + * Next we test all 4 directions around the current pixel: next/prev/up/down + * The test ensures that the outer mask is empty and that the inner mask + * is also empty. If both conditions are true for any one of the 4 adjacent pixels + * then the current pixel is counted as being a true outer edge pixel. + */ + if ((!lomask[pix_nextCol] && !limask[pix_nextCol]) || + (!lomask[pix_prevCol] && !limask[pix_prevCol]) || + (!lomask[pix_nextRow] && !limask[pix_nextRow]) || + (!lomask[pix_prevRow] && !limask[pix_prevRow])) { + in_osz++; // increment the outer boundary pixel count + lres[a] = 3; // flag pixel as part of outer edge + } + else { // it's not a boundary pixel, but it is a gradient pixel + in_gsz++; // increment the gradient pixel count + lres[a] = 2; // flag pixel as gradient + } + } + } + else { + if ((!limask[pix_nextCol] && lomask[pix_nextCol]) || + (!limask[pix_prevCol] && lomask[pix_prevCol]) || + (!limask[pix_nextRow] && lomask[pix_nextRow]) || + (!limask[pix_prevRow] && lomask[pix_prevRow])) { + in_isz++; // increment the inner boundary pixel count + lres[a] = 4; // flag pixel as part of inner edge + } + else { + res[a] = 1.0f; // pixel is part of inner mask, but not at an edge + } + } + a--; + pix_prevRow--; // advance all four "surrounding" pixel pointers + pix_nextRow--; + pix_prevCol--; + pix_nextCol--; + } + } + + rsize[0] = in_isz; // fill in our return sizes for edges + fill + rsize[1] = in_osz; + rsize[2] = in_gsz; +} + +static void do_createEdgeLocationBuffer(unsigned int t, + unsigned int rw, + const unsigned int *lres, + float *res, + unsigned short *gbuf, + unsigned int *innerEdgeOffset, + unsigned int *outerEdgeOffset, + unsigned int isz, + unsigned int gsz) +{ + int x; // x = pixel loop counter + int a; // a = temporary pixel index buffer loop counter + unsigned int ud; // ud = unscaled edge distance + unsigned int dmin; // dmin = minimum edge distance + + unsigned int rsl; // long used for finding fast 1.0/sqrt + unsigned int gradientFillOffset; + + /* For looping inner edge pixel indexes, represents current position from offset. */ + unsigned int innerAccum = 0; + /* For looping outer edge pixel indexes, represents current position from offset. */ + unsigned int outerAccum = 0; + /* For looping gradient pixel indexes, represents current position from offset. */ + unsigned int gradientAccum = 0; + + /* */ + /* clang-format off */ + /* + * Here we compute the size of buffer needed to hold (row,col) coordinates + * for each pixel previously determined to be either gradient, inner edge, + * or outer edge. + * + * Allocation is done by requesting 4 bytes "sizeof(int)" per pixel, even + * though gbuf[] is declared as (unsigned short *) (2 bytes) because we don't + * store the pixel indexes, we only store x,y location of pixel in buffer. + * + * This does make the assumption that x and y can fit in 16 unsigned bits + * so if Blender starts doing renders greater than 65536 in either direction + * this will need to allocate gbuf[] as unsigned int *and allocate 8 bytes + * per flagged pixel. + * + * In general, the buffer on-screen: + * + * Example: 9 by 9 pixel block + * + * . = pixel non-white in both outer and inner mask + * o = pixel white in outer, but not inner mask, adjacent to "." pixel + * g = pixel white in outer, but not inner mask, not adjacent to "." pixel + * i = pixel white in inner mask, adjacent to "g" or "." pixel + * F = pixel white in inner mask, only adjacent to other pixels white in the inner mask + * + * + * ......... <----- pixel #80 + * ..oooo... + * .oggggo.. + * .oggiggo. + * .ogiFigo. + * .oggiggo. + * .oggggo.. + * ..oooo... + * pixel #00 -----> ......... + * + * gsz = 18 (18 "g" pixels above) + * isz = 4 (4 "i" pixels above) + * osz = 18 (18 "o" pixels above) + * + * + * The memory in gbuf[] after filling will look like this: + * + * gradientFillOffset (0 pixels) innerEdgeOffset (18 pixels) outerEdgeOffset (22 pixels) + * / / / + * / / / + * |X Y X Y X Y X Y > <----------------> <------------------------> <----------------+ + * |0 2 4 6 8 10 12 14 > ... <68 70 72 74 > ... <80 82 84 86 88 90 > ... <152 154 156 158 | <- bytes + * +--------------------------------> <----------------> <------------------------> <----------------+ + * |g0 g0 g1 g1 g2 g2 g3 g3 > = 0; x--) { + gradientFillOffset = x << 1; + t = gbuf[gradientFillOffset]; // calculate column of pixel indexed by gbuf[x] + fsz = gbuf[gradientFillOffset + 1]; // calculate row of pixel indexed by gbuf[x] + dmin = 0xffffffff; // reset min distance to edge pixel + for (a = outerEdgeOffset + osz - 1; a >= outerEdgeOffset; + a--) { // loop through all outer edge buffer pixels + ud = a << 1; + dy = t - gbuf[ud]; // set dx to gradient pixel column - outer edge pixel row + dx = fsz - gbuf[ud + 1]; // set dy to gradient pixel row - outer edge pixel column + ud = dx * dx + dy * dy; // compute sum of squares + if (ud < dmin) { // if our new sum of squares is less than the current minimum + dmin = ud; // set a new minimum equal to the new lower value + } + } + odist = (float)(dmin); // cast outer min to a float + rsf = odist * 0.5f; // + rsl = *(unsigned int *)&odist; // use some peculiar properties of the way bits are stored + rsl = 0x5f3759df - (rsl >> 1); // in floats vs. unsigned ints to compute an approximate + odist = *(float *)&rsl; // reciprocal square root + odist = odist * (rsopf - (rsf * odist * + odist)); // -- ** this line can be iterated for more accuracy ** -- + dmin = 0xffffffff; // reset min distance to edge pixel + for (a = innerEdgeOffset + isz - 1; a >= innerEdgeOffset; + a--) { // loop through all inside edge pixels + ud = a << 1; + dy = t - gbuf[ud]; // compute delta in Y from gradient pixel to inside edge pixel + dx = fsz - gbuf[ud + 1]; // compute delta in X from gradient pixel to inside edge pixel + ud = dx * dx + dy * dy; // compute sum of squares + if (ud < dmin) { // if our new sum of squares is less than the current minimum we've found + dmin = ud; // set a new minimum equal to the new lower value + } + } + idist = (float)(dmin); // cast inner min to a float + rsf = idist * 0.5f; // + rsl = *(unsigned int *)&idist; // + rsl = 0x5f3759df - (rsl >> 1); // see notes above + idist = *(float *)&rsl; // + idist = idist * (rsopf - (rsf * idist * idist)); // + /* + * Note once again that since we are using reciprocals of distance values our + * proportion is already the correct intensity, and does not need to be + * subtracted from 1.0 like it would have if we used real distances. + */ + + /* + * Here we reconstruct the pixel's memory location in the CompBuf by + * Pixel Index = Pixel Column + ( Pixel Row * Row Width ) + */ + res[gbuf[gradientFillOffset + 1] + (gbuf[gradientFillOffset] * rw)] = + (idist / (idist + odist)); // set intensity + } +} + +// end of copy + +void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float *res) +{ + unsigned int *lres; // lres = unsigned int pointer to output pixel buffer (for bit operations) + unsigned int *limask; // limask = unsigned int pointer to inner mask (for bit operations) + unsigned int *lomask; // lomask = unsigned int pointer to outer mask (for bit operations) + + int rw; // rw = pixel row width + int t; // t = total number of pixels in buffer - 1 (used for loop starts) + int fsz; // size of the frame + + unsigned int isz = 0; // size (in pixels) of inside edge pixel index buffer + unsigned int osz = 0; // size (in pixels) of outside edge pixel index buffer + unsigned int gsz = 0; // size (in pixels) of gradient pixel index buffer + unsigned int rsize[3]; // size storage to pass to helper functions + unsigned int innerEdgeOffset = + 0; // offset into final buffer where inner edge pixel indexes start + unsigned int outerEdgeOffset = + 0; // offset into final buffer where outer edge pixel indexes start + + unsigned short *gbuf; // gradient/inner/outer pixel location index buffer + + if (true) { // if both input sockets have some data coming in... + + rw = this->getWidth(); // width of a row of pixels + t = (rw * this->getHeight()) - 1; // determine size of the frame + memset(res, + 0, + sizeof(float) * (t + 1)); // clear output buffer (not all pixels will be written later) + + lres = (unsigned int *)res; // unsigned int pointer to output buffer (for bit level ops) + limask = (unsigned int *)imask; // unsigned int pointer to input mask (for bit level ops) + lomask = (unsigned int *)omask; // unsigned int pointer to output mask (for bit level ops) + + /* + * The whole buffer is broken up into 4 parts. The four CORNERS, the FIRST and LAST rows, the + * LEFT and RIGHT edges (excluding the corner pixels), and all OTHER rows. + * This allows for quick computation of outer edge pixels where + * a screen edge pixel is marked to be gradient. + * + * The pixel type (gradient vs inner-edge vs outer-edge) tests change + * depending on the user selected "Inner Edge Mode" and the user selected + * "Buffer Edge Mode" on the node's GUI. There are 4 sets of basically the + * same algorithm: + * + * 1.) Inner Edge -> Adjacent Only + * Buffer Edge -> Keep Inside + * + * 2.) Inner Edge -> Adjacent Only + * Buffer Edge -> Bleed Out + * + * 3.) Inner Edge -> All + * Buffer Edge -> Keep Inside + * + * 4.) Inner Edge -> All + * Buffer Edge -> Bleed Out + * + * Each version has slightly different criteria for detecting an edge pixel. + */ + if (this->m_adjacentOnly) { // if "adjacent only" inner edge mode is turned on + if (this->m_keepInside) { // if "keep inside" buffer edge mode is turned on + do_adjacentKeepBorders(t, rw, limask, lomask, lres, res, rsize); + } + else { // "bleed out" buffer edge mode is turned on + do_adjacentBleedBorders(t, rw, limask, lomask, lres, res, rsize); + } + // set up inner edge, outer edge, and gradient buffer sizes after border pass + isz = rsize[0]; + osz = rsize[1]; + gsz = rsize[2]; + // detect edges in all non-border pixels in the buffer + do_adjacentEdgeDetection(t, rw, limask, lomask, lres, res, rsize, isz, osz, gsz); + } + else { // "all" inner edge mode is turned on + if (this->m_keepInside) { // if "keep inside" buffer edge mode is turned on + do_allKeepBorders(t, rw, limask, lomask, lres, res, rsize); + } + else { // "bleed out" buffer edge mode is turned on + do_allBleedBorders(t, rw, limask, lomask, lres, res, rsize); + } + // set up inner edge, outer edge, and gradient buffer sizes after border pass + isz = rsize[0]; + osz = rsize[1]; + gsz = rsize[2]; + // detect edges in all non-border pixels in the buffer + do_allEdgeDetection(t, rw, limask, lomask, lres, res, rsize, isz, osz, gsz); + } + + // set edge and gradient buffer sizes once again... + // the sizes in rsize[] may have been modified + // by the do_*EdgeDetection() function. + isz = rsize[0]; + osz = rsize[1]; + gsz = rsize[2]; + + // calculate size of pixel index buffer needed + fsz = gsz + isz + osz; + // allocate edge/gradient pixel index buffer + gbuf = (unsigned short *)MEM_callocN(sizeof(unsigned short) * fsz * 2, "DEM"); + + do_createEdgeLocationBuffer( + t, rw, lres, res, gbuf, &innerEdgeOffset, &outerEdgeOffset, isz, gsz); + do_fillGradientBuffer(rw, res, gbuf, isz, osz, gsz, innerEdgeOffset, outerEdgeOffset); + + // free the gradient index buffer + MEM_freeN(gbuf); + } +} + +DoubleEdgeMaskOperation::DoubleEdgeMaskOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->m_inputInnerMask = nullptr; + this->m_inputOuterMask = nullptr; + this->m_adjacentOnly = false; + this->m_keepInside = false; + this->setComplex(true); +} + +bool DoubleEdgeMaskOperation::determineDependingAreaOfInterest(rcti * /*input*/, + ReadBufferOperation *readOperation, + rcti *output) +{ + if (this->m_cachedInstance == nullptr) { + rcti newInput; + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + } + + return false; +} + +void DoubleEdgeMaskOperation::initExecution() +{ + this->m_inputInnerMask = this->getInputSocketReader(0); + this->m_inputOuterMask = this->getInputSocketReader(1); + initMutex(); + this->m_cachedInstance = nullptr; +} + +void *DoubleEdgeMaskOperation::initializeTileData(rcti *rect) +{ + if (this->m_cachedInstance) { + return this->m_cachedInstance; + } + + lockMutex(); + if (this->m_cachedInstance == nullptr) { + MemoryBuffer *innerMask = (MemoryBuffer *)this->m_inputInnerMask->initializeTileData(rect); + MemoryBuffer *outerMask = (MemoryBuffer *)this->m_inputOuterMask->initializeTileData(rect); + float *data = (float *)MEM_mallocN(sizeof(float) * this->getWidth() * this->getHeight(), + __func__); + float *imask = innerMask->getBuffer(); + float *omask = outerMask->getBuffer(); + doDoubleEdgeMask(imask, omask, data); + this->m_cachedInstance = data; + } + unlockMutex(); + return this->m_cachedInstance; +} +void DoubleEdgeMaskOperation::executePixel(float output[4], int x, int y, void *data) +{ + float *buffer = (float *)data; + int index = (y * this->getWidth() + x); + output[0] = buffer[index]; +} + +void DoubleEdgeMaskOperation::deinitExecution() +{ + this->m_inputInnerMask = nullptr; + this->m_inputOuterMask = nullptr; + deinitMutex(); + if (this->m_cachedInstance) { + MEM_freeN(this->m_cachedInstance); + this->m_cachedInstance = nullptr; + } +} diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp deleted file mode 100644 index b548a684ba5..00000000000 --- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp +++ /dev/null @@ -1,1381 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include - -#include "BLI_math.h" -#include "COM_DoubleEdgeMaskOperation.h" -#include "DNA_node_types.h" -#include "MEM_guardedalloc.h" - -// this part has been copied from the double edge mask -static void do_adjacentKeepBorders(unsigned int t, - unsigned int rw, - const unsigned int *limask, - const unsigned int *lomask, - unsigned int *lres, - float *res, - unsigned int *rsize) -{ - int x; - unsigned int isz = 0; // inner edge size - unsigned int osz = 0; // outer edge size - unsigned int gsz = 0; // gradient fill area size - /* Test the four corners */ - /* upper left corner */ - x = t - rw + 1; - // test if inner mask is filled - if (limask[x]) { - // test if pixel underneath, or to the right, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - /* upper right corner */ - x = t; - // test if inner mask is filled - if (limask[x]) { - // test if pixel underneath, or to the left, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x - 1] && lomask[x - 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - /* lower left corner */ - x = 0; - // test if inner mask is filled - if (limask[x]) { - // test if pixel above, or to the right, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - /* lower right corner */ - x = rw - 1; - // test if inner mask is filled - if (limask[x]) { - // test if pixel above, or to the left, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x - 1] && lomask[x - 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - - /* Test the TOP row of pixels in buffer, except corners */ - for (x = t - 1; x >= (t - rw) + 2; x--) { - // test if inner mask is filled - if (limask[x]) { - // test if pixel to the right, or to the left, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - } - - /* Test the BOTTOM row of pixels in buffer, except corners */ - for (x = rw - 2; x; x--) { - // test if inner mask is filled - if (limask[x]) { - // test if pixel to the right, or to the left, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - } - /* Test the LEFT edge of pixels in buffer, except corners */ - for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { - // test if inner mask is filled - if (limask[x]) { - // test if pixel underneath, or above, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - } - - /* Test the RIGHT edge of pixels in buffer, except corners */ - for (x = t - rw; x > rw; x -= rw) { - // test if inner mask is filled - if (limask[x]) { - // test if pixel underneath, or above, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - } - - rsize[0] = isz; // fill in our return sizes for edges + fill - rsize[1] = osz; - rsize[2] = gsz; -} - -static void do_adjacentBleedBorders(unsigned int t, - unsigned int rw, - const unsigned int *limask, - const unsigned int *lomask, - unsigned int *lres, - float *res, - unsigned int *rsize) -{ - int x; - unsigned int isz = 0; // inner edge size - unsigned int osz = 0; // outer edge size - unsigned int gsz = 0; // gradient fill area size - /* Test the four corners */ - /* upper left corner */ - x = t - rw + 1; - // test if inner mask is filled - if (limask[x]) { - // test if pixel underneath, or to the right, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || - !lomask[x + 1]) { // test if outer mask is empty underneath or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - /* upper right corner */ - x = t; - // test if inner mask is filled - if (limask[x]) { - // test if pixel underneath, or to the left, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x - 1] && lomask[x - 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || - !lomask[x - 1]) { // test if outer mask is empty underneath or to the left - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - /* lower left corner */ - x = 0; - // test if inner mask is filled - if (limask[x]) { - // test if pixel above, or to the right, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x + rw] || !lomask[x + 1]) { // test if outer mask is empty above or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - /* lower right corner */ - x = rw - 1; - // test if inner mask is filled - if (limask[x]) { - // test if pixel above, or to the left, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x + rw] && lomask[x + rw]) || (!limask[x - 1] && lomask[x - 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x + rw] || !lomask[x - 1]) { // test if outer mask is empty above or to the left - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - /* Test the TOP row of pixels in buffer, except corners */ - for (x = t - 1; x >= (t - rw) + 2; x--) { - // test if inner mask is filled - if (limask[x]) { - // test if pixel to the left, or to the right, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - 1] || - !lomask[x + 1]) { // test if outer mask is empty to the left or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - } - - /* Test the BOTTOM row of pixels in buffer, except corners */ - for (x = rw - 2; x; x--) { - // test if inner mask is filled - if (limask[x]) { - // test if pixel to the left, or to the right, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - 1] && lomask[x - 1]) || (!limask[x + 1] && lomask[x + 1])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - 1] || - !lomask[x + 1]) { // test if outer mask is empty to the left or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - } - /* Test the LEFT edge of pixels in buffer, except corners */ - for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { - // test if inner mask is filled - if (limask[x]) { - // test if pixel underneath, or above, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - } - - /* Test the RIGHT edge of pixels in buffer, except corners */ - for (x = t - rw; x > rw; x -= rw) { - // test if inner mask is filled - if (limask[x]) { - // test if pixel underneath, or above, are empty in the inner mask, - // but filled in the outer mask - if ((!limask[x - rw] && lomask[x - rw]) || (!limask[x + rw] && lomask[x + rw])) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - } - - rsize[0] = isz; // fill in our return sizes for edges + fill - rsize[1] = osz; - rsize[2] = gsz; -} - -static void do_allKeepBorders(unsigned int t, - unsigned int rw, - const unsigned int *limask, - const unsigned int *lomask, - unsigned int *lres, - float *res, - unsigned int *rsize) -{ - int x; - unsigned int isz = 0; // inner edge size - unsigned int osz = 0; // outer edge size - unsigned int gsz = 0; // gradient fill area size - /* Test the four corners */ - /* upper left corner */ - x = t - rw + 1; - // test if inner mask is filled - if (limask[x]) { - // test if the inner mask is empty underneath or to the right - if (!limask[x - rw] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - /* upper right corner */ - x = t; - // test if inner mask is filled - if (limask[x]) { - // test if the inner mask is empty underneath or to the left - if (!limask[x - rw] || !limask[x - 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - /* lower left corner */ - x = 0; - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty above or to the right - if (!limask[x + rw] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - /* lower right corner */ - x = rw - 1; - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty above or to the left - if (!limask[x + rw] || !limask[x - 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - - /* Test the TOP row of pixels in buffer, except corners */ - for (x = t - 1; x >= (t - rw) + 2; x--) { - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty to the left or to the right - if (!limask[x - 1] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - } - - /* Test the BOTTOM row of pixels in buffer, except corners */ - for (x = rw - 2; x; x--) { - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty to the left or to the right - if (!limask[x - 1] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - } - /* Test the LEFT edge of pixels in buffer, except corners */ - for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty underneath or above - if (!limask[x - rw] || !limask[x + rw]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - } - - /* Test the RIGHT edge of pixels in buffer, except corners */ - for (x = t - rw; x > rw; x -= rw) { - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty underneath or above - if (!limask[x - rw] || !limask[x + rw]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - } - - rsize[0] = isz; // fill in our return sizes for edges + fill - rsize[1] = osz; - rsize[2] = gsz; -} - -static void do_allBleedBorders(unsigned int t, - unsigned int rw, - const unsigned int *limask, - const unsigned int *lomask, - unsigned int *lres, - float *res, - unsigned int *rsize) -{ - int x; - unsigned int isz = 0; // inner edge size - unsigned int osz = 0; // outer edge size - unsigned int gsz = 0; // gradient fill area size - /* Test the four corners */ - /* upper left corner */ - x = t - rw + 1; - // test if inner mask is filled - if (limask[x]) { - // test if the inner mask is empty underneath or to the right - if (!limask[x - rw] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || - !lomask[x + 1]) { // test if outer mask is empty underneath or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - /* upper right corner */ - x = t; - // test if inner mask is filled - if (limask[x]) { - // test if the inner mask is empty underneath or to the left - if (!limask[x - rw] || !limask[x - 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || !lomask[x - 1]) { // test if outer mask is empty above or to the left - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - /* lower left corner */ - x = 0; - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty above or to the right - if (!limask[x + rw] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x + rw] || - !lomask[x + 1]) { // test if outer mask is empty underneath or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - /* lower right corner */ - x = rw - 1; - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty above or to the left - if (!limask[x + rw] || !limask[x - 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x + rw] || - !lomask[x - 1]) { // test if outer mask is empty underneath or to the left - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - /* Test the TOP row of pixels in buffer, except corners */ - for (x = t - 1; x >= (t - rw) + 2; x--) { - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty to the left or to the right - if (!limask[x - 1] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - 1] || - !lomask[x + 1]) { // test if outer mask is empty to the left or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - } - - /* Test the BOTTOM row of pixels in buffer, except corners */ - for (x = rw - 2; x; x--) { - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty to the left or to the right - if (!limask[x - 1] || !limask[x + 1]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - 1] || - !lomask[x + 1]) { // test if outer mask is empty to the left or to the right - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - } - /* Test the LEFT edge of pixels in buffer, except corners */ - for (x = t - (rw << 1) + 1; x >= rw; x -= rw) { - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty underneath or above - if (!limask[x - rw] || !limask[x + rw]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - } - - /* Test the RIGHT edge of pixels in buffer, except corners */ - for (x = t - rw; x > rw; x -= rw) { - // test if inner mask is filled - if (limask[x]) { - // test if inner mask is empty underneath or above - if (!limask[x - rw] || !limask[x + rw]) { - isz++; // increment inner edge size - lres[x] = 4; // flag pixel as inner edge - } - else { - res[x] = 1.0f; // pixel is just part of inner mask, and it's not an edge - } - } - else if (lomask[x]) { // inner mask was empty, test if outer mask is filled - if (!lomask[x - rw] || !lomask[x + rw]) { // test if outer mask is empty underneath or above - osz++; // increment outer edge size - lres[x] = 3; // flag pixel as outer edge - } - else { - gsz++; // increment the gradient pixel count - lres[x] = 2; // flag pixel as gradient - } - } - } - - rsize[0] = isz; // fill in our return sizes for edges + fill - rsize[1] = osz; - rsize[2] = gsz; -} - -static void do_allEdgeDetection(unsigned int t, - unsigned int rw, - const unsigned int *limask, - const unsigned int *lomask, - unsigned int *lres, - float *res, - unsigned int *rsize, - unsigned int in_isz, - unsigned int in_osz, - unsigned int in_gsz) -{ - int x; // x = pixel loop counter - int a; // a = pixel loop counter - int dx; // dx = delta x - int pix_prevRow; // pix_prevRow = pixel one row behind the one we are testing in a loop - int pix_nextRow; // pix_nextRow = pixel one row in front of the one we are testing in a loop - int pix_prevCol; // pix_prevCol = pixel one column behind the one we are testing in a loop - int pix_nextCol; // pix_nextCol = pixel one column in front of the one we are testing in a loop - /* Test all rows between the FIRST and LAST rows, excluding left and right edges */ - for (x = (t - rw) + 1, dx = x - (rw - 2); dx > rw; x -= rw, dx -= rw) { - a = x - 2; - pix_prevRow = a + rw; - pix_nextRow = a - rw; - pix_prevCol = a + 1; - pix_nextCol = a - 1; - while (a > dx - 2) { - if (!limask[a]) { // if the inner mask is empty - if (lomask[a]) { // if the outer mask is full - /* - * Next we test all 4 directions around the current pixel: next/prev/up/down - * The test ensures that the outer mask is empty and that the inner mask - * is also empty. If both conditions are true for any one of the 4 adjacent pixels - * then the current pixel is counted as being a true outer edge pixel. - */ - if ((!lomask[pix_nextCol] && !limask[pix_nextCol]) || - (!lomask[pix_prevCol] && !limask[pix_prevCol]) || - (!lomask[pix_nextRow] && !limask[pix_nextRow]) || - (!lomask[pix_prevRow] && !limask[pix_prevRow])) { - in_osz++; // increment the outer boundary pixel count - lres[a] = 3; // flag pixel as part of outer edge - } - else { // it's not a boundary pixel, but it is a gradient pixel - in_gsz++; // increment the gradient pixel count - lres[a] = 2; // flag pixel as gradient - } - } - } - else { - if (!limask[pix_nextCol] || !limask[pix_prevCol] || !limask[pix_nextRow] || - !limask[pix_prevRow]) { - in_isz++; // increment the inner boundary pixel count - lres[a] = 4; // flag pixel as part of inner edge - } - else { - res[a] = 1.0f; // pixel is part of inner mask, but not at an edge - } - } - a--; - pix_prevRow--; - pix_nextRow--; - pix_prevCol--; - pix_nextCol--; - } - } - - rsize[0] = in_isz; // fill in our return sizes for edges + fill - rsize[1] = in_osz; - rsize[2] = in_gsz; -} - -static void do_adjacentEdgeDetection(unsigned int t, - unsigned int rw, - const unsigned int *limask, - const unsigned int *lomask, - unsigned int *lres, - float *res, - unsigned int *rsize, - unsigned int in_isz, - unsigned int in_osz, - unsigned int in_gsz) -{ - int x; // x = pixel loop counter - int a; // a = pixel loop counter - int dx; // dx = delta x - int pix_prevRow; // pix_prevRow = pixel one row behind the one we are testing in a loop - int pix_nextRow; // pix_nextRow = pixel one row in front of the one we are testing in a loop - int pix_prevCol; // pix_prevCol = pixel one column behind the one we are testing in a loop - int pix_nextCol; // pix_nextCol = pixel one column in front of the one we are testing in a loop - /* Test all rows between the FIRST and LAST rows, excluding left and right edges */ - for (x = (t - rw) + 1, dx = x - (rw - 2); dx > rw; x -= rw, dx -= rw) { - a = x - 2; - pix_prevRow = a + rw; - pix_nextRow = a - rw; - pix_prevCol = a + 1; - pix_nextCol = a - 1; - while (a > dx - 2) { - if (!limask[a]) { // if the inner mask is empty - if (lomask[a]) { // if the outer mask is full - /* - * Next we test all 4 directions around the current pixel: next/prev/up/down - * The test ensures that the outer mask is empty and that the inner mask - * is also empty. If both conditions are true for any one of the 4 adjacent pixels - * then the current pixel is counted as being a true outer edge pixel. - */ - if ((!lomask[pix_nextCol] && !limask[pix_nextCol]) || - (!lomask[pix_prevCol] && !limask[pix_prevCol]) || - (!lomask[pix_nextRow] && !limask[pix_nextRow]) || - (!lomask[pix_prevRow] && !limask[pix_prevRow])) { - in_osz++; // increment the outer boundary pixel count - lres[a] = 3; // flag pixel as part of outer edge - } - else { // it's not a boundary pixel, but it is a gradient pixel - in_gsz++; // increment the gradient pixel count - lres[a] = 2; // flag pixel as gradient - } - } - } - else { - if ((!limask[pix_nextCol] && lomask[pix_nextCol]) || - (!limask[pix_prevCol] && lomask[pix_prevCol]) || - (!limask[pix_nextRow] && lomask[pix_nextRow]) || - (!limask[pix_prevRow] && lomask[pix_prevRow])) { - in_isz++; // increment the inner boundary pixel count - lres[a] = 4; // flag pixel as part of inner edge - } - else { - res[a] = 1.0f; // pixel is part of inner mask, but not at an edge - } - } - a--; - pix_prevRow--; // advance all four "surrounding" pixel pointers - pix_nextRow--; - pix_prevCol--; - pix_nextCol--; - } - } - - rsize[0] = in_isz; // fill in our return sizes for edges + fill - rsize[1] = in_osz; - rsize[2] = in_gsz; -} - -static void do_createEdgeLocationBuffer(unsigned int t, - unsigned int rw, - const unsigned int *lres, - float *res, - unsigned short *gbuf, - unsigned int *innerEdgeOffset, - unsigned int *outerEdgeOffset, - unsigned int isz, - unsigned int gsz) -{ - int x; // x = pixel loop counter - int a; // a = temporary pixel index buffer loop counter - unsigned int ud; // ud = unscaled edge distance - unsigned int dmin; // dmin = minimum edge distance - - unsigned int rsl; // long used for finding fast 1.0/sqrt - unsigned int gradientFillOffset; - - /* For looping inner edge pixel indexes, represents current position from offset. */ - unsigned int innerAccum = 0; - /* For looping outer edge pixel indexes, represents current position from offset. */ - unsigned int outerAccum = 0; - /* For looping gradient pixel indexes, represents current position from offset. */ - unsigned int gradientAccum = 0; - - /* */ - /* clang-format off */ - /* - * Here we compute the size of buffer needed to hold (row,col) coordinates - * for each pixel previously determined to be either gradient, inner edge, - * or outer edge. - * - * Allocation is done by requesting 4 bytes "sizeof(int)" per pixel, even - * though gbuf[] is declared as (unsigned short *) (2 bytes) because we don't - * store the pixel indexes, we only store x,y location of pixel in buffer. - * - * This does make the assumption that x and y can fit in 16 unsigned bits - * so if Blender starts doing renders greater than 65536 in either direction - * this will need to allocate gbuf[] as unsigned int *and allocate 8 bytes - * per flagged pixel. - * - * In general, the buffer on-screen: - * - * Example: 9 by 9 pixel block - * - * . = pixel non-white in both outer and inner mask - * o = pixel white in outer, but not inner mask, adjacent to "." pixel - * g = pixel white in outer, but not inner mask, not adjacent to "." pixel - * i = pixel white in inner mask, adjacent to "g" or "." pixel - * F = pixel white in inner mask, only adjacent to other pixels white in the inner mask - * - * - * ......... <----- pixel #80 - * ..oooo... - * .oggggo.. - * .oggiggo. - * .ogiFigo. - * .oggiggo. - * .oggggo.. - * ..oooo... - * pixel #00 -----> ......... - * - * gsz = 18 (18 "g" pixels above) - * isz = 4 (4 "i" pixels above) - * osz = 18 (18 "o" pixels above) - * - * - * The memory in gbuf[] after filling will look like this: - * - * gradientFillOffset (0 pixels) innerEdgeOffset (18 pixels) outerEdgeOffset (22 pixels) - * / / / - * / / / - * |X Y X Y X Y X Y > <----------------> <------------------------> <----------------+ - * |0 2 4 6 8 10 12 14 > ... <68 70 72 74 > ... <80 82 84 86 88 90 > ... <152 154 156 158 | <- bytes - * +--------------------------------> <----------------> <------------------------> <----------------+ - * |g0 g0 g1 g1 g2 g2 g3 g3 > = 0; x--) { - gradientFillOffset = x << 1; - t = gbuf[gradientFillOffset]; // calculate column of pixel indexed by gbuf[x] - fsz = gbuf[gradientFillOffset + 1]; // calculate row of pixel indexed by gbuf[x] - dmin = 0xffffffff; // reset min distance to edge pixel - for (a = outerEdgeOffset + osz - 1; a >= outerEdgeOffset; - a--) { // loop through all outer edge buffer pixels - ud = a << 1; - dy = t - gbuf[ud]; // set dx to gradient pixel column - outer edge pixel row - dx = fsz - gbuf[ud + 1]; // set dy to gradient pixel row - outer edge pixel column - ud = dx * dx + dy * dy; // compute sum of squares - if (ud < dmin) { // if our new sum of squares is less than the current minimum - dmin = ud; // set a new minimum equal to the new lower value - } - } - odist = (float)(dmin); // cast outer min to a float - rsf = odist * 0.5f; // - rsl = *(unsigned int *)&odist; // use some peculiar properties of the way bits are stored - rsl = 0x5f3759df - (rsl >> 1); // in floats vs. unsigned ints to compute an approximate - odist = *(float *)&rsl; // reciprocal square root - odist = odist * (rsopf - (rsf * odist * - odist)); // -- ** this line can be iterated for more accuracy ** -- - dmin = 0xffffffff; // reset min distance to edge pixel - for (a = innerEdgeOffset + isz - 1; a >= innerEdgeOffset; - a--) { // loop through all inside edge pixels - ud = a << 1; - dy = t - gbuf[ud]; // compute delta in Y from gradient pixel to inside edge pixel - dx = fsz - gbuf[ud + 1]; // compute delta in X from gradient pixel to inside edge pixel - ud = dx * dx + dy * dy; // compute sum of squares - if (ud < dmin) { // if our new sum of squares is less than the current minimum we've found - dmin = ud; // set a new minimum equal to the new lower value - } - } - idist = (float)(dmin); // cast inner min to a float - rsf = idist * 0.5f; // - rsl = *(unsigned int *)&idist; // - rsl = 0x5f3759df - (rsl >> 1); // see notes above - idist = *(float *)&rsl; // - idist = idist * (rsopf - (rsf * idist * idist)); // - /* - * Note once again that since we are using reciprocals of distance values our - * proportion is already the correct intensity, and does not need to be - * subtracted from 1.0 like it would have if we used real distances. - */ - - /* - * Here we reconstruct the pixel's memory location in the CompBuf by - * Pixel Index = Pixel Column + ( Pixel Row * Row Width ) - */ - res[gbuf[gradientFillOffset + 1] + (gbuf[gradientFillOffset] * rw)] = - (idist / (idist + odist)); // set intensity - } -} - -// end of copy - -void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float *res) -{ - unsigned int *lres; // lres = unsigned int pointer to output pixel buffer (for bit operations) - unsigned int *limask; // limask = unsigned int pointer to inner mask (for bit operations) - unsigned int *lomask; // lomask = unsigned int pointer to outer mask (for bit operations) - - int rw; // rw = pixel row width - int t; // t = total number of pixels in buffer - 1 (used for loop starts) - int fsz; // size of the frame - - unsigned int isz = 0; // size (in pixels) of inside edge pixel index buffer - unsigned int osz = 0; // size (in pixels) of outside edge pixel index buffer - unsigned int gsz = 0; // size (in pixels) of gradient pixel index buffer - unsigned int rsize[3]; // size storage to pass to helper functions - unsigned int innerEdgeOffset = - 0; // offset into final buffer where inner edge pixel indexes start - unsigned int outerEdgeOffset = - 0; // offset into final buffer where outer edge pixel indexes start - - unsigned short *gbuf; // gradient/inner/outer pixel location index buffer - - if (true) { // if both input sockets have some data coming in... - - rw = this->getWidth(); // width of a row of pixels - t = (rw * this->getHeight()) - 1; // determine size of the frame - memset(res, - 0, - sizeof(float) * (t + 1)); // clear output buffer (not all pixels will be written later) - - lres = (unsigned int *)res; // unsigned int pointer to output buffer (for bit level ops) - limask = (unsigned int *)imask; // unsigned int pointer to input mask (for bit level ops) - lomask = (unsigned int *)omask; // unsigned int pointer to output mask (for bit level ops) - - /* - * The whole buffer is broken up into 4 parts. The four CORNERS, the FIRST and LAST rows, the - * LEFT and RIGHT edges (excluding the corner pixels), and all OTHER rows. - * This allows for quick computation of outer edge pixels where - * a screen edge pixel is marked to be gradient. - * - * The pixel type (gradient vs inner-edge vs outer-edge) tests change - * depending on the user selected "Inner Edge Mode" and the user selected - * "Buffer Edge Mode" on the node's GUI. There are 4 sets of basically the - * same algorithm: - * - * 1.) Inner Edge -> Adjacent Only - * Buffer Edge -> Keep Inside - * - * 2.) Inner Edge -> Adjacent Only - * Buffer Edge -> Bleed Out - * - * 3.) Inner Edge -> All - * Buffer Edge -> Keep Inside - * - * 4.) Inner Edge -> All - * Buffer Edge -> Bleed Out - * - * Each version has slightly different criteria for detecting an edge pixel. - */ - if (this->m_adjacentOnly) { // if "adjacent only" inner edge mode is turned on - if (this->m_keepInside) { // if "keep inside" buffer edge mode is turned on - do_adjacentKeepBorders(t, rw, limask, lomask, lres, res, rsize); - } - else { // "bleed out" buffer edge mode is turned on - do_adjacentBleedBorders(t, rw, limask, lomask, lres, res, rsize); - } - // set up inner edge, outer edge, and gradient buffer sizes after border pass - isz = rsize[0]; - osz = rsize[1]; - gsz = rsize[2]; - // detect edges in all non-border pixels in the buffer - do_adjacentEdgeDetection(t, rw, limask, lomask, lres, res, rsize, isz, osz, gsz); - } - else { // "all" inner edge mode is turned on - if (this->m_keepInside) { // if "keep inside" buffer edge mode is turned on - do_allKeepBorders(t, rw, limask, lomask, lres, res, rsize); - } - else { // "bleed out" buffer edge mode is turned on - do_allBleedBorders(t, rw, limask, lomask, lres, res, rsize); - } - // set up inner edge, outer edge, and gradient buffer sizes after border pass - isz = rsize[0]; - osz = rsize[1]; - gsz = rsize[2]; - // detect edges in all non-border pixels in the buffer - do_allEdgeDetection(t, rw, limask, lomask, lres, res, rsize, isz, osz, gsz); - } - - // set edge and gradient buffer sizes once again... - // the sizes in rsize[] may have been modified - // by the do_*EdgeDetection() function. - isz = rsize[0]; - osz = rsize[1]; - gsz = rsize[2]; - - // calculate size of pixel index buffer needed - fsz = gsz + isz + osz; - // allocate edge/gradient pixel index buffer - gbuf = (unsigned short *)MEM_callocN(sizeof(unsigned short) * fsz * 2, "DEM"); - - do_createEdgeLocationBuffer( - t, rw, lres, res, gbuf, &innerEdgeOffset, &outerEdgeOffset, isz, gsz); - do_fillGradientBuffer(rw, res, gbuf, isz, osz, gsz, innerEdgeOffset, outerEdgeOffset); - - // free the gradient index buffer - MEM_freeN(gbuf); - } -} - -DoubleEdgeMaskOperation::DoubleEdgeMaskOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputInnerMask = nullptr; - this->m_inputOuterMask = nullptr; - this->m_adjacentOnly = false; - this->m_keepInside = false; - this->setComplex(true); -} - -bool DoubleEdgeMaskOperation::determineDependingAreaOfInterest(rcti * /*input*/, - ReadBufferOperation *readOperation, - rcti *output) -{ - if (this->m_cachedInstance == nullptr) { - rcti newInput; - newInput.xmax = this->getWidth(); - newInput.xmin = 0; - newInput.ymax = this->getHeight(); - newInput.ymin = 0; - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); - } - - return false; -} - -void DoubleEdgeMaskOperation::initExecution() -{ - this->m_inputInnerMask = this->getInputSocketReader(0); - this->m_inputOuterMask = this->getInputSocketReader(1); - initMutex(); - this->m_cachedInstance = nullptr; -} - -void *DoubleEdgeMaskOperation::initializeTileData(rcti *rect) -{ - if (this->m_cachedInstance) { - return this->m_cachedInstance; - } - - lockMutex(); - if (this->m_cachedInstance == nullptr) { - MemoryBuffer *innerMask = (MemoryBuffer *)this->m_inputInnerMask->initializeTileData(rect); - MemoryBuffer *outerMask = (MemoryBuffer *)this->m_inputOuterMask->initializeTileData(rect); - float *data = (float *)MEM_mallocN(sizeof(float) * this->getWidth() * this->getHeight(), - __func__); - float *imask = innerMask->getBuffer(); - float *omask = outerMask->getBuffer(); - doDoubleEdgeMask(imask, omask, data); - this->m_cachedInstance = data; - } - unlockMutex(); - return this->m_cachedInstance; -} -void DoubleEdgeMaskOperation::executePixel(float output[4], int x, int y, void *data) -{ - float *buffer = (float *)data; - int index = (y * this->getWidth() + x); - output[0] = buffer[index]; -} - -void DoubleEdgeMaskOperation::deinitExecution() -{ - this->m_inputInnerMask = nullptr; - this->m_inputOuterMask = nullptr; - deinitMutex(); - if (this->m_cachedInstance) { - MEM_freeN(this->m_cachedInstance); - this->m_cachedInstance = nullptr; - } -} diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc new file mode 100644 index 00000000000..a6985a40625 --- /dev/null +++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc @@ -0,0 +1,119 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_EllipseMaskOperation.h" +#include "BLI_math.h" +#include "DNA_node_types.h" + +EllipseMaskOperation::EllipseMaskOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->m_inputMask = nullptr; + this->m_inputValue = nullptr; + this->m_cosine = 0.0f; + this->m_sine = 0.0f; +} +void EllipseMaskOperation::initExecution() +{ + this->m_inputMask = this->getInputSocketReader(0); + this->m_inputValue = this->getInputSocketReader(1); + const double rad = (double)this->m_data->rotation; + this->m_cosine = cos(rad); + this->m_sine = sin(rad); + this->m_aspectRatio = ((float)this->getWidth()) / this->getHeight(); +} + +void EllipseMaskOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputMask[4]; + float inputValue[4]; + + float rx = x / this->getWidth(); + float ry = y / this->getHeight(); + + const float dy = (ry - this->m_data->y) / this->m_aspectRatio; + const float dx = rx - this->m_data->x; + rx = this->m_data->x + (this->m_cosine * dx + this->m_sine * dy); + ry = this->m_data->y + (-this->m_sine * dx + this->m_cosine * dy); + + this->m_inputMask->readSampled(inputMask, x, y, sampler); + this->m_inputValue->readSampled(inputValue, x, y, sampler); + + const float halfHeight = (this->m_data->height) / 2.0f; + const float halfWidth = this->m_data->width / 2.0f; + float sx = rx - this->m_data->x; + sx *= sx; + const float tx = halfWidth * halfWidth; + float sy = ry - this->m_data->y; + sy *= sy; + const float ty = halfHeight * halfHeight; + + bool inside = ((sx / tx) + (sy / ty)) < 1.0f; + + switch (this->m_maskType) { + case CMP_NODE_MASKTYPE_ADD: + if (inside) { + output[0] = MAX2(inputMask[0], inputValue[0]); + } + else { + output[0] = inputMask[0]; + } + break; + case CMP_NODE_MASKTYPE_SUBTRACT: + if (inside) { + output[0] = inputMask[0] - inputValue[0]; + CLAMP(output[0], 0, 1); + } + else { + output[0] = inputMask[0]; + } + break; + case CMP_NODE_MASKTYPE_MULTIPLY: + if (inside) { + output[0] = inputMask[0] * inputValue[0]; + } + else { + output[0] = 0; + } + break; + case CMP_NODE_MASKTYPE_NOT: + if (inside) { + if (inputMask[0] > 0.0f) { + output[0] = 0; + } + else { + output[0] = inputValue[0]; + } + } + else { + output[0] = inputMask[0]; + } + break; + } +} + +void EllipseMaskOperation::deinitExecution() +{ + this->m_inputMask = nullptr; + this->m_inputValue = nullptr; +} diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp b/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp deleted file mode 100644 index a6985a40625..00000000000 --- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_EllipseMaskOperation.h" -#include "BLI_math.h" -#include "DNA_node_types.h" - -EllipseMaskOperation::EllipseMaskOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputMask = nullptr; - this->m_inputValue = nullptr; - this->m_cosine = 0.0f; - this->m_sine = 0.0f; -} -void EllipseMaskOperation::initExecution() -{ - this->m_inputMask = this->getInputSocketReader(0); - this->m_inputValue = this->getInputSocketReader(1); - const double rad = (double)this->m_data->rotation; - this->m_cosine = cos(rad); - this->m_sine = sin(rad); - this->m_aspectRatio = ((float)this->getWidth()) / this->getHeight(); -} - -void EllipseMaskOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputMask[4]; - float inputValue[4]; - - float rx = x / this->getWidth(); - float ry = y / this->getHeight(); - - const float dy = (ry - this->m_data->y) / this->m_aspectRatio; - const float dx = rx - this->m_data->x; - rx = this->m_data->x + (this->m_cosine * dx + this->m_sine * dy); - ry = this->m_data->y + (-this->m_sine * dx + this->m_cosine * dy); - - this->m_inputMask->readSampled(inputMask, x, y, sampler); - this->m_inputValue->readSampled(inputValue, x, y, sampler); - - const float halfHeight = (this->m_data->height) / 2.0f; - const float halfWidth = this->m_data->width / 2.0f; - float sx = rx - this->m_data->x; - sx *= sx; - const float tx = halfWidth * halfWidth; - float sy = ry - this->m_data->y; - sy *= sy; - const float ty = halfHeight * halfHeight; - - bool inside = ((sx / tx) + (sy / ty)) < 1.0f; - - switch (this->m_maskType) { - case CMP_NODE_MASKTYPE_ADD: - if (inside) { - output[0] = MAX2(inputMask[0], inputValue[0]); - } - else { - output[0] = inputMask[0]; - } - break; - case CMP_NODE_MASKTYPE_SUBTRACT: - if (inside) { - output[0] = inputMask[0] - inputValue[0]; - CLAMP(output[0], 0, 1); - } - else { - output[0] = inputMask[0]; - } - break; - case CMP_NODE_MASKTYPE_MULTIPLY: - if (inside) { - output[0] = inputMask[0] * inputValue[0]; - } - else { - output[0] = 0; - } - break; - case CMP_NODE_MASKTYPE_NOT: - if (inside) { - if (inputMask[0] > 0.0f) { - output[0] = 0; - } - else { - output[0] = inputValue[0]; - } - } - else { - output[0] = inputMask[0]; - } - break; - } -} - -void EllipseMaskOperation::deinitExecution() -{ - this->m_inputMask = nullptr; - this->m_inputValue = nullptr; -} diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc new file mode 100644 index 00000000000..b3c1b6b4413 --- /dev/null +++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc @@ -0,0 +1,343 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include + +#include "BLI_utildefines.h" +#include "COM_FastGaussianBlurOperation.h" +#include "MEM_guardedalloc.h" + +FastGaussianBlurOperation::FastGaussianBlurOperation() : BlurBaseOperation(COM_DT_COLOR) +{ + this->m_iirgaus = nullptr; +} + +void FastGaussianBlurOperation::executePixel(float output[4], int x, int y, void *data) +{ + MemoryBuffer *newData = (MemoryBuffer *)data; + newData->read(output, x, y); +} + +bool FastGaussianBlurOperation::determineDependingAreaOfInterest( + rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + rcti sizeInput; + sizeInput.xmin = 0; + sizeInput.ymin = 0; + sizeInput.xmax = 5; + sizeInput.ymax = 5; + + NodeOperation *operation = this->getInputOperation(1); + if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { + return true; + } + + if (this->m_iirgaus) { + return false; + } + + newInput.xmin = 0; + newInput.ymin = 0; + newInput.xmax = this->getWidth(); + newInput.ymax = this->getHeight(); + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +void FastGaussianBlurOperation::initExecution() +{ + BlurBaseOperation::initExecution(); + BlurBaseOperation::initMutex(); +} + +void FastGaussianBlurOperation::deinitExecution() +{ + if (this->m_iirgaus) { + delete this->m_iirgaus; + this->m_iirgaus = nullptr; + } + BlurBaseOperation::deinitMutex(); +} + +void *FastGaussianBlurOperation::initializeTileData(rcti *rect) +{ + lockMutex(); + if (!this->m_iirgaus) { + MemoryBuffer *newBuf = (MemoryBuffer *)this->m_inputProgram->initializeTileData(rect); + MemoryBuffer *copy = newBuf->duplicate(); + updateSize(); + + int c; + this->m_sx = this->m_data.sizex * this->m_size / 2.0f; + this->m_sy = this->m_data.sizey * this->m_size / 2.0f; + + if ((this->m_sx == this->m_sy) && (this->m_sx > 0.0f)) { + for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) { + IIR_gauss(copy, this->m_sx, c, 3); + } + } + else { + if (this->m_sx > 0.0f) { + for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) { + IIR_gauss(copy, this->m_sx, c, 1); + } + } + if (this->m_sy > 0.0f) { + for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) { + IIR_gauss(copy, this->m_sy, c, 2); + } + } + } + this->m_iirgaus = copy; + } + unlockMutex(); + return this->m_iirgaus; +} + +void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, + float sigma, + unsigned int chan, + unsigned int xy) +{ + double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3]; + double *X, *Y, *W; + const unsigned int src_width = src->getWidth(); + const unsigned int src_height = src->getHeight(); + unsigned int x, y, sz; + unsigned int i; + float *buffer = src->getBuffer(); + const unsigned int num_channels = src->get_num_channels(); + + // <0.5 not valid, though can have a possibly useful sort of sharpening effect + if (sigma < 0.5f) { + return; + } + + if ((xy < 1) || (xy > 3)) { + xy = 3; + } + + // XXX The YVV macro defined below explicitly expects sources of at least 3x3 pixels, + // so just skipping blur along faulty direction if src's def is below that limit! + if (src_width < 3) { + xy &= ~1; + } + if (src_height < 3) { + xy &= ~2; + } + if (xy < 1) { + return; + } + + // see "Recursive Gabor Filtering" by Young/VanVliet + // all factors here in double.prec. + // Required, because for single.prec it seems to blow up if sigma > ~200 + if (sigma >= 3.556f) { + q = 0.9804f * (sigma - 3.556f) + 2.5091f; + } + else { // sigma >= 0.5 + q = (0.0561f * sigma + 0.5784f) * sigma - 0.2568f; + } + q2 = q * q; + sc = (1.1668 + q) * (3.203729649 + (2.21566 + q) * q); + // no gabor filtering here, so no complex multiplies, just the regular coefs. + // all negated here, so as not to have to recalc Triggs/Sdika matrix + cf[1] = q * (5.788961737 + (6.76492 + 3.0 * q) * q) / sc; + cf[2] = -q2 * (3.38246 + 3.0 * q) / sc; + // 0 & 3 unchanged + cf[3] = q2 * q / sc; + cf[0] = 1.0 - cf[1] - cf[2] - cf[3]; + + // Triggs/Sdika border corrections, + // it seems to work, not entirely sure if it is actually totally correct, + // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark), + // found one other implementation by Cristoph Lampert, + // but neither seem to be quite the same, result seems to be ok so far anyway. + // Extra scale factor here to not have to do it in filter, + // though maybe this had something to with the precision errors + sc = cf[0] / ((1.0 + cf[1] - cf[2] + cf[3]) * (1.0 - cf[1] - cf[2] - cf[3]) * + (1.0 + cf[2] + (cf[1] - cf[3]) * cf[3])); + tsM[0] = sc * (-cf[3] * cf[1] + 1.0 - cf[3] * cf[3] - cf[2]); + tsM[1] = sc * ((cf[3] + cf[1]) * (cf[2] + cf[3] * cf[1])); + tsM[2] = sc * (cf[3] * (cf[1] + cf[3] * cf[2])); + tsM[3] = sc * (cf[1] + cf[3] * cf[2]); + tsM[4] = sc * (-(cf[2] - 1.0) * (cf[2] + cf[3] * cf[1])); + tsM[5] = sc * (-(cf[3] * cf[1] + cf[3] * cf[3] + cf[2] - 1.0) * cf[3]); + tsM[6] = sc * (cf[3] * cf[1] + cf[2] + cf[1] * cf[1] - cf[2] * cf[2]); + tsM[7] = sc * (cf[1] * cf[2] + cf[3] * cf[2] * cf[2] - cf[1] * cf[3] * cf[3] - + cf[3] * cf[3] * cf[3] - cf[3] * cf[2] + cf[3]); + tsM[8] = sc * (cf[3] * (cf[1] + cf[3] * cf[2])); + +#define YVV(L) \ + { \ + W[0] = cf[0] * X[0] + cf[1] * X[0] + cf[2] * X[0] + cf[3] * X[0]; \ + W[1] = cf[0] * X[1] + cf[1] * W[0] + cf[2] * X[0] + cf[3] * X[0]; \ + W[2] = cf[0] * X[2] + cf[1] * W[1] + cf[2] * W[0] + cf[3] * X[0]; \ + for (i = 3; i < L; i++) { \ + W[i] = cf[0] * X[i] + cf[1] * W[i - 1] + cf[2] * W[i - 2] + cf[3] * W[i - 3]; \ + } \ + tsu[0] = W[L - 1] - X[L - 1]; \ + tsu[1] = W[L - 2] - X[L - 1]; \ + tsu[2] = W[L - 3] - X[L - 1]; \ + tsv[0] = tsM[0] * tsu[0] + tsM[1] * tsu[1] + tsM[2] * tsu[2] + X[L - 1]; \ + tsv[1] = tsM[3] * tsu[0] + tsM[4] * tsu[1] + tsM[5] * tsu[2] + X[L - 1]; \ + tsv[2] = tsM[6] * tsu[0] + tsM[7] * tsu[1] + tsM[8] * tsu[2] + X[L - 1]; \ + Y[L - 1] = cf[0] * W[L - 1] + cf[1] * tsv[0] + cf[2] * tsv[1] + cf[3] * tsv[2]; \ + Y[L - 2] = cf[0] * W[L - 2] + cf[1] * Y[L - 1] + cf[2] * tsv[0] + cf[3] * tsv[1]; \ + Y[L - 3] = cf[0] * W[L - 3] + cf[1] * Y[L - 2] + cf[2] * Y[L - 1] + cf[3] * tsv[0]; \ + /* 'i != UINT_MAX' is really 'i >= 0', but necessary for unsigned int wrapping */ \ + for (i = L - 4; i != UINT_MAX; i--) { \ + Y[i] = cf[0] * W[i] + cf[1] * Y[i + 1] + cf[2] * Y[i + 2] + cf[3] * Y[i + 3]; \ + } \ + } \ + (void)0 + + // intermediate buffers + sz = MAX2(src_width, src_height); + X = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss X buf"); + Y = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss Y buf"); + W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf"); + if (xy & 1) { // H + int offset; + for (y = 0; y < src_height; y++) { + const int yx = y * src_width; + offset = yx * num_channels + chan; + for (x = 0; x < src_width; x++) { + X[x] = buffer[offset]; + offset += num_channels; + } + YVV(src_width); + offset = yx * num_channels + chan; + for (x = 0; x < src_width; x++) { + buffer[offset] = Y[x]; + offset += num_channels; + } + } + } + if (xy & 2) { // V + int offset; + const int add = src_width * num_channels; + + for (x = 0; x < src_width; x++) { + offset = x * num_channels + chan; + for (y = 0; y < src_height; y++) { + X[y] = buffer[offset]; + offset += add; + } + YVV(src_height); + offset = x * num_channels + chan; + for (y = 0; y < src_height; y++) { + buffer[offset] = Y[y]; + offset += add; + } + } + } + + MEM_freeN(X); + MEM_freeN(W); + MEM_freeN(Y); +#undef YVV +} + +/// +FastGaussianBlurValueOperation::FastGaussianBlurValueOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->m_iirgaus = nullptr; + this->m_inputprogram = nullptr; + this->m_sigma = 1.0f; + this->m_overlay = 0; + setComplex(true); +} + +void FastGaussianBlurValueOperation::executePixel(float output[4], int x, int y, void *data) +{ + MemoryBuffer *newData = (MemoryBuffer *)data; + newData->read(output, x, y); +} + +bool FastGaussianBlurValueOperation::determineDependingAreaOfInterest( + rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + + if (this->m_iirgaus) { + return false; + } + + newInput.xmin = 0; + newInput.ymin = 0; + newInput.xmax = this->getWidth(); + newInput.ymax = this->getHeight(); + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +void FastGaussianBlurValueOperation::initExecution() +{ + this->m_inputprogram = getInputSocketReader(0); + initMutex(); +} + +void FastGaussianBlurValueOperation::deinitExecution() +{ + if (this->m_iirgaus) { + delete this->m_iirgaus; + this->m_iirgaus = nullptr; + } + deinitMutex(); +} + +void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect) +{ + lockMutex(); + if (!this->m_iirgaus) { + MemoryBuffer *newBuf = (MemoryBuffer *)this->m_inputprogram->initializeTileData(rect); + MemoryBuffer *copy = newBuf->duplicate(); + FastGaussianBlurOperation::IIR_gauss(copy, this->m_sigma, 0, 3); + + if (this->m_overlay == FAST_GAUSS_OVERLAY_MIN) { + float *src = newBuf->getBuffer(); + float *dst = copy->getBuffer(); + for (int i = copy->getWidth() * copy->getHeight(); i != 0; + i--, src += COM_NUM_CHANNELS_VALUE, dst += COM_NUM_CHANNELS_VALUE) { + if (*src < *dst) { + *dst = *src; + } + } + } + else if (this->m_overlay == FAST_GAUSS_OVERLAY_MAX) { + float *src = newBuf->getBuffer(); + float *dst = copy->getBuffer(); + for (int i = copy->getWidth() * copy->getHeight(); i != 0; + i--, src += COM_NUM_CHANNELS_VALUE, dst += COM_NUM_CHANNELS_VALUE) { + if (*src > *dst) { + *dst = *src; + } + } + } + + // newBuf-> + + this->m_iirgaus = copy; + } + unlockMutex(); + return this->m_iirgaus; +} diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp deleted file mode 100644 index b3c1b6b4413..00000000000 --- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp +++ /dev/null @@ -1,343 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include - -#include "BLI_utildefines.h" -#include "COM_FastGaussianBlurOperation.h" -#include "MEM_guardedalloc.h" - -FastGaussianBlurOperation::FastGaussianBlurOperation() : BlurBaseOperation(COM_DT_COLOR) -{ - this->m_iirgaus = nullptr; -} - -void FastGaussianBlurOperation::executePixel(float output[4], int x, int y, void *data) -{ - MemoryBuffer *newData = (MemoryBuffer *)data; - newData->read(output, x, y); -} - -bool FastGaussianBlurOperation::determineDependingAreaOfInterest( - rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInput; - rcti sizeInput; - sizeInput.xmin = 0; - sizeInput.ymin = 0; - sizeInput.xmax = 5; - sizeInput.ymax = 5; - - NodeOperation *operation = this->getInputOperation(1); - if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { - return true; - } - - if (this->m_iirgaus) { - return false; - } - - newInput.xmin = 0; - newInput.ymin = 0; - newInput.xmax = this->getWidth(); - newInput.ymax = this->getHeight(); - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -void FastGaussianBlurOperation::initExecution() -{ - BlurBaseOperation::initExecution(); - BlurBaseOperation::initMutex(); -} - -void FastGaussianBlurOperation::deinitExecution() -{ - if (this->m_iirgaus) { - delete this->m_iirgaus; - this->m_iirgaus = nullptr; - } - BlurBaseOperation::deinitMutex(); -} - -void *FastGaussianBlurOperation::initializeTileData(rcti *rect) -{ - lockMutex(); - if (!this->m_iirgaus) { - MemoryBuffer *newBuf = (MemoryBuffer *)this->m_inputProgram->initializeTileData(rect); - MemoryBuffer *copy = newBuf->duplicate(); - updateSize(); - - int c; - this->m_sx = this->m_data.sizex * this->m_size / 2.0f; - this->m_sy = this->m_data.sizey * this->m_size / 2.0f; - - if ((this->m_sx == this->m_sy) && (this->m_sx > 0.0f)) { - for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) { - IIR_gauss(copy, this->m_sx, c, 3); - } - } - else { - if (this->m_sx > 0.0f) { - for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) { - IIR_gauss(copy, this->m_sx, c, 1); - } - } - if (this->m_sy > 0.0f) { - for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) { - IIR_gauss(copy, this->m_sy, c, 2); - } - } - } - this->m_iirgaus = copy; - } - unlockMutex(); - return this->m_iirgaus; -} - -void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, - float sigma, - unsigned int chan, - unsigned int xy) -{ - double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3]; - double *X, *Y, *W; - const unsigned int src_width = src->getWidth(); - const unsigned int src_height = src->getHeight(); - unsigned int x, y, sz; - unsigned int i; - float *buffer = src->getBuffer(); - const unsigned int num_channels = src->get_num_channels(); - - // <0.5 not valid, though can have a possibly useful sort of sharpening effect - if (sigma < 0.5f) { - return; - } - - if ((xy < 1) || (xy > 3)) { - xy = 3; - } - - // XXX The YVV macro defined below explicitly expects sources of at least 3x3 pixels, - // so just skipping blur along faulty direction if src's def is below that limit! - if (src_width < 3) { - xy &= ~1; - } - if (src_height < 3) { - xy &= ~2; - } - if (xy < 1) { - return; - } - - // see "Recursive Gabor Filtering" by Young/VanVliet - // all factors here in double.prec. - // Required, because for single.prec it seems to blow up if sigma > ~200 - if (sigma >= 3.556f) { - q = 0.9804f * (sigma - 3.556f) + 2.5091f; - } - else { // sigma >= 0.5 - q = (0.0561f * sigma + 0.5784f) * sigma - 0.2568f; - } - q2 = q * q; - sc = (1.1668 + q) * (3.203729649 + (2.21566 + q) * q); - // no gabor filtering here, so no complex multiplies, just the regular coefs. - // all negated here, so as not to have to recalc Triggs/Sdika matrix - cf[1] = q * (5.788961737 + (6.76492 + 3.0 * q) * q) / sc; - cf[2] = -q2 * (3.38246 + 3.0 * q) / sc; - // 0 & 3 unchanged - cf[3] = q2 * q / sc; - cf[0] = 1.0 - cf[1] - cf[2] - cf[3]; - - // Triggs/Sdika border corrections, - // it seems to work, not entirely sure if it is actually totally correct, - // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark), - // found one other implementation by Cristoph Lampert, - // but neither seem to be quite the same, result seems to be ok so far anyway. - // Extra scale factor here to not have to do it in filter, - // though maybe this had something to with the precision errors - sc = cf[0] / ((1.0 + cf[1] - cf[2] + cf[3]) * (1.0 - cf[1] - cf[2] - cf[3]) * - (1.0 + cf[2] + (cf[1] - cf[3]) * cf[3])); - tsM[0] = sc * (-cf[3] * cf[1] + 1.0 - cf[3] * cf[3] - cf[2]); - tsM[1] = sc * ((cf[3] + cf[1]) * (cf[2] + cf[3] * cf[1])); - tsM[2] = sc * (cf[3] * (cf[1] + cf[3] * cf[2])); - tsM[3] = sc * (cf[1] + cf[3] * cf[2]); - tsM[4] = sc * (-(cf[2] - 1.0) * (cf[2] + cf[3] * cf[1])); - tsM[5] = sc * (-(cf[3] * cf[1] + cf[3] * cf[3] + cf[2] - 1.0) * cf[3]); - tsM[6] = sc * (cf[3] * cf[1] + cf[2] + cf[1] * cf[1] - cf[2] * cf[2]); - tsM[7] = sc * (cf[1] * cf[2] + cf[3] * cf[2] * cf[2] - cf[1] * cf[3] * cf[3] - - cf[3] * cf[3] * cf[3] - cf[3] * cf[2] + cf[3]); - tsM[8] = sc * (cf[3] * (cf[1] + cf[3] * cf[2])); - -#define YVV(L) \ - { \ - W[0] = cf[0] * X[0] + cf[1] * X[0] + cf[2] * X[0] + cf[3] * X[0]; \ - W[1] = cf[0] * X[1] + cf[1] * W[0] + cf[2] * X[0] + cf[3] * X[0]; \ - W[2] = cf[0] * X[2] + cf[1] * W[1] + cf[2] * W[0] + cf[3] * X[0]; \ - for (i = 3; i < L; i++) { \ - W[i] = cf[0] * X[i] + cf[1] * W[i - 1] + cf[2] * W[i - 2] + cf[3] * W[i - 3]; \ - } \ - tsu[0] = W[L - 1] - X[L - 1]; \ - tsu[1] = W[L - 2] - X[L - 1]; \ - tsu[2] = W[L - 3] - X[L - 1]; \ - tsv[0] = tsM[0] * tsu[0] + tsM[1] * tsu[1] + tsM[2] * tsu[2] + X[L - 1]; \ - tsv[1] = tsM[3] * tsu[0] + tsM[4] * tsu[1] + tsM[5] * tsu[2] + X[L - 1]; \ - tsv[2] = tsM[6] * tsu[0] + tsM[7] * tsu[1] + tsM[8] * tsu[2] + X[L - 1]; \ - Y[L - 1] = cf[0] * W[L - 1] + cf[1] * tsv[0] + cf[2] * tsv[1] + cf[3] * tsv[2]; \ - Y[L - 2] = cf[0] * W[L - 2] + cf[1] * Y[L - 1] + cf[2] * tsv[0] + cf[3] * tsv[1]; \ - Y[L - 3] = cf[0] * W[L - 3] + cf[1] * Y[L - 2] + cf[2] * Y[L - 1] + cf[3] * tsv[0]; \ - /* 'i != UINT_MAX' is really 'i >= 0', but necessary for unsigned int wrapping */ \ - for (i = L - 4; i != UINT_MAX; i--) { \ - Y[i] = cf[0] * W[i] + cf[1] * Y[i + 1] + cf[2] * Y[i + 2] + cf[3] * Y[i + 3]; \ - } \ - } \ - (void)0 - - // intermediate buffers - sz = MAX2(src_width, src_height); - X = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss X buf"); - Y = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss Y buf"); - W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf"); - if (xy & 1) { // H - int offset; - for (y = 0; y < src_height; y++) { - const int yx = y * src_width; - offset = yx * num_channels + chan; - for (x = 0; x < src_width; x++) { - X[x] = buffer[offset]; - offset += num_channels; - } - YVV(src_width); - offset = yx * num_channels + chan; - for (x = 0; x < src_width; x++) { - buffer[offset] = Y[x]; - offset += num_channels; - } - } - } - if (xy & 2) { // V - int offset; - const int add = src_width * num_channels; - - for (x = 0; x < src_width; x++) { - offset = x * num_channels + chan; - for (y = 0; y < src_height; y++) { - X[y] = buffer[offset]; - offset += add; - } - YVV(src_height); - offset = x * num_channels + chan; - for (y = 0; y < src_height; y++) { - buffer[offset] = Y[y]; - offset += add; - } - } - } - - MEM_freeN(X); - MEM_freeN(W); - MEM_freeN(Y); -#undef YVV -} - -/// -FastGaussianBlurValueOperation::FastGaussianBlurValueOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->m_iirgaus = nullptr; - this->m_inputprogram = nullptr; - this->m_sigma = 1.0f; - this->m_overlay = 0; - setComplex(true); -} - -void FastGaussianBlurValueOperation::executePixel(float output[4], int x, int y, void *data) -{ - MemoryBuffer *newData = (MemoryBuffer *)data; - newData->read(output, x, y); -} - -bool FastGaussianBlurValueOperation::determineDependingAreaOfInterest( - rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInput; - - if (this->m_iirgaus) { - return false; - } - - newInput.xmin = 0; - newInput.ymin = 0; - newInput.xmax = this->getWidth(); - newInput.ymax = this->getHeight(); - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -void FastGaussianBlurValueOperation::initExecution() -{ - this->m_inputprogram = getInputSocketReader(0); - initMutex(); -} - -void FastGaussianBlurValueOperation::deinitExecution() -{ - if (this->m_iirgaus) { - delete this->m_iirgaus; - this->m_iirgaus = nullptr; - } - deinitMutex(); -} - -void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect) -{ - lockMutex(); - if (!this->m_iirgaus) { - MemoryBuffer *newBuf = (MemoryBuffer *)this->m_inputprogram->initializeTileData(rect); - MemoryBuffer *copy = newBuf->duplicate(); - FastGaussianBlurOperation::IIR_gauss(copy, this->m_sigma, 0, 3); - - if (this->m_overlay == FAST_GAUSS_OVERLAY_MIN) { - float *src = newBuf->getBuffer(); - float *dst = copy->getBuffer(); - for (int i = copy->getWidth() * copy->getHeight(); i != 0; - i--, src += COM_NUM_CHANNELS_VALUE, dst += COM_NUM_CHANNELS_VALUE) { - if (*src < *dst) { - *dst = *src; - } - } - } - else if (this->m_overlay == FAST_GAUSS_OVERLAY_MAX) { - float *src = newBuf->getBuffer(); - float *dst = copy->getBuffer(); - for (int i = copy->getWidth() * copy->getHeight(); i != 0; - i--, src += COM_NUM_CHANNELS_VALUE, dst += COM_NUM_CHANNELS_VALUE) { - if (*src > *dst) { - *dst = *src; - } - } - } - - // newBuf-> - - this->m_iirgaus = copy; - } - unlockMutex(); - return this->m_iirgaus; -} diff --git a/source/blender/compositor/operations/COM_FlipOperation.cc b/source/blender/compositor/operations/COM_FlipOperation.cc new file mode 100644 index 00000000000..37eaf4868d3 --- /dev/null +++ b/source/blender/compositor/operations/COM_FlipOperation.cc @@ -0,0 +1,74 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_FlipOperation.h" + +FlipOperation::FlipOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + this->m_inputOperation = nullptr; + this->m_flipX = true; + this->m_flipY = false; +} +void FlipOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); +} + +void FlipOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; +} + +void FlipOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float nx = this->m_flipX ? ((int)this->getWidth() - 1) - x : x; + float ny = this->m_flipY ? ((int)this->getHeight() - 1) - y : y; + + this->m_inputOperation->readSampled(output, nx, ny, sampler); +} + +bool FlipOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + + if (this->m_flipX) { + const int w = (int)this->getWidth() - 1; + newInput.xmax = (w - input->xmin) + 1; + newInput.xmin = (w - input->xmax) - 1; + } + else { + newInput.xmin = input->xmin; + newInput.xmax = input->xmax; + } + if (this->m_flipY) { + const int h = (int)this->getHeight() - 1; + newInput.ymax = (h - input->ymin) + 1; + newInput.ymin = (h - input->ymax) - 1; + } + else { + newInput.ymin = input->ymin; + newInput.ymax = input->ymax; + } + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_FlipOperation.cpp b/source/blender/compositor/operations/COM_FlipOperation.cpp deleted file mode 100644 index 37eaf4868d3..00000000000 --- a/source/blender/compositor/operations/COM_FlipOperation.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_FlipOperation.h" - -FlipOperation::FlipOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = nullptr; - this->m_flipX = true; - this->m_flipY = false; -} -void FlipOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void FlipOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; -} - -void FlipOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - float nx = this->m_flipX ? ((int)this->getWidth() - 1) - x : x; - float ny = this->m_flipY ? ((int)this->getHeight() - 1) - y : y; - - this->m_inputOperation->readSampled(output, nx, ny, sampler); -} - -bool FlipOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - - if (this->m_flipX) { - const int w = (int)this->getWidth() - 1; - newInput.xmax = (w - input->xmin) + 1; - newInput.xmin = (w - input->xmax) - 1; - } - else { - newInput.xmin = input->xmin; - newInput.xmax = input->xmax; - } - if (this->m_flipY) { - const int h = (int)this->getHeight() - 1; - newInput.ymax = (h - input->ymin) + 1; - newInput.ymin = (h - input->ymax) - 1; - } - else { - newInput.ymin = input->ymin; - newInput.ymax = input->ymax; - } - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_GammaCorrectOperation.cc b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc new file mode 100644 index 00000000000..d67d67f8e57 --- /dev/null +++ b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc @@ -0,0 +1,104 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GammaCorrectOperation.h" +#include "BLI_math.h" + +GammaCorrectOperation::GammaCorrectOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputProgram = nullptr; +} +void GammaCorrectOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); +} + +void GammaCorrectOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputProgram->readSampled(inputColor, x, y, sampler); + if (inputColor[3] > 0.0f) { + inputColor[0] /= inputColor[3]; + inputColor[1] /= inputColor[3]; + inputColor[2] /= inputColor[3]; + } + + /* check for negative to avoid nan's */ + output[0] = inputColor[0] > 0.0f ? inputColor[0] * inputColor[0] : 0.0f; + output[1] = inputColor[1] > 0.0f ? inputColor[1] * inputColor[1] : 0.0f; + output[2] = inputColor[2] > 0.0f ? inputColor[2] * inputColor[2] : 0.0f; + output[3] = inputColor[3]; + + if (inputColor[3] > 0.0f) { + output[0] *= inputColor[3]; + output[1] *= inputColor[3]; + output[2] *= inputColor[3]; + } +} + +void GammaCorrectOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; +} + +GammaUncorrectOperation::GammaUncorrectOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputProgram = nullptr; +} +void GammaUncorrectOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); +} + +void GammaUncorrectOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputProgram->readSampled(inputColor, x, y, sampler); + + if (inputColor[3] > 0.0f) { + inputColor[0] /= inputColor[3]; + inputColor[1] /= inputColor[3]; + inputColor[2] /= inputColor[3]; + } + + output[0] = inputColor[0] > 0.0f ? sqrtf(inputColor[0]) : 0.0f; + output[1] = inputColor[1] > 0.0f ? sqrtf(inputColor[1]) : 0.0f; + output[2] = inputColor[2] > 0.0f ? sqrtf(inputColor[2]) : 0.0f; + output[3] = inputColor[3]; + + if (inputColor[3] > 0.0f) { + output[0] *= inputColor[3]; + output[1] *= inputColor[3]; + output[2] *= inputColor[3]; + } +} + +void GammaUncorrectOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; +} diff --git a/source/blender/compositor/operations/COM_GammaCorrectOperation.cpp b/source/blender/compositor/operations/COM_GammaCorrectOperation.cpp deleted file mode 100644 index d67d67f8e57..00000000000 --- a/source/blender/compositor/operations/COM_GammaCorrectOperation.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GammaCorrectOperation.h" -#include "BLI_math.h" - -GammaCorrectOperation::GammaCorrectOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputProgram = nullptr; -} -void GammaCorrectOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); -} - -void GammaCorrectOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputProgram->readSampled(inputColor, x, y, sampler); - if (inputColor[3] > 0.0f) { - inputColor[0] /= inputColor[3]; - inputColor[1] /= inputColor[3]; - inputColor[2] /= inputColor[3]; - } - - /* check for negative to avoid nan's */ - output[0] = inputColor[0] > 0.0f ? inputColor[0] * inputColor[0] : 0.0f; - output[1] = inputColor[1] > 0.0f ? inputColor[1] * inputColor[1] : 0.0f; - output[2] = inputColor[2] > 0.0f ? inputColor[2] * inputColor[2] : 0.0f; - output[3] = inputColor[3]; - - if (inputColor[3] > 0.0f) { - output[0] *= inputColor[3]; - output[1] *= inputColor[3]; - output[2] *= inputColor[3]; - } -} - -void GammaCorrectOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; -} - -GammaUncorrectOperation::GammaUncorrectOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputProgram = nullptr; -} -void GammaUncorrectOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); -} - -void GammaUncorrectOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputProgram->readSampled(inputColor, x, y, sampler); - - if (inputColor[3] > 0.0f) { - inputColor[0] /= inputColor[3]; - inputColor[1] /= inputColor[3]; - inputColor[2] /= inputColor[3]; - } - - output[0] = inputColor[0] > 0.0f ? sqrtf(inputColor[0]) : 0.0f; - output[1] = inputColor[1] > 0.0f ? sqrtf(inputColor[1]) : 0.0f; - output[2] = inputColor[2] > 0.0f ? sqrtf(inputColor[2]) : 0.0f; - output[3] = inputColor[3]; - - if (inputColor[3] > 0.0f) { - output[0] *= inputColor[3]; - output[1] *= inputColor[3]; - output[2] *= inputColor[3]; - } -} - -void GammaUncorrectOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; -} diff --git a/source/blender/compositor/operations/COM_GammaOperation.cc b/source/blender/compositor/operations/COM_GammaOperation.cc new file mode 100644 index 00000000000..6baa52a290c --- /dev/null +++ b/source/blender/compositor/operations/COM_GammaOperation.cc @@ -0,0 +1,56 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GammaOperation.h" +#include "BLI_math.h" + +GammaOperation::GammaOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputProgram = nullptr; + this->m_inputGammaProgram = nullptr; +} +void GammaOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); + this->m_inputGammaProgram = this->getInputSocketReader(1); +} + +void GammaOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float inputValue[4]; + float inputGamma[4]; + + this->m_inputProgram->readSampled(inputValue, x, y, sampler); + this->m_inputGammaProgram->readSampled(inputGamma, x, y, sampler); + const float gamma = inputGamma[0]; + /* check for negative to avoid nan's */ + output[0] = inputValue[0] > 0.0f ? powf(inputValue[0], gamma) : inputValue[0]; + output[1] = inputValue[1] > 0.0f ? powf(inputValue[1], gamma) : inputValue[1]; + output[2] = inputValue[2] > 0.0f ? powf(inputValue[2], gamma) : inputValue[2]; + + output[3] = inputValue[3]; +} + +void GammaOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; + this->m_inputGammaProgram = nullptr; +} diff --git a/source/blender/compositor/operations/COM_GammaOperation.cpp b/source/blender/compositor/operations/COM_GammaOperation.cpp deleted file mode 100644 index 6baa52a290c..00000000000 --- a/source/blender/compositor/operations/COM_GammaOperation.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GammaOperation.h" -#include "BLI_math.h" - -GammaOperation::GammaOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputProgram = nullptr; - this->m_inputGammaProgram = nullptr; -} -void GammaOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); - this->m_inputGammaProgram = this->getInputSocketReader(1); -} - -void GammaOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - float inputValue[4]; - float inputGamma[4]; - - this->m_inputProgram->readSampled(inputValue, x, y, sampler); - this->m_inputGammaProgram->readSampled(inputGamma, x, y, sampler); - const float gamma = inputGamma[0]; - /* check for negative to avoid nan's */ - output[0] = inputValue[0] > 0.0f ? powf(inputValue[0], gamma) : inputValue[0]; - output[1] = inputValue[1] > 0.0f ? powf(inputValue[1], gamma) : inputValue[1]; - output[2] = inputValue[2] > 0.0f ? powf(inputValue[2], gamma) : inputValue[2]; - - output[3] = inputValue[3]; -} - -void GammaOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; - this->m_inputGammaProgram = nullptr; -} diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc new file mode 100644 index 00000000000..4d3efec7c85 --- /dev/null +++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc @@ -0,0 +1,191 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GaussianAlphaXBlurOperation.h" +#include "BLI_math.h" +#include "MEM_guardedalloc.h" + +#include "RE_pipeline.h" + +GaussianAlphaXBlurOperation::GaussianAlphaXBlurOperation() : BlurBaseOperation(COM_DT_VALUE) +{ + this->m_gausstab = nullptr; + this->m_filtersize = 0; + this->m_falloff = -1; /* intentionally invalid, so we can detect uninitialized values */ +} + +void *GaussianAlphaXBlurOperation::initializeTileData(rcti * /*rect*/) +{ + lockMutex(); + if (!this->m_sizeavailable) { + updateGauss(); + } + void *buffer = getInputOperation(0)->initializeTileData(nullptr); + unlockMutex(); + return buffer; +} + +void GaussianAlphaXBlurOperation::initExecution() +{ + /* Until we support size input - comment this. */ + // BlurBaseOperation::initExecution(); + + initMutex(); + + if (this->m_sizeavailable) { + float rad = max_ff(m_size * m_data.sizex, 0.0f); + m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); + + m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); + m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff); + } +} + +void GaussianAlphaXBlurOperation::updateGauss() +{ + if (this->m_gausstab == nullptr) { + updateSize(); + float rad = max_ff(m_size * m_data.sizex, 0.0f); + m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); + + m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); + } + + if (this->m_distbuf_inv == nullptr) { + updateSize(); + float rad = max_ff(m_size * m_data.sizex, 0.0f); + rad = min_ff(rad, MAX_GAUSSTAB_RADIUS); + m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); + + m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff); + } +} + +BLI_INLINE float finv_test(const float f, const bool test) +{ + return (LIKELY(test == false)) ? f : 1.0f - f; +} + +void GaussianAlphaXBlurOperation::executePixel(float output[4], int x, int y, void *data) +{ + const bool do_invert = this->m_do_subtract; + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + float *buffer = inputBuffer->getBuffer(); + int bufferwidth = inputBuffer->getWidth(); + int bufferstartx = inputBuffer->getRect()->xmin; + int bufferstarty = inputBuffer->getRect()->ymin; + + rcti &rect = *inputBuffer->getRect(); + int xmin = max_ii(x - m_filtersize, rect.xmin); + int xmax = min_ii(x + m_filtersize + 1, rect.xmax); + int ymin = max_ii(y, rect.ymin); + + /* *** this is the main part which is different to 'GaussianXBlurOperation' *** */ + int step = getStep(); + int bufferindex = ((xmin - bufferstartx)) + ((ymin - bufferstarty) * bufferwidth); + + /* gauss */ + float alpha_accum = 0.0f; + float multiplier_accum = 0.0f; + + /* dilate */ + float value_max = finv_test( + buffer[(x) + (y * bufferwidth)], + do_invert); /* init with the current color to avoid unneeded lookups */ + float distfacinv_max = 1.0f; /* 0 to 1 */ + + for (int nx = xmin; nx < xmax; nx += step) { + const int index = (nx - x) + this->m_filtersize; + float value = finv_test(buffer[bufferindex], do_invert); + float multiplier; + + /* gauss */ + { + multiplier = this->m_gausstab[index]; + alpha_accum += value * multiplier; + multiplier_accum += multiplier; + } + + /* dilate - find most extreme color */ + if (value > value_max) { + multiplier = this->m_distbuf_inv[index]; + value *= multiplier; + if (value > value_max) { + value_max = value; + distfacinv_max = multiplier; + } + } + bufferindex += step; + } + + /* blend between the max value and gauss blue - gives nice feather */ + const float value_blur = alpha_accum / multiplier_accum; + const float value_final = (value_max * distfacinv_max) + (value_blur * (1.0f - distfacinv_max)); + output[0] = finv_test(value_final, do_invert); +} + +void GaussianAlphaXBlurOperation::deinitExecution() +{ + BlurBaseOperation::deinitExecution(); + + if (this->m_gausstab) { + MEM_freeN(this->m_gausstab); + this->m_gausstab = nullptr; + } + + if (this->m_distbuf_inv) { + MEM_freeN(this->m_distbuf_inv); + this->m_distbuf_inv = nullptr; + } + + deinitMutex(); +} + +bool GaussianAlphaXBlurOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; +#if 0 /* until we add size input */ + rcti sizeInput; + sizeInput.xmin = 0; + sizeInput.ymin = 0; + sizeInput.xmax = 5; + sizeInput.ymax = 5; + + NodeOperation *operation = this->getInputOperation(1); + if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { + return true; + } + else +#endif + { + if (this->m_sizeavailable && this->m_gausstab != nullptr) { + newInput.xmax = input->xmax + this->m_filtersize + 1; + newInput.xmin = input->xmin - this->m_filtersize - 1; + newInput.ymax = input->ymax; + newInput.ymin = input->ymin; + } + else { + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + } + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + } +} diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp deleted file mode 100644 index 4d3efec7c85..00000000000 --- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GaussianAlphaXBlurOperation.h" -#include "BLI_math.h" -#include "MEM_guardedalloc.h" - -#include "RE_pipeline.h" - -GaussianAlphaXBlurOperation::GaussianAlphaXBlurOperation() : BlurBaseOperation(COM_DT_VALUE) -{ - this->m_gausstab = nullptr; - this->m_filtersize = 0; - this->m_falloff = -1; /* intentionally invalid, so we can detect uninitialized values */ -} - -void *GaussianAlphaXBlurOperation::initializeTileData(rcti * /*rect*/) -{ - lockMutex(); - if (!this->m_sizeavailable) { - updateGauss(); - } - void *buffer = getInputOperation(0)->initializeTileData(nullptr); - unlockMutex(); - return buffer; -} - -void GaussianAlphaXBlurOperation::initExecution() -{ - /* Until we support size input - comment this. */ - // BlurBaseOperation::initExecution(); - - initMutex(); - - if (this->m_sizeavailable) { - float rad = max_ff(m_size * m_data.sizex, 0.0f); - m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); - - m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); - m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff); - } -} - -void GaussianAlphaXBlurOperation::updateGauss() -{ - if (this->m_gausstab == nullptr) { - updateSize(); - float rad = max_ff(m_size * m_data.sizex, 0.0f); - m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); - - m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); - } - - if (this->m_distbuf_inv == nullptr) { - updateSize(); - float rad = max_ff(m_size * m_data.sizex, 0.0f); - rad = min_ff(rad, MAX_GAUSSTAB_RADIUS); - m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); - - m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff); - } -} - -BLI_INLINE float finv_test(const float f, const bool test) -{ - return (LIKELY(test == false)) ? f : 1.0f - f; -} - -void GaussianAlphaXBlurOperation::executePixel(float output[4], int x, int y, void *data) -{ - const bool do_invert = this->m_do_subtract; - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - float *buffer = inputBuffer->getBuffer(); - int bufferwidth = inputBuffer->getWidth(); - int bufferstartx = inputBuffer->getRect()->xmin; - int bufferstarty = inputBuffer->getRect()->ymin; - - rcti &rect = *inputBuffer->getRect(); - int xmin = max_ii(x - m_filtersize, rect.xmin); - int xmax = min_ii(x + m_filtersize + 1, rect.xmax); - int ymin = max_ii(y, rect.ymin); - - /* *** this is the main part which is different to 'GaussianXBlurOperation' *** */ - int step = getStep(); - int bufferindex = ((xmin - bufferstartx)) + ((ymin - bufferstarty) * bufferwidth); - - /* gauss */ - float alpha_accum = 0.0f; - float multiplier_accum = 0.0f; - - /* dilate */ - float value_max = finv_test( - buffer[(x) + (y * bufferwidth)], - do_invert); /* init with the current color to avoid unneeded lookups */ - float distfacinv_max = 1.0f; /* 0 to 1 */ - - for (int nx = xmin; nx < xmax; nx += step) { - const int index = (nx - x) + this->m_filtersize; - float value = finv_test(buffer[bufferindex], do_invert); - float multiplier; - - /* gauss */ - { - multiplier = this->m_gausstab[index]; - alpha_accum += value * multiplier; - multiplier_accum += multiplier; - } - - /* dilate - find most extreme color */ - if (value > value_max) { - multiplier = this->m_distbuf_inv[index]; - value *= multiplier; - if (value > value_max) { - value_max = value; - distfacinv_max = multiplier; - } - } - bufferindex += step; - } - - /* blend between the max value and gauss blue - gives nice feather */ - const float value_blur = alpha_accum / multiplier_accum; - const float value_final = (value_max * distfacinv_max) + (value_blur * (1.0f - distfacinv_max)); - output[0] = finv_test(value_final, do_invert); -} - -void GaussianAlphaXBlurOperation::deinitExecution() -{ - BlurBaseOperation::deinitExecution(); - - if (this->m_gausstab) { - MEM_freeN(this->m_gausstab); - this->m_gausstab = nullptr; - } - - if (this->m_distbuf_inv) { - MEM_freeN(this->m_distbuf_inv); - this->m_distbuf_inv = nullptr; - } - - deinitMutex(); -} - -bool GaussianAlphaXBlurOperation::determineDependingAreaOfInterest( - rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInput; -#if 0 /* until we add size input */ - rcti sizeInput; - sizeInput.xmin = 0; - sizeInput.ymin = 0; - sizeInput.xmax = 5; - sizeInput.ymax = 5; - - NodeOperation *operation = this->getInputOperation(1); - if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { - return true; - } - else -#endif - { - if (this->m_sizeavailable && this->m_gausstab != nullptr) { - newInput.xmax = input->xmax + this->m_filtersize + 1; - newInput.xmin = input->xmin - this->m_filtersize - 1; - newInput.ymax = input->ymax; - newInput.ymin = input->ymin; - } - else { - newInput.xmax = this->getWidth(); - newInput.xmin = 0; - newInput.ymax = this->getHeight(); - newInput.ymin = 0; - } - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); - } -} diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc new file mode 100644 index 00000000000..a722a879b8d --- /dev/null +++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc @@ -0,0 +1,191 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GaussianAlphaYBlurOperation.h" +#include "BLI_math.h" +#include "MEM_guardedalloc.h" + +#include "RE_pipeline.h" + +GaussianAlphaYBlurOperation::GaussianAlphaYBlurOperation() : BlurBaseOperation(COM_DT_VALUE) +{ + this->m_gausstab = nullptr; + this->m_filtersize = 0; + this->m_falloff = -1; /* intentionally invalid, so we can detect uninitialized values */ +} + +void *GaussianAlphaYBlurOperation::initializeTileData(rcti * /*rect*/) +{ + lockMutex(); + if (!this->m_sizeavailable) { + updateGauss(); + } + void *buffer = getInputOperation(0)->initializeTileData(nullptr); + unlockMutex(); + return buffer; +} + +void GaussianAlphaYBlurOperation::initExecution() +{ + /* Until we support size input - comment this. */ + // BlurBaseOperation::initExecution(); + + initMutex(); + + if (this->m_sizeavailable) { + float rad = max_ff(m_size * m_data.sizey, 0.0f); + m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); + + m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); + m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff); + } +} + +void GaussianAlphaYBlurOperation::updateGauss() +{ + if (this->m_gausstab == nullptr) { + updateSize(); + float rad = max_ff(m_size * m_data.sizey, 0.0f); + rad = min_ff(rad, MAX_GAUSSTAB_RADIUS); + m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); + + m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); + } + + if (this->m_distbuf_inv == nullptr) { + updateSize(); + float rad = max_ff(m_size * m_data.sizey, 0.0f); + m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); + + m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff); + } +} + +BLI_INLINE float finv_test(const float f, const bool test) +{ + return (LIKELY(test == false)) ? f : 1.0f - f; +} + +void GaussianAlphaYBlurOperation::executePixel(float output[4], int x, int y, void *data) +{ + const bool do_invert = this->m_do_subtract; + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + float *buffer = inputBuffer->getBuffer(); + int bufferwidth = inputBuffer->getWidth(); + int bufferstartx = inputBuffer->getRect()->xmin; + int bufferstarty = inputBuffer->getRect()->ymin; + + rcti &rect = *inputBuffer->getRect(); + int xmin = max_ii(x, rect.xmin); + int ymin = max_ii(y - m_filtersize, rect.ymin); + int ymax = min_ii(y + m_filtersize + 1, rect.ymax); + + /* *** this is the main part which is different to 'GaussianYBlurOperation' *** */ + int step = getStep(); + + /* gauss */ + float alpha_accum = 0.0f; + float multiplier_accum = 0.0f; + + /* dilate */ + float value_max = finv_test( + buffer[(x) + (y * bufferwidth)], + do_invert); /* init with the current color to avoid unneeded lookups */ + float distfacinv_max = 1.0f; /* 0 to 1 */ + + for (int ny = ymin; ny < ymax; ny += step) { + int bufferindex = ((xmin - bufferstartx)) + ((ny - bufferstarty) * bufferwidth); + + const int index = (ny - y) + this->m_filtersize; + float value = finv_test(buffer[bufferindex], do_invert); + float multiplier; + + /* gauss */ + { + multiplier = this->m_gausstab[index]; + alpha_accum += value * multiplier; + multiplier_accum += multiplier; + } + + /* dilate - find most extreme color */ + if (value > value_max) { + multiplier = this->m_distbuf_inv[index]; + value *= multiplier; + if (value > value_max) { + value_max = value; + distfacinv_max = multiplier; + } + } + } + + /* blend between the max value and gauss blue - gives nice feather */ + const float value_blur = alpha_accum / multiplier_accum; + const float value_final = (value_max * distfacinv_max) + (value_blur * (1.0f - distfacinv_max)); + output[0] = finv_test(value_final, do_invert); +} + +void GaussianAlphaYBlurOperation::deinitExecution() +{ + BlurBaseOperation::deinitExecution(); + + if (this->m_gausstab) { + MEM_freeN(this->m_gausstab); + this->m_gausstab = nullptr; + } + + if (this->m_distbuf_inv) { + MEM_freeN(this->m_distbuf_inv); + this->m_distbuf_inv = nullptr; + } + + deinitMutex(); +} + +bool GaussianAlphaYBlurOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; +#if 0 /* until we add size input */ + rcti sizeInput; + sizeInput.xmin = 0; + sizeInput.ymin = 0; + sizeInput.xmax = 5; + sizeInput.ymax = 5; + + NodeOperation *operation = this->getInputOperation(1); + if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { + return true; + } + else +#endif + { + if (this->m_sizeavailable && this->m_gausstab != nullptr) { + newInput.xmax = input->xmax; + newInput.xmin = input->xmin; + newInput.ymax = input->ymax + this->m_filtersize + 1; + newInput.ymin = input->ymin - this->m_filtersize - 1; + } + else { + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + } + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + } +} diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp deleted file mode 100644 index a722a879b8d..00000000000 --- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GaussianAlphaYBlurOperation.h" -#include "BLI_math.h" -#include "MEM_guardedalloc.h" - -#include "RE_pipeline.h" - -GaussianAlphaYBlurOperation::GaussianAlphaYBlurOperation() : BlurBaseOperation(COM_DT_VALUE) -{ - this->m_gausstab = nullptr; - this->m_filtersize = 0; - this->m_falloff = -1; /* intentionally invalid, so we can detect uninitialized values */ -} - -void *GaussianAlphaYBlurOperation::initializeTileData(rcti * /*rect*/) -{ - lockMutex(); - if (!this->m_sizeavailable) { - updateGauss(); - } - void *buffer = getInputOperation(0)->initializeTileData(nullptr); - unlockMutex(); - return buffer; -} - -void GaussianAlphaYBlurOperation::initExecution() -{ - /* Until we support size input - comment this. */ - // BlurBaseOperation::initExecution(); - - initMutex(); - - if (this->m_sizeavailable) { - float rad = max_ff(m_size * m_data.sizey, 0.0f); - m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); - - m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); - m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff); - } -} - -void GaussianAlphaYBlurOperation::updateGauss() -{ - if (this->m_gausstab == nullptr) { - updateSize(); - float rad = max_ff(m_size * m_data.sizey, 0.0f); - rad = min_ff(rad, MAX_GAUSSTAB_RADIUS); - m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); - - m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); - } - - if (this->m_distbuf_inv == nullptr) { - updateSize(); - float rad = max_ff(m_size * m_data.sizey, 0.0f); - m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); - - m_distbuf_inv = BlurBaseOperation::make_dist_fac_inverse(rad, m_filtersize, m_falloff); - } -} - -BLI_INLINE float finv_test(const float f, const bool test) -{ - return (LIKELY(test == false)) ? f : 1.0f - f; -} - -void GaussianAlphaYBlurOperation::executePixel(float output[4], int x, int y, void *data) -{ - const bool do_invert = this->m_do_subtract; - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - float *buffer = inputBuffer->getBuffer(); - int bufferwidth = inputBuffer->getWidth(); - int bufferstartx = inputBuffer->getRect()->xmin; - int bufferstarty = inputBuffer->getRect()->ymin; - - rcti &rect = *inputBuffer->getRect(); - int xmin = max_ii(x, rect.xmin); - int ymin = max_ii(y - m_filtersize, rect.ymin); - int ymax = min_ii(y + m_filtersize + 1, rect.ymax); - - /* *** this is the main part which is different to 'GaussianYBlurOperation' *** */ - int step = getStep(); - - /* gauss */ - float alpha_accum = 0.0f; - float multiplier_accum = 0.0f; - - /* dilate */ - float value_max = finv_test( - buffer[(x) + (y * bufferwidth)], - do_invert); /* init with the current color to avoid unneeded lookups */ - float distfacinv_max = 1.0f; /* 0 to 1 */ - - for (int ny = ymin; ny < ymax; ny += step) { - int bufferindex = ((xmin - bufferstartx)) + ((ny - bufferstarty) * bufferwidth); - - const int index = (ny - y) + this->m_filtersize; - float value = finv_test(buffer[bufferindex], do_invert); - float multiplier; - - /* gauss */ - { - multiplier = this->m_gausstab[index]; - alpha_accum += value * multiplier; - multiplier_accum += multiplier; - } - - /* dilate - find most extreme color */ - if (value > value_max) { - multiplier = this->m_distbuf_inv[index]; - value *= multiplier; - if (value > value_max) { - value_max = value; - distfacinv_max = multiplier; - } - } - } - - /* blend between the max value and gauss blue - gives nice feather */ - const float value_blur = alpha_accum / multiplier_accum; - const float value_final = (value_max * distfacinv_max) + (value_blur * (1.0f - distfacinv_max)); - output[0] = finv_test(value_final, do_invert); -} - -void GaussianAlphaYBlurOperation::deinitExecution() -{ - BlurBaseOperation::deinitExecution(); - - if (this->m_gausstab) { - MEM_freeN(this->m_gausstab); - this->m_gausstab = nullptr; - } - - if (this->m_distbuf_inv) { - MEM_freeN(this->m_distbuf_inv); - this->m_distbuf_inv = nullptr; - } - - deinitMutex(); -} - -bool GaussianAlphaYBlurOperation::determineDependingAreaOfInterest( - rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInput; -#if 0 /* until we add size input */ - rcti sizeInput; - sizeInput.xmin = 0; - sizeInput.ymin = 0; - sizeInput.xmax = 5; - sizeInput.ymax = 5; - - NodeOperation *operation = this->getInputOperation(1); - if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { - return true; - } - else -#endif - { - if (this->m_sizeavailable && this->m_gausstab != nullptr) { - newInput.xmax = input->xmax; - newInput.xmin = input->xmin; - newInput.ymax = input->ymax + this->m_filtersize + 1; - newInput.ymin = input->ymin - this->m_filtersize - 1; - } - else { - newInput.xmax = this->getWidth(); - newInput.xmin = 0; - newInput.ymax = this->getHeight(); - newInput.ymin = 0; - } - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); - } -} diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc new file mode 100644 index 00000000000..ca3173001cb --- /dev/null +++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc @@ -0,0 +1,361 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GaussianBokehBlurOperation.h" +#include "BLI_math.h" +#include "MEM_guardedalloc.h" + +#include "RE_pipeline.h" + +GaussianBokehBlurOperation::GaussianBokehBlurOperation() : BlurBaseOperation(COM_DT_COLOR) +{ + this->m_gausstab = nullptr; +} + +void *GaussianBokehBlurOperation::initializeTileData(rcti * /*rect*/) +{ + lockMutex(); + if (!this->m_sizeavailable) { + updateGauss(); + } + void *buffer = getInputOperation(0)->initializeTileData(nullptr); + unlockMutex(); + return buffer; +} + +void GaussianBokehBlurOperation::initExecution() +{ + BlurBaseOperation::initExecution(); + + initMutex(); + + if (this->m_sizeavailable) { + updateGauss(); + } +} + +void GaussianBokehBlurOperation::updateGauss() +{ + if (this->m_gausstab == nullptr) { + float radxf; + float radyf; + int n; + float *dgauss; + float *ddgauss; + int j, i; + const float width = this->getWidth(); + const float height = this->getHeight(); + if (!this->m_sizeavailable) { + updateSize(); + } + radxf = this->m_size * (float)this->m_data.sizex; + CLAMP(radxf, 0.0f, width / 2.0f); + + /* vertical */ + radyf = this->m_size * (float)this->m_data.sizey; + CLAMP(radyf, 0.0f, height / 2.0f); + + this->m_radx = ceil(radxf); + this->m_rady = ceil(radyf); + + int ddwidth = 2 * this->m_radx + 1; + int ddheight = 2 * this->m_rady + 1; + n = ddwidth * ddheight; + + /* create a full filter image */ + ddgauss = (float *)MEM_mallocN(sizeof(float) * n, __func__); + dgauss = ddgauss; + float sum = 0.0f; + float facx = (radxf > 0.0f ? 1.0f / radxf : 0.0f); + float facy = (radyf > 0.0f ? 1.0f / radyf : 0.0f); + for (j = -this->m_rady; j <= this->m_rady; j++) { + for (i = -this->m_radx; i <= this->m_radx; i++, dgauss++) { + float fj = (float)j * facy; + float fi = (float)i * facx; + float dist = sqrt(fj * fj + fi * fi); + *dgauss = RE_filter_value(this->m_data.filtertype, dist); + + sum += *dgauss; + } + } + + if (sum > 0.0f) { + /* normalize */ + float norm = 1.0f / sum; + for (j = n - 1; j >= 0; j--) { + ddgauss[j] *= norm; + } + } + else { + int center = m_rady * ddwidth + m_radx; + ddgauss[center] = 1.0f; + } + + this->m_gausstab = ddgauss; + } +} + +void GaussianBokehBlurOperation::executePixel(float output[4], int x, int y, void *data) +{ + float tempColor[4]; + tempColor[0] = 0; + tempColor[1] = 0; + tempColor[2] = 0; + tempColor[3] = 0; + float multiplier_accum = 0; + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + float *buffer = inputBuffer->getBuffer(); + int bufferwidth = inputBuffer->getWidth(); + int bufferstartx = inputBuffer->getRect()->xmin; + int bufferstarty = inputBuffer->getRect()->ymin; + + rcti &rect = *inputBuffer->getRect(); + int ymin = max_ii(y - this->m_rady, rect.ymin); + int ymax = min_ii(y + this->m_rady + 1, rect.ymax); + int xmin = max_ii(x - this->m_radx, rect.xmin); + int xmax = min_ii(x + this->m_radx + 1, rect.xmax); + + int index; + int step = QualityStepHelper::getStep(); + int offsetadd = QualityStepHelper::getOffsetAdd(); + const int addConst = (xmin - x + this->m_radx); + const int mulConst = (this->m_radx * 2 + 1); + for (int ny = ymin; ny < ymax; ny += step) { + index = ((ny - y) + this->m_rady) * mulConst + addConst; + int bufferindex = ((xmin - bufferstartx) * 4) + ((ny - bufferstarty) * 4 * bufferwidth); + for (int nx = xmin; nx < xmax; nx += step) { + const float multiplier = this->m_gausstab[index]; + madd_v4_v4fl(tempColor, &buffer[bufferindex], multiplier); + multiplier_accum += multiplier; + index += step; + bufferindex += offsetadd; + } + } + + mul_v4_v4fl(output, tempColor, 1.0f / multiplier_accum); +} + +void GaussianBokehBlurOperation::deinitExecution() +{ + BlurBaseOperation::deinitExecution(); + + if (this->m_gausstab) { + MEM_freeN(this->m_gausstab); + this->m_gausstab = nullptr; + } + + deinitMutex(); +} + +bool GaussianBokehBlurOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + rcti sizeInput; + sizeInput.xmin = 0; + sizeInput.ymin = 0; + sizeInput.xmax = 5; + sizeInput.ymax = 5; + NodeOperation *operation = this->getInputOperation(1); + + if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { + return true; + } + + if (this->m_sizeavailable && this->m_gausstab != nullptr) { + newInput.xmin = 0; + newInput.ymin = 0; + newInput.xmax = this->getWidth(); + newInput.ymax = this->getHeight(); + } + else { + int addx = this->m_radx; + int addy = this->m_rady; + newInput.xmax = input->xmax + addx; + newInput.xmin = input->xmin - addx; + newInput.ymax = input->ymax + addy; + newInput.ymin = input->ymin - addy; + } + return BlurBaseOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +// reference image +GaussianBlurReferenceOperation::GaussianBlurReferenceOperation() : BlurBaseOperation(COM_DT_COLOR) +{ + this->m_maintabs = nullptr; +} + +void *GaussianBlurReferenceOperation::initializeTileData(rcti * /*rect*/) +{ + void *buffer = getInputOperation(0)->initializeTileData(nullptr); + return buffer; +} + +void GaussianBlurReferenceOperation::initExecution() +{ + BlurBaseOperation::initExecution(); + // setup gaustab + this->m_data.image_in_width = this->getWidth(); + this->m_data.image_in_height = this->getHeight(); + if (this->m_data.relative) { + switch (this->m_data.aspect) { + case CMP_NODE_BLUR_ASPECT_NONE: + this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_width); + this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_height); + break; + case CMP_NODE_BLUR_ASPECT_Y: + this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_width); + this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_width); + break; + case CMP_NODE_BLUR_ASPECT_X: + this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_height); + this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_height); + break; + } + } + + /* horizontal */ + m_filtersizex = (float)this->m_data.sizex; + int imgx = getWidth() / 2; + if (m_filtersizex > imgx) { + m_filtersizex = imgx; + } + else if (m_filtersizex < 1) { + m_filtersizex = 1; + } + m_radx = (float)m_filtersizex; + + /* vertical */ + m_filtersizey = (float)this->m_data.sizey; + int imgy = getHeight() / 2; + if (m_filtersizey > imgy) { + m_filtersizey = imgy; + } + else if (m_filtersizey < 1) { + m_filtersizey = 1; + } + m_rady = (float)m_filtersizey; + updateGauss(); +} + +void GaussianBlurReferenceOperation::updateGauss() +{ + int i; + int x = MAX2(m_filtersizex, m_filtersizey); + m_maintabs = (float **)MEM_mallocN(x * sizeof(float *), "gauss array"); + for (i = 0; i < x; i++) { + m_maintabs[i] = make_gausstab(i + 1, i + 1); + } +} + +void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y, void *data) +{ + MemoryBuffer *memorybuffer = (MemoryBuffer *)data; + float *buffer = memorybuffer->getBuffer(); + float *gausstabx, *gausstabcenty; + float *gausstaby, *gausstabcentx; + int i, j; + float *src; + float sum, val; + float rval, gval, bval, aval; + int imgx = getWidth(); + int imgy = getHeight(); + float tempSize[4]; + this->m_inputSize->read(tempSize, x, y, data); + float refSize = tempSize[0]; + int refradx = (int)(refSize * m_radx); + int refrady = (int)(refSize * m_rady); + if (refradx > m_filtersizex) { + refradx = m_filtersizex; + } + else if (refradx < 1) { + refradx = 1; + } + if (refrady > m_filtersizey) { + refrady = m_filtersizey; + } + else if (refrady < 1) { + refrady = 1; + } + + if (refradx == 1 && refrady == 1) { + memorybuffer->readNoCheck(output, x, y); + } + else { + int minxr = x - refradx < 0 ? -x : -refradx; + int maxxr = x + refradx > imgx ? imgx - x : refradx; + int minyr = y - refrady < 0 ? -y : -refrady; + int maxyr = y + refrady > imgy ? imgy - y : refrady; + + float *srcd = buffer + COM_NUM_CHANNELS_COLOR * ((y + minyr) * imgx + x + minxr); + + gausstabx = m_maintabs[refradx - 1]; + gausstabcentx = gausstabx + refradx; + gausstaby = m_maintabs[refrady - 1]; + gausstabcenty = gausstaby + refrady; + + sum = gval = rval = bval = aval = 0.0f; + for (i = minyr; i < maxyr; i++, srcd += COM_NUM_CHANNELS_COLOR * imgx) { + src = srcd; + for (j = minxr; j < maxxr; j++, src += COM_NUM_CHANNELS_COLOR) { + + val = gausstabcenty[i] * gausstabcentx[j]; + sum += val; + rval += val * src[0]; + gval += val * src[1]; + bval += val * src[2]; + aval += val * src[3]; + } + } + sum = 1.0f / sum; + output[0] = rval * sum; + output[1] = gval * sum; + output[2] = bval * sum; + output[3] = aval * sum; + } +} + +void GaussianBlurReferenceOperation::deinitExecution() +{ + int x, i; + x = MAX2(this->m_filtersizex, this->m_filtersizey); + for (i = 0; i < x; i++) { + MEM_freeN(this->m_maintabs[i]); + } + MEM_freeN(this->m_maintabs); + BlurBaseOperation::deinitExecution(); +} + +bool GaussianBlurReferenceOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + NodeOperation *operation = this->getInputOperation(1); + + if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { + return true; + } + + int addx = this->m_data.sizex + 2; + int addy = this->m_data.sizey + 2; + newInput.xmax = input->xmax + addx; + newInput.xmin = input->xmin - addx; + newInput.ymax = input->ymax + addy; + newInput.ymin = input->ymin - addy; + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp deleted file mode 100644 index ca3173001cb..00000000000 --- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp +++ /dev/null @@ -1,361 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GaussianBokehBlurOperation.h" -#include "BLI_math.h" -#include "MEM_guardedalloc.h" - -#include "RE_pipeline.h" - -GaussianBokehBlurOperation::GaussianBokehBlurOperation() : BlurBaseOperation(COM_DT_COLOR) -{ - this->m_gausstab = nullptr; -} - -void *GaussianBokehBlurOperation::initializeTileData(rcti * /*rect*/) -{ - lockMutex(); - if (!this->m_sizeavailable) { - updateGauss(); - } - void *buffer = getInputOperation(0)->initializeTileData(nullptr); - unlockMutex(); - return buffer; -} - -void GaussianBokehBlurOperation::initExecution() -{ - BlurBaseOperation::initExecution(); - - initMutex(); - - if (this->m_sizeavailable) { - updateGauss(); - } -} - -void GaussianBokehBlurOperation::updateGauss() -{ - if (this->m_gausstab == nullptr) { - float radxf; - float radyf; - int n; - float *dgauss; - float *ddgauss; - int j, i; - const float width = this->getWidth(); - const float height = this->getHeight(); - if (!this->m_sizeavailable) { - updateSize(); - } - radxf = this->m_size * (float)this->m_data.sizex; - CLAMP(radxf, 0.0f, width / 2.0f); - - /* vertical */ - radyf = this->m_size * (float)this->m_data.sizey; - CLAMP(radyf, 0.0f, height / 2.0f); - - this->m_radx = ceil(radxf); - this->m_rady = ceil(radyf); - - int ddwidth = 2 * this->m_radx + 1; - int ddheight = 2 * this->m_rady + 1; - n = ddwidth * ddheight; - - /* create a full filter image */ - ddgauss = (float *)MEM_mallocN(sizeof(float) * n, __func__); - dgauss = ddgauss; - float sum = 0.0f; - float facx = (radxf > 0.0f ? 1.0f / radxf : 0.0f); - float facy = (radyf > 0.0f ? 1.0f / radyf : 0.0f); - for (j = -this->m_rady; j <= this->m_rady; j++) { - for (i = -this->m_radx; i <= this->m_radx; i++, dgauss++) { - float fj = (float)j * facy; - float fi = (float)i * facx; - float dist = sqrt(fj * fj + fi * fi); - *dgauss = RE_filter_value(this->m_data.filtertype, dist); - - sum += *dgauss; - } - } - - if (sum > 0.0f) { - /* normalize */ - float norm = 1.0f / sum; - for (j = n - 1; j >= 0; j--) { - ddgauss[j] *= norm; - } - } - else { - int center = m_rady * ddwidth + m_radx; - ddgauss[center] = 1.0f; - } - - this->m_gausstab = ddgauss; - } -} - -void GaussianBokehBlurOperation::executePixel(float output[4], int x, int y, void *data) -{ - float tempColor[4]; - tempColor[0] = 0; - tempColor[1] = 0; - tempColor[2] = 0; - tempColor[3] = 0; - float multiplier_accum = 0; - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - float *buffer = inputBuffer->getBuffer(); - int bufferwidth = inputBuffer->getWidth(); - int bufferstartx = inputBuffer->getRect()->xmin; - int bufferstarty = inputBuffer->getRect()->ymin; - - rcti &rect = *inputBuffer->getRect(); - int ymin = max_ii(y - this->m_rady, rect.ymin); - int ymax = min_ii(y + this->m_rady + 1, rect.ymax); - int xmin = max_ii(x - this->m_radx, rect.xmin); - int xmax = min_ii(x + this->m_radx + 1, rect.xmax); - - int index; - int step = QualityStepHelper::getStep(); - int offsetadd = QualityStepHelper::getOffsetAdd(); - const int addConst = (xmin - x + this->m_radx); - const int mulConst = (this->m_radx * 2 + 1); - for (int ny = ymin; ny < ymax; ny += step) { - index = ((ny - y) + this->m_rady) * mulConst + addConst; - int bufferindex = ((xmin - bufferstartx) * 4) + ((ny - bufferstarty) * 4 * bufferwidth); - for (int nx = xmin; nx < xmax; nx += step) { - const float multiplier = this->m_gausstab[index]; - madd_v4_v4fl(tempColor, &buffer[bufferindex], multiplier); - multiplier_accum += multiplier; - index += step; - bufferindex += offsetadd; - } - } - - mul_v4_v4fl(output, tempColor, 1.0f / multiplier_accum); -} - -void GaussianBokehBlurOperation::deinitExecution() -{ - BlurBaseOperation::deinitExecution(); - - if (this->m_gausstab) { - MEM_freeN(this->m_gausstab); - this->m_gausstab = nullptr; - } - - deinitMutex(); -} - -bool GaussianBokehBlurOperation::determineDependingAreaOfInterest( - rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInput; - rcti sizeInput; - sizeInput.xmin = 0; - sizeInput.ymin = 0; - sizeInput.xmax = 5; - sizeInput.ymax = 5; - NodeOperation *operation = this->getInputOperation(1); - - if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { - return true; - } - - if (this->m_sizeavailable && this->m_gausstab != nullptr) { - newInput.xmin = 0; - newInput.ymin = 0; - newInput.xmax = this->getWidth(); - newInput.ymax = this->getHeight(); - } - else { - int addx = this->m_radx; - int addy = this->m_rady; - newInput.xmax = input->xmax + addx; - newInput.xmin = input->xmin - addx; - newInput.ymax = input->ymax + addy; - newInput.ymin = input->ymin - addy; - } - return BlurBaseOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -// reference image -GaussianBlurReferenceOperation::GaussianBlurReferenceOperation() : BlurBaseOperation(COM_DT_COLOR) -{ - this->m_maintabs = nullptr; -} - -void *GaussianBlurReferenceOperation::initializeTileData(rcti * /*rect*/) -{ - void *buffer = getInputOperation(0)->initializeTileData(nullptr); - return buffer; -} - -void GaussianBlurReferenceOperation::initExecution() -{ - BlurBaseOperation::initExecution(); - // setup gaustab - this->m_data.image_in_width = this->getWidth(); - this->m_data.image_in_height = this->getHeight(); - if (this->m_data.relative) { - switch (this->m_data.aspect) { - case CMP_NODE_BLUR_ASPECT_NONE: - this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_width); - this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_height); - break; - case CMP_NODE_BLUR_ASPECT_Y: - this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_width); - this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_width); - break; - case CMP_NODE_BLUR_ASPECT_X: - this->m_data.sizex = (int)(this->m_data.percentx * 0.01f * this->m_data.image_in_height); - this->m_data.sizey = (int)(this->m_data.percenty * 0.01f * this->m_data.image_in_height); - break; - } - } - - /* horizontal */ - m_filtersizex = (float)this->m_data.sizex; - int imgx = getWidth() / 2; - if (m_filtersizex > imgx) { - m_filtersizex = imgx; - } - else if (m_filtersizex < 1) { - m_filtersizex = 1; - } - m_radx = (float)m_filtersizex; - - /* vertical */ - m_filtersizey = (float)this->m_data.sizey; - int imgy = getHeight() / 2; - if (m_filtersizey > imgy) { - m_filtersizey = imgy; - } - else if (m_filtersizey < 1) { - m_filtersizey = 1; - } - m_rady = (float)m_filtersizey; - updateGauss(); -} - -void GaussianBlurReferenceOperation::updateGauss() -{ - int i; - int x = MAX2(m_filtersizex, m_filtersizey); - m_maintabs = (float **)MEM_mallocN(x * sizeof(float *), "gauss array"); - for (i = 0; i < x; i++) { - m_maintabs[i] = make_gausstab(i + 1, i + 1); - } -} - -void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y, void *data) -{ - MemoryBuffer *memorybuffer = (MemoryBuffer *)data; - float *buffer = memorybuffer->getBuffer(); - float *gausstabx, *gausstabcenty; - float *gausstaby, *gausstabcentx; - int i, j; - float *src; - float sum, val; - float rval, gval, bval, aval; - int imgx = getWidth(); - int imgy = getHeight(); - float tempSize[4]; - this->m_inputSize->read(tempSize, x, y, data); - float refSize = tempSize[0]; - int refradx = (int)(refSize * m_radx); - int refrady = (int)(refSize * m_rady); - if (refradx > m_filtersizex) { - refradx = m_filtersizex; - } - else if (refradx < 1) { - refradx = 1; - } - if (refrady > m_filtersizey) { - refrady = m_filtersizey; - } - else if (refrady < 1) { - refrady = 1; - } - - if (refradx == 1 && refrady == 1) { - memorybuffer->readNoCheck(output, x, y); - } - else { - int minxr = x - refradx < 0 ? -x : -refradx; - int maxxr = x + refradx > imgx ? imgx - x : refradx; - int minyr = y - refrady < 0 ? -y : -refrady; - int maxyr = y + refrady > imgy ? imgy - y : refrady; - - float *srcd = buffer + COM_NUM_CHANNELS_COLOR * ((y + minyr) * imgx + x + minxr); - - gausstabx = m_maintabs[refradx - 1]; - gausstabcentx = gausstabx + refradx; - gausstaby = m_maintabs[refrady - 1]; - gausstabcenty = gausstaby + refrady; - - sum = gval = rval = bval = aval = 0.0f; - for (i = minyr; i < maxyr; i++, srcd += COM_NUM_CHANNELS_COLOR * imgx) { - src = srcd; - for (j = minxr; j < maxxr; j++, src += COM_NUM_CHANNELS_COLOR) { - - val = gausstabcenty[i] * gausstabcentx[j]; - sum += val; - rval += val * src[0]; - gval += val * src[1]; - bval += val * src[2]; - aval += val * src[3]; - } - } - sum = 1.0f / sum; - output[0] = rval * sum; - output[1] = gval * sum; - output[2] = bval * sum; - output[3] = aval * sum; - } -} - -void GaussianBlurReferenceOperation::deinitExecution() -{ - int x, i; - x = MAX2(this->m_filtersizex, this->m_filtersizey); - for (i = 0; i < x; i++) { - MEM_freeN(this->m_maintabs[i]); - } - MEM_freeN(this->m_maintabs); - BlurBaseOperation::deinitExecution(); -} - -bool GaussianBlurReferenceOperation::determineDependingAreaOfInterest( - rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInput; - NodeOperation *operation = this->getInputOperation(1); - - if (operation->determineDependingAreaOfInterest(input, readOperation, output)) { - return true; - } - - int addx = this->m_data.sizex + 2; - int addy = this->m_data.sizey + 2; - newInput.xmax = input->xmax + addx; - newInput.xmin = input->xmin - addx; - newInput.ymax = input->ymax + addy; - newInput.ymin = input->ymin - addy; - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc new file mode 100644 index 00000000000..596d439658c --- /dev/null +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc @@ -0,0 +1,207 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GaussianXBlurOperation.h" +#include "BLI_math.h" +#include "COM_OpenCLDevice.h" +#include "MEM_guardedalloc.h" + +#include "RE_pipeline.h" + +GaussianXBlurOperation::GaussianXBlurOperation() : BlurBaseOperation(COM_DT_COLOR) +{ + this->m_gausstab = nullptr; +#ifdef BLI_HAVE_SSE2 + this->m_gausstab_sse = nullptr; +#endif + this->m_filtersize = 0; +} + +void *GaussianXBlurOperation::initializeTileData(rcti * /*rect*/) +{ + lockMutex(); + if (!this->m_sizeavailable) { + updateGauss(); + } + void *buffer = getInputOperation(0)->initializeTileData(nullptr); + unlockMutex(); + return buffer; +} + +void GaussianXBlurOperation::initExecution() +{ + BlurBaseOperation::initExecution(); + + initMutex(); + + if (this->m_sizeavailable) { + float rad = max_ff(m_size * m_data.sizex, 0.0f); + m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); + + /* TODO(sergey): De-duplicate with the case below and Y blur. */ + this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); +#ifdef BLI_HAVE_SSE2 + this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize); +#endif + } +} + +void GaussianXBlurOperation::updateGauss() +{ + if (this->m_gausstab == nullptr) { + updateSize(); + float rad = max_ff(m_size * m_data.sizex, 0.0f); + rad = min_ff(rad, MAX_GAUSSTAB_RADIUS); + m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); + + this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); +#ifdef BLI_HAVE_SSE2 + this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize); +#endif + } +} + +void GaussianXBlurOperation::executePixel(float output[4], int x, int y, void *data) +{ + float ATTR_ALIGN(16) color_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float multiplier_accum = 0.0f; + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + float *buffer = inputBuffer->getBuffer(); + int bufferwidth = inputBuffer->getWidth(); + int bufferstartx = inputBuffer->getRect()->xmin; + int bufferstarty = inputBuffer->getRect()->ymin; + + rcti &rect = *inputBuffer->getRect(); + int xmin = max_ii(x - m_filtersize, rect.xmin); + int xmax = min_ii(x + m_filtersize + 1, rect.xmax); + int ymin = max_ii(y, rect.ymin); + + int step = getStep(); + int offsetadd = getOffsetAdd(); + int bufferindex = ((xmin - bufferstartx) * 4) + ((ymin - bufferstarty) * 4 * bufferwidth); + +#ifdef BLI_HAVE_SSE2 + __m128 accum_r = _mm_load_ps(color_accum); + for (int nx = xmin, index = (xmin - x) + this->m_filtersize; nx < xmax; + nx += step, index += step) { + __m128 reg_a = _mm_load_ps(&buffer[bufferindex]); + reg_a = _mm_mul_ps(reg_a, this->m_gausstab_sse[index]); + accum_r = _mm_add_ps(accum_r, reg_a); + multiplier_accum += this->m_gausstab[index]; + bufferindex += offsetadd; + } + _mm_store_ps(color_accum, accum_r); +#else + for (int nx = xmin, index = (xmin - x) + this->m_filtersize; nx < xmax; + nx += step, index += step) { + const float multiplier = this->m_gausstab[index]; + madd_v4_v4fl(color_accum, &buffer[bufferindex], multiplier); + multiplier_accum += multiplier; + bufferindex += offsetadd; + } +#endif + mul_v4_v4fl(output, color_accum, 1.0f / multiplier_accum); +} + +void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device, + MemoryBuffer *outputMemoryBuffer, + cl_mem clOutputBuffer, + MemoryBuffer **inputMemoryBuffers, + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) +{ + cl_kernel gaussianXBlurOperationKernel = device->COM_clCreateKernel( + "gaussianXBlurOperationKernel", nullptr); + cl_int filter_size = this->m_filtersize; + + cl_mem gausstab = clCreateBuffer(device->getContext(), + CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, + sizeof(float) * (this->m_filtersize * 2 + 1), + this->m_gausstab, + nullptr); + + device->COM_clAttachMemoryBufferToKernelParameter(gaussianXBlurOperationKernel, + 0, + 1, + clMemToCleanUp, + inputMemoryBuffers, + this->m_inputProgram); + device->COM_clAttachOutputMemoryBufferToKernelParameter( + gaussianXBlurOperationKernel, 2, clOutputBuffer); + device->COM_clAttachMemoryBufferOffsetToKernelParameter( + gaussianXBlurOperationKernel, 3, outputMemoryBuffer); + clSetKernelArg(gaussianXBlurOperationKernel, 4, sizeof(cl_int), &filter_size); + device->COM_clAttachSizeToKernelParameter(gaussianXBlurOperationKernel, 5, this); + clSetKernelArg(gaussianXBlurOperationKernel, 6, sizeof(cl_mem), &gausstab); + + device->COM_clEnqueueRange(gaussianXBlurOperationKernel, outputMemoryBuffer, 7, this); + + clReleaseMemObject(gausstab); +} + +void GaussianXBlurOperation::deinitExecution() +{ + BlurBaseOperation::deinitExecution(); + + if (this->m_gausstab) { + MEM_freeN(this->m_gausstab); + this->m_gausstab = nullptr; + } +#ifdef BLI_HAVE_SSE2 + if (this->m_gausstab_sse) { + MEM_freeN(this->m_gausstab_sse); + this->m_gausstab_sse = nullptr; + } +#endif + + deinitMutex(); +} + +bool GaussianXBlurOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + + if (!this->m_sizeavailable) { + rcti sizeInput; + sizeInput.xmin = 0; + sizeInput.ymin = 0; + sizeInput.xmax = 5; + sizeInput.ymax = 5; + NodeOperation *operation = this->getInputOperation(1); + if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { + return true; + } + } + { + if (this->m_sizeavailable && this->m_gausstab != nullptr) { + newInput.xmax = input->xmax + this->m_filtersize + 1; + newInput.xmin = input->xmin - this->m_filtersize - 1; + newInput.ymax = input->ymax; + newInput.ymin = input->ymin; + } + else { + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + } + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + } +} diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp deleted file mode 100644 index 596d439658c..00000000000 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GaussianXBlurOperation.h" -#include "BLI_math.h" -#include "COM_OpenCLDevice.h" -#include "MEM_guardedalloc.h" - -#include "RE_pipeline.h" - -GaussianXBlurOperation::GaussianXBlurOperation() : BlurBaseOperation(COM_DT_COLOR) -{ - this->m_gausstab = nullptr; -#ifdef BLI_HAVE_SSE2 - this->m_gausstab_sse = nullptr; -#endif - this->m_filtersize = 0; -} - -void *GaussianXBlurOperation::initializeTileData(rcti * /*rect*/) -{ - lockMutex(); - if (!this->m_sizeavailable) { - updateGauss(); - } - void *buffer = getInputOperation(0)->initializeTileData(nullptr); - unlockMutex(); - return buffer; -} - -void GaussianXBlurOperation::initExecution() -{ - BlurBaseOperation::initExecution(); - - initMutex(); - - if (this->m_sizeavailable) { - float rad = max_ff(m_size * m_data.sizex, 0.0f); - m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); - - /* TODO(sergey): De-duplicate with the case below and Y blur. */ - this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); -#ifdef BLI_HAVE_SSE2 - this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize); -#endif - } -} - -void GaussianXBlurOperation::updateGauss() -{ - if (this->m_gausstab == nullptr) { - updateSize(); - float rad = max_ff(m_size * m_data.sizex, 0.0f); - rad = min_ff(rad, MAX_GAUSSTAB_RADIUS); - m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); - - this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); -#ifdef BLI_HAVE_SSE2 - this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize); -#endif - } -} - -void GaussianXBlurOperation::executePixel(float output[4], int x, int y, void *data) -{ - float ATTR_ALIGN(16) color_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - float multiplier_accum = 0.0f; - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - float *buffer = inputBuffer->getBuffer(); - int bufferwidth = inputBuffer->getWidth(); - int bufferstartx = inputBuffer->getRect()->xmin; - int bufferstarty = inputBuffer->getRect()->ymin; - - rcti &rect = *inputBuffer->getRect(); - int xmin = max_ii(x - m_filtersize, rect.xmin); - int xmax = min_ii(x + m_filtersize + 1, rect.xmax); - int ymin = max_ii(y, rect.ymin); - - int step = getStep(); - int offsetadd = getOffsetAdd(); - int bufferindex = ((xmin - bufferstartx) * 4) + ((ymin - bufferstarty) * 4 * bufferwidth); - -#ifdef BLI_HAVE_SSE2 - __m128 accum_r = _mm_load_ps(color_accum); - for (int nx = xmin, index = (xmin - x) + this->m_filtersize; nx < xmax; - nx += step, index += step) { - __m128 reg_a = _mm_load_ps(&buffer[bufferindex]); - reg_a = _mm_mul_ps(reg_a, this->m_gausstab_sse[index]); - accum_r = _mm_add_ps(accum_r, reg_a); - multiplier_accum += this->m_gausstab[index]; - bufferindex += offsetadd; - } - _mm_store_ps(color_accum, accum_r); -#else - for (int nx = xmin, index = (xmin - x) + this->m_filtersize; nx < xmax; - nx += step, index += step) { - const float multiplier = this->m_gausstab[index]; - madd_v4_v4fl(color_accum, &buffer[bufferindex], multiplier); - multiplier_accum += multiplier; - bufferindex += offsetadd; - } -#endif - mul_v4_v4fl(output, color_accum, 1.0f / multiplier_accum); -} - -void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device, - MemoryBuffer *outputMemoryBuffer, - cl_mem clOutputBuffer, - MemoryBuffer **inputMemoryBuffers, - std::list *clMemToCleanUp, - std::list * /*clKernelsToCleanUp*/) -{ - cl_kernel gaussianXBlurOperationKernel = device->COM_clCreateKernel( - "gaussianXBlurOperationKernel", nullptr); - cl_int filter_size = this->m_filtersize; - - cl_mem gausstab = clCreateBuffer(device->getContext(), - CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, - sizeof(float) * (this->m_filtersize * 2 + 1), - this->m_gausstab, - nullptr); - - device->COM_clAttachMemoryBufferToKernelParameter(gaussianXBlurOperationKernel, - 0, - 1, - clMemToCleanUp, - inputMemoryBuffers, - this->m_inputProgram); - device->COM_clAttachOutputMemoryBufferToKernelParameter( - gaussianXBlurOperationKernel, 2, clOutputBuffer); - device->COM_clAttachMemoryBufferOffsetToKernelParameter( - gaussianXBlurOperationKernel, 3, outputMemoryBuffer); - clSetKernelArg(gaussianXBlurOperationKernel, 4, sizeof(cl_int), &filter_size); - device->COM_clAttachSizeToKernelParameter(gaussianXBlurOperationKernel, 5, this); - clSetKernelArg(gaussianXBlurOperationKernel, 6, sizeof(cl_mem), &gausstab); - - device->COM_clEnqueueRange(gaussianXBlurOperationKernel, outputMemoryBuffer, 7, this); - - clReleaseMemObject(gausstab); -} - -void GaussianXBlurOperation::deinitExecution() -{ - BlurBaseOperation::deinitExecution(); - - if (this->m_gausstab) { - MEM_freeN(this->m_gausstab); - this->m_gausstab = nullptr; - } -#ifdef BLI_HAVE_SSE2 - if (this->m_gausstab_sse) { - MEM_freeN(this->m_gausstab_sse); - this->m_gausstab_sse = nullptr; - } -#endif - - deinitMutex(); -} - -bool GaussianXBlurOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - - if (!this->m_sizeavailable) { - rcti sizeInput; - sizeInput.xmin = 0; - sizeInput.ymin = 0; - sizeInput.xmax = 5; - sizeInput.ymax = 5; - NodeOperation *operation = this->getInputOperation(1); - if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { - return true; - } - } - { - if (this->m_sizeavailable && this->m_gausstab != nullptr) { - newInput.xmax = input->xmax + this->m_filtersize + 1; - newInput.xmin = input->xmin - this->m_filtersize - 1; - newInput.ymax = input->ymax; - newInput.ymin = input->ymin; - } - else { - newInput.xmax = this->getWidth(); - newInput.xmin = 0; - newInput.ymax = this->getHeight(); - newInput.ymin = 0; - } - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); - } -} diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc new file mode 100644 index 00000000000..55c1551ca42 --- /dev/null +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc @@ -0,0 +1,207 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GaussianYBlurOperation.h" +#include "BLI_math.h" +#include "COM_OpenCLDevice.h" +#include "MEM_guardedalloc.h" + +#include "RE_pipeline.h" + +GaussianYBlurOperation::GaussianYBlurOperation() : BlurBaseOperation(COM_DT_COLOR) +{ + this->m_gausstab = nullptr; +#ifdef BLI_HAVE_SSE2 + this->m_gausstab_sse = nullptr; +#endif + this->m_filtersize = 0; +} + +void *GaussianYBlurOperation::initializeTileData(rcti * /*rect*/) +{ + lockMutex(); + if (!this->m_sizeavailable) { + updateGauss(); + } + void *buffer = getInputOperation(0)->initializeTileData(nullptr); + unlockMutex(); + return buffer; +} + +void GaussianYBlurOperation::initExecution() +{ + BlurBaseOperation::initExecution(); + + initMutex(); + + if (this->m_sizeavailable) { + float rad = max_ff(m_size * m_data.sizey, 0.0f); + m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); + + this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); +#ifdef BLI_HAVE_SSE2 + this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize); +#endif + } +} + +void GaussianYBlurOperation::updateGauss() +{ + if (this->m_gausstab == nullptr) { + updateSize(); + float rad = max_ff(m_size * m_data.sizey, 0.0f); + rad = min_ff(rad, MAX_GAUSSTAB_RADIUS); + m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); + + this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); +#ifdef BLI_HAVE_SSE2 + this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize); +#endif + } +} + +void GaussianYBlurOperation::executePixel(float output[4], int x, int y, void *data) +{ + float ATTR_ALIGN(16) color_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float multiplier_accum = 0.0f; + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + float *buffer = inputBuffer->getBuffer(); + int bufferwidth = inputBuffer->getWidth(); + int bufferstartx = inputBuffer->getRect()->xmin; + int bufferstarty = inputBuffer->getRect()->ymin; + + rcti &rect = *inputBuffer->getRect(); + int xmin = max_ii(x, rect.xmin); + int ymin = max_ii(y - m_filtersize, rect.ymin); + int ymax = min_ii(y + m_filtersize + 1, rect.ymax); + + int index; + int step = getStep(); + const int bufferIndexx = ((xmin - bufferstartx) * 4); + +#ifdef BLI_HAVE_SSE2 + __m128 accum_r = _mm_load_ps(color_accum); + for (int ny = ymin; ny < ymax; ny += step) { + index = (ny - y) + this->m_filtersize; + int bufferindex = bufferIndexx + ((ny - bufferstarty) * 4 * bufferwidth); + const float multiplier = this->m_gausstab[index]; + __m128 reg_a = _mm_load_ps(&buffer[bufferindex]); + reg_a = _mm_mul_ps(reg_a, this->m_gausstab_sse[index]); + accum_r = _mm_add_ps(accum_r, reg_a); + multiplier_accum += multiplier; + } + _mm_store_ps(color_accum, accum_r); +#else + for (int ny = ymin; ny < ymax; ny += step) { + index = (ny - y) + this->m_filtersize; + int bufferindex = bufferIndexx + ((ny - bufferstarty) * 4 * bufferwidth); + const float multiplier = this->m_gausstab[index]; + madd_v4_v4fl(color_accum, &buffer[bufferindex], multiplier); + multiplier_accum += multiplier; + } +#endif + mul_v4_v4fl(output, color_accum, 1.0f / multiplier_accum); +} + +void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device, + MemoryBuffer *outputMemoryBuffer, + cl_mem clOutputBuffer, + MemoryBuffer **inputMemoryBuffers, + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) +{ + cl_kernel gaussianYBlurOperationKernel = device->COM_clCreateKernel( + "gaussianYBlurOperationKernel", nullptr); + cl_int filter_size = this->m_filtersize; + + cl_mem gausstab = clCreateBuffer(device->getContext(), + CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, + sizeof(float) * (this->m_filtersize * 2 + 1), + this->m_gausstab, + nullptr); + + device->COM_clAttachMemoryBufferToKernelParameter(gaussianYBlurOperationKernel, + 0, + 1, + clMemToCleanUp, + inputMemoryBuffers, + this->m_inputProgram); + device->COM_clAttachOutputMemoryBufferToKernelParameter( + gaussianYBlurOperationKernel, 2, clOutputBuffer); + device->COM_clAttachMemoryBufferOffsetToKernelParameter( + gaussianYBlurOperationKernel, 3, outputMemoryBuffer); + clSetKernelArg(gaussianYBlurOperationKernel, 4, sizeof(cl_int), &filter_size); + device->COM_clAttachSizeToKernelParameter(gaussianYBlurOperationKernel, 5, this); + clSetKernelArg(gaussianYBlurOperationKernel, 6, sizeof(cl_mem), &gausstab); + + device->COM_clEnqueueRange(gaussianYBlurOperationKernel, outputMemoryBuffer, 7, this); + + clReleaseMemObject(gausstab); +} + +void GaussianYBlurOperation::deinitExecution() +{ + BlurBaseOperation::deinitExecution(); + + if (this->m_gausstab) { + MEM_freeN(this->m_gausstab); + this->m_gausstab = nullptr; + } +#ifdef BLI_HAVE_SSE2 + if (this->m_gausstab_sse) { + MEM_freeN(this->m_gausstab_sse); + this->m_gausstab_sse = nullptr; + } +#endif + + deinitMutex(); +} + +bool GaussianYBlurOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + + if (!m_sizeavailable) { + rcti sizeInput; + sizeInput.xmin = 0; + sizeInput.ymin = 0; + sizeInput.xmax = 5; + sizeInput.ymax = 5; + NodeOperation *operation = this->getInputOperation(1); + if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { + return true; + } + } + { + if (this->m_sizeavailable && this->m_gausstab != nullptr) { + newInput.xmax = input->xmax; + newInput.xmin = input->xmin; + newInput.ymax = input->ymax + this->m_filtersize + 1; + newInput.ymin = input->ymin - this->m_filtersize - 1; + } + else { + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + } + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + } +} diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp deleted file mode 100644 index 55c1551ca42..00000000000 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GaussianYBlurOperation.h" -#include "BLI_math.h" -#include "COM_OpenCLDevice.h" -#include "MEM_guardedalloc.h" - -#include "RE_pipeline.h" - -GaussianYBlurOperation::GaussianYBlurOperation() : BlurBaseOperation(COM_DT_COLOR) -{ - this->m_gausstab = nullptr; -#ifdef BLI_HAVE_SSE2 - this->m_gausstab_sse = nullptr; -#endif - this->m_filtersize = 0; -} - -void *GaussianYBlurOperation::initializeTileData(rcti * /*rect*/) -{ - lockMutex(); - if (!this->m_sizeavailable) { - updateGauss(); - } - void *buffer = getInputOperation(0)->initializeTileData(nullptr); - unlockMutex(); - return buffer; -} - -void GaussianYBlurOperation::initExecution() -{ - BlurBaseOperation::initExecution(); - - initMutex(); - - if (this->m_sizeavailable) { - float rad = max_ff(m_size * m_data.sizey, 0.0f); - m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); - - this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); -#ifdef BLI_HAVE_SSE2 - this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize); -#endif - } -} - -void GaussianYBlurOperation::updateGauss() -{ - if (this->m_gausstab == nullptr) { - updateSize(); - float rad = max_ff(m_size * m_data.sizey, 0.0f); - rad = min_ff(rad, MAX_GAUSSTAB_RADIUS); - m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS); - - this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize); -#ifdef BLI_HAVE_SSE2 - this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab, m_filtersize); -#endif - } -} - -void GaussianYBlurOperation::executePixel(float output[4], int x, int y, void *data) -{ - float ATTR_ALIGN(16) color_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - float multiplier_accum = 0.0f; - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - float *buffer = inputBuffer->getBuffer(); - int bufferwidth = inputBuffer->getWidth(); - int bufferstartx = inputBuffer->getRect()->xmin; - int bufferstarty = inputBuffer->getRect()->ymin; - - rcti &rect = *inputBuffer->getRect(); - int xmin = max_ii(x, rect.xmin); - int ymin = max_ii(y - m_filtersize, rect.ymin); - int ymax = min_ii(y + m_filtersize + 1, rect.ymax); - - int index; - int step = getStep(); - const int bufferIndexx = ((xmin - bufferstartx) * 4); - -#ifdef BLI_HAVE_SSE2 - __m128 accum_r = _mm_load_ps(color_accum); - for (int ny = ymin; ny < ymax; ny += step) { - index = (ny - y) + this->m_filtersize; - int bufferindex = bufferIndexx + ((ny - bufferstarty) * 4 * bufferwidth); - const float multiplier = this->m_gausstab[index]; - __m128 reg_a = _mm_load_ps(&buffer[bufferindex]); - reg_a = _mm_mul_ps(reg_a, this->m_gausstab_sse[index]); - accum_r = _mm_add_ps(accum_r, reg_a); - multiplier_accum += multiplier; - } - _mm_store_ps(color_accum, accum_r); -#else - for (int ny = ymin; ny < ymax; ny += step) { - index = (ny - y) + this->m_filtersize; - int bufferindex = bufferIndexx + ((ny - bufferstarty) * 4 * bufferwidth); - const float multiplier = this->m_gausstab[index]; - madd_v4_v4fl(color_accum, &buffer[bufferindex], multiplier); - multiplier_accum += multiplier; - } -#endif - mul_v4_v4fl(output, color_accum, 1.0f / multiplier_accum); -} - -void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device, - MemoryBuffer *outputMemoryBuffer, - cl_mem clOutputBuffer, - MemoryBuffer **inputMemoryBuffers, - std::list *clMemToCleanUp, - std::list * /*clKernelsToCleanUp*/) -{ - cl_kernel gaussianYBlurOperationKernel = device->COM_clCreateKernel( - "gaussianYBlurOperationKernel", nullptr); - cl_int filter_size = this->m_filtersize; - - cl_mem gausstab = clCreateBuffer(device->getContext(), - CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, - sizeof(float) * (this->m_filtersize * 2 + 1), - this->m_gausstab, - nullptr); - - device->COM_clAttachMemoryBufferToKernelParameter(gaussianYBlurOperationKernel, - 0, - 1, - clMemToCleanUp, - inputMemoryBuffers, - this->m_inputProgram); - device->COM_clAttachOutputMemoryBufferToKernelParameter( - gaussianYBlurOperationKernel, 2, clOutputBuffer); - device->COM_clAttachMemoryBufferOffsetToKernelParameter( - gaussianYBlurOperationKernel, 3, outputMemoryBuffer); - clSetKernelArg(gaussianYBlurOperationKernel, 4, sizeof(cl_int), &filter_size); - device->COM_clAttachSizeToKernelParameter(gaussianYBlurOperationKernel, 5, this); - clSetKernelArg(gaussianYBlurOperationKernel, 6, sizeof(cl_mem), &gausstab); - - device->COM_clEnqueueRange(gaussianYBlurOperationKernel, outputMemoryBuffer, 7, this); - - clReleaseMemObject(gausstab); -} - -void GaussianYBlurOperation::deinitExecution() -{ - BlurBaseOperation::deinitExecution(); - - if (this->m_gausstab) { - MEM_freeN(this->m_gausstab); - this->m_gausstab = nullptr; - } -#ifdef BLI_HAVE_SSE2 - if (this->m_gausstab_sse) { - MEM_freeN(this->m_gausstab_sse); - this->m_gausstab_sse = nullptr; - } -#endif - - deinitMutex(); -} - -bool GaussianYBlurOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - - if (!m_sizeavailable) { - rcti sizeInput; - sizeInput.xmin = 0; - sizeInput.ymin = 0; - sizeInput.xmax = 5; - sizeInput.ymax = 5; - NodeOperation *operation = this->getInputOperation(1); - if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) { - return true; - } - } - { - if (this->m_sizeavailable && this->m_gausstab != nullptr) { - newInput.xmax = input->xmax; - newInput.xmin = input->xmin; - newInput.ymax = input->ymax + this->m_filtersize + 1; - newInput.ymin = input->ymin - this->m_filtersize - 1; - } - else { - newInput.xmax = this->getWidth(); - newInput.xmin = 0; - newInput.ymax = this->getHeight(); - newInput.ymin = 0; - } - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); - } -} diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.cc b/source/blender/compositor/operations/COM_GlareBaseOperation.cc new file mode 100644 index 00000000000..7b4d38fba3e --- /dev/null +++ b/source/blender/compositor/operations/COM_GlareBaseOperation.cc @@ -0,0 +1,68 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GlareBaseOperation.h" +#include "BLI_math.h" + +GlareBaseOperation::GlareBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_settings = nullptr; +} +void GlareBaseOperation::initExecution() +{ + SingleThreadedOperation::initExecution(); + this->m_inputProgram = getInputSocketReader(0); +} + +void GlareBaseOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; + SingleThreadedOperation::deinitExecution(); +} + +MemoryBuffer *GlareBaseOperation::createMemoryBuffer(rcti *rect2) +{ + MemoryBuffer *tile = (MemoryBuffer *)this->m_inputProgram->initializeTileData(rect2); + rcti rect; + rect.xmin = 0; + rect.ymin = 0; + rect.xmax = getWidth(); + rect.ymax = getHeight(); + MemoryBuffer *result = new MemoryBuffer(COM_DT_COLOR, &rect); + float *data = result->getBuffer(); + this->generateGlare(data, tile, this->m_settings); + return result; +} + +bool GlareBaseOperation::determineDependingAreaOfInterest(rcti * /*input*/, + ReadBufferOperation *readOperation, + rcti *output) +{ + if (isCached()) { + return false; + } + + rcti newInput; + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp b/source/blender/compositor/operations/COM_GlareBaseOperation.cpp deleted file mode 100644 index 7b4d38fba3e..00000000000 --- a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GlareBaseOperation.h" -#include "BLI_math.h" - -GlareBaseOperation::GlareBaseOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_settings = nullptr; -} -void GlareBaseOperation::initExecution() -{ - SingleThreadedOperation::initExecution(); - this->m_inputProgram = getInputSocketReader(0); -} - -void GlareBaseOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; - SingleThreadedOperation::deinitExecution(); -} - -MemoryBuffer *GlareBaseOperation::createMemoryBuffer(rcti *rect2) -{ - MemoryBuffer *tile = (MemoryBuffer *)this->m_inputProgram->initializeTileData(rect2); - rcti rect; - rect.xmin = 0; - rect.ymin = 0; - rect.xmax = getWidth(); - rect.ymax = getHeight(); - MemoryBuffer *result = new MemoryBuffer(COM_DT_COLOR, &rect); - float *data = result->getBuffer(); - this->generateGlare(data, tile, this->m_settings); - return result; -} - -bool GlareBaseOperation::determineDependingAreaOfInterest(rcti * /*input*/, - ReadBufferOperation *readOperation, - rcti *output) -{ - if (isCached()) { - return false; - } - - rcti newInput; - newInput.xmax = this->getWidth(); - newInput.xmin = 0; - newInput.ymax = this->getHeight(); - newInput.ymin = 0; - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc new file mode 100644 index 00000000000..362905761bb --- /dev/null +++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc @@ -0,0 +1,444 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GlareFogGlowOperation.h" +#include "MEM_guardedalloc.h" + +/* + * 2D Fast Hartley Transform, used for convolution + */ + +using fREAL = float; + +// returns next highest power of 2 of x, as well its log2 in L2 +static unsigned int nextPow2(unsigned int x, unsigned int *L2) +{ + unsigned int pw, x_notpow2 = x & (x - 1); + *L2 = 0; + while (x >>= 1) { + ++(*L2); + } + pw = 1 << (*L2); + if (x_notpow2) { + (*L2)++; + pw <<= 1; + } + return pw; +} + +//------------------------------------------------------------------------------ + +// from FXT library by Joerg Arndt, faster in order bitreversal +// use: r = revbin_upd(r, h) where h = N>>1 +static unsigned int revbin_upd(unsigned int r, unsigned int h) +{ + while (!((r ^= h) & h)) { + h >>= 1; + } + return r; +} +//------------------------------------------------------------------------------ +static void FHT(fREAL *data, unsigned int M, unsigned int inverse) +{ + double tt, fc, dc, fs, ds, a = M_PI; + fREAL t1, t2; + int n2, bd, bl, istep, k, len = 1 << M, n = 1; + + int i, j = 0; + unsigned int Nh = len >> 1; + for (i = 1; i < (len - 1); i++) { + j = revbin_upd(j, Nh); + if (j > i) { + t1 = data[i]; + data[i] = data[j]; + data[j] = t1; + } + } + + do { + fREAL *data_n = &data[n]; + + istep = n << 1; + for (k = 0; k < len; k += istep) { + t1 = data_n[k]; + data_n[k] = data[k] - t1; + data[k] += t1; + } + + n2 = n >> 1; + if (n > 2) { + fc = dc = cos(a); + fs = ds = sqrt(1.0 - fc * fc); // sin(a); + bd = n - 2; + for (bl = 1; bl < n2; bl++) { + fREAL *data_nbd = &data_n[bd]; + fREAL *data_bd = &data[bd]; + for (k = bl; k < len; k += istep) { + t1 = fc * (double)data_n[k] + fs * (double)data_nbd[k]; + t2 = fs * (double)data_n[k] - fc * (double)data_nbd[k]; + data_n[k] = data[k] - t1; + data_nbd[k] = data_bd[k] - t2; + data[k] += t1; + data_bd[k] += t2; + } + tt = fc * dc - fs * ds; + fs = fs * dc + fc * ds; + fc = tt; + bd -= 2; + } + } + + if (n > 1) { + for (k = n2; k < len; k += istep) { + t1 = data_n[k]; + data_n[k] = data[k] - t1; + data[k] += t1; + } + } + + n = istep; + a *= 0.5; + } while (n < len); + + if (inverse) { + fREAL sc = (fREAL)1 / (fREAL)len; + for (k = 0; k < len; k++) { + data[k] *= sc; + } + } +} +//------------------------------------------------------------------------------ +/* 2D Fast Hartley Transform, Mx/My -> log2 of width/height, + * nzp -> the row where zero pad data starts, + * inverse -> see above */ +static void FHT2D( + fREAL *data, unsigned int Mx, unsigned int My, unsigned int nzp, unsigned int inverse) +{ + unsigned int i, j, Nx, Ny, maxy; + + Nx = 1 << Mx; + Ny = 1 << My; + + // rows (forward transform skips 0 pad data) + maxy = inverse ? Ny : nzp; + for (j = 0; j < maxy; j++) { + FHT(&data[Nx * j], Mx, inverse); + } + + // transpose data + if (Nx == Ny) { // square + for (j = 0; j < Ny; j++) { + for (i = j + 1; i < Nx; i++) { + unsigned int op = i + (j << Mx), np = j + (i << My); + SWAP(fREAL, data[op], data[np]); + } + } + } + else { // rectangular + unsigned int k, Nym = Ny - 1, stm = 1 << (Mx + My); + for (i = 0; stm > 0; i++) { +#define PRED(k) (((k & Nym) << Mx) + (k >> My)) + for (j = PRED(i); j > i; j = PRED(j)) { + /* pass */ + } + if (j < i) { + continue; + } + for (k = i, j = PRED(i); j != i; k = j, j = PRED(j), stm--) { + SWAP(fREAL, data[j], data[k]); + } +#undef PRED + stm--; + } + } + + SWAP(unsigned int, Nx, Ny); + SWAP(unsigned int, Mx, My); + + // now columns == transposed rows + for (j = 0; j < Ny; j++) { + FHT(&data[Nx * j], Mx, inverse); + } + + // finalize + for (j = 0; j <= (Ny >> 1); j++) { + unsigned int jm = (Ny - j) & (Ny - 1); + unsigned int ji = j << Mx; + unsigned int jmi = jm << Mx; + for (i = 0; i <= (Nx >> 1); i++) { + unsigned int im = (Nx - i) & (Nx - 1); + fREAL A = data[ji + i]; + fREAL B = data[jmi + i]; + fREAL C = data[ji + im]; + fREAL D = data[jmi + im]; + fREAL E = (fREAL)0.5 * ((A + D) - (B + C)); + data[ji + i] = A - E; + data[jmi + i] = B + E; + data[ji + im] = C + E; + data[jmi + im] = D - E; + } + } +} + +//------------------------------------------------------------------------------ + +/* 2D convolution calc, d1 *= d2, M/N - > log2 of width/height */ +static void fht_convolve(fREAL *d1, const fREAL *d2, unsigned int M, unsigned int N) +{ + fREAL a, b; + unsigned int i, j, k, L, mj, mL; + unsigned int m = 1 << M, n = 1 << N; + unsigned int m2 = 1 << (M - 1), n2 = 1 << (N - 1); + unsigned int mn2 = m << (N - 1); + + d1[0] *= d2[0]; + d1[mn2] *= d2[mn2]; + d1[m2] *= d2[m2]; + d1[m2 + mn2] *= d2[m2 + mn2]; + for (i = 1; i < m2; i++) { + k = m - i; + a = d1[i] * d2[i] - d1[k] * d2[k]; + b = d1[k] * d2[i] + d1[i] * d2[k]; + d1[i] = (b + a) * (fREAL)0.5; + d1[k] = (b - a) * (fREAL)0.5; + a = d1[i + mn2] * d2[i + mn2] - d1[k + mn2] * d2[k + mn2]; + b = d1[k + mn2] * d2[i + mn2] + d1[i + mn2] * d2[k + mn2]; + d1[i + mn2] = (b + a) * (fREAL)0.5; + d1[k + mn2] = (b - a) * (fREAL)0.5; + } + for (j = 1; j < n2; j++) { + L = n - j; + mj = j << M; + mL = L << M; + a = d1[mj] * d2[mj] - d1[mL] * d2[mL]; + b = d1[mL] * d2[mj] + d1[mj] * d2[mL]; + d1[mj] = (b + a) * (fREAL)0.5; + d1[mL] = (b - a) * (fREAL)0.5; + a = d1[m2 + mj] * d2[m2 + mj] - d1[m2 + mL] * d2[m2 + mL]; + b = d1[m2 + mL] * d2[m2 + mj] + d1[m2 + mj] * d2[m2 + mL]; + d1[m2 + mj] = (b + a) * (fREAL)0.5; + d1[m2 + mL] = (b - a) * (fREAL)0.5; + } + for (i = 1; i < m2; i++) { + k = m - i; + for (j = 1; j < n2; j++) { + L = n - j; + mj = j << M; + mL = L << M; + a = d1[i + mj] * d2[i + mj] - d1[k + mL] * d2[k + mL]; + b = d1[k + mL] * d2[i + mj] + d1[i + mj] * d2[k + mL]; + d1[i + mj] = (b + a) * (fREAL)0.5; + d1[k + mL] = (b - a) * (fREAL)0.5; + a = d1[i + mL] * d2[i + mL] - d1[k + mj] * d2[k + mj]; + b = d1[k + mj] * d2[i + mL] + d1[i + mL] * d2[k + mj]; + d1[i + mL] = (b + a) * (fREAL)0.5; + d1[k + mj] = (b - a) * (fREAL)0.5; + } + } +} +//------------------------------------------------------------------------------ + +static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2) +{ + fREAL *data1, *data2, *fp; + unsigned int w2, h2, hw, hh, log2_w, log2_h; + fRGB wt, *colp; + int x, y, ch; + int xbl, ybl, nxb, nyb, xbsz, ybsz; + bool in2done = false; + const unsigned int kernelWidth = in2->getWidth(); + const unsigned int kernelHeight = in2->getHeight(); + const unsigned int imageWidth = in1->getWidth(); + const unsigned int imageHeight = in1->getHeight(); + float *kernelBuffer = in2->getBuffer(); + float *imageBuffer = in1->getBuffer(); + + MemoryBuffer *rdst = new MemoryBuffer(COM_DT_COLOR, in1->getRect()); + memset(rdst->getBuffer(), + 0, + rdst->getWidth() * rdst->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); + + // convolution result width & height + w2 = 2 * kernelWidth - 1; + h2 = 2 * kernelHeight - 1; + // FFT pow2 required size & log2 + w2 = nextPow2(w2, &log2_w); + h2 = nextPow2(h2, &log2_h); + + // alloc space + data1 = (fREAL *)MEM_callocN(3 * w2 * h2 * sizeof(fREAL), "convolve_fast FHT data1"); + data2 = (fREAL *)MEM_callocN(w2 * h2 * sizeof(fREAL), "convolve_fast FHT data2"); + + // normalize convolutor + wt[0] = wt[1] = wt[2] = 0.0f; + for (y = 0; y < kernelHeight; y++) { + colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR]; + for (x = 0; x < kernelWidth; x++) { + add_v3_v3(wt, colp[x]); + } + } + if (wt[0] != 0.0f) { + wt[0] = 1.0f / wt[0]; + } + if (wt[1] != 0.0f) { + wt[1] = 1.0f / wt[1]; + } + if (wt[2] != 0.0f) { + wt[2] = 1.0f / wt[2]; + } + for (y = 0; y < kernelHeight; y++) { + colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR]; + for (x = 0; x < kernelWidth; x++) { + mul_v3_v3(colp[x], wt); + } + } + + // copy image data, unpacking interleaved RGBA into separate channels + // only need to calc data1 once + + // block add-overlap + hw = kernelWidth >> 1; + hh = kernelHeight >> 1; + xbsz = (w2 + 1) - kernelWidth; + ybsz = (h2 + 1) - kernelHeight; + nxb = imageWidth / xbsz; + if (imageWidth % xbsz) { + nxb++; + } + nyb = imageHeight / ybsz; + if (imageHeight % ybsz) { + nyb++; + } + for (ybl = 0; ybl < nyb; ybl++) { + for (xbl = 0; xbl < nxb; xbl++) { + + // each channel one by one + for (ch = 0; ch < 3; ch++) { + fREAL *data1ch = &data1[ch * w2 * h2]; + + // only need to calc fht data from in2 once, can re-use for every block + if (!in2done) { + // in2, channel ch -> data1 + for (y = 0; y < kernelHeight; y++) { + fp = &data1ch[y * w2]; + colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR]; + for (x = 0; x < kernelWidth; x++) { + fp[x] = colp[x][ch]; + } + } + } + + // in1, channel ch -> data2 + memset(data2, 0, w2 * h2 * sizeof(fREAL)); + for (y = 0; y < ybsz; y++) { + int yy = ybl * ybsz + y; + if (yy >= imageHeight) { + continue; + } + fp = &data2[y * w2]; + colp = (fRGB *)&imageBuffer[yy * imageWidth * COM_NUM_CHANNELS_COLOR]; + for (x = 0; x < xbsz; x++) { + int xx = xbl * xbsz + x; + if (xx >= imageWidth) { + continue; + } + fp[x] = colp[xx][ch]; + } + } + + // forward FHT + // zero pad data start is different for each == height+1 + if (!in2done) { + FHT2D(data1ch, log2_w, log2_h, kernelHeight + 1, 0); + } + FHT2D(data2, log2_w, log2_h, kernelHeight + 1, 0); + + // FHT2D transposed data, row/col now swapped + // convolve & inverse FHT + fht_convolve(data2, data1ch, log2_h, log2_w); + FHT2D(data2, log2_h, log2_w, 0, 1); + // data again transposed, so in order again + + // overlap-add result + for (y = 0; y < (int)h2; y++) { + const int yy = ybl * ybsz + y - hh; + if ((yy < 0) || (yy >= imageHeight)) { + continue; + } + fp = &data2[y * w2]; + colp = (fRGB *)&rdst->getBuffer()[yy * imageWidth * COM_NUM_CHANNELS_COLOR]; + for (x = 0; x < (int)w2; x++) { + const int xx = xbl * xbsz + x - hw; + if ((xx < 0) || (xx >= imageWidth)) { + continue; + } + colp[xx][ch] += fp[x]; + } + } + } + in2done = true; + } + } + + MEM_freeN(data2); + MEM_freeN(data1); + memcpy( + dst, rdst->getBuffer(), sizeof(float) * imageWidth * imageHeight * COM_NUM_CHANNELS_COLOR); + delete (rdst); +} + +void GlareFogGlowOperation::generateGlare(float *data, + MemoryBuffer *inputTile, + NodeGlare *settings) +{ + int x, y; + float scale, u, v, r, w, d; + fRGB fcol; + MemoryBuffer *ckrn; + unsigned int sz = 1 << settings->size; + const float cs_r = 1.0f, cs_g = 1.0f, cs_b = 1.0f; + + // temp. src image + // make the convolution kernel + rcti kernelRect; + BLI_rcti_init(&kernelRect, 0, sz, 0, sz); + ckrn = new MemoryBuffer(COM_DT_COLOR, &kernelRect); + + scale = 0.25f * sqrtf((float)(sz * sz)); + + for (y = 0; y < sz; y++) { + v = 2.0f * (y / (float)sz) - 1.0f; + for (x = 0; x < sz; x++) { + u = 2.0f * (x / (float)sz) - 1.0f; + r = (u * u + v * v) * scale; + d = -sqrtf(sqrtf(sqrtf(r))) * 9.0f; + fcol[0] = expf(d * cs_r); + fcol[1] = expf(d * cs_g); + fcol[2] = expf(d * cs_b); + // linear window good enough here, visual result counts, not scientific analysis + // w = (1.0f-fabs(u))*(1.0f-fabs(v)); + // actually, Hanning window is ok, cos^2 for some reason is slower + w = (0.5f + 0.5f * cosf(u * (float)M_PI)) * (0.5f + 0.5f * cosf(v * (float)M_PI)); + mul_v3_fl(fcol, w); + ckrn->writePixel(x, y, fcol); + } + } + + convolve(data, inputTile, ckrn); + delete ckrn; +} diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp deleted file mode 100644 index 362905761bb..00000000000 --- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp +++ /dev/null @@ -1,444 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GlareFogGlowOperation.h" -#include "MEM_guardedalloc.h" - -/* - * 2D Fast Hartley Transform, used for convolution - */ - -using fREAL = float; - -// returns next highest power of 2 of x, as well its log2 in L2 -static unsigned int nextPow2(unsigned int x, unsigned int *L2) -{ - unsigned int pw, x_notpow2 = x & (x - 1); - *L2 = 0; - while (x >>= 1) { - ++(*L2); - } - pw = 1 << (*L2); - if (x_notpow2) { - (*L2)++; - pw <<= 1; - } - return pw; -} - -//------------------------------------------------------------------------------ - -// from FXT library by Joerg Arndt, faster in order bitreversal -// use: r = revbin_upd(r, h) where h = N>>1 -static unsigned int revbin_upd(unsigned int r, unsigned int h) -{ - while (!((r ^= h) & h)) { - h >>= 1; - } - return r; -} -//------------------------------------------------------------------------------ -static void FHT(fREAL *data, unsigned int M, unsigned int inverse) -{ - double tt, fc, dc, fs, ds, a = M_PI; - fREAL t1, t2; - int n2, bd, bl, istep, k, len = 1 << M, n = 1; - - int i, j = 0; - unsigned int Nh = len >> 1; - for (i = 1; i < (len - 1); i++) { - j = revbin_upd(j, Nh); - if (j > i) { - t1 = data[i]; - data[i] = data[j]; - data[j] = t1; - } - } - - do { - fREAL *data_n = &data[n]; - - istep = n << 1; - for (k = 0; k < len; k += istep) { - t1 = data_n[k]; - data_n[k] = data[k] - t1; - data[k] += t1; - } - - n2 = n >> 1; - if (n > 2) { - fc = dc = cos(a); - fs = ds = sqrt(1.0 - fc * fc); // sin(a); - bd = n - 2; - for (bl = 1; bl < n2; bl++) { - fREAL *data_nbd = &data_n[bd]; - fREAL *data_bd = &data[bd]; - for (k = bl; k < len; k += istep) { - t1 = fc * (double)data_n[k] + fs * (double)data_nbd[k]; - t2 = fs * (double)data_n[k] - fc * (double)data_nbd[k]; - data_n[k] = data[k] - t1; - data_nbd[k] = data_bd[k] - t2; - data[k] += t1; - data_bd[k] += t2; - } - tt = fc * dc - fs * ds; - fs = fs * dc + fc * ds; - fc = tt; - bd -= 2; - } - } - - if (n > 1) { - for (k = n2; k < len; k += istep) { - t1 = data_n[k]; - data_n[k] = data[k] - t1; - data[k] += t1; - } - } - - n = istep; - a *= 0.5; - } while (n < len); - - if (inverse) { - fREAL sc = (fREAL)1 / (fREAL)len; - for (k = 0; k < len; k++) { - data[k] *= sc; - } - } -} -//------------------------------------------------------------------------------ -/* 2D Fast Hartley Transform, Mx/My -> log2 of width/height, - * nzp -> the row where zero pad data starts, - * inverse -> see above */ -static void FHT2D( - fREAL *data, unsigned int Mx, unsigned int My, unsigned int nzp, unsigned int inverse) -{ - unsigned int i, j, Nx, Ny, maxy; - - Nx = 1 << Mx; - Ny = 1 << My; - - // rows (forward transform skips 0 pad data) - maxy = inverse ? Ny : nzp; - for (j = 0; j < maxy; j++) { - FHT(&data[Nx * j], Mx, inverse); - } - - // transpose data - if (Nx == Ny) { // square - for (j = 0; j < Ny; j++) { - for (i = j + 1; i < Nx; i++) { - unsigned int op = i + (j << Mx), np = j + (i << My); - SWAP(fREAL, data[op], data[np]); - } - } - } - else { // rectangular - unsigned int k, Nym = Ny - 1, stm = 1 << (Mx + My); - for (i = 0; stm > 0; i++) { -#define PRED(k) (((k & Nym) << Mx) + (k >> My)) - for (j = PRED(i); j > i; j = PRED(j)) { - /* pass */ - } - if (j < i) { - continue; - } - for (k = i, j = PRED(i); j != i; k = j, j = PRED(j), stm--) { - SWAP(fREAL, data[j], data[k]); - } -#undef PRED - stm--; - } - } - - SWAP(unsigned int, Nx, Ny); - SWAP(unsigned int, Mx, My); - - // now columns == transposed rows - for (j = 0; j < Ny; j++) { - FHT(&data[Nx * j], Mx, inverse); - } - - // finalize - for (j = 0; j <= (Ny >> 1); j++) { - unsigned int jm = (Ny - j) & (Ny - 1); - unsigned int ji = j << Mx; - unsigned int jmi = jm << Mx; - for (i = 0; i <= (Nx >> 1); i++) { - unsigned int im = (Nx - i) & (Nx - 1); - fREAL A = data[ji + i]; - fREAL B = data[jmi + i]; - fREAL C = data[ji + im]; - fREAL D = data[jmi + im]; - fREAL E = (fREAL)0.5 * ((A + D) - (B + C)); - data[ji + i] = A - E; - data[jmi + i] = B + E; - data[ji + im] = C + E; - data[jmi + im] = D - E; - } - } -} - -//------------------------------------------------------------------------------ - -/* 2D convolution calc, d1 *= d2, M/N - > log2 of width/height */ -static void fht_convolve(fREAL *d1, const fREAL *d2, unsigned int M, unsigned int N) -{ - fREAL a, b; - unsigned int i, j, k, L, mj, mL; - unsigned int m = 1 << M, n = 1 << N; - unsigned int m2 = 1 << (M - 1), n2 = 1 << (N - 1); - unsigned int mn2 = m << (N - 1); - - d1[0] *= d2[0]; - d1[mn2] *= d2[mn2]; - d1[m2] *= d2[m2]; - d1[m2 + mn2] *= d2[m2 + mn2]; - for (i = 1; i < m2; i++) { - k = m - i; - a = d1[i] * d2[i] - d1[k] * d2[k]; - b = d1[k] * d2[i] + d1[i] * d2[k]; - d1[i] = (b + a) * (fREAL)0.5; - d1[k] = (b - a) * (fREAL)0.5; - a = d1[i + mn2] * d2[i + mn2] - d1[k + mn2] * d2[k + mn2]; - b = d1[k + mn2] * d2[i + mn2] + d1[i + mn2] * d2[k + mn2]; - d1[i + mn2] = (b + a) * (fREAL)0.5; - d1[k + mn2] = (b - a) * (fREAL)0.5; - } - for (j = 1; j < n2; j++) { - L = n - j; - mj = j << M; - mL = L << M; - a = d1[mj] * d2[mj] - d1[mL] * d2[mL]; - b = d1[mL] * d2[mj] + d1[mj] * d2[mL]; - d1[mj] = (b + a) * (fREAL)0.5; - d1[mL] = (b - a) * (fREAL)0.5; - a = d1[m2 + mj] * d2[m2 + mj] - d1[m2 + mL] * d2[m2 + mL]; - b = d1[m2 + mL] * d2[m2 + mj] + d1[m2 + mj] * d2[m2 + mL]; - d1[m2 + mj] = (b + a) * (fREAL)0.5; - d1[m2 + mL] = (b - a) * (fREAL)0.5; - } - for (i = 1; i < m2; i++) { - k = m - i; - for (j = 1; j < n2; j++) { - L = n - j; - mj = j << M; - mL = L << M; - a = d1[i + mj] * d2[i + mj] - d1[k + mL] * d2[k + mL]; - b = d1[k + mL] * d2[i + mj] + d1[i + mj] * d2[k + mL]; - d1[i + mj] = (b + a) * (fREAL)0.5; - d1[k + mL] = (b - a) * (fREAL)0.5; - a = d1[i + mL] * d2[i + mL] - d1[k + mj] * d2[k + mj]; - b = d1[k + mj] * d2[i + mL] + d1[i + mL] * d2[k + mj]; - d1[i + mL] = (b + a) * (fREAL)0.5; - d1[k + mj] = (b - a) * (fREAL)0.5; - } - } -} -//------------------------------------------------------------------------------ - -static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2) -{ - fREAL *data1, *data2, *fp; - unsigned int w2, h2, hw, hh, log2_w, log2_h; - fRGB wt, *colp; - int x, y, ch; - int xbl, ybl, nxb, nyb, xbsz, ybsz; - bool in2done = false; - const unsigned int kernelWidth = in2->getWidth(); - const unsigned int kernelHeight = in2->getHeight(); - const unsigned int imageWidth = in1->getWidth(); - const unsigned int imageHeight = in1->getHeight(); - float *kernelBuffer = in2->getBuffer(); - float *imageBuffer = in1->getBuffer(); - - MemoryBuffer *rdst = new MemoryBuffer(COM_DT_COLOR, in1->getRect()); - memset(rdst->getBuffer(), - 0, - rdst->getWidth() * rdst->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); - - // convolution result width & height - w2 = 2 * kernelWidth - 1; - h2 = 2 * kernelHeight - 1; - // FFT pow2 required size & log2 - w2 = nextPow2(w2, &log2_w); - h2 = nextPow2(h2, &log2_h); - - // alloc space - data1 = (fREAL *)MEM_callocN(3 * w2 * h2 * sizeof(fREAL), "convolve_fast FHT data1"); - data2 = (fREAL *)MEM_callocN(w2 * h2 * sizeof(fREAL), "convolve_fast FHT data2"); - - // normalize convolutor - wt[0] = wt[1] = wt[2] = 0.0f; - for (y = 0; y < kernelHeight; y++) { - colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR]; - for (x = 0; x < kernelWidth; x++) { - add_v3_v3(wt, colp[x]); - } - } - if (wt[0] != 0.0f) { - wt[0] = 1.0f / wt[0]; - } - if (wt[1] != 0.0f) { - wt[1] = 1.0f / wt[1]; - } - if (wt[2] != 0.0f) { - wt[2] = 1.0f / wt[2]; - } - for (y = 0; y < kernelHeight; y++) { - colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR]; - for (x = 0; x < kernelWidth; x++) { - mul_v3_v3(colp[x], wt); - } - } - - // copy image data, unpacking interleaved RGBA into separate channels - // only need to calc data1 once - - // block add-overlap - hw = kernelWidth >> 1; - hh = kernelHeight >> 1; - xbsz = (w2 + 1) - kernelWidth; - ybsz = (h2 + 1) - kernelHeight; - nxb = imageWidth / xbsz; - if (imageWidth % xbsz) { - nxb++; - } - nyb = imageHeight / ybsz; - if (imageHeight % ybsz) { - nyb++; - } - for (ybl = 0; ybl < nyb; ybl++) { - for (xbl = 0; xbl < nxb; xbl++) { - - // each channel one by one - for (ch = 0; ch < 3; ch++) { - fREAL *data1ch = &data1[ch * w2 * h2]; - - // only need to calc fht data from in2 once, can re-use for every block - if (!in2done) { - // in2, channel ch -> data1 - for (y = 0; y < kernelHeight; y++) { - fp = &data1ch[y * w2]; - colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR]; - for (x = 0; x < kernelWidth; x++) { - fp[x] = colp[x][ch]; - } - } - } - - // in1, channel ch -> data2 - memset(data2, 0, w2 * h2 * sizeof(fREAL)); - for (y = 0; y < ybsz; y++) { - int yy = ybl * ybsz + y; - if (yy >= imageHeight) { - continue; - } - fp = &data2[y * w2]; - colp = (fRGB *)&imageBuffer[yy * imageWidth * COM_NUM_CHANNELS_COLOR]; - for (x = 0; x < xbsz; x++) { - int xx = xbl * xbsz + x; - if (xx >= imageWidth) { - continue; - } - fp[x] = colp[xx][ch]; - } - } - - // forward FHT - // zero pad data start is different for each == height+1 - if (!in2done) { - FHT2D(data1ch, log2_w, log2_h, kernelHeight + 1, 0); - } - FHT2D(data2, log2_w, log2_h, kernelHeight + 1, 0); - - // FHT2D transposed data, row/col now swapped - // convolve & inverse FHT - fht_convolve(data2, data1ch, log2_h, log2_w); - FHT2D(data2, log2_h, log2_w, 0, 1); - // data again transposed, so in order again - - // overlap-add result - for (y = 0; y < (int)h2; y++) { - const int yy = ybl * ybsz + y - hh; - if ((yy < 0) || (yy >= imageHeight)) { - continue; - } - fp = &data2[y * w2]; - colp = (fRGB *)&rdst->getBuffer()[yy * imageWidth * COM_NUM_CHANNELS_COLOR]; - for (x = 0; x < (int)w2; x++) { - const int xx = xbl * xbsz + x - hw; - if ((xx < 0) || (xx >= imageWidth)) { - continue; - } - colp[xx][ch] += fp[x]; - } - } - } - in2done = true; - } - } - - MEM_freeN(data2); - MEM_freeN(data1); - memcpy( - dst, rdst->getBuffer(), sizeof(float) * imageWidth * imageHeight * COM_NUM_CHANNELS_COLOR); - delete (rdst); -} - -void GlareFogGlowOperation::generateGlare(float *data, - MemoryBuffer *inputTile, - NodeGlare *settings) -{ - int x, y; - float scale, u, v, r, w, d; - fRGB fcol; - MemoryBuffer *ckrn; - unsigned int sz = 1 << settings->size; - const float cs_r = 1.0f, cs_g = 1.0f, cs_b = 1.0f; - - // temp. src image - // make the convolution kernel - rcti kernelRect; - BLI_rcti_init(&kernelRect, 0, sz, 0, sz); - ckrn = new MemoryBuffer(COM_DT_COLOR, &kernelRect); - - scale = 0.25f * sqrtf((float)(sz * sz)); - - for (y = 0; y < sz; y++) { - v = 2.0f * (y / (float)sz) - 1.0f; - for (x = 0; x < sz; x++) { - u = 2.0f * (x / (float)sz) - 1.0f; - r = (u * u + v * v) * scale; - d = -sqrtf(sqrtf(sqrtf(r))) * 9.0f; - fcol[0] = expf(d * cs_r); - fcol[1] = expf(d * cs_g); - fcol[2] = expf(d * cs_b); - // linear window good enough here, visual result counts, not scientific analysis - // w = (1.0f-fabs(u))*(1.0f-fabs(v)); - // actually, Hanning window is ok, cos^2 for some reason is slower - w = (0.5f + 0.5f * cosf(u * (float)M_PI)) * (0.5f + 0.5f * cosf(v * (float)M_PI)); - mul_v3_fl(fcol, w); - ckrn->writePixel(x, y, fcol); - } - } - - convolve(data, inputTile, ckrn); - delete ckrn; -} diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cc b/source/blender/compositor/operations/COM_GlareGhostOperation.cc new file mode 100644 index 00000000000..760b833d1e1 --- /dev/null +++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cc @@ -0,0 +1,159 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GlareGhostOperation.h" +#include "BLI_math.h" +#include "COM_FastGaussianBlurOperation.h" + +static float smoothMask(float x, float y) +{ + float t; + x = 2.0f * x - 1.0f; + y = 2.0f * y - 1.0f; + if ((t = 1.0f - sqrtf(x * x + y * y)) > 0.0f) { + return t; + } + + return 0.0f; +} + +void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) +{ + const int qt = 1 << settings->quality; + const float s1 = 4.0f / (float)qt, s2 = 2.0f * s1; + int x, y, n, p, np; + fRGB c, tc, cm[64]; + float sc, isc, u, v, sm, s, t, ofs, scalef[64]; + const float cmo = 1.0f - settings->colmod; + + MemoryBuffer *gbuf = inputTile->duplicate(); + MemoryBuffer *tbuf1 = inputTile->duplicate(); + + bool breaked = false; + + FastGaussianBlurOperation::IIR_gauss(tbuf1, s1, 0, 3); + if (!breaked) { + FastGaussianBlurOperation::IIR_gauss(tbuf1, s1, 1, 3); + } + if (isBraked()) { + breaked = true; + } + if (!breaked) { + FastGaussianBlurOperation::IIR_gauss(tbuf1, s1, 2, 3); + } + + MemoryBuffer *tbuf2 = tbuf1->duplicate(); + + if (isBraked()) { + breaked = true; + } + if (!breaked) { + FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 0, 3); + } + if (isBraked()) { + breaked = true; + } + if (!breaked) { + FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 1, 3); + } + if (isBraked()) { + breaked = true; + } + if (!breaked) { + FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 2, 3); + } + + ofs = (settings->iter & 1) ? 0.5f : 0.0f; + for (x = 0; x < (settings->iter * 4); x++) { + y = x & 3; + cm[x][0] = cm[x][1] = cm[x][2] = 1; + if (y == 1) { + fRGB_rgbmult(cm[x], 1.0f, cmo, cmo); + } + if (y == 2) { + fRGB_rgbmult(cm[x], cmo, cmo, 1.0f); + } + if (y == 3) { + fRGB_rgbmult(cm[x], cmo, 1.0f, cmo); + } + scalef[x] = 2.1f * (1.0f - (x + ofs) / (float)(settings->iter * 4)); + if (x & 1) { + scalef[x] = -0.99f / scalef[x]; + } + } + + sc = 2.13; + isc = -0.97; + for (y = 0; y < gbuf->getHeight() && (!breaked); y++) { + v = ((float)y + 0.5f) / (float)gbuf->getHeight(); + for (x = 0; x < gbuf->getWidth(); x++) { + u = ((float)x + 0.5f) / (float)gbuf->getWidth(); + s = (u - 0.5f) * sc + 0.5f; + t = (v - 0.5f) * sc + 0.5f; + tbuf1->readBilinear(c, s * gbuf->getWidth(), t * gbuf->getHeight()); + sm = smoothMask(s, t); + mul_v3_fl(c, sm); + s = (u - 0.5f) * isc + 0.5f; + t = (v - 0.5f) * isc + 0.5f; + tbuf2->readBilinear(tc, s * gbuf->getWidth() - 0.5f, t * gbuf->getHeight() - 0.5f); + sm = smoothMask(s, t); + madd_v3_v3fl(c, tc, sm); + + gbuf->writePixel(x, y, c); + } + if (isBraked()) { + breaked = true; + } + } + + memset(tbuf1->getBuffer(), + 0, + tbuf1->getWidth() * tbuf1->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); + for (n = 1; n < settings->iter && (!breaked); n++) { + for (y = 0; y < gbuf->getHeight() && (!breaked); y++) { + v = ((float)y + 0.5f) / (float)gbuf->getHeight(); + for (x = 0; x < gbuf->getWidth(); x++) { + u = ((float)x + 0.5f) / (float)gbuf->getWidth(); + tc[0] = tc[1] = tc[2] = 0.0f; + for (p = 0; p < 4; p++) { + np = (n << 2) + p; + s = (u - 0.5f) * scalef[np] + 0.5f; + t = (v - 0.5f) * scalef[np] + 0.5f; + gbuf->readBilinear(c, s * gbuf->getWidth() - 0.5f, t * gbuf->getHeight() - 0.5f); + mul_v3_v3(c, cm[np]); + sm = smoothMask(s, t) * 0.25f; + madd_v3_v3fl(tc, c, sm); + } + tbuf1->addPixel(x, y, tc); + } + if (isBraked()) { + breaked = true; + } + } + memcpy(gbuf->getBuffer(), + tbuf1->getBuffer(), + tbuf1->getWidth() * tbuf1->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); + } + memcpy(data, + gbuf->getBuffer(), + gbuf->getWidth() * gbuf->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); + + delete gbuf; + delete tbuf1; + delete tbuf2; +} diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp deleted file mode 100644 index 760b833d1e1..00000000000 --- a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GlareGhostOperation.h" -#include "BLI_math.h" -#include "COM_FastGaussianBlurOperation.h" - -static float smoothMask(float x, float y) -{ - float t; - x = 2.0f * x - 1.0f; - y = 2.0f * y - 1.0f; - if ((t = 1.0f - sqrtf(x * x + y * y)) > 0.0f) { - return t; - } - - return 0.0f; -} - -void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) -{ - const int qt = 1 << settings->quality; - const float s1 = 4.0f / (float)qt, s2 = 2.0f * s1; - int x, y, n, p, np; - fRGB c, tc, cm[64]; - float sc, isc, u, v, sm, s, t, ofs, scalef[64]; - const float cmo = 1.0f - settings->colmod; - - MemoryBuffer *gbuf = inputTile->duplicate(); - MemoryBuffer *tbuf1 = inputTile->duplicate(); - - bool breaked = false; - - FastGaussianBlurOperation::IIR_gauss(tbuf1, s1, 0, 3); - if (!breaked) { - FastGaussianBlurOperation::IIR_gauss(tbuf1, s1, 1, 3); - } - if (isBraked()) { - breaked = true; - } - if (!breaked) { - FastGaussianBlurOperation::IIR_gauss(tbuf1, s1, 2, 3); - } - - MemoryBuffer *tbuf2 = tbuf1->duplicate(); - - if (isBraked()) { - breaked = true; - } - if (!breaked) { - FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 0, 3); - } - if (isBraked()) { - breaked = true; - } - if (!breaked) { - FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 1, 3); - } - if (isBraked()) { - breaked = true; - } - if (!breaked) { - FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 2, 3); - } - - ofs = (settings->iter & 1) ? 0.5f : 0.0f; - for (x = 0; x < (settings->iter * 4); x++) { - y = x & 3; - cm[x][0] = cm[x][1] = cm[x][2] = 1; - if (y == 1) { - fRGB_rgbmult(cm[x], 1.0f, cmo, cmo); - } - if (y == 2) { - fRGB_rgbmult(cm[x], cmo, cmo, 1.0f); - } - if (y == 3) { - fRGB_rgbmult(cm[x], cmo, 1.0f, cmo); - } - scalef[x] = 2.1f * (1.0f - (x + ofs) / (float)(settings->iter * 4)); - if (x & 1) { - scalef[x] = -0.99f / scalef[x]; - } - } - - sc = 2.13; - isc = -0.97; - for (y = 0; y < gbuf->getHeight() && (!breaked); y++) { - v = ((float)y + 0.5f) / (float)gbuf->getHeight(); - for (x = 0; x < gbuf->getWidth(); x++) { - u = ((float)x + 0.5f) / (float)gbuf->getWidth(); - s = (u - 0.5f) * sc + 0.5f; - t = (v - 0.5f) * sc + 0.5f; - tbuf1->readBilinear(c, s * gbuf->getWidth(), t * gbuf->getHeight()); - sm = smoothMask(s, t); - mul_v3_fl(c, sm); - s = (u - 0.5f) * isc + 0.5f; - t = (v - 0.5f) * isc + 0.5f; - tbuf2->readBilinear(tc, s * gbuf->getWidth() - 0.5f, t * gbuf->getHeight() - 0.5f); - sm = smoothMask(s, t); - madd_v3_v3fl(c, tc, sm); - - gbuf->writePixel(x, y, c); - } - if (isBraked()) { - breaked = true; - } - } - - memset(tbuf1->getBuffer(), - 0, - tbuf1->getWidth() * tbuf1->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); - for (n = 1; n < settings->iter && (!breaked); n++) { - for (y = 0; y < gbuf->getHeight() && (!breaked); y++) { - v = ((float)y + 0.5f) / (float)gbuf->getHeight(); - for (x = 0; x < gbuf->getWidth(); x++) { - u = ((float)x + 0.5f) / (float)gbuf->getWidth(); - tc[0] = tc[1] = tc[2] = 0.0f; - for (p = 0; p < 4; p++) { - np = (n << 2) + p; - s = (u - 0.5f) * scalef[np] + 0.5f; - t = (v - 0.5f) * scalef[np] + 0.5f; - gbuf->readBilinear(c, s * gbuf->getWidth() - 0.5f, t * gbuf->getHeight() - 0.5f); - mul_v3_v3(c, cm[np]); - sm = smoothMask(s, t) * 0.25f; - madd_v3_v3fl(tc, c, sm); - } - tbuf1->addPixel(x, y, tc); - } - if (isBraked()) { - breaked = true; - } - } - memcpy(gbuf->getBuffer(), - tbuf1->getBuffer(), - tbuf1->getWidth() * tbuf1->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); - } - memcpy(data, - gbuf->getBuffer(), - gbuf->getWidth() * gbuf->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); - - delete gbuf; - delete tbuf1; - delete tbuf2; -} diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc new file mode 100644 index 00000000000..75c2ae51bde --- /dev/null +++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc @@ -0,0 +1,102 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GlareSimpleStarOperation.h" + +void GlareSimpleStarOperation::generateGlare(float *data, + MemoryBuffer *inputTile, + NodeGlare *settings) +{ + int i, x, y, ym, yp, xm, xp; + float c[4] = {0, 0, 0, 0}, tc[4] = {0, 0, 0, 0}; + const float f1 = 1.0f - settings->fade; + const float f2 = (1.0f - f1) * 0.5f; + + MemoryBuffer *tbuf1 = inputTile->duplicate(); + MemoryBuffer *tbuf2 = inputTile->duplicate(); + + bool breaked = false; + for (i = 0; i < settings->iter && (!breaked); i++) { + // // (x || x-1, y-1) to (x || x+1, y+1) + // // F + for (y = 0; y < this->getHeight() && (!breaked); y++) { + ym = y - i; + yp = y + i; + for (x = 0; x < this->getWidth(); x++) { + xm = x - i; + xp = x + i; + tbuf1->read(c, x, y); + mul_v3_fl(c, f1); + tbuf1->read(tc, (settings->star_45 ? xm : x), ym); + madd_v3_v3fl(c, tc, f2); + tbuf1->read(tc, (settings->star_45 ? xp : x), yp); + madd_v3_v3fl(c, tc, f2); + c[3] = 1.0f; + tbuf1->writePixel(x, y, c); + + tbuf2->read(c, x, y); + mul_v3_fl(c, f1); + tbuf2->read(tc, xm, (settings->star_45 ? yp : y)); + madd_v3_v3fl(c, tc, f2); + tbuf2->read(tc, xp, (settings->star_45 ? ym : y)); + madd_v3_v3fl(c, tc, f2); + c[3] = 1.0f; + tbuf2->writePixel(x, y, c); + } + if (isBraked()) { + breaked = true; + } + } + // // B + for (y = this->getHeight() - 1; y >= 0 && (!breaked); y--) { + ym = y - i; + yp = y + i; + for (x = this->getWidth() - 1; x >= 0; x--) { + xm = x - i; + xp = x + i; + tbuf1->read(c, x, y); + mul_v3_fl(c, f1); + tbuf1->read(tc, (settings->star_45 ? xm : x), ym); + madd_v3_v3fl(c, tc, f2); + tbuf1->read(tc, (settings->star_45 ? xp : x), yp); + madd_v3_v3fl(c, tc, f2); + c[3] = 1.0f; + tbuf1->writePixel(x, y, c); + + tbuf2->read(c, x, y); + mul_v3_fl(c, f1); + tbuf2->read(tc, xm, (settings->star_45 ? yp : y)); + madd_v3_v3fl(c, tc, f2); + tbuf2->read(tc, xp, (settings->star_45 ? ym : y)); + madd_v3_v3fl(c, tc, f2); + c[3] = 1.0f; + tbuf2->writePixel(x, y, c); + } + if (isBraked()) { + breaked = true; + } + } + } + + for (i = 0; i < this->getWidth() * this->getHeight() * 4; i++) { + data[i] = tbuf1->getBuffer()[i] + tbuf2->getBuffer()[i]; + } + + delete tbuf1; + delete tbuf2; +} diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp deleted file mode 100644 index 75c2ae51bde..00000000000 --- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GlareSimpleStarOperation.h" - -void GlareSimpleStarOperation::generateGlare(float *data, - MemoryBuffer *inputTile, - NodeGlare *settings) -{ - int i, x, y, ym, yp, xm, xp; - float c[4] = {0, 0, 0, 0}, tc[4] = {0, 0, 0, 0}; - const float f1 = 1.0f - settings->fade; - const float f2 = (1.0f - f1) * 0.5f; - - MemoryBuffer *tbuf1 = inputTile->duplicate(); - MemoryBuffer *tbuf2 = inputTile->duplicate(); - - bool breaked = false; - for (i = 0; i < settings->iter && (!breaked); i++) { - // // (x || x-1, y-1) to (x || x+1, y+1) - // // F - for (y = 0; y < this->getHeight() && (!breaked); y++) { - ym = y - i; - yp = y + i; - for (x = 0; x < this->getWidth(); x++) { - xm = x - i; - xp = x + i; - tbuf1->read(c, x, y); - mul_v3_fl(c, f1); - tbuf1->read(tc, (settings->star_45 ? xm : x), ym); - madd_v3_v3fl(c, tc, f2); - tbuf1->read(tc, (settings->star_45 ? xp : x), yp); - madd_v3_v3fl(c, tc, f2); - c[3] = 1.0f; - tbuf1->writePixel(x, y, c); - - tbuf2->read(c, x, y); - mul_v3_fl(c, f1); - tbuf2->read(tc, xm, (settings->star_45 ? yp : y)); - madd_v3_v3fl(c, tc, f2); - tbuf2->read(tc, xp, (settings->star_45 ? ym : y)); - madd_v3_v3fl(c, tc, f2); - c[3] = 1.0f; - tbuf2->writePixel(x, y, c); - } - if (isBraked()) { - breaked = true; - } - } - // // B - for (y = this->getHeight() - 1; y >= 0 && (!breaked); y--) { - ym = y - i; - yp = y + i; - for (x = this->getWidth() - 1; x >= 0; x--) { - xm = x - i; - xp = x + i; - tbuf1->read(c, x, y); - mul_v3_fl(c, f1); - tbuf1->read(tc, (settings->star_45 ? xm : x), ym); - madd_v3_v3fl(c, tc, f2); - tbuf1->read(tc, (settings->star_45 ? xp : x), yp); - madd_v3_v3fl(c, tc, f2); - c[3] = 1.0f; - tbuf1->writePixel(x, y, c); - - tbuf2->read(c, x, y); - mul_v3_fl(c, f1); - tbuf2->read(tc, xm, (settings->star_45 ? yp : y)); - madd_v3_v3fl(c, tc, f2); - tbuf2->read(tc, xp, (settings->star_45 ? ym : y)); - madd_v3_v3fl(c, tc, f2); - c[3] = 1.0f; - tbuf2->writePixel(x, y, c); - } - if (isBraked()) { - breaked = true; - } - } - } - - for (i = 0; i < this->getWidth() * this->getHeight() * 4; i++) { - data[i] = tbuf1->getBuffer()[i] + tbuf2->getBuffer()[i]; - } - - delete tbuf1; - delete tbuf2; -} diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cc b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc new file mode 100644 index 00000000000..4fccb62e3df --- /dev/null +++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc @@ -0,0 +1,102 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GlareStreaksOperation.h" +#include "BLI_math.h" + +void GlareStreaksOperation::generateGlare(float *data, + MemoryBuffer *inputTile, + NodeGlare *settings) +{ + int x, y, n; + unsigned int nump = 0; + float c1[4], c2[4], c3[4], c4[4]; + float a, ang = DEG2RADF(360.0f) / (float)settings->streaks; + + int size = inputTile->getWidth() * inputTile->getHeight(); + int size4 = size * 4; + + bool breaked = false; + + MemoryBuffer *tsrc = inputTile->duplicate(); + MemoryBuffer *tdst = new MemoryBuffer(COM_DT_COLOR, inputTile->getRect()); + tdst->clear(); + memset(data, 0, size4 * sizeof(float)); + + for (a = 0.0f; a < DEG2RADF(360.0f) && (!breaked); a += ang) { + const float an = a + settings->angle_ofs; + const float vx = cos((double)an), vy = sin((double)an); + for (n = 0; n < settings->iter && (!breaked); n++) { + const float p4 = pow(4.0, (double)n); + const float vxp = vx * p4, vyp = vy * p4; + const float wt = pow((double)settings->fade, (double)p4); + const float cmo = 1.0f - + (float)pow((double)settings->colmod, + (double)n + + 1); // colormodulation amount relative to current pass + float *tdstcol = tdst->getBuffer(); + for (y = 0; y < tsrc->getHeight() && (!breaked); y++) { + for (x = 0; x < tsrc->getWidth(); x++, tdstcol += 4) { + // first pass no offset, always same for every pass, exact copy, + // otherwise results in uneven brightness, only need once + if (n == 0) { + tsrc->read(c1, x, y); + } + else { + c1[0] = c1[1] = c1[2] = 0; + } + tsrc->readBilinear(c2, x + vxp, y + vyp); + tsrc->readBilinear(c3, x + vxp * 2.0f, y + vyp * 2.0f); + tsrc->readBilinear(c4, x + vxp * 3.0f, y + vyp * 3.0f); + // modulate color to look vaguely similar to a color spectrum + c2[1] *= cmo; + c2[2] *= cmo; + + c3[0] *= cmo; + c3[1] *= cmo; + + c4[0] *= cmo; + c4[2] *= cmo; + + tdstcol[0] = 0.5f * (tdstcol[0] + c1[0] + wt * (c2[0] + wt * (c3[0] + wt * c4[0]))); + tdstcol[1] = 0.5f * (tdstcol[1] + c1[1] + wt * (c2[1] + wt * (c3[1] + wt * c4[1]))); + tdstcol[2] = 0.5f * (tdstcol[2] + c1[2] + wt * (c2[2] + wt * (c3[2] + wt * c4[2]))); + tdstcol[3] = 1.0f; + } + if (isBraked()) { + breaked = true; + } + } + memcpy(tsrc->getBuffer(), tdst->getBuffer(), sizeof(float) * size4); + } + + float *sourcebuffer = tsrc->getBuffer(); + float factor = 1.0f / (float)(6 - settings->iter); + for (int i = 0; i < size4; i += 4) { + madd_v3_v3fl(&data[i], &sourcebuffer[i], factor); + data[i + 3] = 1.0f; + } + + tdst->clear(); + memcpy(tsrc->getBuffer(), inputTile->getBuffer(), sizeof(float) * size4); + nump++; + } + + delete tsrc; + delete tdst; +} diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp deleted file mode 100644 index 4fccb62e3df..00000000000 --- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GlareStreaksOperation.h" -#include "BLI_math.h" - -void GlareStreaksOperation::generateGlare(float *data, - MemoryBuffer *inputTile, - NodeGlare *settings) -{ - int x, y, n; - unsigned int nump = 0; - float c1[4], c2[4], c3[4], c4[4]; - float a, ang = DEG2RADF(360.0f) / (float)settings->streaks; - - int size = inputTile->getWidth() * inputTile->getHeight(); - int size4 = size * 4; - - bool breaked = false; - - MemoryBuffer *tsrc = inputTile->duplicate(); - MemoryBuffer *tdst = new MemoryBuffer(COM_DT_COLOR, inputTile->getRect()); - tdst->clear(); - memset(data, 0, size4 * sizeof(float)); - - for (a = 0.0f; a < DEG2RADF(360.0f) && (!breaked); a += ang) { - const float an = a + settings->angle_ofs; - const float vx = cos((double)an), vy = sin((double)an); - for (n = 0; n < settings->iter && (!breaked); n++) { - const float p4 = pow(4.0, (double)n); - const float vxp = vx * p4, vyp = vy * p4; - const float wt = pow((double)settings->fade, (double)p4); - const float cmo = 1.0f - - (float)pow((double)settings->colmod, - (double)n + - 1); // colormodulation amount relative to current pass - float *tdstcol = tdst->getBuffer(); - for (y = 0; y < tsrc->getHeight() && (!breaked); y++) { - for (x = 0; x < tsrc->getWidth(); x++, tdstcol += 4) { - // first pass no offset, always same for every pass, exact copy, - // otherwise results in uneven brightness, only need once - if (n == 0) { - tsrc->read(c1, x, y); - } - else { - c1[0] = c1[1] = c1[2] = 0; - } - tsrc->readBilinear(c2, x + vxp, y + vyp); - tsrc->readBilinear(c3, x + vxp * 2.0f, y + vyp * 2.0f); - tsrc->readBilinear(c4, x + vxp * 3.0f, y + vyp * 3.0f); - // modulate color to look vaguely similar to a color spectrum - c2[1] *= cmo; - c2[2] *= cmo; - - c3[0] *= cmo; - c3[1] *= cmo; - - c4[0] *= cmo; - c4[2] *= cmo; - - tdstcol[0] = 0.5f * (tdstcol[0] + c1[0] + wt * (c2[0] + wt * (c3[0] + wt * c4[0]))); - tdstcol[1] = 0.5f * (tdstcol[1] + c1[1] + wt * (c2[1] + wt * (c3[1] + wt * c4[1]))); - tdstcol[2] = 0.5f * (tdstcol[2] + c1[2] + wt * (c2[2] + wt * (c3[2] + wt * c4[2]))); - tdstcol[3] = 1.0f; - } - if (isBraked()) { - breaked = true; - } - } - memcpy(tsrc->getBuffer(), tdst->getBuffer(), sizeof(float) * size4); - } - - float *sourcebuffer = tsrc->getBuffer(); - float factor = 1.0f / (float)(6 - settings->iter); - for (int i = 0; i < size4; i += 4) { - madd_v3_v3fl(&data[i], &sourcebuffer[i], factor); - data[i + 3] = 1.0f; - } - - tdst->clear(); - memcpy(tsrc->getBuffer(), inputTile->getBuffer(), sizeof(float) * size4); - nump++; - } - - delete tsrc; - delete tdst; -} diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cc b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc new file mode 100644 index 00000000000..cfa4b99cd70 --- /dev/null +++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc @@ -0,0 +1,69 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_GlareThresholdOperation.h" +#include "BLI_math.h" + +#include "IMB_colormanagement.h" + +GlareThresholdOperation::GlareThresholdOperation() +{ + this->addInputSocket(COM_DT_COLOR, COM_SC_FIT); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputProgram = nullptr; +} + +void GlareThresholdOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + NodeOperation::determineResolution(resolution, preferredResolution); + resolution[0] = resolution[0] / (1 << this->m_settings->quality); + resolution[1] = resolution[1] / (1 << this->m_settings->quality); +} + +void GlareThresholdOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); +} + +void GlareThresholdOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + const float threshold = this->m_settings->threshold; + + this->m_inputProgram->readSampled(output, x, y, sampler); + if (IMB_colormanagement_get_luminance(output) >= threshold) { + output[0] -= threshold; + output[1] -= threshold; + output[2] -= threshold; + + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); + } + else { + zero_v3(output); + } +} + +void GlareThresholdOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; +} diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp deleted file mode 100644 index cfa4b99cd70..00000000000 --- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_GlareThresholdOperation.h" -#include "BLI_math.h" - -#include "IMB_colormanagement.h" - -GlareThresholdOperation::GlareThresholdOperation() -{ - this->addInputSocket(COM_DT_COLOR, COM_SC_FIT); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputProgram = nullptr; -} - -void GlareThresholdOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - NodeOperation::determineResolution(resolution, preferredResolution); - resolution[0] = resolution[0] / (1 << this->m_settings->quality); - resolution[1] = resolution[1] / (1 << this->m_settings->quality); -} - -void GlareThresholdOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); -} - -void GlareThresholdOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - const float threshold = this->m_settings->threshold; - - this->m_inputProgram->readSampled(output, x, y, sampler); - if (IMB_colormanagement_get_luminance(output) >= threshold) { - output[0] -= threshold; - output[1] -= threshold; - output[2] -= threshold; - - output[0] = MAX2(output[0], 0.0f); - output[1] = MAX2(output[1], 0.0f); - output[2] = MAX2(output[2], 0.0f); - } - else { - zero_v3(output); - } -} - -void GlareThresholdOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; -} diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc new file mode 100644 index 00000000000..df30e75cf27 --- /dev/null +++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc @@ -0,0 +1,72 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_HueSaturationValueCorrectOperation.h" + +#include "BLI_math.h" + +#include "BKE_colortools.h" + +HueSaturationValueCorrectOperation::HueSaturationValueCorrectOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + + this->m_inputProgram = nullptr; +} +void HueSaturationValueCorrectOperation::initExecution() +{ + CurveBaseOperation::initExecution(); + this->m_inputProgram = this->getInputSocketReader(0); +} + +void HueSaturationValueCorrectOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float hsv[4], f; + + this->m_inputProgram->readSampled(hsv, x, y, sampler); + + /* adjust hue, scaling returned default 0.5 up to 1 */ + f = BKE_curvemapping_evaluateF(this->m_curveMapping, 0, hsv[0]); + hsv[0] += f - 0.5f; + + /* adjust saturation, scaling returned default 0.5 up to 1 */ + f = BKE_curvemapping_evaluateF(this->m_curveMapping, 1, hsv[0]); + hsv[1] *= (f * 2.0f); + + /* adjust value, scaling returned default 0.5 up to 1 */ + f = BKE_curvemapping_evaluateF(this->m_curveMapping, 2, hsv[0]); + hsv[2] *= (f * 2.0f); + + hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */ + CLAMP(hsv[1], 0.0f, 1.0f); + + output[0] = hsv[0]; + output[1] = hsv[1]; + output[2] = hsv[2]; + output[3] = hsv[3]; +} + +void HueSaturationValueCorrectOperation::deinitExecution() +{ + CurveBaseOperation::deinitExecution(); + this->m_inputProgram = nullptr; +} diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp deleted file mode 100644 index df30e75cf27..00000000000 --- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_HueSaturationValueCorrectOperation.h" - -#include "BLI_math.h" - -#include "BKE_colortools.h" - -HueSaturationValueCorrectOperation::HueSaturationValueCorrectOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - - this->m_inputProgram = nullptr; -} -void HueSaturationValueCorrectOperation::initExecution() -{ - CurveBaseOperation::initExecution(); - this->m_inputProgram = this->getInputSocketReader(0); -} - -void HueSaturationValueCorrectOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float hsv[4], f; - - this->m_inputProgram->readSampled(hsv, x, y, sampler); - - /* adjust hue, scaling returned default 0.5 up to 1 */ - f = BKE_curvemapping_evaluateF(this->m_curveMapping, 0, hsv[0]); - hsv[0] += f - 0.5f; - - /* adjust saturation, scaling returned default 0.5 up to 1 */ - f = BKE_curvemapping_evaluateF(this->m_curveMapping, 1, hsv[0]); - hsv[1] *= (f * 2.0f); - - /* adjust value, scaling returned default 0.5 up to 1 */ - f = BKE_curvemapping_evaluateF(this->m_curveMapping, 2, hsv[0]); - hsv[2] *= (f * 2.0f); - - hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */ - CLAMP(hsv[1], 0.0f, 1.0f); - - output[0] = hsv[0]; - output[1] = hsv[1]; - output[2] = hsv[2]; - output[3] = hsv[3]; -} - -void HueSaturationValueCorrectOperation::deinitExecution() -{ - CurveBaseOperation::deinitExecution(); - this->m_inputProgram = nullptr; -} diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.cc b/source/blender/compositor/operations/COM_IDMaskOperation.cc new file mode 100644 index 00000000000..8113adb9bbc --- /dev/null +++ b/source/blender/compositor/operations/COM_IDMaskOperation.cc @@ -0,0 +1,41 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_IDMaskOperation.h" + +IDMaskOperation::IDMaskOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->setComplex(true); +} + +void *IDMaskOperation::initializeTileData(rcti *rect) +{ + void *buffer = getInputOperation(0)->initializeTileData(rect); + return buffer; +} + +void IDMaskOperation::executePixel(float output[4], int x, int y, void *data) +{ + MemoryBuffer *input_buffer = (MemoryBuffer *)data; + const int buffer_width = input_buffer->getWidth(); + float *buffer = input_buffer->getBuffer(); + int buffer_index = (y * buffer_width + x); + output[0] = (roundf(buffer[buffer_index]) == this->m_objectIndex) ? 1.0f : 0.0f; +} diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.cpp b/source/blender/compositor/operations/COM_IDMaskOperation.cpp deleted file mode 100644 index 8113adb9bbc..00000000000 --- a/source/blender/compositor/operations/COM_IDMaskOperation.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_IDMaskOperation.h" - -IDMaskOperation::IDMaskOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->setComplex(true); -} - -void *IDMaskOperation::initializeTileData(rcti *rect) -{ - void *buffer = getInputOperation(0)->initializeTileData(rect); - return buffer; -} - -void IDMaskOperation::executePixel(float output[4], int x, int y, void *data) -{ - MemoryBuffer *input_buffer = (MemoryBuffer *)data; - const int buffer_width = input_buffer->getWidth(); - float *buffer = input_buffer->getBuffer(); - int buffer_index = (y * buffer_width + x); - output[0] = (roundf(buffer[buffer_index]) == this->m_objectIndex) ? 1.0f : 0.0f; -} diff --git a/source/blender/compositor/operations/COM_ImageOperation.cc b/source/blender/compositor/operations/COM_ImageOperation.cc new file mode 100644 index 00000000000..ae5b7293a8c --- /dev/null +++ b/source/blender/compositor/operations/COM_ImageOperation.cc @@ -0,0 +1,205 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ImageOperation.h" + +#include "BKE_image.h" +#include "BKE_scene.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "DNA_image_types.h" + +#include "IMB_colormanagement.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "RE_pipeline.h" +#include "RE_texture.h" + +BaseImageOperation::BaseImageOperation() +{ + this->m_image = nullptr; + this->m_buffer = nullptr; + this->m_imageFloatBuffer = nullptr; + this->m_imageByteBuffer = nullptr; + this->m_imageUser = nullptr; + this->m_imagewidth = 0; + this->m_imageheight = 0; + this->m_framenumber = 0; + this->m_depthBuffer = nullptr; + this->m_numberOfChannels = 0; + this->m_rd = nullptr; + this->m_viewName = nullptr; +} +ImageOperation::ImageOperation() : BaseImageOperation() +{ + this->addOutputSocket(COM_DT_COLOR); +} +ImageAlphaOperation::ImageAlphaOperation() : BaseImageOperation() +{ + this->addOutputSocket(COM_DT_VALUE); +} +ImageDepthOperation::ImageDepthOperation() : BaseImageOperation() +{ + this->addOutputSocket(COM_DT_VALUE); +} + +ImBuf *BaseImageOperation::getImBuf() +{ + ImBuf *ibuf; + ImageUser iuser = *this->m_imageUser; + + if (this->m_image == nullptr) { + return nullptr; + } + + /* local changes to the original ImageUser */ + if (BKE_image_is_multilayer(this->m_image) == false) { + iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName); + } + + ibuf = BKE_image_acquire_ibuf(this->m_image, &iuser, nullptr); + if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) { + BKE_image_release_ibuf(this->m_image, ibuf, nullptr); + return nullptr; + } + return ibuf; +} + +void BaseImageOperation::initExecution() +{ + ImBuf *stackbuf = getImBuf(); + this->m_buffer = stackbuf; + if (stackbuf) { + this->m_imageFloatBuffer = stackbuf->rect_float; + this->m_imageByteBuffer = stackbuf->rect; + this->m_depthBuffer = stackbuf->zbuf_float; + this->m_imagewidth = stackbuf->x; + this->m_imageheight = stackbuf->y; + this->m_numberOfChannels = stackbuf->channels; + } +} + +void BaseImageOperation::deinitExecution() +{ + this->m_imageFloatBuffer = nullptr; + this->m_imageByteBuffer = nullptr; + BKE_image_release_ibuf(this->m_image, this->m_buffer, nullptr); +} + +void BaseImageOperation::determineResolution(unsigned int resolution[2], + unsigned int /*preferredResolution*/[2]) +{ + ImBuf *stackbuf = getImBuf(); + + resolution[0] = 0; + resolution[1] = 0; + + if (stackbuf) { + resolution[0] = stackbuf->x; + resolution[1] = stackbuf->y; + } + + BKE_image_release_ibuf(this->m_image, stackbuf, nullptr); +} + +static void sampleImageAtLocation( + ImBuf *ibuf, float x, float y, PixelSampler sampler, bool make_linear_rgb, float color[4]) +{ + if (ibuf->rect_float) { + switch (sampler) { + case COM_PS_NEAREST: + nearest_interpolation_color(ibuf, nullptr, color, x, y); + break; + case COM_PS_BILINEAR: + bilinear_interpolation_color(ibuf, nullptr, color, x, y); + break; + case COM_PS_BICUBIC: + bicubic_interpolation_color(ibuf, nullptr, color, x, y); + break; + } + } + else { + unsigned char byte_color[4]; + switch (sampler) { + case COM_PS_NEAREST: + nearest_interpolation_color(ibuf, byte_color, nullptr, x, y); + break; + case COM_PS_BILINEAR: + bilinear_interpolation_color(ibuf, byte_color, nullptr, x, y); + break; + case COM_PS_BICUBIC: + bicubic_interpolation_color(ibuf, byte_color, nullptr, x, y); + break; + } + rgba_uchar_to_float(color, byte_color); + if (make_linear_rgb) { + IMB_colormanagement_colorspace_to_scene_linear_v4(color, false, ibuf->rect_colorspace); + } + } +} + +void ImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + int ix = x, iy = y; + if (this->m_imageFloatBuffer == nullptr && this->m_imageByteBuffer == nullptr) { + zero_v4(output); + } + else if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) { + zero_v4(output); + } + else { + sampleImageAtLocation(this->m_buffer, x, y, sampler, true, output); + } +} + +void ImageAlphaOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float tempcolor[4]; + + if (this->m_imageFloatBuffer == nullptr && this->m_imageByteBuffer == nullptr) { + output[0] = 0.0f; + } + else { + tempcolor[3] = 1.0f; + sampleImageAtLocation(this->m_buffer, x, y, sampler, false, tempcolor); + output[0] = tempcolor[3]; + } +} + +void ImageDepthOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + if (this->m_depthBuffer == nullptr) { + output[0] = 0.0f; + } + else { + if (x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight()) { + output[0] = 0.0f; + } + else { + int offset = y * this->m_width + x; + output[0] = this->m_depthBuffer[offset]; + } + } +} diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp deleted file mode 100644 index ae5b7293a8c..00000000000 --- a/source/blender/compositor/operations/COM_ImageOperation.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ImageOperation.h" - -#include "BKE_image.h" -#include "BKE_scene.h" -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "DNA_image_types.h" - -#include "IMB_colormanagement.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -#include "RE_pipeline.h" -#include "RE_texture.h" - -BaseImageOperation::BaseImageOperation() -{ - this->m_image = nullptr; - this->m_buffer = nullptr; - this->m_imageFloatBuffer = nullptr; - this->m_imageByteBuffer = nullptr; - this->m_imageUser = nullptr; - this->m_imagewidth = 0; - this->m_imageheight = 0; - this->m_framenumber = 0; - this->m_depthBuffer = nullptr; - this->m_numberOfChannels = 0; - this->m_rd = nullptr; - this->m_viewName = nullptr; -} -ImageOperation::ImageOperation() : BaseImageOperation() -{ - this->addOutputSocket(COM_DT_COLOR); -} -ImageAlphaOperation::ImageAlphaOperation() : BaseImageOperation() -{ - this->addOutputSocket(COM_DT_VALUE); -} -ImageDepthOperation::ImageDepthOperation() : BaseImageOperation() -{ - this->addOutputSocket(COM_DT_VALUE); -} - -ImBuf *BaseImageOperation::getImBuf() -{ - ImBuf *ibuf; - ImageUser iuser = *this->m_imageUser; - - if (this->m_image == nullptr) { - return nullptr; - } - - /* local changes to the original ImageUser */ - if (BKE_image_is_multilayer(this->m_image) == false) { - iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName); - } - - ibuf = BKE_image_acquire_ibuf(this->m_image, &iuser, nullptr); - if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) { - BKE_image_release_ibuf(this->m_image, ibuf, nullptr); - return nullptr; - } - return ibuf; -} - -void BaseImageOperation::initExecution() -{ - ImBuf *stackbuf = getImBuf(); - this->m_buffer = stackbuf; - if (stackbuf) { - this->m_imageFloatBuffer = stackbuf->rect_float; - this->m_imageByteBuffer = stackbuf->rect; - this->m_depthBuffer = stackbuf->zbuf_float; - this->m_imagewidth = stackbuf->x; - this->m_imageheight = stackbuf->y; - this->m_numberOfChannels = stackbuf->channels; - } -} - -void BaseImageOperation::deinitExecution() -{ - this->m_imageFloatBuffer = nullptr; - this->m_imageByteBuffer = nullptr; - BKE_image_release_ibuf(this->m_image, this->m_buffer, nullptr); -} - -void BaseImageOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) -{ - ImBuf *stackbuf = getImBuf(); - - resolution[0] = 0; - resolution[1] = 0; - - if (stackbuf) { - resolution[0] = stackbuf->x; - resolution[1] = stackbuf->y; - } - - BKE_image_release_ibuf(this->m_image, stackbuf, nullptr); -} - -static void sampleImageAtLocation( - ImBuf *ibuf, float x, float y, PixelSampler sampler, bool make_linear_rgb, float color[4]) -{ - if (ibuf->rect_float) { - switch (sampler) { - case COM_PS_NEAREST: - nearest_interpolation_color(ibuf, nullptr, color, x, y); - break; - case COM_PS_BILINEAR: - bilinear_interpolation_color(ibuf, nullptr, color, x, y); - break; - case COM_PS_BICUBIC: - bicubic_interpolation_color(ibuf, nullptr, color, x, y); - break; - } - } - else { - unsigned char byte_color[4]; - switch (sampler) { - case COM_PS_NEAREST: - nearest_interpolation_color(ibuf, byte_color, nullptr, x, y); - break; - case COM_PS_BILINEAR: - bilinear_interpolation_color(ibuf, byte_color, nullptr, x, y); - break; - case COM_PS_BICUBIC: - bicubic_interpolation_color(ibuf, byte_color, nullptr, x, y); - break; - } - rgba_uchar_to_float(color, byte_color); - if (make_linear_rgb) { - IMB_colormanagement_colorspace_to_scene_linear_v4(color, false, ibuf->rect_colorspace); - } - } -} - -void ImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - int ix = x, iy = y; - if (this->m_imageFloatBuffer == nullptr && this->m_imageByteBuffer == nullptr) { - zero_v4(output); - } - else if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) { - zero_v4(output); - } - else { - sampleImageAtLocation(this->m_buffer, x, y, sampler, true, output); - } -} - -void ImageAlphaOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float tempcolor[4]; - - if (this->m_imageFloatBuffer == nullptr && this->m_imageByteBuffer == nullptr) { - output[0] = 0.0f; - } - else { - tempcolor[3] = 1.0f; - sampleImageAtLocation(this->m_buffer, x, y, sampler, false, tempcolor); - output[0] = tempcolor[3]; - } -} - -void ImageDepthOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - if (this->m_depthBuffer == nullptr) { - output[0] = 0.0f; - } - else { - if (x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight()) { - output[0] = 0.0f; - } - else { - int offset = y * this->m_width + x; - output[0] = this->m_depthBuffer[offset]; - } - } -} diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cc b/source/blender/compositor/operations/COM_InpaintOperation.cc new file mode 100644 index 00000000000..502b33d7e14 --- /dev/null +++ b/source/blender/compositor/operations/COM_InpaintOperation.cc @@ -0,0 +1,284 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "MEM_guardedalloc.h" + +#include "COM_InpaintOperation.h" +#include "COM_OpenCLDevice.h" + +#include "BLI_math.h" + +#define ASSERT_XY_RANGE(x, y) \ + BLI_assert(x >= 0 && x < this->getWidth() && y >= 0 && y < this->getHeight()) + +// Inpaint (simple convolve using average of known pixels) +InpaintSimpleOperation::InpaintSimpleOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->setComplex(true); + this->m_inputImageProgram = nullptr; + this->m_pixelorder = nullptr; + this->m_manhattan_distance = nullptr; + this->m_cached_buffer = nullptr; + this->m_cached_buffer_ready = false; +} +void InpaintSimpleOperation::initExecution() +{ + this->m_inputImageProgram = this->getInputSocketReader(0); + + this->m_pixelorder = nullptr; + this->m_manhattan_distance = nullptr; + this->m_cached_buffer = nullptr; + this->m_cached_buffer_ready = false; + + this->initMutex(); +} + +void InpaintSimpleOperation::clamp_xy(int &x, int &y) +{ + int width = this->getWidth(); + int height = this->getHeight(); + + if (x < 0) { + x = 0; + } + else if (x >= width) { + x = width - 1; + } + + if (y < 0) { + y = 0; + } + else if (y >= height) { + y = height - 1; + } +} + +float *InpaintSimpleOperation::get_pixel(int x, int y) +{ + int width = this->getWidth(); + + ASSERT_XY_RANGE(x, y); + + return &this->m_cached_buffer[y * width * COM_NUM_CHANNELS_COLOR + x * COM_NUM_CHANNELS_COLOR]; +} + +int InpaintSimpleOperation::mdist(int x, int y) +{ + int width = this->getWidth(); + + ASSERT_XY_RANGE(x, y); + + return this->m_manhattan_distance[y * width + x]; +} + +bool InpaintSimpleOperation::next_pixel(int &x, int &y, int &curr, int iters) +{ + int width = this->getWidth(); + + if (curr >= this->m_area_size) { + return false; + } + + int r = this->m_pixelorder[curr++]; + + x = r % width; + y = r / width; + + if (this->mdist(x, y) > iters) { + return false; + } + + return true; +} + +void InpaintSimpleOperation::calc_manhattan_distance() +{ + int width = this->getWidth(); + int height = this->getHeight(); + short *m = this->m_manhattan_distance = (short *)MEM_mallocN(sizeof(short) * width * height, + __func__); + int *offsets; + + offsets = (int *)MEM_callocN(sizeof(int) * (width + height + 1), + "InpaintSimpleOperation offsets"); + + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + int r = 0; + /* no need to clamp here */ + if (this->get_pixel(i, j)[3] < 1.0f) { + r = width + height; + if (i > 0) { + r = min_ii(r, m[j * width + i - 1] + 1); + } + if (j > 0) { + r = min_ii(r, m[(j - 1) * width + i] + 1); + } + } + m[j * width + i] = r; + } + } + + for (int j = height - 1; j >= 0; j--) { + for (int i = width - 1; i >= 0; i--) { + int r = m[j * width + i]; + + if (i + 1 < width) { + r = min_ii(r, m[j * width + i + 1] + 1); + } + if (j + 1 < height) { + r = min_ii(r, m[(j + 1) * width + i] + 1); + } + + m[j * width + i] = r; + + offsets[r]++; + } + } + + offsets[0] = 0; + + for (int i = 1; i < width + height + 1; i++) { + offsets[i] += offsets[i - 1]; + } + + this->m_area_size = offsets[width + height]; + this->m_pixelorder = (int *)MEM_mallocN(sizeof(int) * this->m_area_size, __func__); + + for (int i = 0; i < width * height; i++) { + if (m[i] > 0) { + this->m_pixelorder[offsets[m[i] - 1]++] = i; + } + } + + MEM_freeN(offsets); +} + +void InpaintSimpleOperation::pix_step(int x, int y) +{ + const int d = this->mdist(x, y); + float pix[3] = {0.0f, 0.0f, 0.0f}; + float pix_divider = 0.0f; + + for (int dx = -1; dx <= 1; dx++) { + for (int dy = -1; dy <= 1; dy++) { + /* changing to both != 0 gives dithering artifacts */ + if (dx != 0 || dy != 0) { + int x_ofs = x + dx; + int y_ofs = y + dy; + + this->clamp_xy(x_ofs, y_ofs); + + if (this->mdist(x_ofs, y_ofs) < d) { + + float weight; + + if (dx == 0 || dy == 0) { + weight = 1.0f; + } + else { + weight = M_SQRT1_2; /* 1.0f / sqrt(2) */ + } + + madd_v3_v3fl(pix, this->get_pixel(x_ofs, y_ofs), weight); + pix_divider += weight; + } + } + } + } + + float *output = this->get_pixel(x, y); + if (pix_divider != 0.0f) { + mul_v3_fl(pix, 1.0f / pix_divider); + /* use existing pixels alpha to blend into */ + interp_v3_v3v3(output, pix, output, output[3]); + output[3] = 1.0f; + } +} + +void *InpaintSimpleOperation::initializeTileData(rcti *rect) +{ + if (this->m_cached_buffer_ready) { + return this->m_cached_buffer; + } + lockMutex(); + if (!this->m_cached_buffer_ready) { + MemoryBuffer *buf = (MemoryBuffer *)this->m_inputImageProgram->initializeTileData(rect); + this->m_cached_buffer = (float *)MEM_dupallocN(buf->getBuffer()); + + this->calc_manhattan_distance(); + + int curr = 0; + int x, y; + + while (this->next_pixel(x, y, curr, this->m_iterations)) { + this->pix_step(x, y); + } + this->m_cached_buffer_ready = true; + } + + unlockMutex(); + return this->m_cached_buffer; +} + +void InpaintSimpleOperation::executePixel(float output[4], int x, int y, void * /*data*/) +{ + this->clamp_xy(x, y); + copy_v4_v4(output, this->get_pixel(x, y)); +} + +void InpaintSimpleOperation::deinitExecution() +{ + this->m_inputImageProgram = nullptr; + this->deinitMutex(); + if (this->m_cached_buffer) { + MEM_freeN(this->m_cached_buffer); + this->m_cached_buffer = nullptr; + } + + if (this->m_pixelorder) { + MEM_freeN(this->m_pixelorder); + this->m_pixelorder = nullptr; + } + + if (this->m_manhattan_distance) { + MEM_freeN(this->m_manhattan_distance); + this->m_manhattan_distance = nullptr; + } + this->m_cached_buffer_ready = false; +} + +bool InpaintSimpleOperation::determineDependingAreaOfInterest(rcti * /*input*/, + ReadBufferOperation *readOperation, + rcti *output) +{ + if (this->m_cached_buffer_ready) { + return false; + } + + rcti newInput; + + newInput.xmax = getWidth(); + newInput.xmin = 0; + newInput.ymax = getHeight(); + newInput.ymin = 0; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cpp b/source/blender/compositor/operations/COM_InpaintOperation.cpp deleted file mode 100644 index 502b33d7e14..00000000000 --- a/source/blender/compositor/operations/COM_InpaintOperation.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "MEM_guardedalloc.h" - -#include "COM_InpaintOperation.h" -#include "COM_OpenCLDevice.h" - -#include "BLI_math.h" - -#define ASSERT_XY_RANGE(x, y) \ - BLI_assert(x >= 0 && x < this->getWidth() && y >= 0 && y < this->getHeight()) - -// Inpaint (simple convolve using average of known pixels) -InpaintSimpleOperation::InpaintSimpleOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->setComplex(true); - this->m_inputImageProgram = nullptr; - this->m_pixelorder = nullptr; - this->m_manhattan_distance = nullptr; - this->m_cached_buffer = nullptr; - this->m_cached_buffer_ready = false; -} -void InpaintSimpleOperation::initExecution() -{ - this->m_inputImageProgram = this->getInputSocketReader(0); - - this->m_pixelorder = nullptr; - this->m_manhattan_distance = nullptr; - this->m_cached_buffer = nullptr; - this->m_cached_buffer_ready = false; - - this->initMutex(); -} - -void InpaintSimpleOperation::clamp_xy(int &x, int &y) -{ - int width = this->getWidth(); - int height = this->getHeight(); - - if (x < 0) { - x = 0; - } - else if (x >= width) { - x = width - 1; - } - - if (y < 0) { - y = 0; - } - else if (y >= height) { - y = height - 1; - } -} - -float *InpaintSimpleOperation::get_pixel(int x, int y) -{ - int width = this->getWidth(); - - ASSERT_XY_RANGE(x, y); - - return &this->m_cached_buffer[y * width * COM_NUM_CHANNELS_COLOR + x * COM_NUM_CHANNELS_COLOR]; -} - -int InpaintSimpleOperation::mdist(int x, int y) -{ - int width = this->getWidth(); - - ASSERT_XY_RANGE(x, y); - - return this->m_manhattan_distance[y * width + x]; -} - -bool InpaintSimpleOperation::next_pixel(int &x, int &y, int &curr, int iters) -{ - int width = this->getWidth(); - - if (curr >= this->m_area_size) { - return false; - } - - int r = this->m_pixelorder[curr++]; - - x = r % width; - y = r / width; - - if (this->mdist(x, y) > iters) { - return false; - } - - return true; -} - -void InpaintSimpleOperation::calc_manhattan_distance() -{ - int width = this->getWidth(); - int height = this->getHeight(); - short *m = this->m_manhattan_distance = (short *)MEM_mallocN(sizeof(short) * width * height, - __func__); - int *offsets; - - offsets = (int *)MEM_callocN(sizeof(int) * (width + height + 1), - "InpaintSimpleOperation offsets"); - - for (int j = 0; j < height; j++) { - for (int i = 0; i < width; i++) { - int r = 0; - /* no need to clamp here */ - if (this->get_pixel(i, j)[3] < 1.0f) { - r = width + height; - if (i > 0) { - r = min_ii(r, m[j * width + i - 1] + 1); - } - if (j > 0) { - r = min_ii(r, m[(j - 1) * width + i] + 1); - } - } - m[j * width + i] = r; - } - } - - for (int j = height - 1; j >= 0; j--) { - for (int i = width - 1; i >= 0; i--) { - int r = m[j * width + i]; - - if (i + 1 < width) { - r = min_ii(r, m[j * width + i + 1] + 1); - } - if (j + 1 < height) { - r = min_ii(r, m[(j + 1) * width + i] + 1); - } - - m[j * width + i] = r; - - offsets[r]++; - } - } - - offsets[0] = 0; - - for (int i = 1; i < width + height + 1; i++) { - offsets[i] += offsets[i - 1]; - } - - this->m_area_size = offsets[width + height]; - this->m_pixelorder = (int *)MEM_mallocN(sizeof(int) * this->m_area_size, __func__); - - for (int i = 0; i < width * height; i++) { - if (m[i] > 0) { - this->m_pixelorder[offsets[m[i] - 1]++] = i; - } - } - - MEM_freeN(offsets); -} - -void InpaintSimpleOperation::pix_step(int x, int y) -{ - const int d = this->mdist(x, y); - float pix[3] = {0.0f, 0.0f, 0.0f}; - float pix_divider = 0.0f; - - for (int dx = -1; dx <= 1; dx++) { - for (int dy = -1; dy <= 1; dy++) { - /* changing to both != 0 gives dithering artifacts */ - if (dx != 0 || dy != 0) { - int x_ofs = x + dx; - int y_ofs = y + dy; - - this->clamp_xy(x_ofs, y_ofs); - - if (this->mdist(x_ofs, y_ofs) < d) { - - float weight; - - if (dx == 0 || dy == 0) { - weight = 1.0f; - } - else { - weight = M_SQRT1_2; /* 1.0f / sqrt(2) */ - } - - madd_v3_v3fl(pix, this->get_pixel(x_ofs, y_ofs), weight); - pix_divider += weight; - } - } - } - } - - float *output = this->get_pixel(x, y); - if (pix_divider != 0.0f) { - mul_v3_fl(pix, 1.0f / pix_divider); - /* use existing pixels alpha to blend into */ - interp_v3_v3v3(output, pix, output, output[3]); - output[3] = 1.0f; - } -} - -void *InpaintSimpleOperation::initializeTileData(rcti *rect) -{ - if (this->m_cached_buffer_ready) { - return this->m_cached_buffer; - } - lockMutex(); - if (!this->m_cached_buffer_ready) { - MemoryBuffer *buf = (MemoryBuffer *)this->m_inputImageProgram->initializeTileData(rect); - this->m_cached_buffer = (float *)MEM_dupallocN(buf->getBuffer()); - - this->calc_manhattan_distance(); - - int curr = 0; - int x, y; - - while (this->next_pixel(x, y, curr, this->m_iterations)) { - this->pix_step(x, y); - } - this->m_cached_buffer_ready = true; - } - - unlockMutex(); - return this->m_cached_buffer; -} - -void InpaintSimpleOperation::executePixel(float output[4], int x, int y, void * /*data*/) -{ - this->clamp_xy(x, y); - copy_v4_v4(output, this->get_pixel(x, y)); -} - -void InpaintSimpleOperation::deinitExecution() -{ - this->m_inputImageProgram = nullptr; - this->deinitMutex(); - if (this->m_cached_buffer) { - MEM_freeN(this->m_cached_buffer); - this->m_cached_buffer = nullptr; - } - - if (this->m_pixelorder) { - MEM_freeN(this->m_pixelorder); - this->m_pixelorder = nullptr; - } - - if (this->m_manhattan_distance) { - MEM_freeN(this->m_manhattan_distance); - this->m_manhattan_distance = nullptr; - } - this->m_cached_buffer_ready = false; -} - -bool InpaintSimpleOperation::determineDependingAreaOfInterest(rcti * /*input*/, - ReadBufferOperation *readOperation, - rcti *output) -{ - if (this->m_cached_buffer_ready) { - return false; - } - - rcti newInput; - - newInput.xmax = getWidth(); - newInput.xmin = 0; - newInput.ymax = getHeight(); - newInput.ymin = 0; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_InvertOperation.cc b/source/blender/compositor/operations/COM_InvertOperation.cc new file mode 100644 index 00000000000..d9f436a3e28 --- /dev/null +++ b/source/blender/compositor/operations/COM_InvertOperation.cc @@ -0,0 +1,69 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_InvertOperation.h" + +InvertOperation::InvertOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputValueProgram = nullptr; + this->m_inputColorProgram = nullptr; + this->m_color = true; + this->m_alpha = false; + setResolutionInputSocketIndex(1); +} +void InvertOperation::initExecution() +{ + this->m_inputValueProgram = this->getInputSocketReader(0); + this->m_inputColorProgram = this->getInputSocketReader(1); +} + +void InvertOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float inputValue[4]; + float inputColor[4]; + this->m_inputValueProgram->readSampled(inputValue, x, y, sampler); + this->m_inputColorProgram->readSampled(inputColor, x, y, sampler); + + const float value = inputValue[0]; + const float invertedValue = 1.0f - value; + + if (this->m_color) { + output[0] = (1.0f - inputColor[0]) * value + inputColor[0] * invertedValue; + output[1] = (1.0f - inputColor[1]) * value + inputColor[1] * invertedValue; + output[2] = (1.0f - inputColor[2]) * value + inputColor[2] * invertedValue; + } + else { + copy_v3_v3(output, inputColor); + } + + if (this->m_alpha) { + output[3] = (1.0f - inputColor[3]) * value + inputColor[3] * invertedValue; + } + else { + output[3] = inputColor[3]; + } +} + +void InvertOperation::deinitExecution() +{ + this->m_inputValueProgram = nullptr; + this->m_inputColorProgram = nullptr; +} diff --git a/source/blender/compositor/operations/COM_InvertOperation.cpp b/source/blender/compositor/operations/COM_InvertOperation.cpp deleted file mode 100644 index d9f436a3e28..00000000000 --- a/source/blender/compositor/operations/COM_InvertOperation.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_InvertOperation.h" - -InvertOperation::InvertOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputValueProgram = nullptr; - this->m_inputColorProgram = nullptr; - this->m_color = true; - this->m_alpha = false; - setResolutionInputSocketIndex(1); -} -void InvertOperation::initExecution() -{ - this->m_inputValueProgram = this->getInputSocketReader(0); - this->m_inputColorProgram = this->getInputSocketReader(1); -} - -void InvertOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - float inputValue[4]; - float inputColor[4]; - this->m_inputValueProgram->readSampled(inputValue, x, y, sampler); - this->m_inputColorProgram->readSampled(inputColor, x, y, sampler); - - const float value = inputValue[0]; - const float invertedValue = 1.0f - value; - - if (this->m_color) { - output[0] = (1.0f - inputColor[0]) * value + inputColor[0] * invertedValue; - output[1] = (1.0f - inputColor[1]) * value + inputColor[1] * invertedValue; - output[2] = (1.0f - inputColor[2]) * value + inputColor[2] * invertedValue; - } - else { - copy_v3_v3(output, inputColor); - } - - if (this->m_alpha) { - output[3] = (1.0f - inputColor[3]) * value + inputColor[3] * invertedValue; - } - else { - output[3] = inputColor[3]; - } -} - -void InvertOperation::deinitExecution() -{ - this->m_inputValueProgram = nullptr; - this->m_inputColorProgram = nullptr; -} diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cc b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc new file mode 100644 index 00000000000..c9cc8ebc045 --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc @@ -0,0 +1,95 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_KeyingBlurOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +KeyingBlurOperation::KeyingBlurOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + + this->m_size = 0; + this->m_axis = BLUR_AXIS_X; + + this->setComplex(true); +} + +void *KeyingBlurOperation::initializeTileData(rcti *rect) +{ + void *buffer = getInputOperation(0)->initializeTileData(rect); + + return buffer; +} + +void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data) +{ + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + const int bufferWidth = inputBuffer->getWidth(); + float *buffer = inputBuffer->getBuffer(); + int count = 0; + float average = 0.0f; + + if (this->m_axis == 0) { + const int start = MAX2(0, x - this->m_size + 1), end = MIN2(bufferWidth, x + this->m_size); + for (int cx = start; cx < end; cx++) { + int bufferIndex = (y * bufferWidth + cx); + average += buffer[bufferIndex]; + count++; + } + } + else { + const int start = MAX2(0, y - this->m_size + 1), + end = MIN2(inputBuffer->getHeight(), y + this->m_size); + for (int cy = start; cy < end; cy++) { + int bufferIndex = (cy * bufferWidth + x); + average += buffer[bufferIndex]; + count++; + } + } + + average /= (float)count; + + output[0] = average; +} + +bool KeyingBlurOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + + if (this->m_axis == BLUR_AXIS_X) { + newInput.xmin = input->xmin - this->m_size; + newInput.ymin = input->ymin; + newInput.xmax = input->xmax + this->m_size; + newInput.ymax = input->ymax; + } + else { + newInput.xmin = input->xmin; + newInput.ymin = input->ymin - this->m_size; + newInput.xmax = input->xmax; + newInput.ymax = input->ymax + this->m_size; + } + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp deleted file mode 100644 index c9cc8ebc045..00000000000 --- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_KeyingBlurOperation.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" - -KeyingBlurOperation::KeyingBlurOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - - this->m_size = 0; - this->m_axis = BLUR_AXIS_X; - - this->setComplex(true); -} - -void *KeyingBlurOperation::initializeTileData(rcti *rect) -{ - void *buffer = getInputOperation(0)->initializeTileData(rect); - - return buffer; -} - -void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data) -{ - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - const int bufferWidth = inputBuffer->getWidth(); - float *buffer = inputBuffer->getBuffer(); - int count = 0; - float average = 0.0f; - - if (this->m_axis == 0) { - const int start = MAX2(0, x - this->m_size + 1), end = MIN2(bufferWidth, x + this->m_size); - for (int cx = start; cx < end; cx++) { - int bufferIndex = (y * bufferWidth + cx); - average += buffer[bufferIndex]; - count++; - } - } - else { - const int start = MAX2(0, y - this->m_size + 1), - end = MIN2(inputBuffer->getHeight(), y + this->m_size); - for (int cy = start; cy < end; cy++) { - int bufferIndex = (cy * bufferWidth + x); - average += buffer[bufferIndex]; - count++; - } - } - - average /= (float)count; - - output[0] = average; -} - -bool KeyingBlurOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - - if (this->m_axis == BLUR_AXIS_X) { - newInput.xmin = input->xmin - this->m_size; - newInput.ymin = input->ymin; - newInput.xmax = input->xmax + this->m_size; - newInput.ymax = input->ymax; - } - else { - newInput.xmin = input->xmin; - newInput.ymin = input->ymin - this->m_size; - newInput.xmax = input->xmax; - newInput.ymax = input->ymax + this->m_size; - } - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cc b/source/blender/compositor/operations/COM_KeyingClipOperation.cc new file mode 100644 index 00000000000..592f116c451 --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cc @@ -0,0 +1,129 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_KeyingClipOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +KeyingClipOperation::KeyingClipOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + + this->m_kernelRadius = 3; + this->m_kernelTolerance = 0.1f; + + this->m_clipBlack = 0.0f; + this->m_clipWhite = 1.0f; + + this->m_isEdgeMatte = false; + + this->setComplex(true); +} + +void *KeyingClipOperation::initializeTileData(rcti *rect) +{ + void *buffer = getInputOperation(0)->initializeTileData(rect); + + return buffer; +} + +void KeyingClipOperation::executePixel(float output[4], int x, int y, void *data) +{ + const int delta = this->m_kernelRadius; + const float tolerance = this->m_kernelTolerance; + + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + float *buffer = inputBuffer->getBuffer(); + + int bufferWidth = inputBuffer->getWidth(); + int bufferHeight = inputBuffer->getHeight(); + + float value = buffer[(y * bufferWidth + x)]; + + bool ok = false; + int start_x = max_ff(0, x - delta + 1), start_y = max_ff(0, y - delta + 1), + end_x = min_ff(x + delta - 1, bufferWidth - 1), + end_y = min_ff(y + delta - 1, bufferHeight - 1); + + int count = 0, totalCount = (end_x - start_x + 1) * (end_y - start_y + 1) - 1; + int thresholdCount = ceil((float)totalCount * 0.9f); + + if (delta == 0) { + ok = true; + } + + for (int cx = start_x; ok == false && cx <= end_x; cx++) { + for (int cy = start_y; ok == false && cy <= end_y; cy++) { + if (UNLIKELY(cx == x && cy == y)) { + continue; + } + + int bufferIndex = (cy * bufferWidth + cx); + float currentValue = buffer[bufferIndex]; + + if (fabsf(currentValue - value) < tolerance) { + count++; + if (count >= thresholdCount) { + ok = true; + } + } + } + } + + if (this->m_isEdgeMatte) { + if (ok) { + output[0] = 0.0f; + } + else { + output[0] = 1.0f; + } + } + else { + output[0] = value; + + if (ok) { + if (output[0] < this->m_clipBlack) { + output[0] = 0.0f; + } + else if (output[0] >= this->m_clipWhite) { + output[0] = 1.0f; + } + else { + output[0] = (output[0] - this->m_clipBlack) / (this->m_clipWhite - this->m_clipBlack); + } + } + } +} + +bool KeyingClipOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + + newInput.xmin = input->xmin - this->m_kernelRadius; + newInput.ymin = input->ymin - this->m_kernelRadius; + newInput.xmax = input->xmax + this->m_kernelRadius; + newInput.ymax = input->ymax + this->m_kernelRadius; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp b/source/blender/compositor/operations/COM_KeyingClipOperation.cpp deleted file mode 100644 index 592f116c451..00000000000 --- a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_KeyingClipOperation.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" - -KeyingClipOperation::KeyingClipOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - - this->m_kernelRadius = 3; - this->m_kernelTolerance = 0.1f; - - this->m_clipBlack = 0.0f; - this->m_clipWhite = 1.0f; - - this->m_isEdgeMatte = false; - - this->setComplex(true); -} - -void *KeyingClipOperation::initializeTileData(rcti *rect) -{ - void *buffer = getInputOperation(0)->initializeTileData(rect); - - return buffer; -} - -void KeyingClipOperation::executePixel(float output[4], int x, int y, void *data) -{ - const int delta = this->m_kernelRadius; - const float tolerance = this->m_kernelTolerance; - - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - float *buffer = inputBuffer->getBuffer(); - - int bufferWidth = inputBuffer->getWidth(); - int bufferHeight = inputBuffer->getHeight(); - - float value = buffer[(y * bufferWidth + x)]; - - bool ok = false; - int start_x = max_ff(0, x - delta + 1), start_y = max_ff(0, y - delta + 1), - end_x = min_ff(x + delta - 1, bufferWidth - 1), - end_y = min_ff(y + delta - 1, bufferHeight - 1); - - int count = 0, totalCount = (end_x - start_x + 1) * (end_y - start_y + 1) - 1; - int thresholdCount = ceil((float)totalCount * 0.9f); - - if (delta == 0) { - ok = true; - } - - for (int cx = start_x; ok == false && cx <= end_x; cx++) { - for (int cy = start_y; ok == false && cy <= end_y; cy++) { - if (UNLIKELY(cx == x && cy == y)) { - continue; - } - - int bufferIndex = (cy * bufferWidth + cx); - float currentValue = buffer[bufferIndex]; - - if (fabsf(currentValue - value) < tolerance) { - count++; - if (count >= thresholdCount) { - ok = true; - } - } - } - } - - if (this->m_isEdgeMatte) { - if (ok) { - output[0] = 0.0f; - } - else { - output[0] = 1.0f; - } - } - else { - output[0] = value; - - if (ok) { - if (output[0] < this->m_clipBlack) { - output[0] = 0.0f; - } - else if (output[0] >= this->m_clipWhite) { - output[0] = 1.0f; - } - else { - output[0] = (output[0] - this->m_clipBlack) / (this->m_clipWhite - this->m_clipBlack); - } - } - } -} - -bool KeyingClipOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - - newInput.xmin = input->xmin - this->m_kernelRadius; - newInput.ymin = input->ymin - this->m_kernelRadius; - newInput.xmax = input->xmax + this->m_kernelRadius; - newInput.ymax = input->ymax + this->m_kernelRadius; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.cc b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc new file mode 100644 index 00000000000..f4d0d6c6a00 --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc @@ -0,0 +1,81 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_KeyingDespillOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +KeyingDespillOperation::KeyingDespillOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + + this->m_despillFactor = 0.5f; + this->m_colorBalance = 0.5f; + + this->m_pixelReader = nullptr; + this->m_screenReader = nullptr; +} + +void KeyingDespillOperation::initExecution() +{ + this->m_pixelReader = this->getInputSocketReader(0); + this->m_screenReader = this->getInputSocketReader(1); +} + +void KeyingDespillOperation::deinitExecution() +{ + this->m_pixelReader = nullptr; + this->m_screenReader = nullptr; +} + +void KeyingDespillOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float pixelColor[4]; + float screenColor[4]; + + this->m_pixelReader->readSampled(pixelColor, x, y, sampler); + this->m_screenReader->readSampled(screenColor, x, y, sampler); + + const int screen_primary_channel = max_axis_v3(screenColor); + const int other_1 = (screen_primary_channel + 1) % 3; + const int other_2 = (screen_primary_channel + 2) % 3; + + const int min_channel = MIN2(other_1, other_2); + const int max_channel = MAX2(other_1, other_2); + + float average_value, amount; + + average_value = this->m_colorBalance * pixelColor[min_channel] + + (1.0f - this->m_colorBalance) * pixelColor[max_channel]; + amount = (pixelColor[screen_primary_channel] - average_value); + + copy_v4_v4(output, pixelColor); + + const float amount_despill = this->m_despillFactor * amount; + if (amount_despill > 0.0f) { + output[screen_primary_channel] = pixelColor[screen_primary_channel] - amount_despill; + } +} diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp b/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp deleted file mode 100644 index f4d0d6c6a00..00000000000 --- a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_KeyingDespillOperation.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" - -KeyingDespillOperation::KeyingDespillOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - - this->m_despillFactor = 0.5f; - this->m_colorBalance = 0.5f; - - this->m_pixelReader = nullptr; - this->m_screenReader = nullptr; -} - -void KeyingDespillOperation::initExecution() -{ - this->m_pixelReader = this->getInputSocketReader(0); - this->m_screenReader = this->getInputSocketReader(1); -} - -void KeyingDespillOperation::deinitExecution() -{ - this->m_pixelReader = nullptr; - this->m_screenReader = nullptr; -} - -void KeyingDespillOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float pixelColor[4]; - float screenColor[4]; - - this->m_pixelReader->readSampled(pixelColor, x, y, sampler); - this->m_screenReader->readSampled(screenColor, x, y, sampler); - - const int screen_primary_channel = max_axis_v3(screenColor); - const int other_1 = (screen_primary_channel + 1) % 3; - const int other_2 = (screen_primary_channel + 2) % 3; - - const int min_channel = MIN2(other_1, other_2); - const int max_channel = MAX2(other_1, other_2); - - float average_value, amount; - - average_value = this->m_colorBalance * pixelColor[min_channel] + - (1.0f - this->m_colorBalance) * pixelColor[max_channel]; - amount = (pixelColor[screen_primary_channel] - average_value); - - copy_v4_v4(output, pixelColor); - - const float amount_despill = this->m_despillFactor * amount; - if (amount_despill > 0.0f) { - output[screen_primary_channel] = pixelColor[screen_primary_channel] - amount_despill; - } -} diff --git a/source/blender/compositor/operations/COM_KeyingOperation.cc b/source/blender/compositor/operations/COM_KeyingOperation.cc new file mode 100644 index 00000000000..94e65181207 --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingOperation.cc @@ -0,0 +1,109 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_KeyingOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +static float get_pixel_saturation(const float pixelColor[4], + float screen_balance, + int primary_channel) +{ + const int other_1 = (primary_channel + 1) % 3; + const int other_2 = (primary_channel + 2) % 3; + + const int min_channel = MIN2(other_1, other_2); + const int max_channel = MAX2(other_1, other_2); + + const float val = screen_balance * pixelColor[min_channel] + + (1.0f - screen_balance) * pixelColor[max_channel]; + + return (pixelColor[primary_channel] - val) * fabsf(1.0f - val); +} + +KeyingOperation::KeyingOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_VALUE); + + this->m_screenBalance = 0.5f; + + this->m_pixelReader = nullptr; + this->m_screenReader = nullptr; +} + +void KeyingOperation::initExecution() +{ + this->m_pixelReader = this->getInputSocketReader(0); + this->m_screenReader = this->getInputSocketReader(1); +} + +void KeyingOperation::deinitExecution() +{ + this->m_pixelReader = nullptr; + this->m_screenReader = nullptr; +} + +void KeyingOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float pixel_color[4]; + float screen_color[4]; + + this->m_pixelReader->readSampled(pixel_color, x, y, sampler); + this->m_screenReader->readSampled(screen_color, x, y, sampler); + + const int primary_channel = max_axis_v3(screen_color); + const float min_pixel_color = min_fff(pixel_color[0], pixel_color[1], pixel_color[2]); + + if (min_pixel_color > 1.0f) { + /* overexposure doesn't happen on screen itself and usually happens + * on light sources in the shot, this need to be checked separately + * because saturation and falloff calculation is based on the fact + * that pixels are not overexposed + */ + output[0] = 1.0f; + } + else { + float saturation = get_pixel_saturation(pixel_color, this->m_screenBalance, primary_channel); + float screen_saturation = get_pixel_saturation( + screen_color, this->m_screenBalance, primary_channel); + + if (saturation < 0) { + /* means main channel of pixel is different from screen, + * assume this is completely a foreground + */ + output[0] = 1.0f; + } + else if (saturation >= screen_saturation) { + /* matched main channels and higher saturation on pixel + * is treated as completely background + */ + output[0] = 0.0f; + } + else { + /* nice alpha falloff on edges */ + float distance = 1.0f - saturation / screen_saturation; + + output[0] = distance; + } + } +} diff --git a/source/blender/compositor/operations/COM_KeyingOperation.cpp b/source/blender/compositor/operations/COM_KeyingOperation.cpp deleted file mode 100644 index 94e65181207..00000000000 --- a/source/blender/compositor/operations/COM_KeyingOperation.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_KeyingOperation.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" - -static float get_pixel_saturation(const float pixelColor[4], - float screen_balance, - int primary_channel) -{ - const int other_1 = (primary_channel + 1) % 3; - const int other_2 = (primary_channel + 2) % 3; - - const int min_channel = MIN2(other_1, other_2); - const int max_channel = MAX2(other_1, other_2); - - const float val = screen_balance * pixelColor[min_channel] + - (1.0f - screen_balance) * pixelColor[max_channel]; - - return (pixelColor[primary_channel] - val) * fabsf(1.0f - val); -} - -KeyingOperation::KeyingOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_VALUE); - - this->m_screenBalance = 0.5f; - - this->m_pixelReader = nullptr; - this->m_screenReader = nullptr; -} - -void KeyingOperation::initExecution() -{ - this->m_pixelReader = this->getInputSocketReader(0); - this->m_screenReader = this->getInputSocketReader(1); -} - -void KeyingOperation::deinitExecution() -{ - this->m_pixelReader = nullptr; - this->m_screenReader = nullptr; -} - -void KeyingOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - float pixel_color[4]; - float screen_color[4]; - - this->m_pixelReader->readSampled(pixel_color, x, y, sampler); - this->m_screenReader->readSampled(screen_color, x, y, sampler); - - const int primary_channel = max_axis_v3(screen_color); - const float min_pixel_color = min_fff(pixel_color[0], pixel_color[1], pixel_color[2]); - - if (min_pixel_color > 1.0f) { - /* overexposure doesn't happen on screen itself and usually happens - * on light sources in the shot, this need to be checked separately - * because saturation and falloff calculation is based on the fact - * that pixels are not overexposed - */ - output[0] = 1.0f; - } - else { - float saturation = get_pixel_saturation(pixel_color, this->m_screenBalance, primary_channel); - float screen_saturation = get_pixel_saturation( - screen_color, this->m_screenBalance, primary_channel); - - if (saturation < 0) { - /* means main channel of pixel is different from screen, - * assume this is completely a foreground - */ - output[0] = 1.0f; - } - else if (saturation >= screen_saturation) { - /* matched main channels and higher saturation on pixel - * is treated as completely background - */ - output[0] = 0.0f; - } - else { - /* nice alpha falloff on edges */ - float distance = 1.0f - saturation / screen_saturation; - - output[0] = distance; - } - } -} diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc new file mode 100644 index 00000000000..463a6fe49c0 --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc @@ -0,0 +1,346 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_KeyingScreenOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" + +#include "BKE_movieclip.h" +#include "BKE_tracking.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +KeyingScreenOperation::KeyingScreenOperation() +{ + this->addOutputSocket(COM_DT_COLOR); + this->m_movieClip = nullptr; + this->m_framenumber = 0; + this->m_trackingObject[0] = 0; + setComplex(true); +} + +void KeyingScreenOperation::initExecution() +{ + initMutex(); + this->m_cachedTriangulation = nullptr; +} + +void KeyingScreenOperation::deinitExecution() +{ + if (this->m_cachedTriangulation) { + TriangulationData *triangulation = this->m_cachedTriangulation; + + if (triangulation->triangulated_points) { + MEM_freeN(triangulation->triangulated_points); + } + + if (triangulation->triangles) { + MEM_freeN(triangulation->triangles); + } + + if (triangulation->triangles_AABB) { + MEM_freeN(triangulation->triangles_AABB); + } + + MEM_freeN(this->m_cachedTriangulation); + + this->m_cachedTriangulation = nullptr; + } +} + +KeyingScreenOperation::TriangulationData *KeyingScreenOperation::buildVoronoiTriangulation() +{ + MovieClipUser user = {0}; + TriangulationData *triangulation; + MovieTracking *tracking = &this->m_movieClip->tracking; + MovieTrackingTrack *track; + VoronoiSite *sites, *site; + ImBuf *ibuf; + ListBase *tracksbase; + ListBase edges = {nullptr, nullptr}; + int sites_total; + int i; + int width = this->getWidth(); + int height = this->getHeight(); + int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber); + + if (this->m_trackingObject[0]) { + MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, this->m_trackingObject); + + if (!object) { + return nullptr; + } + + tracksbase = BKE_tracking_object_get_tracks(tracking, object); + } + else { + tracksbase = BKE_tracking_get_active_tracks(tracking); + } + + /* count sites */ + for (track = (MovieTrackingTrack *)tracksbase->first, sites_total = 0; track; + track = track->next) { + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame); + float pos[2]; + + if (marker->flag & MARKER_DISABLED) { + continue; + } + + add_v2_v2v2(pos, marker->pos, track->offset); + + if (!IN_RANGE_INCL(pos[0], 0.0f, 1.0f) || !IN_RANGE_INCL(pos[1], 0.0f, 1.0f)) { + continue; + } + + sites_total++; + } + + if (!sites_total) { + return nullptr; + } + + BKE_movieclip_user_set_frame(&user, clip_frame); + ibuf = BKE_movieclip_get_ibuf(this->m_movieClip, &user); + + if (!ibuf) { + return nullptr; + } + + triangulation = (TriangulationData *)MEM_callocN(sizeof(TriangulationData), + "keying screen triangulation data"); + + sites = (VoronoiSite *)MEM_callocN(sizeof(VoronoiSite) * sites_total, + "keyingscreen voronoi sites"); + track = (MovieTrackingTrack *)tracksbase->first; + for (track = (MovieTrackingTrack *)tracksbase->first, site = sites; track; track = track->next) { + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame); + ImBuf *pattern_ibuf; + int j; + float pos[2]; + + if (marker->flag & MARKER_DISABLED) { + continue; + } + + add_v2_v2v2(pos, marker->pos, track->offset); + + if (!IN_RANGE_INCL(pos[0], 0.0f, 1.0f) || !IN_RANGE_INCL(pos[1], 0.0f, 1.0f)) { + continue; + } + + pattern_ibuf = BKE_tracking_get_pattern_imbuf(ibuf, track, marker, true, false); + + zero_v3(site->color); + + if (pattern_ibuf) { + for (j = 0; j < pattern_ibuf->x * pattern_ibuf->y; j++) { + if (pattern_ibuf->rect_float) { + add_v3_v3(site->color, &pattern_ibuf->rect_float[4 * j]); + } + else { + unsigned char *rrgb = (unsigned char *)pattern_ibuf->rect; + + site->color[0] += srgb_to_linearrgb((float)rrgb[4 * j + 0] / 255.0f); + site->color[1] += srgb_to_linearrgb((float)rrgb[4 * j + 1] / 255.0f); + site->color[2] += srgb_to_linearrgb((float)rrgb[4 * j + 2] / 255.0f); + } + } + + mul_v3_fl(site->color, 1.0f / (pattern_ibuf->x * pattern_ibuf->y)); + IMB_freeImBuf(pattern_ibuf); + } + + site->co[0] = pos[0] * width; + site->co[1] = pos[1] * height; + + site++; + } + + IMB_freeImBuf(ibuf); + + BLI_voronoi_compute(sites, sites_total, width, height, &edges); + + BLI_voronoi_triangulate(sites, + sites_total, + &edges, + width, + height, + &triangulation->triangulated_points, + &triangulation->triangulated_points_total, + &triangulation->triangles, + &triangulation->triangles_total); + + MEM_freeN(sites); + BLI_freelistN(&edges); + + if (triangulation->triangles_total) { + rcti *rect; + rect = triangulation->triangles_AABB = (rcti *)MEM_callocN( + sizeof(rcti) * triangulation->triangles_total, "voronoi triangulation AABB"); + + for (i = 0; i < triangulation->triangles_total; i++, rect++) { + int *triangle = triangulation->triangles[i]; + VoronoiTriangulationPoint *a = &triangulation->triangulated_points[triangle[0]], + *b = &triangulation->triangulated_points[triangle[1]], + *c = &triangulation->triangulated_points[triangle[2]]; + + float min[2], max[2]; + + INIT_MINMAX2(min, max); + + minmax_v2v2_v2(min, max, a->co); + minmax_v2v2_v2(min, max, b->co); + minmax_v2v2_v2(min, max, c->co); + + rect->xmin = (int)min[0]; + rect->ymin = (int)min[1]; + + rect->xmax = (int)max[0] + 1; + rect->ymax = (int)max[1] + 1; + } + } + + return triangulation; +} + +void *KeyingScreenOperation::initializeTileData(rcti *rect) +{ + TileData *tile_data; + TriangulationData *triangulation; + int triangles_allocated = 0; + int chunk_size = 20; + int i; + + if (this->m_movieClip == nullptr) { + return nullptr; + } + + if (!this->m_cachedTriangulation) { + lockMutex(); + if (this->m_cachedTriangulation == nullptr) { + this->m_cachedTriangulation = buildVoronoiTriangulation(); + } + unlockMutex(); + } + + triangulation = this->m_cachedTriangulation; + + if (!triangulation) { + return nullptr; + } + + tile_data = (TileData *)MEM_callocN(sizeof(TileData), "keying screen tile data"); + + for (i = 0; i < triangulation->triangles_total; i++) { + if (BLI_rcti_isect(rect, &triangulation->triangles_AABB[i], nullptr)) { + tile_data->triangles_total++; + + if (tile_data->triangles_total > triangles_allocated) { + if (!tile_data->triangles) { + tile_data->triangles = (int *)MEM_mallocN(sizeof(int) * chunk_size, + "keying screen tile triangles chunk"); + } + else { + tile_data->triangles = (int *)MEM_reallocN( + tile_data->triangles, sizeof(int) * (triangles_allocated + chunk_size)); + } + + triangles_allocated += chunk_size; + } + + tile_data->triangles[tile_data->triangles_total - 1] = i; + } + } + + return tile_data; +} + +void KeyingScreenOperation::deinitializeTileData(rcti * /*rect*/, void *data) +{ + TileData *tile_data = (TileData *)data; + + if (tile_data->triangles) { + MEM_freeN(tile_data->triangles); + } + + MEM_freeN(tile_data); +} + +void KeyingScreenOperation::determineResolution(unsigned int resolution[2], + unsigned int /*preferredResolution*/[2]) +{ + resolution[0] = 0; + resolution[1] = 0; + + if (this->m_movieClip) { + MovieClipUser user = {0}; + int width, height; + int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, + this->m_framenumber); + + BKE_movieclip_user_set_frame(&user, clip_frame); + BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height); + + resolution[0] = width; + resolution[1] = height; + } +} + +void KeyingScreenOperation::executePixel(float output[4], int x, int y, void *data) +{ + output[0] = 0.0f; + output[1] = 0.0f; + output[2] = 0.0f; + output[3] = 1.0f; + + if (this->m_movieClip && data) { + TriangulationData *triangulation = this->m_cachedTriangulation; + TileData *tile_data = (TileData *)data; + int i; + float co[2] = {(float)x, (float)y}; + + for (i = 0; i < tile_data->triangles_total; i++) { + int triangle_idx = tile_data->triangles[i]; + rcti *rect = &triangulation->triangles_AABB[triangle_idx]; + + if (IN_RANGE_INCL(x, rect->xmin, rect->xmax) && IN_RANGE_INCL(y, rect->ymin, rect->ymax)) { + int *triangle = triangulation->triangles[triangle_idx]; + VoronoiTriangulationPoint *a = &triangulation->triangulated_points[triangle[0]], + *b = &triangulation->triangulated_points[triangle[1]], + *c = &triangulation->triangulated_points[triangle[2]]; + float w[3]; + + if (barycentric_coords_v2(a->co, b->co, c->co, co, w)) { + if (barycentric_inside_triangle_v2(w)) { + output[0] = a->color[0] * w[0] + b->color[0] * w[1] + c->color[0] * w[2]; + output[1] = a->color[1] * w[0] + b->color[1] * w[1] + c->color[1] * w[2]; + output[2] = a->color[2] * w[0] + b->color[2] * w[1] + c->color[2] * w[2]; + + break; + } + } + } + } + } +} diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp b/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp deleted file mode 100644 index 463a6fe49c0..00000000000 --- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp +++ /dev/null @@ -1,346 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_KeyingScreenOperation.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_math_color.h" - -#include "BKE_movieclip.h" -#include "BKE_tracking.h" - -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -KeyingScreenOperation::KeyingScreenOperation() -{ - this->addOutputSocket(COM_DT_COLOR); - this->m_movieClip = nullptr; - this->m_framenumber = 0; - this->m_trackingObject[0] = 0; - setComplex(true); -} - -void KeyingScreenOperation::initExecution() -{ - initMutex(); - this->m_cachedTriangulation = nullptr; -} - -void KeyingScreenOperation::deinitExecution() -{ - if (this->m_cachedTriangulation) { - TriangulationData *triangulation = this->m_cachedTriangulation; - - if (triangulation->triangulated_points) { - MEM_freeN(triangulation->triangulated_points); - } - - if (triangulation->triangles) { - MEM_freeN(triangulation->triangles); - } - - if (triangulation->triangles_AABB) { - MEM_freeN(triangulation->triangles_AABB); - } - - MEM_freeN(this->m_cachedTriangulation); - - this->m_cachedTriangulation = nullptr; - } -} - -KeyingScreenOperation::TriangulationData *KeyingScreenOperation::buildVoronoiTriangulation() -{ - MovieClipUser user = {0}; - TriangulationData *triangulation; - MovieTracking *tracking = &this->m_movieClip->tracking; - MovieTrackingTrack *track; - VoronoiSite *sites, *site; - ImBuf *ibuf; - ListBase *tracksbase; - ListBase edges = {nullptr, nullptr}; - int sites_total; - int i; - int width = this->getWidth(); - int height = this->getHeight(); - int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber); - - if (this->m_trackingObject[0]) { - MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, this->m_trackingObject); - - if (!object) { - return nullptr; - } - - tracksbase = BKE_tracking_object_get_tracks(tracking, object); - } - else { - tracksbase = BKE_tracking_get_active_tracks(tracking); - } - - /* count sites */ - for (track = (MovieTrackingTrack *)tracksbase->first, sites_total = 0; track; - track = track->next) { - MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame); - float pos[2]; - - if (marker->flag & MARKER_DISABLED) { - continue; - } - - add_v2_v2v2(pos, marker->pos, track->offset); - - if (!IN_RANGE_INCL(pos[0], 0.0f, 1.0f) || !IN_RANGE_INCL(pos[1], 0.0f, 1.0f)) { - continue; - } - - sites_total++; - } - - if (!sites_total) { - return nullptr; - } - - BKE_movieclip_user_set_frame(&user, clip_frame); - ibuf = BKE_movieclip_get_ibuf(this->m_movieClip, &user); - - if (!ibuf) { - return nullptr; - } - - triangulation = (TriangulationData *)MEM_callocN(sizeof(TriangulationData), - "keying screen triangulation data"); - - sites = (VoronoiSite *)MEM_callocN(sizeof(VoronoiSite) * sites_total, - "keyingscreen voronoi sites"); - track = (MovieTrackingTrack *)tracksbase->first; - for (track = (MovieTrackingTrack *)tracksbase->first, site = sites; track; track = track->next) { - MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame); - ImBuf *pattern_ibuf; - int j; - float pos[2]; - - if (marker->flag & MARKER_DISABLED) { - continue; - } - - add_v2_v2v2(pos, marker->pos, track->offset); - - if (!IN_RANGE_INCL(pos[0], 0.0f, 1.0f) || !IN_RANGE_INCL(pos[1], 0.0f, 1.0f)) { - continue; - } - - pattern_ibuf = BKE_tracking_get_pattern_imbuf(ibuf, track, marker, true, false); - - zero_v3(site->color); - - if (pattern_ibuf) { - for (j = 0; j < pattern_ibuf->x * pattern_ibuf->y; j++) { - if (pattern_ibuf->rect_float) { - add_v3_v3(site->color, &pattern_ibuf->rect_float[4 * j]); - } - else { - unsigned char *rrgb = (unsigned char *)pattern_ibuf->rect; - - site->color[0] += srgb_to_linearrgb((float)rrgb[4 * j + 0] / 255.0f); - site->color[1] += srgb_to_linearrgb((float)rrgb[4 * j + 1] / 255.0f); - site->color[2] += srgb_to_linearrgb((float)rrgb[4 * j + 2] / 255.0f); - } - } - - mul_v3_fl(site->color, 1.0f / (pattern_ibuf->x * pattern_ibuf->y)); - IMB_freeImBuf(pattern_ibuf); - } - - site->co[0] = pos[0] * width; - site->co[1] = pos[1] * height; - - site++; - } - - IMB_freeImBuf(ibuf); - - BLI_voronoi_compute(sites, sites_total, width, height, &edges); - - BLI_voronoi_triangulate(sites, - sites_total, - &edges, - width, - height, - &triangulation->triangulated_points, - &triangulation->triangulated_points_total, - &triangulation->triangles, - &triangulation->triangles_total); - - MEM_freeN(sites); - BLI_freelistN(&edges); - - if (triangulation->triangles_total) { - rcti *rect; - rect = triangulation->triangles_AABB = (rcti *)MEM_callocN( - sizeof(rcti) * triangulation->triangles_total, "voronoi triangulation AABB"); - - for (i = 0; i < triangulation->triangles_total; i++, rect++) { - int *triangle = triangulation->triangles[i]; - VoronoiTriangulationPoint *a = &triangulation->triangulated_points[triangle[0]], - *b = &triangulation->triangulated_points[triangle[1]], - *c = &triangulation->triangulated_points[triangle[2]]; - - float min[2], max[2]; - - INIT_MINMAX2(min, max); - - minmax_v2v2_v2(min, max, a->co); - minmax_v2v2_v2(min, max, b->co); - minmax_v2v2_v2(min, max, c->co); - - rect->xmin = (int)min[0]; - rect->ymin = (int)min[1]; - - rect->xmax = (int)max[0] + 1; - rect->ymax = (int)max[1] + 1; - } - } - - return triangulation; -} - -void *KeyingScreenOperation::initializeTileData(rcti *rect) -{ - TileData *tile_data; - TriangulationData *triangulation; - int triangles_allocated = 0; - int chunk_size = 20; - int i; - - if (this->m_movieClip == nullptr) { - return nullptr; - } - - if (!this->m_cachedTriangulation) { - lockMutex(); - if (this->m_cachedTriangulation == nullptr) { - this->m_cachedTriangulation = buildVoronoiTriangulation(); - } - unlockMutex(); - } - - triangulation = this->m_cachedTriangulation; - - if (!triangulation) { - return nullptr; - } - - tile_data = (TileData *)MEM_callocN(sizeof(TileData), "keying screen tile data"); - - for (i = 0; i < triangulation->triangles_total; i++) { - if (BLI_rcti_isect(rect, &triangulation->triangles_AABB[i], nullptr)) { - tile_data->triangles_total++; - - if (tile_data->triangles_total > triangles_allocated) { - if (!tile_data->triangles) { - tile_data->triangles = (int *)MEM_mallocN(sizeof(int) * chunk_size, - "keying screen tile triangles chunk"); - } - else { - tile_data->triangles = (int *)MEM_reallocN( - tile_data->triangles, sizeof(int) * (triangles_allocated + chunk_size)); - } - - triangles_allocated += chunk_size; - } - - tile_data->triangles[tile_data->triangles_total - 1] = i; - } - } - - return tile_data; -} - -void KeyingScreenOperation::deinitializeTileData(rcti * /*rect*/, void *data) -{ - TileData *tile_data = (TileData *)data; - - if (tile_data->triangles) { - MEM_freeN(tile_data->triangles); - } - - MEM_freeN(tile_data); -} - -void KeyingScreenOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) -{ - resolution[0] = 0; - resolution[1] = 0; - - if (this->m_movieClip) { - MovieClipUser user = {0}; - int width, height; - int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, - this->m_framenumber); - - BKE_movieclip_user_set_frame(&user, clip_frame); - BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height); - - resolution[0] = width; - resolution[1] = height; - } -} - -void KeyingScreenOperation::executePixel(float output[4], int x, int y, void *data) -{ - output[0] = 0.0f; - output[1] = 0.0f; - output[2] = 0.0f; - output[3] = 1.0f; - - if (this->m_movieClip && data) { - TriangulationData *triangulation = this->m_cachedTriangulation; - TileData *tile_data = (TileData *)data; - int i; - float co[2] = {(float)x, (float)y}; - - for (i = 0; i < tile_data->triangles_total; i++) { - int triangle_idx = tile_data->triangles[i]; - rcti *rect = &triangulation->triangles_AABB[triangle_idx]; - - if (IN_RANGE_INCL(x, rect->xmin, rect->xmax) && IN_RANGE_INCL(y, rect->ymin, rect->ymax)) { - int *triangle = triangulation->triangles[triangle_idx]; - VoronoiTriangulationPoint *a = &triangulation->triangulated_points[triangle[0]], - *b = &triangulation->triangulated_points[triangle[1]], - *c = &triangulation->triangulated_points[triangle[2]]; - float w[3]; - - if (barycentric_coords_v2(a->co, b->co, c->co, co, w)) { - if (barycentric_inside_triangle_v2(w)) { - output[0] = a->color[0] * w[0] + b->color[0] * w[1] + c->color[0] * w[2]; - output[1] = a->color[1] * w[0] + b->color[1] * w[1] + c->color[1] * w[2]; - output[2] = a->color[2] * w[0] + b->color[2] * w[1] + c->color[2] * w[2]; - - break; - } - } - } - } - } -} diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc new file mode 100644 index 00000000000..2bd7493625e --- /dev/null +++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc @@ -0,0 +1,77 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_LuminanceMatteOperation.h" +#include "BLI_math.h" + +#include "IMB_colormanagement.h" + +LuminanceMatteOperation::LuminanceMatteOperation() +{ + addInputSocket(COM_DT_COLOR); + addOutputSocket(COM_DT_VALUE); + + this->m_inputImageProgram = nullptr; +} + +void LuminanceMatteOperation::initExecution() +{ + this->m_inputImageProgram = this->getInputSocketReader(0); +} + +void LuminanceMatteOperation::deinitExecution() +{ + this->m_inputImageProgram = nullptr; +} + +void LuminanceMatteOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inColor[4]; + this->m_inputImageProgram->readSampled(inColor, x, y, sampler); + + const float high = this->m_settings->t1; + const float low = this->m_settings->t2; + const float luminance = IMB_colormanagement_get_luminance(inColor); + + float alpha; + + /* one line thread-friend algorithm: + * output[0] = MIN2(inputValue[3], MIN2(1.0f, MAX2(0.0f, ((luminance - low) / (high - low)))); + */ + + /* test range */ + if (luminance > high) { + alpha = 1.0f; + } + else if (luminance < low) { + alpha = 0.0f; + } + else { /*blend */ + alpha = (luminance - low) / (high - low); + } + + /* Store matte(alpha) value in [0] to go with + * COM_SetAlphaMultiplyOperation and the Value output. + */ + + /* don't make something that was more transparent less transparent */ + output[0] = min_ff(alpha, inColor[3]); +} diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp deleted file mode 100644 index 2bd7493625e..00000000000 --- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_LuminanceMatteOperation.h" -#include "BLI_math.h" - -#include "IMB_colormanagement.h" - -LuminanceMatteOperation::LuminanceMatteOperation() -{ - addInputSocket(COM_DT_COLOR); - addOutputSocket(COM_DT_VALUE); - - this->m_inputImageProgram = nullptr; -} - -void LuminanceMatteOperation::initExecution() -{ - this->m_inputImageProgram = this->getInputSocketReader(0); -} - -void LuminanceMatteOperation::deinitExecution() -{ - this->m_inputImageProgram = nullptr; -} - -void LuminanceMatteOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inColor[4]; - this->m_inputImageProgram->readSampled(inColor, x, y, sampler); - - const float high = this->m_settings->t1; - const float low = this->m_settings->t2; - const float luminance = IMB_colormanagement_get_luminance(inColor); - - float alpha; - - /* one line thread-friend algorithm: - * output[0] = MIN2(inputValue[3], MIN2(1.0f, MAX2(0.0f, ((luminance - low) / (high - low)))); - */ - - /* test range */ - if (luminance > high) { - alpha = 1.0f; - } - else if (luminance < low) { - alpha = 0.0f; - } - else { /*blend */ - alpha = (luminance - low) / (high - low); - } - - /* Store matte(alpha) value in [0] to go with - * COM_SetAlphaMultiplyOperation and the Value output. - */ - - /* don't make something that was more transparent less transparent */ - output[0] = min_ff(alpha, inColor[3]); -} diff --git a/source/blender/compositor/operations/COM_MapRangeOperation.cc b/source/blender/compositor/operations/COM_MapRangeOperation.cc new file mode 100644 index 00000000000..95b3c27ac2f --- /dev/null +++ b/source/blender/compositor/operations/COM_MapRangeOperation.cc @@ -0,0 +1,103 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_MapRangeOperation.h" + +MapRangeOperation::MapRangeOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->m_inputOperation = nullptr; + this->m_useClamp = false; +} + +void MapRangeOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); + this->m_sourceMinOperation = this->getInputSocketReader(1); + this->m_sourceMaxOperation = this->getInputSocketReader(2); + this->m_destMinOperation = this->getInputSocketReader(3); + this->m_destMaxOperation = this->getInputSocketReader(4); +} + +/* The code below assumes all data is inside range +- this, and that input buffer is single channel + */ +#define BLENDER_ZMAX 10000.0f + +void MapRangeOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputs[8]; /* includes the 5 inputs + 3 pads */ + float value; + float source_min, source_max; + float dest_min, dest_max; + + this->m_inputOperation->readSampled(inputs, x, y, sampler); + this->m_sourceMinOperation->readSampled(inputs + 1, x, y, sampler); + this->m_sourceMaxOperation->readSampled(inputs + 2, x, y, sampler); + this->m_destMinOperation->readSampled(inputs + 3, x, y, sampler); + this->m_destMaxOperation->readSampled(inputs + 4, x, y, sampler); + + value = inputs[0]; + source_min = inputs[1]; + source_max = inputs[2]; + dest_min = inputs[3]; + dest_max = inputs[4]; + + if (fabsf(source_max - source_min) < 1e-6f) { + output[0] = 0.0f; + return; + } + + if (value >= -BLENDER_ZMAX && value <= BLENDER_ZMAX) { + value = (value - source_min) / (source_max - source_min); + value = dest_min + value * (dest_max - dest_min); + } + else if (value > BLENDER_ZMAX) { + value = dest_max; + } + else { + value = dest_min; + } + + if (this->m_useClamp) { + if (dest_max > dest_min) { + CLAMP(value, dest_min, dest_max); + } + else { + CLAMP(value, dest_max, dest_min); + } + } + + output[0] = value; +} + +void MapRangeOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; + this->m_sourceMinOperation = nullptr; + this->m_sourceMaxOperation = nullptr; + this->m_destMinOperation = nullptr; + this->m_destMaxOperation = nullptr; +} diff --git a/source/blender/compositor/operations/COM_MapRangeOperation.cpp b/source/blender/compositor/operations/COM_MapRangeOperation.cpp deleted file mode 100644 index 95b3c27ac2f..00000000000 --- a/source/blender/compositor/operations/COM_MapRangeOperation.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_MapRangeOperation.h" - -MapRangeOperation::MapRangeOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputOperation = nullptr; - this->m_useClamp = false; -} - -void MapRangeOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); - this->m_sourceMinOperation = this->getInputSocketReader(1); - this->m_sourceMaxOperation = this->getInputSocketReader(2); - this->m_destMinOperation = this->getInputSocketReader(3); - this->m_destMaxOperation = this->getInputSocketReader(4); -} - -/* The code below assumes all data is inside range +- this, and that input buffer is single channel - */ -#define BLENDER_ZMAX 10000.0f - -void MapRangeOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputs[8]; /* includes the 5 inputs + 3 pads */ - float value; - float source_min, source_max; - float dest_min, dest_max; - - this->m_inputOperation->readSampled(inputs, x, y, sampler); - this->m_sourceMinOperation->readSampled(inputs + 1, x, y, sampler); - this->m_sourceMaxOperation->readSampled(inputs + 2, x, y, sampler); - this->m_destMinOperation->readSampled(inputs + 3, x, y, sampler); - this->m_destMaxOperation->readSampled(inputs + 4, x, y, sampler); - - value = inputs[0]; - source_min = inputs[1]; - source_max = inputs[2]; - dest_min = inputs[3]; - dest_max = inputs[4]; - - if (fabsf(source_max - source_min) < 1e-6f) { - output[0] = 0.0f; - return; - } - - if (value >= -BLENDER_ZMAX && value <= BLENDER_ZMAX) { - value = (value - source_min) / (source_max - source_min); - value = dest_min + value * (dest_max - dest_min); - } - else if (value > BLENDER_ZMAX) { - value = dest_max; - } - else { - value = dest_min; - } - - if (this->m_useClamp) { - if (dest_max > dest_min) { - CLAMP(value, dest_min, dest_max); - } - else { - CLAMP(value, dest_max, dest_min); - } - } - - output[0] = value; -} - -void MapRangeOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; - this->m_sourceMinOperation = nullptr; - this->m_sourceMaxOperation = nullptr; - this->m_destMinOperation = nullptr; - this->m_destMaxOperation = nullptr; -} diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cc b/source/blender/compositor/operations/COM_MapUVOperation.cc new file mode 100644 index 00000000000..32ab63ae028 --- /dev/null +++ b/source/blender/compositor/operations/COM_MapUVOperation.cc @@ -0,0 +1,185 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MapUVOperation.h" +#include "BLI_math.h" + +MapUVOperation::MapUVOperation() +{ + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); + this->addInputSocket(COM_DT_VECTOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_alpha = 0.0f; + this->setComplex(true); + setResolutionInputSocketIndex(1); + + this->m_inputUVProgram = nullptr; + this->m_inputColorProgram = nullptr; +} + +void MapUVOperation::initExecution() +{ + this->m_inputColorProgram = this->getInputSocketReader(0); + this->m_inputUVProgram = this->getInputSocketReader(1); +} + +void MapUVOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + float xy[2] = {x, y}; + float uv[2], deriv[2][2], alpha; + + pixelTransform(xy, uv, deriv, alpha); + if (alpha == 0.0f) { + zero_v4(output); + return; + } + + /* EWA filtering */ + this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]); + + /* UV to alpha threshold */ + const float threshold = this->m_alpha * 0.05f; + /* XXX alpha threshold is used to fade out pixels on boundaries with invalid derivatives. + * this calculation is not very well defined, should be looked into if it becomes a problem ... + */ + float du = len_v2(deriv[0]); + float dv = len_v2(deriv[1]); + float factor = 1.0f - threshold * (du / m_inputColorProgram->getWidth() + + dv / m_inputColorProgram->getHeight()); + if (factor < 0.0f) { + alpha = 0.0f; + } + else { + alpha *= factor; + } + + /* "premul" */ + if (alpha < 1.0f) { + mul_v4_fl(output, alpha); + } +} + +bool MapUVOperation::read_uv(float x, float y, float &r_u, float &r_v, float &r_alpha) +{ + float width = m_inputUVProgram->getWidth(); + float height = m_inputUVProgram->getHeight(); + if (x < 0.0f || x >= width || y < 0.0f || y >= height) { + r_u = 0.0f; + r_v = 0.0f; + r_alpha = 0.0f; + return false; + } + + float vector[3]; + m_inputUVProgram->readSampled(vector, x, y, COM_PS_BILINEAR); + r_u = vector[0] * m_inputColorProgram->getWidth(); + r_v = vector[1] * m_inputColorProgram->getHeight(); + r_alpha = vector[2]; + return true; +} + +void MapUVOperation::pixelTransform(const float xy[2], + float r_uv[2], + float r_deriv[2][2], + float &r_alpha) +{ + float uv[2], alpha; /* temporary variables for derivative estimation */ + int num; + + read_uv(xy[0], xy[1], r_uv[0], r_uv[1], r_alpha); + + /* Estimate partial derivatives using 1-pixel offsets */ + const float epsilon[2] = {1.0f, 1.0f}; + + zero_v2(r_deriv[0]); + zero_v2(r_deriv[1]); + + num = 0; + if (read_uv(xy[0] + epsilon[0], xy[1], uv[0], uv[1], alpha)) { + r_deriv[0][0] += uv[0] - r_uv[0]; + r_deriv[1][0] += uv[1] - r_uv[1]; + num++; + } + if (read_uv(xy[0] - epsilon[0], xy[1], uv[0], uv[1], alpha)) { + r_deriv[0][0] += r_uv[0] - uv[0]; + r_deriv[1][0] += r_uv[1] - uv[1]; + num++; + } + if (num > 0) { + float numinv = 1.0f / (float)num; + r_deriv[0][0] *= numinv; + r_deriv[1][0] *= numinv; + } + + num = 0; + if (read_uv(xy[0], xy[1] + epsilon[1], uv[0], uv[1], alpha)) { + r_deriv[0][1] += uv[0] - r_uv[0]; + r_deriv[1][1] += uv[1] - r_uv[1]; + num++; + } + if (read_uv(xy[0], xy[1] - epsilon[1], uv[0], uv[1], alpha)) { + r_deriv[0][1] += r_uv[0] - uv[0]; + r_deriv[1][1] += r_uv[1] - uv[1]; + num++; + } + if (num > 0) { + float numinv = 1.0f / (float)num; + r_deriv[0][1] *= numinv; + r_deriv[1][1] *= numinv; + } +} + +void MapUVOperation::deinitExecution() +{ + this->m_inputUVProgram = nullptr; + this->m_inputColorProgram = nullptr; +} + +bool MapUVOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti colorInput; + rcti uvInput; + NodeOperation *operation = nullptr; + + /* the uv buffer only needs a 3x3 buffer. The image needs whole buffer */ + + operation = getInputOperation(0); + colorInput.xmax = operation->getWidth(); + colorInput.xmin = 0; + colorInput.ymax = operation->getHeight(); + colorInput.ymin = 0; + if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) { + return true; + } + + operation = getInputOperation(1); + uvInput.xmax = input->xmax + 1; + uvInput.xmin = input->xmin - 1; + uvInput.ymax = input->ymax + 1; + uvInput.ymin = input->ymin - 1; + if (operation->determineDependingAreaOfInterest(&uvInput, readOperation, output)) { + return true; + } + + return false; +} diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp deleted file mode 100644 index 32ab63ae028..00000000000 --- a/source/blender/compositor/operations/COM_MapUVOperation.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MapUVOperation.h" -#include "BLI_math.h" - -MapUVOperation::MapUVOperation() -{ - this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); - this->addInputSocket(COM_DT_VECTOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_alpha = 0.0f; - this->setComplex(true); - setResolutionInputSocketIndex(1); - - this->m_inputUVProgram = nullptr; - this->m_inputColorProgram = nullptr; -} - -void MapUVOperation::initExecution() -{ - this->m_inputColorProgram = this->getInputSocketReader(0); - this->m_inputUVProgram = this->getInputSocketReader(1); -} - -void MapUVOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - float xy[2] = {x, y}; - float uv[2], deriv[2][2], alpha; - - pixelTransform(xy, uv, deriv, alpha); - if (alpha == 0.0f) { - zero_v4(output); - return; - } - - /* EWA filtering */ - this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]); - - /* UV to alpha threshold */ - const float threshold = this->m_alpha * 0.05f; - /* XXX alpha threshold is used to fade out pixels on boundaries with invalid derivatives. - * this calculation is not very well defined, should be looked into if it becomes a problem ... - */ - float du = len_v2(deriv[0]); - float dv = len_v2(deriv[1]); - float factor = 1.0f - threshold * (du / m_inputColorProgram->getWidth() + - dv / m_inputColorProgram->getHeight()); - if (factor < 0.0f) { - alpha = 0.0f; - } - else { - alpha *= factor; - } - - /* "premul" */ - if (alpha < 1.0f) { - mul_v4_fl(output, alpha); - } -} - -bool MapUVOperation::read_uv(float x, float y, float &r_u, float &r_v, float &r_alpha) -{ - float width = m_inputUVProgram->getWidth(); - float height = m_inputUVProgram->getHeight(); - if (x < 0.0f || x >= width || y < 0.0f || y >= height) { - r_u = 0.0f; - r_v = 0.0f; - r_alpha = 0.0f; - return false; - } - - float vector[3]; - m_inputUVProgram->readSampled(vector, x, y, COM_PS_BILINEAR); - r_u = vector[0] * m_inputColorProgram->getWidth(); - r_v = vector[1] * m_inputColorProgram->getHeight(); - r_alpha = vector[2]; - return true; -} - -void MapUVOperation::pixelTransform(const float xy[2], - float r_uv[2], - float r_deriv[2][2], - float &r_alpha) -{ - float uv[2], alpha; /* temporary variables for derivative estimation */ - int num; - - read_uv(xy[0], xy[1], r_uv[0], r_uv[1], r_alpha); - - /* Estimate partial derivatives using 1-pixel offsets */ - const float epsilon[2] = {1.0f, 1.0f}; - - zero_v2(r_deriv[0]); - zero_v2(r_deriv[1]); - - num = 0; - if (read_uv(xy[0] + epsilon[0], xy[1], uv[0], uv[1], alpha)) { - r_deriv[0][0] += uv[0] - r_uv[0]; - r_deriv[1][0] += uv[1] - r_uv[1]; - num++; - } - if (read_uv(xy[0] - epsilon[0], xy[1], uv[0], uv[1], alpha)) { - r_deriv[0][0] += r_uv[0] - uv[0]; - r_deriv[1][0] += r_uv[1] - uv[1]; - num++; - } - if (num > 0) { - float numinv = 1.0f / (float)num; - r_deriv[0][0] *= numinv; - r_deriv[1][0] *= numinv; - } - - num = 0; - if (read_uv(xy[0], xy[1] + epsilon[1], uv[0], uv[1], alpha)) { - r_deriv[0][1] += uv[0] - r_uv[0]; - r_deriv[1][1] += uv[1] - r_uv[1]; - num++; - } - if (read_uv(xy[0], xy[1] - epsilon[1], uv[0], uv[1], alpha)) { - r_deriv[0][1] += r_uv[0] - uv[0]; - r_deriv[1][1] += r_uv[1] - uv[1]; - num++; - } - if (num > 0) { - float numinv = 1.0f / (float)num; - r_deriv[0][1] *= numinv; - r_deriv[1][1] *= numinv; - } -} - -void MapUVOperation::deinitExecution() -{ - this->m_inputUVProgram = nullptr; - this->m_inputColorProgram = nullptr; -} - -bool MapUVOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti colorInput; - rcti uvInput; - NodeOperation *operation = nullptr; - - /* the uv buffer only needs a 3x3 buffer. The image needs whole buffer */ - - operation = getInputOperation(0); - colorInput.xmax = operation->getWidth(); - colorInput.xmin = 0; - colorInput.ymax = operation->getHeight(); - colorInput.ymin = 0; - if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) { - return true; - } - - operation = getInputOperation(1); - uvInput.xmax = input->xmax + 1; - uvInput.xmin = input->xmin - 1; - uvInput.ymax = input->ymax + 1; - uvInput.ymin = input->ymin - 1; - if (operation->determineDependingAreaOfInterest(&uvInput, readOperation, output)) { - return true; - } - - return false; -} diff --git a/source/blender/compositor/operations/COM_MapValueOperation.cc b/source/blender/compositor/operations/COM_MapValueOperation.cc new file mode 100644 index 00000000000..7f2044b9139 --- /dev/null +++ b/source/blender/compositor/operations/COM_MapValueOperation.cc @@ -0,0 +1,59 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MapValueOperation.h" + +MapValueOperation::MapValueOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->m_inputOperation = nullptr; +} + +void MapValueOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); +} + +void MapValueOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float src[4]; + this->m_inputOperation->readSampled(src, x, y, sampler); + TexMapping *texmap = this->m_settings; + float value = (src[0] + texmap->loc[0]) * texmap->size[0]; + if (texmap->flag & TEXMAP_CLIP_MIN) { + if (value < texmap->min[0]) { + value = texmap->min[0]; + } + } + if (texmap->flag & TEXMAP_CLIP_MAX) { + if (value > texmap->max[0]) { + value = texmap->max[0]; + } + } + + output[0] = value; +} + +void MapValueOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; +} diff --git a/source/blender/compositor/operations/COM_MapValueOperation.cpp b/source/blender/compositor/operations/COM_MapValueOperation.cpp deleted file mode 100644 index 7f2044b9139..00000000000 --- a/source/blender/compositor/operations/COM_MapValueOperation.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MapValueOperation.h" - -MapValueOperation::MapValueOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputOperation = nullptr; -} - -void MapValueOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void MapValueOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float src[4]; - this->m_inputOperation->readSampled(src, x, y, sampler); - TexMapping *texmap = this->m_settings; - float value = (src[0] + texmap->loc[0]) * texmap->size[0]; - if (texmap->flag & TEXMAP_CLIP_MIN) { - if (value < texmap->min[0]) { - value = texmap->min[0]; - } - } - if (texmap->flag & TEXMAP_CLIP_MAX) { - if (value > texmap->max[0]) { - value = texmap->max[0]; - } - } - - output[0] = value; -} - -void MapValueOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; -} diff --git a/source/blender/compositor/operations/COM_MaskOperation.cc b/source/blender/compositor/operations/COM_MaskOperation.cc new file mode 100644 index 00000000000..ab908590c55 --- /dev/null +++ b/source/blender/compositor/operations/COM_MaskOperation.cc @@ -0,0 +1,160 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_MaskOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "BKE_lib_id.h" +#include "BKE_mask.h" + +MaskOperation::MaskOperation() +{ + this->addOutputSocket(COM_DT_VALUE); + this->m_mask = nullptr; + this->m_maskWidth = 0; + this->m_maskHeight = 0; + this->m_maskWidthInv = 0.0f; + this->m_maskHeightInv = 0.0f; + this->m_frame_shutter = 0.0f; + this->m_frame_number = 0; + this->m_rasterMaskHandleTot = 1; + memset(this->m_rasterMaskHandles, 0, sizeof(this->m_rasterMaskHandles)); +} + +void MaskOperation::initExecution() +{ + if (this->m_mask && this->m_rasterMaskHandles[0] == nullptr) { + if (this->m_rasterMaskHandleTot == 1) { + this->m_rasterMaskHandles[0] = BKE_maskrasterize_handle_new(); + + BKE_maskrasterize_handle_init(this->m_rasterMaskHandles[0], + this->m_mask, + this->m_maskWidth, + this->m_maskHeight, + true, + true, + this->m_do_feather); + } + else { + /* make a throw away copy of the mask */ + const float frame = (float)this->m_frame_number - this->m_frame_shutter; + const float frame_step = (this->m_frame_shutter * 2.0f) / this->m_rasterMaskHandleTot; + float frame_iter = frame; + + Mask *mask_temp = (Mask *)BKE_id_copy_ex( + nullptr, &this->m_mask->id, nullptr, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA); + + /* trick so we can get unkeyed edits to display */ + { + MaskLayer *masklay; + MaskLayerShape *masklay_shape; + + for (masklay = (MaskLayer *)mask_temp->masklayers.first; masklay; + masklay = masklay->next) { + masklay_shape = BKE_mask_layer_shape_verify_frame(masklay, this->m_frame_number); + BKE_mask_layer_shape_from_mask(masklay, masklay_shape); + } + } + + for (unsigned int i = 0; i < this->m_rasterMaskHandleTot; i++) { + this->m_rasterMaskHandles[i] = BKE_maskrasterize_handle_new(); + + /* re-eval frame info */ + BKE_mask_evaluate(mask_temp, frame_iter, true); + + BKE_maskrasterize_handle_init(this->m_rasterMaskHandles[i], + mask_temp, + this->m_maskWidth, + this->m_maskHeight, + true, + true, + this->m_do_feather); + + frame_iter += frame_step; + } + + BKE_id_free(nullptr, &mask_temp->id); + } + } +} + +void MaskOperation::deinitExecution() +{ + for (unsigned int i = 0; i < this->m_rasterMaskHandleTot; i++) { + if (this->m_rasterMaskHandles[i]) { + BKE_maskrasterize_handle_free(this->m_rasterMaskHandles[i]); + this->m_rasterMaskHandles[i] = nullptr; + } + } +} + +void MaskOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + if (this->m_maskWidth == 0 || this->m_maskHeight == 0) { + NodeOperation::determineResolution(resolution, preferredResolution); + } + else { + unsigned int nr[2]; + + nr[0] = this->m_maskWidth; + nr[1] = this->m_maskHeight; + + NodeOperation::determineResolution(resolution, nr); + + resolution[0] = this->m_maskWidth; + resolution[1] = this->m_maskHeight; + } +} + +void MaskOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + const float xy[2] = { + (x * this->m_maskWidthInv) + this->m_mask_px_ofs[0], + (y * this->m_maskHeightInv) + this->m_mask_px_ofs[1], + }; + + if (this->m_rasterMaskHandleTot == 1) { + if (this->m_rasterMaskHandles[0]) { + output[0] = BKE_maskrasterize_handle_sample(this->m_rasterMaskHandles[0], xy); + } + else { + output[0] = 0.0f; + } + } + else { + /* In case loop below fails. */ + output[0] = 0.0f; + + for (unsigned int i = 0; i < this->m_rasterMaskHandleTot; i++) { + if (this->m_rasterMaskHandles[i]) { + output[0] += BKE_maskrasterize_handle_sample(this->m_rasterMaskHandles[i], xy); + } + } + + /* until we get better falloff */ + output[0] /= this->m_rasterMaskHandleTot; + } +} diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp deleted file mode 100644 index ab908590c55..00000000000 --- a/source/blender/compositor/operations/COM_MaskOperation.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_MaskOperation.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" - -#include "BKE_lib_id.h" -#include "BKE_mask.h" - -MaskOperation::MaskOperation() -{ - this->addOutputSocket(COM_DT_VALUE); - this->m_mask = nullptr; - this->m_maskWidth = 0; - this->m_maskHeight = 0; - this->m_maskWidthInv = 0.0f; - this->m_maskHeightInv = 0.0f; - this->m_frame_shutter = 0.0f; - this->m_frame_number = 0; - this->m_rasterMaskHandleTot = 1; - memset(this->m_rasterMaskHandles, 0, sizeof(this->m_rasterMaskHandles)); -} - -void MaskOperation::initExecution() -{ - if (this->m_mask && this->m_rasterMaskHandles[0] == nullptr) { - if (this->m_rasterMaskHandleTot == 1) { - this->m_rasterMaskHandles[0] = BKE_maskrasterize_handle_new(); - - BKE_maskrasterize_handle_init(this->m_rasterMaskHandles[0], - this->m_mask, - this->m_maskWidth, - this->m_maskHeight, - true, - true, - this->m_do_feather); - } - else { - /* make a throw away copy of the mask */ - const float frame = (float)this->m_frame_number - this->m_frame_shutter; - const float frame_step = (this->m_frame_shutter * 2.0f) / this->m_rasterMaskHandleTot; - float frame_iter = frame; - - Mask *mask_temp = (Mask *)BKE_id_copy_ex( - nullptr, &this->m_mask->id, nullptr, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA); - - /* trick so we can get unkeyed edits to display */ - { - MaskLayer *masklay; - MaskLayerShape *masklay_shape; - - for (masklay = (MaskLayer *)mask_temp->masklayers.first; masklay; - masklay = masklay->next) { - masklay_shape = BKE_mask_layer_shape_verify_frame(masklay, this->m_frame_number); - BKE_mask_layer_shape_from_mask(masklay, masklay_shape); - } - } - - for (unsigned int i = 0; i < this->m_rasterMaskHandleTot; i++) { - this->m_rasterMaskHandles[i] = BKE_maskrasterize_handle_new(); - - /* re-eval frame info */ - BKE_mask_evaluate(mask_temp, frame_iter, true); - - BKE_maskrasterize_handle_init(this->m_rasterMaskHandles[i], - mask_temp, - this->m_maskWidth, - this->m_maskHeight, - true, - true, - this->m_do_feather); - - frame_iter += frame_step; - } - - BKE_id_free(nullptr, &mask_temp->id); - } - } -} - -void MaskOperation::deinitExecution() -{ - for (unsigned int i = 0; i < this->m_rasterMaskHandleTot; i++) { - if (this->m_rasterMaskHandles[i]) { - BKE_maskrasterize_handle_free(this->m_rasterMaskHandles[i]); - this->m_rasterMaskHandles[i] = nullptr; - } - } -} - -void MaskOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - if (this->m_maskWidth == 0 || this->m_maskHeight == 0) { - NodeOperation::determineResolution(resolution, preferredResolution); - } - else { - unsigned int nr[2]; - - nr[0] = this->m_maskWidth; - nr[1] = this->m_maskHeight; - - NodeOperation::determineResolution(resolution, nr); - - resolution[0] = this->m_maskWidth; - resolution[1] = this->m_maskHeight; - } -} - -void MaskOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - const float xy[2] = { - (x * this->m_maskWidthInv) + this->m_mask_px_ofs[0], - (y * this->m_maskHeightInv) + this->m_mask_px_ofs[1], - }; - - if (this->m_rasterMaskHandleTot == 1) { - if (this->m_rasterMaskHandles[0]) { - output[0] = BKE_maskrasterize_handle_sample(this->m_rasterMaskHandles[0], xy); - } - else { - output[0] = 0.0f; - } - } - else { - /* In case loop below fails. */ - output[0] = 0.0f; - - for (unsigned int i = 0; i < this->m_rasterMaskHandleTot; i++) { - if (this->m_rasterMaskHandles[i]) { - output[0] += BKE_maskrasterize_handle_sample(this->m_rasterMaskHandles[i], xy); - } - } - - /* until we get better falloff */ - output[0] /= this->m_rasterMaskHandleTot; - } -} diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cc b/source/blender/compositor/operations/COM_MathBaseOperation.cc new file mode 100644 index 00000000000..692c1e70462 --- /dev/null +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cc @@ -0,0 +1,750 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MathBaseOperation.h" + +#include "BLI_math.h" + +MathBaseOperation::MathBaseOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->m_inputValue1Operation = nullptr; + this->m_inputValue2Operation = nullptr; + this->m_inputValue3Operation = nullptr; + this->m_useClamp = false; +} + +void MathBaseOperation::initExecution() +{ + this->m_inputValue1Operation = this->getInputSocketReader(0); + this->m_inputValue2Operation = this->getInputSocketReader(1); + this->m_inputValue3Operation = this->getInputSocketReader(2); +} + +void MathBaseOperation::deinitExecution() +{ + this->m_inputValue1Operation = nullptr; + this->m_inputValue2Operation = nullptr; + this->m_inputValue3Operation = nullptr; +} + +void MathBaseOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + NodeOperationInput *socket; + unsigned int tempPreferredResolution[2] = {0, 0}; + unsigned int tempResolution[2]; + + socket = this->getInputSocket(0); + socket->determineResolution(tempResolution, tempPreferredResolution); + if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { + this->setResolutionInputSocketIndex(0); + } + else { + this->setResolutionInputSocketIndex(1); + } + NodeOperation::determineResolution(resolution, preferredResolution); +} + +void MathBaseOperation::clampIfNeeded(float *color) +{ + if (this->m_useClamp) { + CLAMP(color[0], 0.0f, 1.0f); + } +} + +void MathAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = inputValue1[0] + inputValue2[0]; + + clampIfNeeded(output); +} + +void MathSubtractOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = inputValue1[0] - inputValue2[0]; + + clampIfNeeded(output); +} + +void MathMultiplyOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = inputValue1[0] * inputValue2[0]; + + clampIfNeeded(output); +} + +void MathDivideOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + if (inputValue2[0] == 0) { /* We don't want to divide by zero. */ + output[0] = 0.0; + } + else { + output[0] = inputValue1[0] / inputValue2[0]; + } + + clampIfNeeded(output); +} + +void MathSineOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = sin(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathCosineOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = cos(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathTangentOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = tan(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathHyperbolicSineOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = sinh(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathHyperbolicCosineOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = cosh(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathHyperbolicTangentOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = tanh(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathArcSineOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + if (inputValue1[0] <= 1 && inputValue1[0] >= -1) { + output[0] = asin(inputValue1[0]); + } + else { + output[0] = 0.0; + } + + clampIfNeeded(output); +} + +void MathArcCosineOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + if (inputValue1[0] <= 1 && inputValue1[0] >= -1) { + output[0] = acos(inputValue1[0]); + } + else { + output[0] = 0.0; + } + + clampIfNeeded(output); +} + +void MathArcTangentOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = atan(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathPowerOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + if (inputValue1[0] >= 0) { + output[0] = pow(inputValue1[0], inputValue2[0]); + } + else { + float y_mod_1 = fmod(inputValue2[0], 1); + /* if input value is not nearly an integer, fall back to zero, nicer than straight rounding */ + if (y_mod_1 > 0.999f || y_mod_1 < 0.001f) { + output[0] = pow(inputValue1[0], floorf(inputValue2[0] + 0.5f)); + } + else { + output[0] = 0.0; + } + } + + clampIfNeeded(output); +} + +void MathLogarithmOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + if (inputValue1[0] > 0 && inputValue2[0] > 0) { + output[0] = log(inputValue1[0]) / log(inputValue2[0]); + } + else { + output[0] = 0.0; + } + + clampIfNeeded(output); +} + +void MathMinimumOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = MIN2(inputValue1[0], inputValue2[0]); + + clampIfNeeded(output); +} + +void MathMaximumOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = MAX2(inputValue1[0], inputValue2[0]); + + clampIfNeeded(output); +} + +void MathRoundOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = round(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathLessThanOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = inputValue1[0] < inputValue2[0] ? 1.0f : 0.0f; + + clampIfNeeded(output); +} + +void MathGreaterThanOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = inputValue1[0] > inputValue2[0] ? 1.0f : 0.0f; + + clampIfNeeded(output); +} + +void MathModuloOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + if (inputValue2[0] == 0) { + output[0] = 0.0; + } + else { + output[0] = fmod(inputValue1[0], inputValue2[0]); + } + + clampIfNeeded(output); +} + +void MathAbsoluteOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = fabs(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathRadiansOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = DEG2RADF(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathDegreesOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = RAD2DEGF(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathArcTan2Operation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = atan2(inputValue1[0], inputValue2[0]); + + clampIfNeeded(output); +} + +void MathFloorOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = floor(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathCeilOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = ceil(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathFractOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = inputValue1[0] - floor(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathSqrtOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + if (inputValue1[0] > 0) { + output[0] = sqrt(inputValue1[0]); + } + else { + output[0] = 0.0f; + } + + clampIfNeeded(output); +} + +void MathInverseSqrtOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + if (inputValue1[0] > 0) { + output[0] = 1.0f / sqrt(inputValue1[0]); + } + else { + output[0] = 0.0f; + } + + clampIfNeeded(output); +} + +void MathSignOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = compatible_signf(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathExponentOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = expf(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathTruncOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + + output[0] = (inputValue1[0] >= 0.0f) ? floor(inputValue1[0]) : ceil(inputValue1[0]); + + clampIfNeeded(output); +} + +void MathSnapOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + if (inputValue1[0] == 0 || inputValue2[0] == 0) { /* We don't want to divide by zero. */ + output[0] = 0.0f; + } + else { + output[0] = floorf(inputValue1[0] / inputValue2[0]) * inputValue2[0]; + } + + clampIfNeeded(output); +} + +void MathWrapOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + float inputValue3[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); + + output[0] = wrapf(inputValue1[0], inputValue2[0], inputValue3[0]); + + clampIfNeeded(output); +} + +void MathPingpongOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + + output[0] = pingpongf(inputValue1[0], inputValue2[0]); + + clampIfNeeded(output); +} + +void MathCompareOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + float inputValue3[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); + + output[0] = (fabsf(inputValue1[0] - inputValue2[0]) <= MAX2(inputValue3[0], 1e-5f)) ? 1.0f : + 0.0f; + + clampIfNeeded(output); +} + +void MathMultiplyAddOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + float inputValue3[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); + + output[0] = inputValue1[0] * inputValue2[0] + inputValue3[0]; + + clampIfNeeded(output); +} + +void MathSmoothMinOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + float inputValue3[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); + + output[0] = smoothminf(inputValue1[0], inputValue2[0], inputValue3[0]); + + clampIfNeeded(output); +} + +void MathSmoothMaxOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue1[4]; + float inputValue2[4]; + float inputValue3[4]; + + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); + this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); + + output[0] = -smoothminf(-inputValue1[0], -inputValue2[0], inputValue3[0]); + + clampIfNeeded(output); +} diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cpp deleted file mode 100644 index 692c1e70462..00000000000 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp +++ /dev/null @@ -1,750 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MathBaseOperation.h" - -#include "BLI_math.h" - -MathBaseOperation::MathBaseOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputValue1Operation = nullptr; - this->m_inputValue2Operation = nullptr; - this->m_inputValue3Operation = nullptr; - this->m_useClamp = false; -} - -void MathBaseOperation::initExecution() -{ - this->m_inputValue1Operation = this->getInputSocketReader(0); - this->m_inputValue2Operation = this->getInputSocketReader(1); - this->m_inputValue3Operation = this->getInputSocketReader(2); -} - -void MathBaseOperation::deinitExecution() -{ - this->m_inputValue1Operation = nullptr; - this->m_inputValue2Operation = nullptr; - this->m_inputValue3Operation = nullptr; -} - -void MathBaseOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - NodeOperationInput *socket; - unsigned int tempPreferredResolution[2] = {0, 0}; - unsigned int tempResolution[2]; - - socket = this->getInputSocket(0); - socket->determineResolution(tempResolution, tempPreferredResolution); - if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { - this->setResolutionInputSocketIndex(0); - } - else { - this->setResolutionInputSocketIndex(1); - } - NodeOperation::determineResolution(resolution, preferredResolution); -} - -void MathBaseOperation::clampIfNeeded(float *color) -{ - if (this->m_useClamp) { - CLAMP(color[0], 0.0f, 1.0f); - } -} - -void MathAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = inputValue1[0] + inputValue2[0]; - - clampIfNeeded(output); -} - -void MathSubtractOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = inputValue1[0] - inputValue2[0]; - - clampIfNeeded(output); -} - -void MathMultiplyOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = inputValue1[0] * inputValue2[0]; - - clampIfNeeded(output); -} - -void MathDivideOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - if (inputValue2[0] == 0) { /* We don't want to divide by zero. */ - output[0] = 0.0; - } - else { - output[0] = inputValue1[0] / inputValue2[0]; - } - - clampIfNeeded(output); -} - -void MathSineOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = sin(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathCosineOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = cos(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathTangentOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = tan(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathHyperbolicSineOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = sinh(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathHyperbolicCosineOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = cosh(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathHyperbolicTangentOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = tanh(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathArcSineOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - if (inputValue1[0] <= 1 && inputValue1[0] >= -1) { - output[0] = asin(inputValue1[0]); - } - else { - output[0] = 0.0; - } - - clampIfNeeded(output); -} - -void MathArcCosineOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - if (inputValue1[0] <= 1 && inputValue1[0] >= -1) { - output[0] = acos(inputValue1[0]); - } - else { - output[0] = 0.0; - } - - clampIfNeeded(output); -} - -void MathArcTangentOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = atan(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathPowerOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - if (inputValue1[0] >= 0) { - output[0] = pow(inputValue1[0], inputValue2[0]); - } - else { - float y_mod_1 = fmod(inputValue2[0], 1); - /* if input value is not nearly an integer, fall back to zero, nicer than straight rounding */ - if (y_mod_1 > 0.999f || y_mod_1 < 0.001f) { - output[0] = pow(inputValue1[0], floorf(inputValue2[0] + 0.5f)); - } - else { - output[0] = 0.0; - } - } - - clampIfNeeded(output); -} - -void MathLogarithmOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - if (inputValue1[0] > 0 && inputValue2[0] > 0) { - output[0] = log(inputValue1[0]) / log(inputValue2[0]); - } - else { - output[0] = 0.0; - } - - clampIfNeeded(output); -} - -void MathMinimumOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = MIN2(inputValue1[0], inputValue2[0]); - - clampIfNeeded(output); -} - -void MathMaximumOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = MAX2(inputValue1[0], inputValue2[0]); - - clampIfNeeded(output); -} - -void MathRoundOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = round(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathLessThanOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = inputValue1[0] < inputValue2[0] ? 1.0f : 0.0f; - - clampIfNeeded(output); -} - -void MathGreaterThanOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = inputValue1[0] > inputValue2[0] ? 1.0f : 0.0f; - - clampIfNeeded(output); -} - -void MathModuloOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - if (inputValue2[0] == 0) { - output[0] = 0.0; - } - else { - output[0] = fmod(inputValue1[0], inputValue2[0]); - } - - clampIfNeeded(output); -} - -void MathAbsoluteOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - - output[0] = fabs(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathRadiansOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - - output[0] = DEG2RADF(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathDegreesOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - - output[0] = RAD2DEGF(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathArcTan2Operation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = atan2(inputValue1[0], inputValue2[0]); - - clampIfNeeded(output); -} - -void MathFloorOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - - output[0] = floor(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathCeilOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - - output[0] = ceil(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathFractOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - - output[0] = inputValue1[0] - floor(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathSqrtOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - - if (inputValue1[0] > 0) { - output[0] = sqrt(inputValue1[0]); - } - else { - output[0] = 0.0f; - } - - clampIfNeeded(output); -} - -void MathInverseSqrtOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - - if (inputValue1[0] > 0) { - output[0] = 1.0f / sqrt(inputValue1[0]); - } - else { - output[0] = 0.0f; - } - - clampIfNeeded(output); -} - -void MathSignOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - - output[0] = compatible_signf(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathExponentOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - - output[0] = expf(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathTruncOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - - output[0] = (inputValue1[0] >= 0.0f) ? floor(inputValue1[0]) : ceil(inputValue1[0]); - - clampIfNeeded(output); -} - -void MathSnapOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - if (inputValue1[0] == 0 || inputValue2[0] == 0) { /* We don't want to divide by zero. */ - output[0] = 0.0f; - } - else { - output[0] = floorf(inputValue1[0] / inputValue2[0]) * inputValue2[0]; - } - - clampIfNeeded(output); -} - -void MathWrapOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - float inputValue3[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); - - output[0] = wrapf(inputValue1[0], inputValue2[0], inputValue3[0]); - - clampIfNeeded(output); -} - -void MathPingpongOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - - output[0] = pingpongf(inputValue1[0], inputValue2[0]); - - clampIfNeeded(output); -} - -void MathCompareOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - float inputValue3[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); - - output[0] = (fabsf(inputValue1[0] - inputValue2[0]) <= MAX2(inputValue3[0], 1e-5f)) ? 1.0f : - 0.0f; - - clampIfNeeded(output); -} - -void MathMultiplyAddOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - float inputValue3[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); - - output[0] = inputValue1[0] * inputValue2[0] + inputValue3[0]; - - clampIfNeeded(output); -} - -void MathSmoothMinOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - float inputValue3[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); - - output[0] = smoothminf(inputValue1[0], inputValue2[0], inputValue3[0]); - - clampIfNeeded(output); -} - -void MathSmoothMaxOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputValue1[4]; - float inputValue2[4]; - float inputValue3[4]; - - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - this->m_inputValue3Operation->readSampled(inputValue3, x, y, sampler); - - output[0] = -smoothminf(-inputValue1[0], -inputValue2[0], inputValue3[0]); - - clampIfNeeded(output); -} diff --git a/source/blender/compositor/operations/COM_MixOperation.cc b/source/blender/compositor/operations/COM_MixOperation.cc new file mode 100644 index 00000000000..11df0900345 --- /dev/null +++ b/source/blender/compositor/operations/COM_MixOperation.cc @@ -0,0 +1,946 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MixOperation.h" + +#include "BLI_math.h" + +/* ******** Mix Base Operation ******** */ + +MixBaseOperation::MixBaseOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputValueOperation = nullptr; + this->m_inputColor1Operation = nullptr; + this->m_inputColor2Operation = nullptr; + this->setUseValueAlphaMultiply(false); + this->setUseClamp(false); +} + +void MixBaseOperation::initExecution() +{ + this->m_inputValueOperation = this->getInputSocketReader(0); + this->m_inputColor1Operation = this->getInputSocketReader(1); + this->m_inputColor2Operation = this->getInputSocketReader(2); +} + +void MixBaseOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]); + output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]); + output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]); + output[3] = inputColor1[3]; +} + +void MixBaseOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + NodeOperationInput *socket; + unsigned int tempPreferredResolution[2] = {0, 0}; + unsigned int tempResolution[2]; + + socket = this->getInputSocket(1); + socket->determineResolution(tempResolution, tempPreferredResolution); + if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { + this->setResolutionInputSocketIndex(1); + } + else { + socket = this->getInputSocket(2); + socket->determineResolution(tempResolution, tempPreferredResolution); + if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { + this->setResolutionInputSocketIndex(2); + } + else { + this->setResolutionInputSocketIndex(0); + } + } + NodeOperation::determineResolution(resolution, preferredResolution); +} + +void MixBaseOperation::deinitExecution() +{ + this->m_inputValueOperation = nullptr; + this->m_inputColor1Operation = nullptr; + this->m_inputColor2Operation = nullptr; +} + +/* ******** Mix Add Operation ******** */ + +MixAddOperation::MixAddOperation() +{ + /* pass */ +} + +void MixAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + output[0] = inputColor1[0] + value * inputColor2[0]; + output[1] = inputColor1[1] + value * inputColor2[1]; + output[2] = inputColor1[2] + value * inputColor2[2]; + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Blend Operation ******** */ + +MixBlendOperation::MixBlendOperation() +{ + /* pass */ +} + +void MixBlendOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + float value; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + value = inputValue[0]; + + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]); + output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]); + output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Burn Operation ******** */ + +MixColorBurnOperation::MixColorBurnOperation() +{ + /* pass */ +} + +void MixColorBurnOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + float tmp; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + tmp = valuem + value * inputColor2[0]; + if (tmp <= 0.0f) { + output[0] = 0.0f; + } + else { + tmp = 1.0f - (1.0f - inputColor1[0]) / tmp; + if (tmp < 0.0f) { + output[0] = 0.0f; + } + else if (tmp > 1.0f) { + output[0] = 1.0f; + } + else { + output[0] = tmp; + } + } + + tmp = valuem + value * inputColor2[1]; + if (tmp <= 0.0f) { + output[1] = 0.0f; + } + else { + tmp = 1.0f - (1.0f - inputColor1[1]) / tmp; + if (tmp < 0.0f) { + output[1] = 0.0f; + } + else if (tmp > 1.0f) { + output[1] = 1.0f; + } + else { + output[1] = tmp; + } + } + + tmp = valuem + value * inputColor2[2]; + if (tmp <= 0.0f) { + output[2] = 0.0f; + } + else { + tmp = 1.0f - (1.0f - inputColor1[2]) / tmp; + if (tmp < 0.0f) { + output[2] = 0.0f; + } + else if (tmp > 1.0f) { + output[2] = 1.0f; + } + else { + output[2] = tmp; + } + } + + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Color Operation ******** */ + +MixColorOperation::MixColorOperation() +{ + /* pass */ +} + +void MixColorOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + float colH, colS, colV; + rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); + if (colS != 0.0f) { + float rH, rS, rV; + float tmpr, tmpg, tmpb; + rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); + hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb); + output[0] = (valuem * inputColor1[0]) + (value * tmpr); + output[1] = (valuem * inputColor1[1]) + (value * tmpg); + output[2] = (valuem * inputColor1[2]) + (value * tmpb); + } + else { + copy_v3_v3(output, inputColor1); + } + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Darken Operation ******** */ + +MixDarkenOperation::MixDarkenOperation() +{ + /* pass */ +} + +void MixDarkenOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + output[0] = min_ff(inputColor1[0], inputColor2[0]) * value + inputColor1[0] * valuem; + output[1] = min_ff(inputColor1[1], inputColor2[1]) * value + inputColor1[1] * valuem; + output[2] = min_ff(inputColor1[2], inputColor2[2]) * value + inputColor1[2] * valuem; + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Difference Operation ******** */ + +MixDifferenceOperation::MixDifferenceOperation() +{ + /* pass */ +} + +void MixDifferenceOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + output[0] = valuem * inputColor1[0] + value * fabsf(inputColor1[0] - inputColor2[0]); + output[1] = valuem * inputColor1[1] + value * fabsf(inputColor1[1] - inputColor2[1]); + output[2] = valuem * inputColor1[2] + value * fabsf(inputColor1[2] - inputColor2[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Difference Operation ******** */ + +MixDivideOperation::MixDivideOperation() +{ + /* pass */ +} + +void MixDivideOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + if (inputColor2[0] != 0.0f) { + output[0] = valuem * (inputColor1[0]) + value * (inputColor1[0]) / inputColor2[0]; + } + else { + output[0] = 0.0f; + } + if (inputColor2[1] != 0.0f) { + output[1] = valuem * (inputColor1[1]) + value * (inputColor1[1]) / inputColor2[1]; + } + else { + output[1] = 0.0f; + } + if (inputColor2[2] != 0.0f) { + output[2] = valuem * (inputColor1[2]) + value * (inputColor1[2]) / inputColor2[2]; + } + else { + output[2] = 0.0f; + } + + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Dodge Operation ******** */ + +MixDodgeOperation::MixDodgeOperation() +{ + /* pass */ +} + +void MixDodgeOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + float tmp; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + + if (inputColor1[0] != 0.0f) { + tmp = 1.0f - value * inputColor2[0]; + if (tmp <= 0.0f) { + output[0] = 1.0f; + } + else { + tmp = inputColor1[0] / tmp; + if (tmp > 1.0f) { + output[0] = 1.0f; + } + else { + output[0] = tmp; + } + } + } + else { + output[0] = 0.0f; + } + + if (inputColor1[1] != 0.0f) { + tmp = 1.0f - value * inputColor2[1]; + if (tmp <= 0.0f) { + output[1] = 1.0f; + } + else { + tmp = inputColor1[1] / tmp; + if (tmp > 1.0f) { + output[1] = 1.0f; + } + else { + output[1] = tmp; + } + } + } + else { + output[1] = 0.0f; + } + + if (inputColor1[2] != 0.0f) { + tmp = 1.0f - value * inputColor2[2]; + if (tmp <= 0.0f) { + output[2] = 1.0f; + } + else { + tmp = inputColor1[2] / tmp; + if (tmp > 1.0f) { + output[2] = 1.0f; + } + else { + output[2] = tmp; + } + } + } + else { + output[2] = 0.0f; + } + + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Glare Operation ******** */ + +MixGlareOperation::MixGlareOperation() +{ + /* pass */ +} + +void MixGlareOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + float value; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + value = inputValue[0]; + float mf = 2.0f - 2.0f * fabsf(value - 0.5f); + + if (inputColor1[0] < 0.0f) { + inputColor1[0] = 0.0f; + } + if (inputColor1[1] < 0.0f) { + inputColor1[1] = 0.0f; + } + if (inputColor1[2] < 0.0f) { + inputColor1[2] = 0.0f; + } + + output[0] = mf * MAX2(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f); + output[1] = mf * MAX2(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f); + output[2] = mf * MAX2(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Hue Operation ******** */ + +MixHueOperation::MixHueOperation() +{ + /* pass */ +} + +void MixHueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + float colH, colS, colV; + rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); + if (colS != 0.0f) { + float rH, rS, rV; + float tmpr, tmpg, tmpb; + rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); + hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb); + output[0] = valuem * (inputColor1[0]) + value * tmpr; + output[1] = valuem * (inputColor1[1]) + value * tmpg; + output[2] = valuem * (inputColor1[2]) + value * tmpb; + } + else { + copy_v3_v3(output, inputColor1); + } + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Lighten Operation ******** */ + +MixLightenOperation::MixLightenOperation() +{ + /* pass */ +} + +void MixLightenOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float tmp; + tmp = value * inputColor2[0]; + if (tmp > inputColor1[0]) { + output[0] = tmp; + } + else { + output[0] = inputColor1[0]; + } + tmp = value * inputColor2[1]; + if (tmp > inputColor1[1]) { + output[1] = tmp; + } + else { + output[1] = inputColor1[1]; + } + tmp = value * inputColor2[2]; + if (tmp > inputColor1[2]) { + output[2] = tmp; + } + else { + output[2] = inputColor1[2]; + } + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Linear Light Operation ******** */ + +MixLinearLightOperation::MixLinearLightOperation() +{ + /* pass */ +} + +void MixLinearLightOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + if (inputColor2[0] > 0.5f) { + output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0] - 0.5f)); + } + else { + output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0]) - 1.0f); + } + if (inputColor2[1] > 0.5f) { + output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1] - 0.5f)); + } + else { + output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1]) - 1.0f); + } + if (inputColor2[2] > 0.5f) { + output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2] - 0.5f)); + } + else { + output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2]) - 1.0f); + } + + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Multiply Operation ******** */ + +MixMultiplyOperation::MixMultiplyOperation() +{ + /* pass */ +} + +void MixMultiplyOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + output[0] = inputColor1[0] * (valuem + value * inputColor2[0]); + output[1] = inputColor1[1] * (valuem + value * inputColor2[1]); + output[2] = inputColor1[2] * (valuem + value * inputColor2[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Overlay Operation ******** */ + +MixOverlayOperation::MixOverlayOperation() +{ + /* pass */ +} + +void MixOverlayOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + + float valuem = 1.0f - value; + + if (inputColor1[0] < 0.5f) { + output[0] = inputColor1[0] * (valuem + 2.0f * value * inputColor2[0]); + } + else { + output[0] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]); + } + if (inputColor1[1] < 0.5f) { + output[1] = inputColor1[1] * (valuem + 2.0f * value * inputColor2[1]); + } + else { + output[1] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]); + } + if (inputColor1[2] < 0.5f) { + output[2] = inputColor1[2] * (valuem + 2.0f * value * inputColor2[2]); + } + else { + output[2] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]); + } + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Saturation Operation ******** */ + +MixSaturationOperation::MixSaturationOperation() +{ + /* pass */ +} + +void MixSaturationOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + float rH, rS, rV; + rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); + if (rS != 0.0f) { + float colH, colS, colV; + rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); + hsv_to_rgb(rH, (valuem * rS + value * colS), rV, &output[0], &output[1], &output[2]); + } + else { + copy_v3_v3(output, inputColor1); + } + + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Screen Operation ******** */ + +MixScreenOperation::MixScreenOperation() +{ + /* pass */ +} + +void MixScreenOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + output[0] = 1.0f - (valuem + value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]); + output[1] = 1.0f - (valuem + value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]); + output[2] = 1.0f - (valuem + value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Soft Light Operation ******** */ + +MixSoftLightOperation::MixSoftLightOperation() +{ + /* pass */ +} + +void MixSoftLightOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + float scr, scg, scb; + + /* first calculate non-fac based Screen mix */ + scr = 1.0f - (1.0f - inputColor2[0]) * (1.0f - inputColor1[0]); + scg = 1.0f - (1.0f - inputColor2[1]) * (1.0f - inputColor1[1]); + scb = 1.0f - (1.0f - inputColor2[2]) * (1.0f - inputColor1[2]); + + output[0] = valuem * (inputColor1[0]) + + value * (((1.0f - inputColor1[0]) * inputColor2[0] * (inputColor1[0])) + + (inputColor1[0] * scr)); + output[1] = valuem * (inputColor1[1]) + + value * (((1.0f - inputColor1[1]) * inputColor2[1] * (inputColor1[1])) + + (inputColor1[1] * scg)); + output[2] = valuem * (inputColor1[2]) + + value * (((1.0f - inputColor1[2]) * inputColor2[2] * (inputColor1[2])) + + (inputColor1[2] * scb)); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Subtract Operation ******** */ + +MixSubtractOperation::MixSubtractOperation() +{ + /* pass */ +} + +void MixSubtractOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + output[0] = inputColor1[0] - value * (inputColor2[0]); + output[1] = inputColor1[1] - value * (inputColor2[1]); + output[2] = inputColor1[2] - value * (inputColor2[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Value Operation ******** */ + +MixValueOperation::MixValueOperation() +{ + /* pass */ +} + +void MixValueOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); + this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); + this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + float rH, rS, rV; + float colH, colS, colV; + rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); + rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); + hsv_to_rgb(rH, rS, (valuem * rV + value * colV), &output[0], &output[1], &output[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} diff --git a/source/blender/compositor/operations/COM_MixOperation.cpp b/source/blender/compositor/operations/COM_MixOperation.cpp deleted file mode 100644 index 11df0900345..00000000000 --- a/source/blender/compositor/operations/COM_MixOperation.cpp +++ /dev/null @@ -1,946 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MixOperation.h" - -#include "BLI_math.h" - -/* ******** Mix Base Operation ******** */ - -MixBaseOperation::MixBaseOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputValueOperation = nullptr; - this->m_inputColor1Operation = nullptr; - this->m_inputColor2Operation = nullptr; - this->setUseValueAlphaMultiply(false); - this->setUseClamp(false); -} - -void MixBaseOperation::initExecution() -{ - this->m_inputValueOperation = this->getInputSocketReader(0); - this->m_inputColor1Operation = this->getInputSocketReader(1); - this->m_inputColor2Operation = this->getInputSocketReader(2); -} - -void MixBaseOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]); - output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]); - output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]); - output[3] = inputColor1[3]; -} - -void MixBaseOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - NodeOperationInput *socket; - unsigned int tempPreferredResolution[2] = {0, 0}; - unsigned int tempResolution[2]; - - socket = this->getInputSocket(1); - socket->determineResolution(tempResolution, tempPreferredResolution); - if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { - this->setResolutionInputSocketIndex(1); - } - else { - socket = this->getInputSocket(2); - socket->determineResolution(tempResolution, tempPreferredResolution); - if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { - this->setResolutionInputSocketIndex(2); - } - else { - this->setResolutionInputSocketIndex(0); - } - } - NodeOperation::determineResolution(resolution, preferredResolution); -} - -void MixBaseOperation::deinitExecution() -{ - this->m_inputValueOperation = nullptr; - this->m_inputColor1Operation = nullptr; - this->m_inputColor2Operation = nullptr; -} - -/* ******** Mix Add Operation ******** */ - -MixAddOperation::MixAddOperation() -{ - /* pass */ -} - -void MixAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - output[0] = inputColor1[0] + value * inputColor2[0]; - output[1] = inputColor1[1] + value * inputColor2[1]; - output[2] = inputColor1[2] + value * inputColor2[2]; - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Blend Operation ******** */ - -MixBlendOperation::MixBlendOperation() -{ - /* pass */ -} - -void MixBlendOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - float value; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - value = inputValue[0]; - - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]); - output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]); - output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Burn Operation ******** */ - -MixColorBurnOperation::MixColorBurnOperation() -{ - /* pass */ -} - -void MixColorBurnOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - float tmp; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - tmp = valuem + value * inputColor2[0]; - if (tmp <= 0.0f) { - output[0] = 0.0f; - } - else { - tmp = 1.0f - (1.0f - inputColor1[0]) / tmp; - if (tmp < 0.0f) { - output[0] = 0.0f; - } - else if (tmp > 1.0f) { - output[0] = 1.0f; - } - else { - output[0] = tmp; - } - } - - tmp = valuem + value * inputColor2[1]; - if (tmp <= 0.0f) { - output[1] = 0.0f; - } - else { - tmp = 1.0f - (1.0f - inputColor1[1]) / tmp; - if (tmp < 0.0f) { - output[1] = 0.0f; - } - else if (tmp > 1.0f) { - output[1] = 1.0f; - } - else { - output[1] = tmp; - } - } - - tmp = valuem + value * inputColor2[2]; - if (tmp <= 0.0f) { - output[2] = 0.0f; - } - else { - tmp = 1.0f - (1.0f - inputColor1[2]) / tmp; - if (tmp < 0.0f) { - output[2] = 0.0f; - } - else if (tmp > 1.0f) { - output[2] = 1.0f; - } - else { - output[2] = tmp; - } - } - - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Color Operation ******** */ - -MixColorOperation::MixColorOperation() -{ - /* pass */ -} - -void MixColorOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - float colH, colS, colV; - rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); - if (colS != 0.0f) { - float rH, rS, rV; - float tmpr, tmpg, tmpb; - rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); - hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb); - output[0] = (valuem * inputColor1[0]) + (value * tmpr); - output[1] = (valuem * inputColor1[1]) + (value * tmpg); - output[2] = (valuem * inputColor1[2]) + (value * tmpb); - } - else { - copy_v3_v3(output, inputColor1); - } - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Darken Operation ******** */ - -MixDarkenOperation::MixDarkenOperation() -{ - /* pass */ -} - -void MixDarkenOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - output[0] = min_ff(inputColor1[0], inputColor2[0]) * value + inputColor1[0] * valuem; - output[1] = min_ff(inputColor1[1], inputColor2[1]) * value + inputColor1[1] * valuem; - output[2] = min_ff(inputColor1[2], inputColor2[2]) * value + inputColor1[2] * valuem; - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Difference Operation ******** */ - -MixDifferenceOperation::MixDifferenceOperation() -{ - /* pass */ -} - -void MixDifferenceOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - output[0] = valuem * inputColor1[0] + value * fabsf(inputColor1[0] - inputColor2[0]); - output[1] = valuem * inputColor1[1] + value * fabsf(inputColor1[1] - inputColor2[1]); - output[2] = valuem * inputColor1[2] + value * fabsf(inputColor1[2] - inputColor2[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Difference Operation ******** */ - -MixDivideOperation::MixDivideOperation() -{ - /* pass */ -} - -void MixDivideOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - if (inputColor2[0] != 0.0f) { - output[0] = valuem * (inputColor1[0]) + value * (inputColor1[0]) / inputColor2[0]; - } - else { - output[0] = 0.0f; - } - if (inputColor2[1] != 0.0f) { - output[1] = valuem * (inputColor1[1]) + value * (inputColor1[1]) / inputColor2[1]; - } - else { - output[1] = 0.0f; - } - if (inputColor2[2] != 0.0f) { - output[2] = valuem * (inputColor1[2]) + value * (inputColor1[2]) / inputColor2[2]; - } - else { - output[2] = 0.0f; - } - - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Dodge Operation ******** */ - -MixDodgeOperation::MixDodgeOperation() -{ - /* pass */ -} - -void MixDodgeOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - float tmp; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - - if (inputColor1[0] != 0.0f) { - tmp = 1.0f - value * inputColor2[0]; - if (tmp <= 0.0f) { - output[0] = 1.0f; - } - else { - tmp = inputColor1[0] / tmp; - if (tmp > 1.0f) { - output[0] = 1.0f; - } - else { - output[0] = tmp; - } - } - } - else { - output[0] = 0.0f; - } - - if (inputColor1[1] != 0.0f) { - tmp = 1.0f - value * inputColor2[1]; - if (tmp <= 0.0f) { - output[1] = 1.0f; - } - else { - tmp = inputColor1[1] / tmp; - if (tmp > 1.0f) { - output[1] = 1.0f; - } - else { - output[1] = tmp; - } - } - } - else { - output[1] = 0.0f; - } - - if (inputColor1[2] != 0.0f) { - tmp = 1.0f - value * inputColor2[2]; - if (tmp <= 0.0f) { - output[2] = 1.0f; - } - else { - tmp = inputColor1[2] / tmp; - if (tmp > 1.0f) { - output[2] = 1.0f; - } - else { - output[2] = tmp; - } - } - } - else { - output[2] = 0.0f; - } - - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Glare Operation ******** */ - -MixGlareOperation::MixGlareOperation() -{ - /* pass */ -} - -void MixGlareOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - float value; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - value = inputValue[0]; - float mf = 2.0f - 2.0f * fabsf(value - 0.5f); - - if (inputColor1[0] < 0.0f) { - inputColor1[0] = 0.0f; - } - if (inputColor1[1] < 0.0f) { - inputColor1[1] = 0.0f; - } - if (inputColor1[2] < 0.0f) { - inputColor1[2] = 0.0f; - } - - output[0] = mf * MAX2(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f); - output[1] = mf * MAX2(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f); - output[2] = mf * MAX2(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Hue Operation ******** */ - -MixHueOperation::MixHueOperation() -{ - /* pass */ -} - -void MixHueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - float colH, colS, colV; - rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); - if (colS != 0.0f) { - float rH, rS, rV; - float tmpr, tmpg, tmpb; - rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); - hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb); - output[0] = valuem * (inputColor1[0]) + value * tmpr; - output[1] = valuem * (inputColor1[1]) + value * tmpg; - output[2] = valuem * (inputColor1[2]) + value * tmpb; - } - else { - copy_v3_v3(output, inputColor1); - } - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Lighten Operation ******** */ - -MixLightenOperation::MixLightenOperation() -{ - /* pass */ -} - -void MixLightenOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float tmp; - tmp = value * inputColor2[0]; - if (tmp > inputColor1[0]) { - output[0] = tmp; - } - else { - output[0] = inputColor1[0]; - } - tmp = value * inputColor2[1]; - if (tmp > inputColor1[1]) { - output[1] = tmp; - } - else { - output[1] = inputColor1[1]; - } - tmp = value * inputColor2[2]; - if (tmp > inputColor1[2]) { - output[2] = tmp; - } - else { - output[2] = inputColor1[2]; - } - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Linear Light Operation ******** */ - -MixLinearLightOperation::MixLinearLightOperation() -{ - /* pass */ -} - -void MixLinearLightOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - if (inputColor2[0] > 0.5f) { - output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0] - 0.5f)); - } - else { - output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0]) - 1.0f); - } - if (inputColor2[1] > 0.5f) { - output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1] - 0.5f)); - } - else { - output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1]) - 1.0f); - } - if (inputColor2[2] > 0.5f) { - output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2] - 0.5f)); - } - else { - output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2]) - 1.0f); - } - - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Multiply Operation ******** */ - -MixMultiplyOperation::MixMultiplyOperation() -{ - /* pass */ -} - -void MixMultiplyOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - output[0] = inputColor1[0] * (valuem + value * inputColor2[0]); - output[1] = inputColor1[1] * (valuem + value * inputColor2[1]); - output[2] = inputColor1[2] * (valuem + value * inputColor2[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Overlay Operation ******** */ - -MixOverlayOperation::MixOverlayOperation() -{ - /* pass */ -} - -void MixOverlayOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - - float valuem = 1.0f - value; - - if (inputColor1[0] < 0.5f) { - output[0] = inputColor1[0] * (valuem + 2.0f * value * inputColor2[0]); - } - else { - output[0] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]); - } - if (inputColor1[1] < 0.5f) { - output[1] = inputColor1[1] * (valuem + 2.0f * value * inputColor2[1]); - } - else { - output[1] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]); - } - if (inputColor1[2] < 0.5f) { - output[2] = inputColor1[2] * (valuem + 2.0f * value * inputColor2[2]); - } - else { - output[2] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]); - } - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Saturation Operation ******** */ - -MixSaturationOperation::MixSaturationOperation() -{ - /* pass */ -} - -void MixSaturationOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - float rH, rS, rV; - rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); - if (rS != 0.0f) { - float colH, colS, colV; - rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); - hsv_to_rgb(rH, (valuem * rS + value * colS), rV, &output[0], &output[1], &output[2]); - } - else { - copy_v3_v3(output, inputColor1); - } - - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Screen Operation ******** */ - -MixScreenOperation::MixScreenOperation() -{ - /* pass */ -} - -void MixScreenOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - output[0] = 1.0f - (valuem + value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]); - output[1] = 1.0f - (valuem + value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]); - output[2] = 1.0f - (valuem + value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Soft Light Operation ******** */ - -MixSoftLightOperation::MixSoftLightOperation() -{ - /* pass */ -} - -void MixSoftLightOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - float scr, scg, scb; - - /* first calculate non-fac based Screen mix */ - scr = 1.0f - (1.0f - inputColor2[0]) * (1.0f - inputColor1[0]); - scg = 1.0f - (1.0f - inputColor2[1]) * (1.0f - inputColor1[1]); - scb = 1.0f - (1.0f - inputColor2[2]) * (1.0f - inputColor1[2]); - - output[0] = valuem * (inputColor1[0]) + - value * (((1.0f - inputColor1[0]) * inputColor2[0] * (inputColor1[0])) + - (inputColor1[0] * scr)); - output[1] = valuem * (inputColor1[1]) + - value * (((1.0f - inputColor1[1]) * inputColor2[1] * (inputColor1[1])) + - (inputColor1[1] * scg)); - output[2] = valuem * (inputColor1[2]) + - value * (((1.0f - inputColor1[2]) * inputColor2[2] * (inputColor1[2])) + - (inputColor1[2] * scb)); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Subtract Operation ******** */ - -MixSubtractOperation::MixSubtractOperation() -{ - /* pass */ -} - -void MixSubtractOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - output[0] = inputColor1[0] - value * (inputColor2[0]); - output[1] = inputColor1[1] - value * (inputColor2[1]); - output[2] = inputColor1[2] - value * (inputColor2[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - -/* ******** Mix Value Operation ******** */ - -MixValueOperation::MixValueOperation() -{ - /* pass */ -} - -void MixValueOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->readSampled(inputValue, x, y, sampler); - this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler); - this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - float rH, rS, rV; - float colH, colS, colV; - rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); - rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); - hsv_to_rgb(rH, rS, (valuem * rV + value * colV), &output[0], &output[1], &output[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc new file mode 100644 index 00000000000..725aacc7d34 --- /dev/null +++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc @@ -0,0 +1,82 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MovieClipAttributeOperation.h" + +#include "BKE_movieclip.h" +#include "BKE_tracking.h" + +MovieClipAttributeOperation::MovieClipAttributeOperation() +{ + this->addOutputSocket(COM_DT_VALUE); + this->m_framenumber = 0; + this->m_attribute = MCA_X; + this->m_invert = false; +} + +void MovieClipAttributeOperation::initExecution() +{ + if (this->m_clip == nullptr) { + return; + } + float loc[2], scale, angle; + loc[0] = 0.0f; + loc[1] = 0.0f; + scale = 1.0f; + angle = 0.0f; + int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_clip, this->m_framenumber); + BKE_tracking_stabilization_data_get( + this->m_clip, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle); + switch (this->m_attribute) { + case MCA_SCALE: + this->m_value = scale; + break; + case MCA_ANGLE: + this->m_value = angle; + break; + case MCA_X: + this->m_value = loc[0]; + break; + case MCA_Y: + this->m_value = loc[1]; + break; + } + if (this->m_invert) { + if (this->m_attribute != MCA_SCALE) { + this->m_value = -this->m_value; + } + else { + this->m_value = 1.0f / this->m_value; + } + } +} + +void MovieClipAttributeOperation::executePixelSampled(float output[4], + float /*x*/, + float /*y*/, + PixelSampler /*sampler*/) +{ + output[0] = this->m_value; +} + +void MovieClipAttributeOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + resolution[0] = preferredResolution[0]; + resolution[1] = preferredResolution[1]; +} diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp deleted file mode 100644 index 725aacc7d34..00000000000 --- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MovieClipAttributeOperation.h" - -#include "BKE_movieclip.h" -#include "BKE_tracking.h" - -MovieClipAttributeOperation::MovieClipAttributeOperation() -{ - this->addOutputSocket(COM_DT_VALUE); - this->m_framenumber = 0; - this->m_attribute = MCA_X; - this->m_invert = false; -} - -void MovieClipAttributeOperation::initExecution() -{ - if (this->m_clip == nullptr) { - return; - } - float loc[2], scale, angle; - loc[0] = 0.0f; - loc[1] = 0.0f; - scale = 1.0f; - angle = 0.0f; - int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_clip, this->m_framenumber); - BKE_tracking_stabilization_data_get( - this->m_clip, clip_framenr, getWidth(), getHeight(), loc, &scale, &angle); - switch (this->m_attribute) { - case MCA_SCALE: - this->m_value = scale; - break; - case MCA_ANGLE: - this->m_value = angle; - break; - case MCA_X: - this->m_value = loc[0]; - break; - case MCA_Y: - this->m_value = loc[1]; - break; - } - if (this->m_invert) { - if (this->m_attribute != MCA_SCALE) { - this->m_value = -this->m_value; - } - else { - this->m_value = 1.0f / this->m_value; - } - } -} - -void MovieClipAttributeOperation::executePixelSampled(float output[4], - float /*x*/, - float /*y*/, - PixelSampler /*sampler*/) -{ - output[0] = this->m_value; -} - -void MovieClipAttributeOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; -} diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cc b/source/blender/compositor/operations/COM_MovieClipOperation.cc new file mode 100644 index 00000000000..4f819bf27af --- /dev/null +++ b/source/blender/compositor/operations/COM_MovieClipOperation.cc @@ -0,0 +1,135 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MovieClipOperation.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "BKE_image.h" +#include "BKE_movieclip.h" + +#include "IMB_imbuf.h" + +MovieClipBaseOperation::MovieClipBaseOperation() +{ + this->m_movieClip = nullptr; + this->m_movieClipBuffer = nullptr; + this->m_movieClipUser = nullptr; + this->m_movieClipwidth = 0; + this->m_movieClipheight = 0; + this->m_framenumber = 0; +} + +void MovieClipBaseOperation::initExecution() +{ + if (this->m_movieClip) { + BKE_movieclip_user_set_frame(this->m_movieClipUser, this->m_framenumber); + ImBuf *ibuf; + + if (this->m_cacheFrame) { + ibuf = BKE_movieclip_get_ibuf(this->m_movieClip, this->m_movieClipUser); + } + else { + ibuf = BKE_movieclip_get_ibuf_flag( + this->m_movieClip, this->m_movieClipUser, this->m_movieClip->flag, MOVIECLIP_CACHE_SKIP); + } + + if (ibuf) { + this->m_movieClipBuffer = ibuf; + if (ibuf->rect_float == nullptr || ibuf->userflags & IB_RECT_INVALID) { + IMB_float_from_rect(ibuf); + ibuf->userflags &= ~IB_RECT_INVALID; + } + } + } +} + +void MovieClipBaseOperation::deinitExecution() +{ + if (this->m_movieClipBuffer) { + IMB_freeImBuf(this->m_movieClipBuffer); + + this->m_movieClipBuffer = nullptr; + } +} + +void MovieClipBaseOperation::determineResolution(unsigned int resolution[2], + unsigned int /*preferredResolution*/[2]) +{ + resolution[0] = 0; + resolution[1] = 0; + + if (this->m_movieClip) { + int width, height; + + BKE_movieclip_get_size(this->m_movieClip, this->m_movieClipUser, &width, &height); + + resolution[0] = width; + resolution[1] = height; + } +} + +void MovieClipBaseOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + ImBuf *ibuf = this->m_movieClipBuffer; + + if (ibuf == nullptr) { + zero_v4(output); + } + else if (ibuf->rect == nullptr && ibuf->rect_float == nullptr) { + /* Happens for multilayer exr, i.e. */ + zero_v4(output); + } + else { + switch (sampler) { + case COM_PS_NEAREST: + nearest_interpolation_color(ibuf, nullptr, output, x, y); + break; + case COM_PS_BILINEAR: + bilinear_interpolation_color(ibuf, nullptr, output, x, y); + break; + case COM_PS_BICUBIC: + bicubic_interpolation_color(ibuf, nullptr, output, x, y); + break; + } + } +} + +MovieClipOperation::MovieClipOperation() : MovieClipBaseOperation() +{ + this->addOutputSocket(COM_DT_COLOR); +} + +MovieClipAlphaOperation::MovieClipAlphaOperation() : MovieClipBaseOperation() +{ + this->addOutputSocket(COM_DT_VALUE); +} + +void MovieClipAlphaOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float result[4]; + MovieClipBaseOperation::executePixelSampled(result, x, y, sampler); + output[0] = result[3]; +} diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cpp b/source/blender/compositor/operations/COM_MovieClipOperation.cpp deleted file mode 100644 index 4f819bf27af..00000000000 --- a/source/blender/compositor/operations/COM_MovieClipOperation.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MovieClipOperation.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" - -#include "BKE_image.h" -#include "BKE_movieclip.h" - -#include "IMB_imbuf.h" - -MovieClipBaseOperation::MovieClipBaseOperation() -{ - this->m_movieClip = nullptr; - this->m_movieClipBuffer = nullptr; - this->m_movieClipUser = nullptr; - this->m_movieClipwidth = 0; - this->m_movieClipheight = 0; - this->m_framenumber = 0; -} - -void MovieClipBaseOperation::initExecution() -{ - if (this->m_movieClip) { - BKE_movieclip_user_set_frame(this->m_movieClipUser, this->m_framenumber); - ImBuf *ibuf; - - if (this->m_cacheFrame) { - ibuf = BKE_movieclip_get_ibuf(this->m_movieClip, this->m_movieClipUser); - } - else { - ibuf = BKE_movieclip_get_ibuf_flag( - this->m_movieClip, this->m_movieClipUser, this->m_movieClip->flag, MOVIECLIP_CACHE_SKIP); - } - - if (ibuf) { - this->m_movieClipBuffer = ibuf; - if (ibuf->rect_float == nullptr || ibuf->userflags & IB_RECT_INVALID) { - IMB_float_from_rect(ibuf); - ibuf->userflags &= ~IB_RECT_INVALID; - } - } - } -} - -void MovieClipBaseOperation::deinitExecution() -{ - if (this->m_movieClipBuffer) { - IMB_freeImBuf(this->m_movieClipBuffer); - - this->m_movieClipBuffer = nullptr; - } -} - -void MovieClipBaseOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) -{ - resolution[0] = 0; - resolution[1] = 0; - - if (this->m_movieClip) { - int width, height; - - BKE_movieclip_get_size(this->m_movieClip, this->m_movieClipUser, &width, &height); - - resolution[0] = width; - resolution[1] = height; - } -} - -void MovieClipBaseOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - ImBuf *ibuf = this->m_movieClipBuffer; - - if (ibuf == nullptr) { - zero_v4(output); - } - else if (ibuf->rect == nullptr && ibuf->rect_float == nullptr) { - /* Happens for multilayer exr, i.e. */ - zero_v4(output); - } - else { - switch (sampler) { - case COM_PS_NEAREST: - nearest_interpolation_color(ibuf, nullptr, output, x, y); - break; - case COM_PS_BILINEAR: - bilinear_interpolation_color(ibuf, nullptr, output, x, y); - break; - case COM_PS_BICUBIC: - bicubic_interpolation_color(ibuf, nullptr, output, x, y); - break; - } - } -} - -MovieClipOperation::MovieClipOperation() : MovieClipBaseOperation() -{ - this->addOutputSocket(COM_DT_COLOR); -} - -MovieClipAlphaOperation::MovieClipAlphaOperation() : MovieClipBaseOperation() -{ - this->addOutputSocket(COM_DT_VALUE); -} - -void MovieClipAlphaOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float result[4]; - MovieClipBaseOperation::executePixelSampled(result, x, y, sampler); - output[0] = result[3]; -} diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc new file mode 100644 index 00000000000..5031d590720 --- /dev/null +++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc @@ -0,0 +1,127 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MovieDistortionOperation.h" + +#include "BKE_movieclip.h" +#include "BKE_tracking.h" + +#include "BLI_linklist.h" + +MovieDistortionOperation::MovieDistortionOperation(bool distortion) +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + this->m_inputOperation = nullptr; + this->m_movieClip = nullptr; + this->m_apply = distortion; +} + +void MovieDistortionOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); + if (this->m_movieClip) { + MovieTracking *tracking = &this->m_movieClip->tracking; + MovieClipUser clipUser = {0}; + int calibration_width, calibration_height; + + BKE_movieclip_user_set_frame(&clipUser, this->m_framenumber); + BKE_movieclip_get_size(this->m_movieClip, &clipUser, &calibration_width, &calibration_height); + + float delta[2]; + rcti full_frame; + full_frame.xmin = full_frame.ymin = 0; + full_frame.xmax = this->m_width; + full_frame.ymax = this->m_height; + BKE_tracking_max_distortion_delta_across_bound( + tracking, this->m_width, this->m_height, &full_frame, !this->m_apply, delta); + + /* 5 is just in case we didn't hit real max of distortion in + * BKE_tracking_max_undistortion_delta_across_bound + */ + m_margin[0] = delta[0] + 5; + m_margin[1] = delta[1] + 5; + + this->m_distortion = BKE_tracking_distortion_new( + tracking, calibration_width, calibration_height); + this->m_calibration_width = calibration_width; + this->m_calibration_height = calibration_height; + this->m_pixel_aspect = tracking->camera.pixel_aspect; + } + else { + m_margin[0] = m_margin[1] = 0; + this->m_distortion = nullptr; + } +} + +void MovieDistortionOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; + this->m_movieClip = nullptr; + if (this->m_distortion != nullptr) { + BKE_tracking_distortion_free(this->m_distortion); + } +} + +void MovieDistortionOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + if (this->m_distortion != nullptr) { + /* float overscan = 0.0f; */ + const float pixel_aspect = this->m_pixel_aspect; + const float w = (float)this->m_width /* / (1 + overscan) */; + const float h = (float)this->m_height /* / (1 + overscan) */; + const float aspx = w / (float)this->m_calibration_width; + const float aspy = h / (float)this->m_calibration_height; + float in[2]; + float out[2]; + + in[0] = (x /* - 0.5 * overscan * w */) / aspx; + in[1] = (y /* - 0.5 * overscan * h */) / aspy / pixel_aspect; + + if (this->m_apply) { + BKE_tracking_distortion_undistort_v2(this->m_distortion, in, out); + } + else { + BKE_tracking_distortion_distort_v2(this->m_distortion, in, out); + } + + float u = out[0] * aspx /* + 0.5 * overscan * w */, + v = (out[1] * aspy /* + 0.5 * overscan * h */) * pixel_aspect; + + this->m_inputOperation->readSampled(output, u, v, COM_PS_BILINEAR); + } + else { + this->m_inputOperation->readSampled(output, x, y, COM_PS_BILINEAR); + } +} + +bool MovieDistortionOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + newInput.xmin = input->xmin - m_margin[0]; + newInput.ymin = input->ymin - m_margin[1]; + newInput.xmax = input->xmax + m_margin[0]; + newInput.ymax = input->ymax + m_margin[1]; + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp deleted file mode 100644 index 5031d590720..00000000000 --- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MovieDistortionOperation.h" - -#include "BKE_movieclip.h" -#include "BKE_tracking.h" - -#include "BLI_linklist.h" - -MovieDistortionOperation::MovieDistortionOperation(bool distortion) -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = nullptr; - this->m_movieClip = nullptr; - this->m_apply = distortion; -} - -void MovieDistortionOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); - if (this->m_movieClip) { - MovieTracking *tracking = &this->m_movieClip->tracking; - MovieClipUser clipUser = {0}; - int calibration_width, calibration_height; - - BKE_movieclip_user_set_frame(&clipUser, this->m_framenumber); - BKE_movieclip_get_size(this->m_movieClip, &clipUser, &calibration_width, &calibration_height); - - float delta[2]; - rcti full_frame; - full_frame.xmin = full_frame.ymin = 0; - full_frame.xmax = this->m_width; - full_frame.ymax = this->m_height; - BKE_tracking_max_distortion_delta_across_bound( - tracking, this->m_width, this->m_height, &full_frame, !this->m_apply, delta); - - /* 5 is just in case we didn't hit real max of distortion in - * BKE_tracking_max_undistortion_delta_across_bound - */ - m_margin[0] = delta[0] + 5; - m_margin[1] = delta[1] + 5; - - this->m_distortion = BKE_tracking_distortion_new( - tracking, calibration_width, calibration_height); - this->m_calibration_width = calibration_width; - this->m_calibration_height = calibration_height; - this->m_pixel_aspect = tracking->camera.pixel_aspect; - } - else { - m_margin[0] = m_margin[1] = 0; - this->m_distortion = nullptr; - } -} - -void MovieDistortionOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; - this->m_movieClip = nullptr; - if (this->m_distortion != nullptr) { - BKE_tracking_distortion_free(this->m_distortion); - } -} - -void MovieDistortionOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - if (this->m_distortion != nullptr) { - /* float overscan = 0.0f; */ - const float pixel_aspect = this->m_pixel_aspect; - const float w = (float)this->m_width /* / (1 + overscan) */; - const float h = (float)this->m_height /* / (1 + overscan) */; - const float aspx = w / (float)this->m_calibration_width; - const float aspy = h / (float)this->m_calibration_height; - float in[2]; - float out[2]; - - in[0] = (x /* - 0.5 * overscan * w */) / aspx; - in[1] = (y /* - 0.5 * overscan * h */) / aspy / pixel_aspect; - - if (this->m_apply) { - BKE_tracking_distortion_undistort_v2(this->m_distortion, in, out); - } - else { - BKE_tracking_distortion_distort_v2(this->m_distortion, in, out); - } - - float u = out[0] * aspx /* + 0.5 * overscan * w */, - v = (out[1] * aspy /* + 0.5 * overscan * h */) * pixel_aspect; - - this->m_inputOperation->readSampled(output, u, v, COM_PS_BILINEAR); - } - else { - this->m_inputOperation->readSampled(output, x, y, COM_PS_BILINEAR); - } -} - -bool MovieDistortionOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - newInput.xmin = input->xmin - m_margin[0]; - newInput.ymin = input->ymin - m_margin[1]; - newInput.xmax = input->xmax + m_margin[0]; - newInput.ymax = input->ymax + m_margin[1]; - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cc b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc new file mode 100644 index 00000000000..60936ee1939 --- /dev/null +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc @@ -0,0 +1,157 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_MultilayerImageOperation.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +MultilayerBaseOperation::MultilayerBaseOperation(RenderLayer *render_layer, + RenderPass *render_pass, + int view) +{ + this->m_passId = BLI_findindex(&render_layer->passes, render_pass); + this->m_view = view; + this->m_renderLayer = render_layer; + this->m_renderPass = render_pass; +} + +ImBuf *MultilayerBaseOperation::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->pass = this->m_passId; + + 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 nullptr; +} + +std::unique_ptr MultilayerColorOperation::getMetaData() const +{ + BLI_assert(this->m_buffer); + MetaDataExtractCallbackData callback_data = {nullptr}; + RenderResult *render_result = this->m_image->rr; + if (render_result && render_result->stamp_data) { + RenderLayer *render_layer = this->m_renderLayer; + RenderPass *render_pass = this->m_renderPass; + std::string full_layer_name = + std::string(render_layer->name, + BLI_strnlen(render_layer->name, sizeof(render_layer->name))) + + "." + + std::string(render_pass->name, BLI_strnlen(render_pass->name, sizeof(render_pass->name))); + blender::StringRef cryptomatte_layer_name = + blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name(full_layer_name); + callback_data.setCryptomatteKeys(cryptomatte_layer_name); + + BKE_stamp_info_callback(&callback_data, + render_result->stamp_data, + MetaDataExtractCallbackData::extract_cryptomatte_meta_data, + false); + } + + return std::move(callback_data.meta_data); +} + +void MultilayerColorOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + if (this->m_imageFloatBuffer == nullptr) { + zero_v4(output); + } + else { + if (this->m_numberOfChannels == 4) { + switch (sampler) { + case COM_PS_NEAREST: + nearest_interpolation_color(this->m_buffer, nullptr, output, x, y); + break; + case COM_PS_BILINEAR: + bilinear_interpolation_color(this->m_buffer, nullptr, output, x, y); + break; + case COM_PS_BICUBIC: + bicubic_interpolation_color(this->m_buffer, nullptr, output, x, y); + break; + } + } + else { + int yi = y; + int xi = x; + if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || + (unsigned int)yi >= this->getHeight()) { + zero_v4(output); + } + else { + int offset = (yi * this->getWidth() + xi) * 3; + copy_v3_v3(output, &this->m_imageFloatBuffer[offset]); + } + } + } +} + +void MultilayerValueOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + if (this->m_imageFloatBuffer == nullptr) { + output[0] = 0.0f; + } + else { + int yi = y; + int xi = x; + if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || + (unsigned int)yi >= this->getHeight()) { + output[0] = 0.0f; + } + else { + float result = this->m_imageFloatBuffer[yi * this->getWidth() + xi]; + output[0] = result; + } + } +} + +void MultilayerVectorOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + if (this->m_imageFloatBuffer == nullptr) { + output[0] = 0.0f; + } + else { + int yi = y; + int xi = x; + if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || + (unsigned int)yi >= this->getHeight()) { + output[0] = 0.0f; + } + else { + int offset = (yi * this->getWidth() + xi) * 3; + copy_v3_v3(output, &this->m_imageFloatBuffer[offset]); + } + } +} diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp deleted file mode 100644 index 60936ee1939..00000000000 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_MultilayerImageOperation.h" - -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -MultilayerBaseOperation::MultilayerBaseOperation(RenderLayer *render_layer, - RenderPass *render_pass, - int view) -{ - this->m_passId = BLI_findindex(&render_layer->passes, render_pass); - this->m_view = view; - this->m_renderLayer = render_layer; - this->m_renderPass = render_pass; -} - -ImBuf *MultilayerBaseOperation::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->pass = this->m_passId; - - 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 nullptr; -} - -std::unique_ptr MultilayerColorOperation::getMetaData() const -{ - BLI_assert(this->m_buffer); - MetaDataExtractCallbackData callback_data = {nullptr}; - RenderResult *render_result = this->m_image->rr; - if (render_result && render_result->stamp_data) { - RenderLayer *render_layer = this->m_renderLayer; - RenderPass *render_pass = this->m_renderPass; - std::string full_layer_name = - std::string(render_layer->name, - BLI_strnlen(render_layer->name, sizeof(render_layer->name))) + - "." + - std::string(render_pass->name, BLI_strnlen(render_pass->name, sizeof(render_pass->name))); - blender::StringRef cryptomatte_layer_name = - blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name(full_layer_name); - callback_data.setCryptomatteKeys(cryptomatte_layer_name); - - BKE_stamp_info_callback(&callback_data, - render_result->stamp_data, - MetaDataExtractCallbackData::extract_cryptomatte_meta_data, - false); - } - - return std::move(callback_data.meta_data); -} - -void MultilayerColorOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - if (this->m_imageFloatBuffer == nullptr) { - zero_v4(output); - } - else { - if (this->m_numberOfChannels == 4) { - switch (sampler) { - case COM_PS_NEAREST: - nearest_interpolation_color(this->m_buffer, nullptr, output, x, y); - break; - case COM_PS_BILINEAR: - bilinear_interpolation_color(this->m_buffer, nullptr, output, x, y); - break; - case COM_PS_BICUBIC: - bicubic_interpolation_color(this->m_buffer, nullptr, output, x, y); - break; - } - } - else { - int yi = y; - int xi = x; - if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || - (unsigned int)yi >= this->getHeight()) { - zero_v4(output); - } - else { - int offset = (yi * this->getWidth() + xi) * 3; - copy_v3_v3(output, &this->m_imageFloatBuffer[offset]); - } - } - } -} - -void MultilayerValueOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - if (this->m_imageFloatBuffer == nullptr) { - output[0] = 0.0f; - } - else { - int yi = y; - int xi = x; - if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || - (unsigned int)yi >= this->getHeight()) { - output[0] = 0.0f; - } - else { - float result = this->m_imageFloatBuffer[yi * this->getWidth() + xi]; - output[0] = result; - } - } -} - -void MultilayerVectorOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - if (this->m_imageFloatBuffer == nullptr) { - output[0] = 0.0f; - } - else { - int yi = y; - int xi = x; - if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || - (unsigned int)yi >= this->getHeight()) { - output[0] = 0.0f; - } - else { - int offset = (yi * this->getWidth() + xi) * 3; - copy_v3_v3(output, &this->m_imageFloatBuffer[offset]); - } - } -} diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cc b/source/blender/compositor/operations/COM_NormalizeOperation.cc new file mode 100644 index 00000000000..a8448685332 --- /dev/null +++ b/source/blender/compositor/operations/COM_NormalizeOperation.cc @@ -0,0 +1,126 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_NormalizeOperation.h" + +NormalizeOperation::NormalizeOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + this->m_imageReader = nullptr; + this->m_cachedInstance = nullptr; + this->setComplex(true); +} +void NormalizeOperation::initExecution() +{ + this->m_imageReader = this->getInputSocketReader(0); + NodeOperation::initMutex(); +} + +void NormalizeOperation::executePixel(float output[4], int x, int y, void *data) +{ + /* using generic two floats struct to store x: min y: mult */ + NodeTwoFloats *minmult = (NodeTwoFloats *)data; + + this->m_imageReader->read(output, x, y, nullptr); + + output[0] = (output[0] - minmult->x) * minmult->y; + + /* clamp infinities */ + if (output[0] > 1.0f) { + output[0] = 1.0f; + } + else if (output[0] < 0.0f) { + output[0] = 0.0f; + } +} + +void NormalizeOperation::deinitExecution() +{ + this->m_imageReader = nullptr; + delete this->m_cachedInstance; + NodeOperation::deinitMutex(); +} + +bool NormalizeOperation::determineDependingAreaOfInterest(rcti * /*input*/, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti imageInput; + if (this->m_cachedInstance) { + return false; + } + + NodeOperation *operation = getInputOperation(0); + imageInput.xmax = operation->getWidth(); + imageInput.xmin = 0; + imageInput.ymax = operation->getHeight(); + imageInput.ymin = 0; + + if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) { + return true; + } + return false; +} + +/* The code below assumes all data is inside range +- this, and that input buffer is single channel + */ +#define BLENDER_ZMAX 10000.0f + +void *NormalizeOperation::initializeTileData(rcti *rect) +{ + lockMutex(); + if (this->m_cachedInstance == nullptr) { + MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect); + /* using generic two floats struct to store x: min y: mult */ + NodeTwoFloats *minmult = new NodeTwoFloats(); + + float *buffer = tile->getBuffer(); + int p = tile->getWidth() * tile->getHeight(); + float *bc = buffer; + + float minv = 1.0f + BLENDER_ZMAX; + float maxv = -1.0f - BLENDER_ZMAX; + + float value; + while (p--) { + value = bc[0]; + if ((value > maxv) && (value <= BLENDER_ZMAX)) { + maxv = value; + } + if ((value < minv) && (value >= -BLENDER_ZMAX)) { + minv = value; + } + bc++; + } + + minmult->x = minv; + /* The rare case of flat buffer would cause a divide by 0 */ + minmult->y = ((maxv != minv) ? 1.0f / (maxv - minv) : 0.0f); + + this->m_cachedInstance = minmult; + } + + unlockMutex(); + return this->m_cachedInstance; +} + +void NormalizeOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/) +{ + /* pass */ +} diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cpp b/source/blender/compositor/operations/COM_NormalizeOperation.cpp deleted file mode 100644 index a8448685332..00000000000 --- a/source/blender/compositor/operations/COM_NormalizeOperation.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_NormalizeOperation.h" - -NormalizeOperation::NormalizeOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VALUE); - this->m_imageReader = nullptr; - this->m_cachedInstance = nullptr; - this->setComplex(true); -} -void NormalizeOperation::initExecution() -{ - this->m_imageReader = this->getInputSocketReader(0); - NodeOperation::initMutex(); -} - -void NormalizeOperation::executePixel(float output[4], int x, int y, void *data) -{ - /* using generic two floats struct to store x: min y: mult */ - NodeTwoFloats *minmult = (NodeTwoFloats *)data; - - this->m_imageReader->read(output, x, y, nullptr); - - output[0] = (output[0] - minmult->x) * minmult->y; - - /* clamp infinities */ - if (output[0] > 1.0f) { - output[0] = 1.0f; - } - else if (output[0] < 0.0f) { - output[0] = 0.0f; - } -} - -void NormalizeOperation::deinitExecution() -{ - this->m_imageReader = nullptr; - delete this->m_cachedInstance; - NodeOperation::deinitMutex(); -} - -bool NormalizeOperation::determineDependingAreaOfInterest(rcti * /*input*/, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti imageInput; - if (this->m_cachedInstance) { - return false; - } - - NodeOperation *operation = getInputOperation(0); - imageInput.xmax = operation->getWidth(); - imageInput.xmin = 0; - imageInput.ymax = operation->getHeight(); - imageInput.ymin = 0; - - if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) { - return true; - } - return false; -} - -/* The code below assumes all data is inside range +- this, and that input buffer is single channel - */ -#define BLENDER_ZMAX 10000.0f - -void *NormalizeOperation::initializeTileData(rcti *rect) -{ - lockMutex(); - if (this->m_cachedInstance == nullptr) { - MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect); - /* using generic two floats struct to store x: min y: mult */ - NodeTwoFloats *minmult = new NodeTwoFloats(); - - float *buffer = tile->getBuffer(); - int p = tile->getWidth() * tile->getHeight(); - float *bc = buffer; - - float minv = 1.0f + BLENDER_ZMAX; - float maxv = -1.0f - BLENDER_ZMAX; - - float value; - while (p--) { - value = bc[0]; - if ((value > maxv) && (value <= BLENDER_ZMAX)) { - maxv = value; - } - if ((value < minv) && (value >= -BLENDER_ZMAX)) { - minv = value; - } - bc++; - } - - minmult->x = minv; - /* The rare case of flat buffer would cause a divide by 0 */ - minmult->y = ((maxv != minv) ? 1.0f / (maxv - minv) : 0.0f); - - this->m_cachedInstance = minmult; - } - - unlockMutex(); - return this->m_cachedInstance; -} - -void NormalizeOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/) -{ - /* pass */ -} diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc new file mode 100644 index 00000000000..7044fe402eb --- /dev/null +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc @@ -0,0 +1,382 @@ +/* + * 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. + * + * Copyright 2015, Blender Foundation. + */ + +#include "COM_OutputFileMultiViewOperation.h" +#include "COM_OutputFileOperation.h" + +#include + +#include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "DNA_color_types.h" +#include "MEM_guardedalloc.h" + +#include "IMB_colormanagement.h" +#include "IMB_imbuf.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, + const bool saveAsRender) + : OutputSingleLayerOperation( + rd, tree, datatype, format, path, viewSettings, displaySettings, viewName, saveAsRender) +{ +} + +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, nullptr, this->m_datatype, srv->name, width, false, nullptr); + } + + 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, nullptr) == 0) { + printf("Error Writing Singlelayer Multiview Openexr\n"); + IMB_exr_close(exrhandle); + } + else { + IMB_exr_clear_channels(exrhandle); + return exrhandle; + } + } + return nullptr; +} + +void OutputOpenExrSingleLayerMultiViewOperation::deinitExecution() +{ + unsigned int width = this->getWidth(); + unsigned int height = this->getHeight(); + + if (width != 0 && height != 0) { + void *exrhandle; + char filename[FILE_MAX]; + + BKE_image_path_from_imtype(filename, + this->m_path, + BKE_main_blendfile_path_from_global(), + this->m_rd->cfra, + R_IMF_IMTYPE_OPENEXR, + (this->m_rd->scemode & R_EXTENSION) != 0, + true, + nullptr); + + exrhandle = this->get_handle(filename); + add_exr_channels(exrhandle, + nullptr, + this->m_datatype, + this->m_viewName, + width, + this->m_format->depth == R_IMF_CHAN_DEPTH_16, + this->m_outputBuffer); + + /* memory can only be freed after we write all views to the file */ + this->m_outputBuffer = nullptr; + this->m_imageInput = nullptr; + + /* 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, nullptr, this->m_datatype); + + /* remove exr handle and data */ + IMB_exr_close(exrhandle); + } + } +} + +/************************************ OpenEXR Multilayer Multiview *******************************/ + +OutputOpenExrMultiLayerMultiViewOperation::OutputOpenExrMultiLayerMultiViewOperation( + const Scene *scene, + const RenderData *rd, + const bNodeTree *tree, + const char *path, + char exr_codec, + bool exr_half_float, + const char *viewName) + : OutputOpenExrMultiLayerOperation(scene, rd, tree, path, exr_codec, exr_half_float, 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, + this->m_exr_half_float, + nullptr); + } + } + + BLI_make_existing_file(filename); + + /* prepare the file with all the channels for the header */ + StampData *stamp_data = createStampData(); + if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, stamp_data) == + 0) { + printf("Error Writing Multilayer Multiview Openexr\n"); + IMB_exr_close(exrhandle); + BKE_stamp_data_free(stamp_data); + } + else { + IMB_exr_clear_channels(exrhandle); + BKE_stamp_data_free(stamp_data); + return exrhandle; + } + } + return nullptr; +} + +void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution() +{ + unsigned int width = this->getWidth(); + unsigned int height = this->getHeight(); + + if (width != 0 && height != 0) { + void *exrhandle; + char filename[FILE_MAX]; + + BKE_image_path_from_imtype(filename, + this->m_path, + BKE_main_blendfile_path_from_global(), + this->m_rd->cfra, + R_IMF_IMTYPE_MULTILAYER, + (this->m_rd->scemode & R_EXTENSION) != 0, + true, + nullptr); + + 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_exr_half_float, + 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 = nullptr; + this->m_layers[i].imageInput = nullptr; + } + + /* 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, + const bool saveAsRender) + : OutputSingleLayerOperation( + rd, tree, datatype, format, path, viewSettings, displaySettings, viewName, saveAsRender) +{ + 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 nullptr; +} + +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, + nullptr, + this->m_name, + this->m_viewName, + 1, + this->m_channels * width * height, + buf, + this->m_format->depth == R_IMF_CHAN_DEPTH_16); + + this->m_imageInput = nullptr; + this->m_outputBuffer = nullptr; + + /* create stereo ibuf */ + if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) { + ImBuf *ibuf[3] = {nullptr}; + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; + char filename[FILE_MAX]; + int i; + + /* get rectf from EXR */ + for (i = 0; i < 2; i++) { + float *rectf = IMB_exr_channel_rect(exrhandle, nullptr, 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, + BKE_main_blendfile_path_from_global(), + this->m_rd->cfra, + this->m_format, + (this->m_rd->scemode & R_EXTENSION) != 0, + true, + nullptr); + + 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.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp deleted file mode 100644 index 7044fe402eb..00000000000 --- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* - * 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. - * - * Copyright 2015, Blender Foundation. - */ - -#include "COM_OutputFileMultiViewOperation.h" -#include "COM_OutputFileOperation.h" - -#include - -#include "BLI_listbase.h" -#include "BLI_path_util.h" -#include "BLI_string.h" - -#include "BKE_global.h" -#include "BKE_image.h" -#include "BKE_main.h" -#include "BKE_scene.h" - -#include "DNA_color_types.h" -#include "MEM_guardedalloc.h" - -#include "IMB_colormanagement.h" -#include "IMB_imbuf.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, - const bool saveAsRender) - : OutputSingleLayerOperation( - rd, tree, datatype, format, path, viewSettings, displaySettings, viewName, saveAsRender) -{ -} - -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, nullptr, this->m_datatype, srv->name, width, false, nullptr); - } - - 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, nullptr) == 0) { - printf("Error Writing Singlelayer Multiview Openexr\n"); - IMB_exr_close(exrhandle); - } - else { - IMB_exr_clear_channels(exrhandle); - return exrhandle; - } - } - return nullptr; -} - -void OutputOpenExrSingleLayerMultiViewOperation::deinitExecution() -{ - unsigned int width = this->getWidth(); - unsigned int height = this->getHeight(); - - if (width != 0 && height != 0) { - void *exrhandle; - char filename[FILE_MAX]; - - BKE_image_path_from_imtype(filename, - this->m_path, - BKE_main_blendfile_path_from_global(), - this->m_rd->cfra, - R_IMF_IMTYPE_OPENEXR, - (this->m_rd->scemode & R_EXTENSION) != 0, - true, - nullptr); - - exrhandle = this->get_handle(filename); - add_exr_channels(exrhandle, - nullptr, - this->m_datatype, - this->m_viewName, - width, - this->m_format->depth == R_IMF_CHAN_DEPTH_16, - this->m_outputBuffer); - - /* memory can only be freed after we write all views to the file */ - this->m_outputBuffer = nullptr; - this->m_imageInput = nullptr; - - /* 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, nullptr, this->m_datatype); - - /* remove exr handle and data */ - IMB_exr_close(exrhandle); - } - } -} - -/************************************ OpenEXR Multilayer Multiview *******************************/ - -OutputOpenExrMultiLayerMultiViewOperation::OutputOpenExrMultiLayerMultiViewOperation( - const Scene *scene, - const RenderData *rd, - const bNodeTree *tree, - const char *path, - char exr_codec, - bool exr_half_float, - const char *viewName) - : OutputOpenExrMultiLayerOperation(scene, rd, tree, path, exr_codec, exr_half_float, 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, - this->m_exr_half_float, - nullptr); - } - } - - BLI_make_existing_file(filename); - - /* prepare the file with all the channels for the header */ - StampData *stamp_data = createStampData(); - if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, stamp_data) == - 0) { - printf("Error Writing Multilayer Multiview Openexr\n"); - IMB_exr_close(exrhandle); - BKE_stamp_data_free(stamp_data); - } - else { - IMB_exr_clear_channels(exrhandle); - BKE_stamp_data_free(stamp_data); - return exrhandle; - } - } - return nullptr; -} - -void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution() -{ - unsigned int width = this->getWidth(); - unsigned int height = this->getHeight(); - - if (width != 0 && height != 0) { - void *exrhandle; - char filename[FILE_MAX]; - - BKE_image_path_from_imtype(filename, - this->m_path, - BKE_main_blendfile_path_from_global(), - this->m_rd->cfra, - R_IMF_IMTYPE_MULTILAYER, - (this->m_rd->scemode & R_EXTENSION) != 0, - true, - nullptr); - - 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_exr_half_float, - 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 = nullptr; - this->m_layers[i].imageInput = nullptr; - } - - /* 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, - const bool saveAsRender) - : OutputSingleLayerOperation( - rd, tree, datatype, format, path, viewSettings, displaySettings, viewName, saveAsRender) -{ - 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 nullptr; -} - -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, - nullptr, - this->m_name, - this->m_viewName, - 1, - this->m_channels * width * height, - buf, - this->m_format->depth == R_IMF_CHAN_DEPTH_16); - - this->m_imageInput = nullptr; - this->m_outputBuffer = nullptr; - - /* create stereo ibuf */ - if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) { - ImBuf *ibuf[3] = {nullptr}; - const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - char filename[FILE_MAX]; - int i; - - /* get rectf from EXR */ - for (i = 0; i < 2; i++) { - float *rectf = IMB_exr_channel_rect(exrhandle, nullptr, 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, - BKE_main_blendfile_path_from_global(), - this->m_rd->cfra, - this->m_format, - (this->m_rd->scemode & R_EXTENSION) != 0, - true, - nullptr); - - 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_OutputFileOperation.cc b/source/blender/compositor/operations/COM_OutputFileOperation.cc new file mode 100644 index 00000000000..bb1b312ffec --- /dev/null +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc @@ -0,0 +1,443 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_OutputFileOperation.h" + +#include "COM_MetaData.h" + +#include + +#include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "DNA_color_types.h" +#include "MEM_guardedalloc.h" + +#include "IMB_colormanagement.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "RE_pipeline.h" + +void add_exr_channels(void *exrhandle, + const char *layerName, + const DataType datatype, + const char *viewName, + const size_t width, + bool use_half_float, + float *buf) +{ + /* create channels */ + switch (datatype) { + case COM_DT_VALUE: + IMB_exr_add_channel( + exrhandle, layerName, "V", viewName, 1, width, buf ? buf : nullptr, use_half_float); + break; + case COM_DT_VECTOR: + IMB_exr_add_channel( + exrhandle, layerName, "X", viewName, 3, 3 * width, buf ? buf : nullptr, use_half_float); + IMB_exr_add_channel(exrhandle, + layerName, + "Y", + viewName, + 3, + 3 * width, + buf ? buf + 1 : nullptr, + use_half_float); + IMB_exr_add_channel(exrhandle, + layerName, + "Z", + viewName, + 3, + 3 * width, + buf ? buf + 2 : nullptr, + use_half_float); + break; + case COM_DT_COLOR: + IMB_exr_add_channel( + exrhandle, layerName, "R", viewName, 4, 4 * width, buf ? buf : nullptr, use_half_float); + IMB_exr_add_channel(exrhandle, + layerName, + "G", + viewName, + 4, + 4 * width, + buf ? buf + 1 : nullptr, + use_half_float); + IMB_exr_add_channel(exrhandle, + layerName, + "B", + viewName, + 4, + 4 * width, + buf ? buf + 2 : nullptr, + use_half_float); + IMB_exr_add_channel(exrhandle, + layerName, + "A", + viewName, + 4, + 4 * width, + buf ? buf + 3 : nullptr, + use_half_float); + 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 = nullptr; + + 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; + case COM_DT_VECTOR: + return 3; + case COM_DT_COLOR: + return 4; + default: + return 0; + } +} + +static float *init_buffer(unsigned int width, unsigned int height, DataType datatype) +{ + // When initializing the tree during initial load the width and height can be zero. + if (width != 0 && height != 0) { + int size = get_datatype_size(datatype); + return (float *)MEM_callocN(width * height * size * sizeof(float), "OutputFile buffer"); + } + + return nullptr; +} + +static void write_buffer_rect(rcti *rect, + const bNodeTree *tree, + SocketReader *reader, + float *buffer, + unsigned int width, + DataType datatype) +{ + float color[4]; + int i, size = get_datatype_size(datatype); + + if (!buffer) { + return; + } + int x1 = rect->xmin; + int y1 = rect->ymin; + int x2 = rect->xmax; + int y2 = rect->ymax; + int offset = (y1 * width + x1) * size; + int x; + int y; + bool breaked = false; + + for (y = y1; y < y2 && (!breaked); y++) { + for (x = x1; x < x2 && (!breaked); x++) { + reader->readSampled(color, x, y, COM_PS_NEAREST); + + for (i = 0; i < size; i++) { + buffer[offset + i] = color[i]; + } + offset += size; + + if (tree->test_break && tree->test_break(tree->tbh)) { + breaked = true; + } + } + offset += (width - (x2 - x1)) * size; + } +} + +OutputSingleLayerOperation::OutputSingleLayerOperation( + const RenderData *rd, + const bNodeTree *tree, + DataType datatype, + ImageFormatData *format, + const char *path, + const ColorManagedViewSettings *viewSettings, + const ColorManagedDisplaySettings *displaySettings, + const char *viewName, + const bool saveAsRender) +{ + this->m_rd = rd; + this->m_tree = tree; + + this->addInputSocket(datatype); + + this->m_outputBuffer = nullptr; + this->m_datatype = datatype; + this->m_imageInput = nullptr; + + this->m_format = format; + BLI_strncpy(this->m_path, path, sizeof(this->m_path)); + + this->m_viewSettings = viewSettings; + this->m_displaySettings = displaySettings; + this->m_viewName = viewName; + this->m_saveAsRender = saveAsRender; +} + +void OutputSingleLayerOperation::initExecution() +{ + this->m_imageInput = getInputSocketReader(0); + this->m_outputBuffer = init_buffer(this->getWidth(), this->getHeight(), this->m_datatype); +} + +void OutputSingleLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) +{ + write_buffer_rect(rect, + this->m_tree, + this->m_imageInput, + this->m_outputBuffer, + this->getWidth(), + this->m_datatype); +} + +void OutputSingleLayerOperation::deinitExecution() +{ + if (this->getWidth() * this->getHeight() != 0) { + + int size = get_datatype_size(this->m_datatype); + ImBuf *ibuf = IMB_allocImBuf(this->getWidth(), this->getHeight(), this->m_format->planes, 0); + char filename[FILE_MAX]; + const char *suffix; + + ibuf->channels = size; + ibuf->rect_float = this->m_outputBuffer; + ibuf->mall |= IB_rectfloat; + ibuf->dither = this->m_rd->dither_intensity; + + IMB_colormanagement_imbuf_for_write( + ibuf, m_saveAsRender, 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, + BKE_main_blendfile_path_from_global(), + 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 { + printf("Saved: %s\n", filename); + } + + IMB_freeImBuf(ibuf); + } + this->m_outputBuffer = nullptr; + this->m_imageInput = nullptr; +} + +/******************************* MultiLayer *******************************/ + +OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bool use_layer_) +{ + BLI_strncpy(this->name, name_, sizeof(this->name)); + this->datatype = datatype_; + this->use_layer = use_layer_; + + /* these are created in initExecution */ + this->outputBuffer = nullptr; + this->imageInput = nullptr; +} + +OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation(const Scene *scene, + const RenderData *rd, + const bNodeTree *tree, + const char *path, + char exr_codec, + bool exr_half_float, + const char *viewName) +{ + this->m_scene = scene; + 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_exr_half_float = exr_half_float; + this->m_viewName = viewName; +} + +void OutputOpenExrMultiLayerOperation::add_layer(const char *name, + DataType datatype, + bool use_layer) +{ + this->addInputSocket(datatype); + this->m_layers.push_back(OutputOpenExrLayer(name, datatype, use_layer)); +} + +StampData *OutputOpenExrMultiLayerOperation::createStampData() const +{ + /* StampData API doesn't provide functions to modify an instance without having a RenderResult. + */ + RenderResult render_result; + StampData *stamp_data = BKE_stamp_info_from_scene_static(m_scene); + render_result.stamp_data = stamp_data; + for (int i = 0; i < this->m_layers.size(); i++) { + const OutputOpenExrLayer *layer = &this->m_layers[i]; + /* Skip unconnected sockets. */ + if (layer->imageInput == nullptr) { + continue; + } + std::unique_ptr meta_data = layer->imageInput->getMetaData(); + if (meta_data) { + blender::StringRef layer_name = + blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name( + blender::StringRef(layer->name, BLI_strnlen(layer->name, sizeof(layer->name)))); + meta_data->replaceHashNeutralCryptomatteKeys(layer_name); + meta_data->addToRenderResult(&render_result); + } + } + return stamp_data; +} + +void OutputOpenExrMultiLayerOperation::initExecution() +{ + for (unsigned int i = 0; i < this->m_layers.size(); i++) { + if (this->m_layers[i].use_layer) { + SocketReader *reader = getInputSocketReader(i); + this->m_layers[i].imageInput = reader; + this->m_layers[i].outputBuffer = init_buffer( + this->getWidth(), this->getHeight(), this->m_layers[i].datatype); + } + } +} + +void OutputOpenExrMultiLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) +{ + for (unsigned int i = 0; i < this->m_layers.size(); i++) { + OutputOpenExrLayer &layer = this->m_layers[i]; + if (layer.imageInput) { + write_buffer_rect(rect, + this->m_tree, + layer.imageInput, + layer.outputBuffer, + this->getWidth(), + layer.datatype); + } + } +} + +void OutputOpenExrMultiLayerOperation::deinitExecution() +{ + unsigned int width = this->getWidth(); + unsigned int height = this->getHeight(); + if (width != 0 && height != 0) { + 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, + BKE_main_blendfile_path_from_global(), + this->m_rd->cfra, + R_IMF_IMTYPE_MULTILAYER, + (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 */ + } + + add_exr_channels(exrhandle, + this->m_layers[i].name, + this->m_layers[i].datatype, + "", + width, + this->m_exr_half_float, + this->m_layers[i].outputBuffer); + } + + /* when the filename has no permissions, this can fail */ + StampData *stamp_data = createStampData(); + if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, stamp_data)) { + IMB_exr_write_channels(exrhandle); + } + else { + /* TODO, get the error from openexr's exception */ + /* XXX nice way to do report? */ + printf("Error Writing Render Result, see console\n"); + } + + IMB_exr_close(exrhandle); + for (unsigned int i = 0; i < this->m_layers.size(); i++) { + if (this->m_layers[i].outputBuffer) { + MEM_freeN(this->m_layers[i].outputBuffer); + this->m_layers[i].outputBuffer = nullptr; + } + + this->m_layers[i].imageInput = nullptr; + } + BKE_stamp_data_free(stamp_data); + } +} diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp deleted file mode 100644 index bb1b312ffec..00000000000 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_OutputFileOperation.h" - -#include "COM_MetaData.h" - -#include - -#include "BLI_listbase.h" -#include "BLI_path_util.h" -#include "BLI_string.h" - -#include "BKE_global.h" -#include "BKE_image.h" -#include "BKE_main.h" -#include "BKE_scene.h" - -#include "DNA_color_types.h" -#include "MEM_guardedalloc.h" - -#include "IMB_colormanagement.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -#include "RE_pipeline.h" - -void add_exr_channels(void *exrhandle, - const char *layerName, - const DataType datatype, - const char *viewName, - const size_t width, - bool use_half_float, - float *buf) -{ - /* create channels */ - switch (datatype) { - case COM_DT_VALUE: - IMB_exr_add_channel( - exrhandle, layerName, "V", viewName, 1, width, buf ? buf : nullptr, use_half_float); - break; - case COM_DT_VECTOR: - IMB_exr_add_channel( - exrhandle, layerName, "X", viewName, 3, 3 * width, buf ? buf : nullptr, use_half_float); - IMB_exr_add_channel(exrhandle, - layerName, - "Y", - viewName, - 3, - 3 * width, - buf ? buf + 1 : nullptr, - use_half_float); - IMB_exr_add_channel(exrhandle, - layerName, - "Z", - viewName, - 3, - 3 * width, - buf ? buf + 2 : nullptr, - use_half_float); - break; - case COM_DT_COLOR: - IMB_exr_add_channel( - exrhandle, layerName, "R", viewName, 4, 4 * width, buf ? buf : nullptr, use_half_float); - IMB_exr_add_channel(exrhandle, - layerName, - "G", - viewName, - 4, - 4 * width, - buf ? buf + 1 : nullptr, - use_half_float); - IMB_exr_add_channel(exrhandle, - layerName, - "B", - viewName, - 4, - 4 * width, - buf ? buf + 2 : nullptr, - use_half_float); - IMB_exr_add_channel(exrhandle, - layerName, - "A", - viewName, - 4, - 4 * width, - buf ? buf + 3 : nullptr, - use_half_float); - 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 = nullptr; - - 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; - case COM_DT_VECTOR: - return 3; - case COM_DT_COLOR: - return 4; - default: - return 0; - } -} - -static float *init_buffer(unsigned int width, unsigned int height, DataType datatype) -{ - // When initializing the tree during initial load the width and height can be zero. - if (width != 0 && height != 0) { - int size = get_datatype_size(datatype); - return (float *)MEM_callocN(width * height * size * sizeof(float), "OutputFile buffer"); - } - - return nullptr; -} - -static void write_buffer_rect(rcti *rect, - const bNodeTree *tree, - SocketReader *reader, - float *buffer, - unsigned int width, - DataType datatype) -{ - float color[4]; - int i, size = get_datatype_size(datatype); - - if (!buffer) { - return; - } - int x1 = rect->xmin; - int y1 = rect->ymin; - int x2 = rect->xmax; - int y2 = rect->ymax; - int offset = (y1 * width + x1) * size; - int x; - int y; - bool breaked = false; - - for (y = y1; y < y2 && (!breaked); y++) { - for (x = x1; x < x2 && (!breaked); x++) { - reader->readSampled(color, x, y, COM_PS_NEAREST); - - for (i = 0; i < size; i++) { - buffer[offset + i] = color[i]; - } - offset += size; - - if (tree->test_break && tree->test_break(tree->tbh)) { - breaked = true; - } - } - offset += (width - (x2 - x1)) * size; - } -} - -OutputSingleLayerOperation::OutputSingleLayerOperation( - const RenderData *rd, - const bNodeTree *tree, - DataType datatype, - ImageFormatData *format, - const char *path, - const ColorManagedViewSettings *viewSettings, - const ColorManagedDisplaySettings *displaySettings, - const char *viewName, - const bool saveAsRender) -{ - this->m_rd = rd; - this->m_tree = tree; - - this->addInputSocket(datatype); - - this->m_outputBuffer = nullptr; - this->m_datatype = datatype; - this->m_imageInput = nullptr; - - this->m_format = format; - BLI_strncpy(this->m_path, path, sizeof(this->m_path)); - - this->m_viewSettings = viewSettings; - this->m_displaySettings = displaySettings; - this->m_viewName = viewName; - this->m_saveAsRender = saveAsRender; -} - -void OutputSingleLayerOperation::initExecution() -{ - this->m_imageInput = getInputSocketReader(0); - this->m_outputBuffer = init_buffer(this->getWidth(), this->getHeight(), this->m_datatype); -} - -void OutputSingleLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) -{ - write_buffer_rect(rect, - this->m_tree, - this->m_imageInput, - this->m_outputBuffer, - this->getWidth(), - this->m_datatype); -} - -void OutputSingleLayerOperation::deinitExecution() -{ - if (this->getWidth() * this->getHeight() != 0) { - - int size = get_datatype_size(this->m_datatype); - ImBuf *ibuf = IMB_allocImBuf(this->getWidth(), this->getHeight(), this->m_format->planes, 0); - char filename[FILE_MAX]; - const char *suffix; - - ibuf->channels = size; - ibuf->rect_float = this->m_outputBuffer; - ibuf->mall |= IB_rectfloat; - ibuf->dither = this->m_rd->dither_intensity; - - IMB_colormanagement_imbuf_for_write( - ibuf, m_saveAsRender, 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, - BKE_main_blendfile_path_from_global(), - 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 { - printf("Saved: %s\n", filename); - } - - IMB_freeImBuf(ibuf); - } - this->m_outputBuffer = nullptr; - this->m_imageInput = nullptr; -} - -/******************************* MultiLayer *******************************/ - -OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bool use_layer_) -{ - BLI_strncpy(this->name, name_, sizeof(this->name)); - this->datatype = datatype_; - this->use_layer = use_layer_; - - /* these are created in initExecution */ - this->outputBuffer = nullptr; - this->imageInput = nullptr; -} - -OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation(const Scene *scene, - const RenderData *rd, - const bNodeTree *tree, - const char *path, - char exr_codec, - bool exr_half_float, - const char *viewName) -{ - this->m_scene = scene; - 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_exr_half_float = exr_half_float; - this->m_viewName = viewName; -} - -void OutputOpenExrMultiLayerOperation::add_layer(const char *name, - DataType datatype, - bool use_layer) -{ - this->addInputSocket(datatype); - this->m_layers.push_back(OutputOpenExrLayer(name, datatype, use_layer)); -} - -StampData *OutputOpenExrMultiLayerOperation::createStampData() const -{ - /* StampData API doesn't provide functions to modify an instance without having a RenderResult. - */ - RenderResult render_result; - StampData *stamp_data = BKE_stamp_info_from_scene_static(m_scene); - render_result.stamp_data = stamp_data; - for (int i = 0; i < this->m_layers.size(); i++) { - const OutputOpenExrLayer *layer = &this->m_layers[i]; - /* Skip unconnected sockets. */ - if (layer->imageInput == nullptr) { - continue; - } - std::unique_ptr meta_data = layer->imageInput->getMetaData(); - if (meta_data) { - blender::StringRef layer_name = - blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name( - blender::StringRef(layer->name, BLI_strnlen(layer->name, sizeof(layer->name)))); - meta_data->replaceHashNeutralCryptomatteKeys(layer_name); - meta_data->addToRenderResult(&render_result); - } - } - return stamp_data; -} - -void OutputOpenExrMultiLayerOperation::initExecution() -{ - for (unsigned int i = 0; i < this->m_layers.size(); i++) { - if (this->m_layers[i].use_layer) { - SocketReader *reader = getInputSocketReader(i); - this->m_layers[i].imageInput = reader; - this->m_layers[i].outputBuffer = init_buffer( - this->getWidth(), this->getHeight(), this->m_layers[i].datatype); - } - } -} - -void OutputOpenExrMultiLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) -{ - for (unsigned int i = 0; i < this->m_layers.size(); i++) { - OutputOpenExrLayer &layer = this->m_layers[i]; - if (layer.imageInput) { - write_buffer_rect(rect, - this->m_tree, - layer.imageInput, - layer.outputBuffer, - this->getWidth(), - layer.datatype); - } - } -} - -void OutputOpenExrMultiLayerOperation::deinitExecution() -{ - unsigned int width = this->getWidth(); - unsigned int height = this->getHeight(); - if (width != 0 && height != 0) { - 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, - BKE_main_blendfile_path_from_global(), - this->m_rd->cfra, - R_IMF_IMTYPE_MULTILAYER, - (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 */ - } - - add_exr_channels(exrhandle, - this->m_layers[i].name, - this->m_layers[i].datatype, - "", - width, - this->m_exr_half_float, - this->m_layers[i].outputBuffer); - } - - /* when the filename has no permissions, this can fail */ - StampData *stamp_data = createStampData(); - if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, stamp_data)) { - IMB_exr_write_channels(exrhandle); - } - else { - /* TODO, get the error from openexr's exception */ - /* XXX nice way to do report? */ - printf("Error Writing Render Result, see console\n"); - } - - IMB_exr_close(exrhandle); - for (unsigned int i = 0; i < this->m_layers.size(); i++) { - if (this->m_layers[i].outputBuffer) { - MEM_freeN(this->m_layers[i].outputBuffer); - this->m_layers[i].outputBuffer = nullptr; - } - - this->m_layers[i].imageInput = nullptr; - } - BKE_stamp_data_free(stamp_data); - } -} diff --git a/source/blender/compositor/operations/COM_PixelateOperation.cc b/source/blender/compositor/operations/COM_PixelateOperation.cc new file mode 100644 index 00000000000..0d810c80ab4 --- /dev/null +++ b/source/blender/compositor/operations/COM_PixelateOperation.cc @@ -0,0 +1,47 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_PixelateOperation.h" + +PixelateOperation::PixelateOperation(DataType datatype) +{ + this->addInputSocket(datatype); + this->addOutputSocket(datatype); + this->setResolutionInputSocketIndex(0); + this->m_inputOperation = nullptr; +} + +void PixelateOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); +} + +void PixelateOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; +} + +void PixelateOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float nx = round(x); + float ny = round(y); + this->m_inputOperation->readSampled(output, nx, ny, sampler); +} diff --git a/source/blender/compositor/operations/COM_PixelateOperation.cpp b/source/blender/compositor/operations/COM_PixelateOperation.cpp deleted file mode 100644 index 0d810c80ab4..00000000000 --- a/source/blender/compositor/operations/COM_PixelateOperation.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_PixelateOperation.h" - -PixelateOperation::PixelateOperation(DataType datatype) -{ - this->addInputSocket(datatype); - this->addOutputSocket(datatype); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = nullptr; -} - -void PixelateOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void PixelateOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; -} - -void PixelateOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float nx = round(x); - float ny = round(y); - this->m_inputOperation->readSampled(output, nx, ny, sampler); -} diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc new file mode 100644 index 00000000000..d4f2ca7bbe8 --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc @@ -0,0 +1,226 @@ +/* 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. + * + * Copyright 2014, Blender Foundation. + */ + +#include "COM_PlaneCornerPinOperation.h" +#include "COM_ReadBufferOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" + +#include "BKE_node.h" + +static bool check_corners(float corners[4][2]) +{ + int i, next, prev; + float cross = 0.0f; + + for (i = 0; i < 4; i++) { + float v1[2], v2[2], cur_cross; + + next = (i + 1) % 4; + prev = (4 + i - 1) % 4; + + sub_v2_v2v2(v1, corners[i], corners[prev]); + sub_v2_v2v2(v2, corners[next], corners[i]); + + cur_cross = cross_v2v2(v1, v2); + if (fabsf(cur_cross) <= FLT_EPSILON) { + return false; + } + + if (cross == 0.0f) { + cross = cur_cross; + } + else if (cross * cur_cross < 0.0f) { + return false; + } + } + + return true; +} + +static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float corners[4][2]) +{ + for (int i = 0; i < 4; i++) { + float result[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + readers[i]->readSampled(result, rect->xmin, rect->ymin, COM_PS_NEAREST); + corners[i][0] = result[0]; + corners[i][1] = result[1]; + } + + /* convexity check: + * concave corners need to be prevented, otherwise + * BKE_tracking_homography_between_two_quads will freeze + */ + if (!check_corners(corners)) { + /* simply revert to default corners + * there could be a more elegant solution, + * this prevents freezing at least. + */ + corners[0][0] = 0.0f; + corners[0][1] = 0.0f; + corners[1][0] = 1.0f; + corners[1][1] = 0.0f; + corners[2][0] = 1.0f; + corners[2][1] = 1.0f; + corners[3][0] = 0.0f; + corners[3][1] = 1.0f; + } +} + +/* ******** PlaneCornerPinMaskOperation ******** */ + +PlaneCornerPinMaskOperation::PlaneCornerPinMaskOperation() : m_corners_ready(false) +{ + addInputSocket(COM_DT_VECTOR); + addInputSocket(COM_DT_VECTOR); + addInputSocket(COM_DT_VECTOR); + addInputSocket(COM_DT_VECTOR); + + /* XXX this is stupid: we need to make this "complex", + * so we can use the initializeTileData function + * to read corners from input sockets ... + */ + setComplex(true); +} + +void PlaneCornerPinMaskOperation::initExecution() +{ + PlaneDistortMaskOperation::initExecution(); + + initMutex(); +} + +void PlaneCornerPinMaskOperation::deinitExecution() +{ + PlaneDistortMaskOperation::deinitExecution(); + + deinitMutex(); +} + +void *PlaneCornerPinMaskOperation::initializeTileData(rcti *rect) +{ + void *data = PlaneDistortMaskOperation::initializeTileData(rect); + + /* get corner values once, by reading inputs at (0,0) + * XXX this assumes invariable values (no image inputs), + * we don't have a nice generic system for that yet + */ + lockMutex(); + if (!m_corners_ready) { + SocketReader *readers[4] = { + getInputSocketReader(0), + getInputSocketReader(1), + getInputSocketReader(2), + getInputSocketReader(3), + }; + float corners[4][2]; + readCornersFromSockets(rect, readers, corners); + calculateCorners(corners, true, 0); + + m_corners_ready = true; + } + unlockMutex(); + + return data; +} + +void PlaneCornerPinMaskOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + resolution[0] = preferredResolution[0]; + resolution[1] = preferredResolution[1]; +} + +/* ******** PlaneCornerPinWarpImageOperation ******** */ + +PlaneCornerPinWarpImageOperation::PlaneCornerPinWarpImageOperation() : m_corners_ready(false) +{ + addInputSocket(COM_DT_VECTOR); + addInputSocket(COM_DT_VECTOR); + addInputSocket(COM_DT_VECTOR); + addInputSocket(COM_DT_VECTOR); +} + +void PlaneCornerPinWarpImageOperation::initExecution() +{ + PlaneDistortWarpImageOperation::initExecution(); + + initMutex(); +} + +void PlaneCornerPinWarpImageOperation::deinitExecution() +{ + PlaneDistortWarpImageOperation::deinitExecution(); + + deinitMutex(); +} + +void *PlaneCornerPinWarpImageOperation::initializeTileData(rcti *rect) +{ + void *data = PlaneDistortWarpImageOperation::initializeTileData(rect); + + /* get corner values once, by reading inputs at (0,0) + * XXX this assumes invariable values (no image inputs), + * we don't have a nice generic system for that yet + */ + lockMutex(); + if (!m_corners_ready) { + /* corner sockets start at index 1 */ + SocketReader *readers[4] = { + getInputSocketReader(1), + getInputSocketReader(2), + getInputSocketReader(3), + getInputSocketReader(4), + }; + float corners[4][2]; + readCornersFromSockets(rect, readers, corners); + calculateCorners(corners, true, 0); + + m_corners_ready = true; + } + unlockMutex(); + + return data; +} + +bool PlaneCornerPinWarpImageOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + for (int i = 0; i < 4; i++) { + if (getInputOperation(i + 1)->determineDependingAreaOfInterest(input, readOperation, output)) { + return true; + } + } + + /* XXX this is bad, but unavoidable with the current design: + * we don't know the actual corners and matrix at this point, + * so all we can do is get the full input image + */ + output->xmin = 0; + output->ymin = 0; + output->xmax = getInputOperation(0)->getWidth(); + output->ymax = getInputOperation(0)->getHeight(); + return true; +#if 0 + return PlaneDistortWarpImageOperation::determineDependingAreaOfInterest( + input, readOperation, output); +#endif +} diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp deleted file mode 100644 index d4f2ca7bbe8..00000000000 --- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* 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. - * - * Copyright 2014, Blender Foundation. - */ - -#include "COM_PlaneCornerPinOperation.h" -#include "COM_ReadBufferOperation.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_math_color.h" - -#include "BKE_node.h" - -static bool check_corners(float corners[4][2]) -{ - int i, next, prev; - float cross = 0.0f; - - for (i = 0; i < 4; i++) { - float v1[2], v2[2], cur_cross; - - next = (i + 1) % 4; - prev = (4 + i - 1) % 4; - - sub_v2_v2v2(v1, corners[i], corners[prev]); - sub_v2_v2v2(v2, corners[next], corners[i]); - - cur_cross = cross_v2v2(v1, v2); - if (fabsf(cur_cross) <= FLT_EPSILON) { - return false; - } - - if (cross == 0.0f) { - cross = cur_cross; - } - else if (cross * cur_cross < 0.0f) { - return false; - } - } - - return true; -} - -static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float corners[4][2]) -{ - for (int i = 0; i < 4; i++) { - float result[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - readers[i]->readSampled(result, rect->xmin, rect->ymin, COM_PS_NEAREST); - corners[i][0] = result[0]; - corners[i][1] = result[1]; - } - - /* convexity check: - * concave corners need to be prevented, otherwise - * BKE_tracking_homography_between_two_quads will freeze - */ - if (!check_corners(corners)) { - /* simply revert to default corners - * there could be a more elegant solution, - * this prevents freezing at least. - */ - corners[0][0] = 0.0f; - corners[0][1] = 0.0f; - corners[1][0] = 1.0f; - corners[1][1] = 0.0f; - corners[2][0] = 1.0f; - corners[2][1] = 1.0f; - corners[3][0] = 0.0f; - corners[3][1] = 1.0f; - } -} - -/* ******** PlaneCornerPinMaskOperation ******** */ - -PlaneCornerPinMaskOperation::PlaneCornerPinMaskOperation() : m_corners_ready(false) -{ - addInputSocket(COM_DT_VECTOR); - addInputSocket(COM_DT_VECTOR); - addInputSocket(COM_DT_VECTOR); - addInputSocket(COM_DT_VECTOR); - - /* XXX this is stupid: we need to make this "complex", - * so we can use the initializeTileData function - * to read corners from input sockets ... - */ - setComplex(true); -} - -void PlaneCornerPinMaskOperation::initExecution() -{ - PlaneDistortMaskOperation::initExecution(); - - initMutex(); -} - -void PlaneCornerPinMaskOperation::deinitExecution() -{ - PlaneDistortMaskOperation::deinitExecution(); - - deinitMutex(); -} - -void *PlaneCornerPinMaskOperation::initializeTileData(rcti *rect) -{ - void *data = PlaneDistortMaskOperation::initializeTileData(rect); - - /* get corner values once, by reading inputs at (0,0) - * XXX this assumes invariable values (no image inputs), - * we don't have a nice generic system for that yet - */ - lockMutex(); - if (!m_corners_ready) { - SocketReader *readers[4] = { - getInputSocketReader(0), - getInputSocketReader(1), - getInputSocketReader(2), - getInputSocketReader(3), - }; - float corners[4][2]; - readCornersFromSockets(rect, readers, corners); - calculateCorners(corners, true, 0); - - m_corners_ready = true; - } - unlockMutex(); - - return data; -} - -void PlaneCornerPinMaskOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; -} - -/* ******** PlaneCornerPinWarpImageOperation ******** */ - -PlaneCornerPinWarpImageOperation::PlaneCornerPinWarpImageOperation() : m_corners_ready(false) -{ - addInputSocket(COM_DT_VECTOR); - addInputSocket(COM_DT_VECTOR); - addInputSocket(COM_DT_VECTOR); - addInputSocket(COM_DT_VECTOR); -} - -void PlaneCornerPinWarpImageOperation::initExecution() -{ - PlaneDistortWarpImageOperation::initExecution(); - - initMutex(); -} - -void PlaneCornerPinWarpImageOperation::deinitExecution() -{ - PlaneDistortWarpImageOperation::deinitExecution(); - - deinitMutex(); -} - -void *PlaneCornerPinWarpImageOperation::initializeTileData(rcti *rect) -{ - void *data = PlaneDistortWarpImageOperation::initializeTileData(rect); - - /* get corner values once, by reading inputs at (0,0) - * XXX this assumes invariable values (no image inputs), - * we don't have a nice generic system for that yet - */ - lockMutex(); - if (!m_corners_ready) { - /* corner sockets start at index 1 */ - SocketReader *readers[4] = { - getInputSocketReader(1), - getInputSocketReader(2), - getInputSocketReader(3), - getInputSocketReader(4), - }; - float corners[4][2]; - readCornersFromSockets(rect, readers, corners); - calculateCorners(corners, true, 0); - - m_corners_ready = true; - } - unlockMutex(); - - return data; -} - -bool PlaneCornerPinWarpImageOperation::determineDependingAreaOfInterest( - rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - for (int i = 0; i < 4; i++) { - if (getInputOperation(i + 1)->determineDependingAreaOfInterest(input, readOperation, output)) { - return true; - } - } - - /* XXX this is bad, but unavoidable with the current design: - * we don't know the actual corners and matrix at this point, - * so all we can do is get the full input image - */ - output->xmin = 0; - output->ymin = 0; - output->xmax = getInputOperation(0)->getWidth(); - output->ymax = getInputOperation(0)->getHeight(); - return true; -#if 0 - return PlaneDistortWarpImageOperation::determineDependingAreaOfInterest( - input, readOperation, output); -#endif -} diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc new file mode 100644 index 00000000000..c395f795a22 --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc @@ -0,0 +1,228 @@ +/* + * 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. + * + * Copyright 2013, Blender Foundation. + */ + +#include "COM_PlaneDistortCommonOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_jitter_2d.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" + +#include "BKE_movieclip.h" +#include "BKE_node.h" +#include "BKE_tracking.h" + +/* ******** PlaneDistort WarpImage ******** */ + +BLI_INLINE void warpCoord(float x, float y, float matrix[3][3], float uv[2], float deriv[2][2]) +{ + float vec[3] = {x, y, 1.0f}; + mul_m3_v3(matrix, vec); + uv[0] = vec[0] / vec[2]; + uv[1] = vec[1] / vec[2]; + + deriv[0][0] = (matrix[0][0] - matrix[0][2] * uv[0]) / vec[2]; + deriv[1][0] = (matrix[0][1] - matrix[0][2] * uv[1]) / vec[2]; + deriv[0][1] = (matrix[1][0] - matrix[1][2] * uv[0]) / vec[2]; + deriv[1][1] = (matrix[1][1] - matrix[1][2] * uv[1]) / vec[2]; +} + +PlaneDistortWarpImageOperation::PlaneDistortWarpImageOperation() +{ + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); + this->addOutputSocket(COM_DT_COLOR); + this->m_pixelReader = nullptr; + this->m_motion_blur_samples = 1; + this->m_motion_blur_shutter = 0.5f; + this->setComplex(true); +} + +void PlaneDistortWarpImageOperation::calculateCorners(const float corners[4][2], + bool normalized, + int sample) +{ + BLI_assert(sample < this->m_motion_blur_samples); + const int width = this->m_pixelReader->getWidth(); + const int height = this->m_pixelReader->getHeight(); + float frame_corners[4][2] = { + {0.0f, 0.0f}, {(float)width, 0.0f}, {(float)width, (float)height}, {0.0f, (float)height}}; + MotionSample *sample_data = &this->m_samples[sample]; + if (normalized) { + for (int i = 0; i < 4; i++) { + sample_data->frameSpaceCorners[i][0] = corners[i][0] * this->getWidth(); + sample_data->frameSpaceCorners[i][1] = corners[i][1] * this->getHeight(); + } + } + else { + for (int i = 0; i < 4; i++) { + sample_data->frameSpaceCorners[i][0] = corners[i][0]; + sample_data->frameSpaceCorners[i][1] = corners[i][1]; + } + } + BKE_tracking_homography_between_two_quads( + sample_data->frameSpaceCorners, frame_corners, sample_data->perspectiveMatrix); +} + +void PlaneDistortWarpImageOperation::initExecution() +{ + this->m_pixelReader = this->getInputSocketReader(0); +} + +void PlaneDistortWarpImageOperation::deinitExecution() +{ + this->m_pixelReader = nullptr; +} + +void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + float uv[2]; + float deriv[2][2]; + if (this->m_motion_blur_samples == 1) { + warpCoord(x, y, this->m_samples[0].perspectiveMatrix, uv, deriv); + m_pixelReader->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]); + } + else { + zero_v4(output); + for (int sample = 0; sample < this->m_motion_blur_samples; sample++) { + float color[4]; + warpCoord(x, y, this->m_samples[sample].perspectiveMatrix, uv, deriv); + m_pixelReader->readFiltered(color, uv[0], uv[1], deriv[0], deriv[1]); + add_v4_v4(output, color); + } + mul_v4_fl(output, 1.0f / (float)this->m_motion_blur_samples); + } +} + +bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + float min[2], max[2]; + INIT_MINMAX2(min, max); + + for (int sample = 0; sample < this->m_motion_blur_samples; sample++) { + float UVs[4][2]; + float deriv[2][2]; + MotionSample *sample_data = &this->m_samples[sample]; + /* TODO(sergey): figure out proper way to do this. */ + warpCoord(input->xmin - 2, input->ymin - 2, sample_data->perspectiveMatrix, UVs[0], deriv); + warpCoord(input->xmax + 2, input->ymin - 2, sample_data->perspectiveMatrix, UVs[1], deriv); + warpCoord(input->xmax + 2, input->ymax + 2, sample_data->perspectiveMatrix, UVs[2], deriv); + warpCoord(input->xmin - 2, input->ymax + 2, sample_data->perspectiveMatrix, UVs[3], deriv); + for (int i = 0; i < 4; i++) { + minmax_v2v2_v2(min, max, UVs[i]); + } + } + + rcti newInput; + + newInput.xmin = min[0] - 1; + newInput.ymin = min[1] - 1; + newInput.xmax = max[0] + 1; + newInput.ymax = max[1] + 1; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +/* ******** PlaneDistort Mask ******** */ + +PlaneDistortMaskOperation::PlaneDistortMaskOperation() +{ + addOutputSocket(COM_DT_VALUE); + + /* Currently hardcoded to 8 samples. */ + m_osa = 8; + this->m_motion_blur_samples = 1; + this->m_motion_blur_shutter = 0.5f; +} + +void PlaneDistortMaskOperation::calculateCorners(const float corners[4][2], + bool normalized, + int sample) +{ + BLI_assert(sample < this->m_motion_blur_samples); + MotionSample *sample_data = &this->m_samples[sample]; + if (normalized) { + for (int i = 0; i < 4; i++) { + sample_data->frameSpaceCorners[i][0] = corners[i][0] * this->getWidth(); + sample_data->frameSpaceCorners[i][1] = corners[i][1] * this->getHeight(); + } + } + else { + for (int i = 0; i < 4; i++) { + sample_data->frameSpaceCorners[i][0] = corners[i][0]; + sample_data->frameSpaceCorners[i][1] = corners[i][1]; + } + } +} + +void PlaneDistortMaskOperation::initExecution() +{ + BLI_jitter_init(m_jitter, m_osa); +} + +void PlaneDistortMaskOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + float point[2]; + int inside_counter = 0; + if (this->m_motion_blur_samples == 1) { + MotionSample *sample_data = &this->m_samples[0]; + for (int sample = 0; sample < this->m_osa; sample++) { + point[0] = x + this->m_jitter[sample][0]; + point[1] = y + this->m_jitter[sample][1]; + if (isect_point_tri_v2(point, + sample_data->frameSpaceCorners[0], + sample_data->frameSpaceCorners[1], + sample_data->frameSpaceCorners[2]) || + isect_point_tri_v2(point, + sample_data->frameSpaceCorners[0], + sample_data->frameSpaceCorners[2], + sample_data->frameSpaceCorners[3])) { + inside_counter++; + } + } + output[0] = (float)inside_counter / this->m_osa; + } + else { + for (int motion_sample = 0; motion_sample < this->m_motion_blur_samples; motion_sample++) { + MotionSample *sample_data = &this->m_samples[motion_sample]; + for (int osa_sample = 0; osa_sample < this->m_osa; osa_sample++) { + point[0] = x + this->m_jitter[osa_sample][0]; + point[1] = y + this->m_jitter[osa_sample][1]; + if (isect_point_tri_v2(point, + sample_data->frameSpaceCorners[0], + sample_data->frameSpaceCorners[1], + sample_data->frameSpaceCorners[2]) || + isect_point_tri_v2(point, + sample_data->frameSpaceCorners[0], + sample_data->frameSpaceCorners[2], + sample_data->frameSpaceCorners[3])) { + inside_counter++; + } + } + } + output[0] = (float)inside_counter / (this->m_osa * this->m_motion_blur_samples); + } +} diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp deleted file mode 100644 index c395f795a22..00000000000 --- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - * 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. - * - * Copyright 2013, Blender Foundation. - */ - -#include "COM_PlaneDistortCommonOperation.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_jitter_2d.h" -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_math_color.h" - -#include "BKE_movieclip.h" -#include "BKE_node.h" -#include "BKE_tracking.h" - -/* ******** PlaneDistort WarpImage ******** */ - -BLI_INLINE void warpCoord(float x, float y, float matrix[3][3], float uv[2], float deriv[2][2]) -{ - float vec[3] = {x, y, 1.0f}; - mul_m3_v3(matrix, vec); - uv[0] = vec[0] / vec[2]; - uv[1] = vec[1] / vec[2]; - - deriv[0][0] = (matrix[0][0] - matrix[0][2] * uv[0]) / vec[2]; - deriv[1][0] = (matrix[0][1] - matrix[0][2] * uv[1]) / vec[2]; - deriv[0][1] = (matrix[1][0] - matrix[1][2] * uv[0]) / vec[2]; - deriv[1][1] = (matrix[1][1] - matrix[1][2] * uv[1]) / vec[2]; -} - -PlaneDistortWarpImageOperation::PlaneDistortWarpImageOperation() -{ - this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); - this->addOutputSocket(COM_DT_COLOR); - this->m_pixelReader = nullptr; - this->m_motion_blur_samples = 1; - this->m_motion_blur_shutter = 0.5f; - this->setComplex(true); -} - -void PlaneDistortWarpImageOperation::calculateCorners(const float corners[4][2], - bool normalized, - int sample) -{ - BLI_assert(sample < this->m_motion_blur_samples); - const int width = this->m_pixelReader->getWidth(); - const int height = this->m_pixelReader->getHeight(); - float frame_corners[4][2] = { - {0.0f, 0.0f}, {(float)width, 0.0f}, {(float)width, (float)height}, {0.0f, (float)height}}; - MotionSample *sample_data = &this->m_samples[sample]; - if (normalized) { - for (int i = 0; i < 4; i++) { - sample_data->frameSpaceCorners[i][0] = corners[i][0] * this->getWidth(); - sample_data->frameSpaceCorners[i][1] = corners[i][1] * this->getHeight(); - } - } - else { - for (int i = 0; i < 4; i++) { - sample_data->frameSpaceCorners[i][0] = corners[i][0]; - sample_data->frameSpaceCorners[i][1] = corners[i][1]; - } - } - BKE_tracking_homography_between_two_quads( - sample_data->frameSpaceCorners, frame_corners, sample_data->perspectiveMatrix); -} - -void PlaneDistortWarpImageOperation::initExecution() -{ - this->m_pixelReader = this->getInputSocketReader(0); -} - -void PlaneDistortWarpImageOperation::deinitExecution() -{ - this->m_pixelReader = nullptr; -} - -void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - float uv[2]; - float deriv[2][2]; - if (this->m_motion_blur_samples == 1) { - warpCoord(x, y, this->m_samples[0].perspectiveMatrix, uv, deriv); - m_pixelReader->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]); - } - else { - zero_v4(output); - for (int sample = 0; sample < this->m_motion_blur_samples; sample++) { - float color[4]; - warpCoord(x, y, this->m_samples[sample].perspectiveMatrix, uv, deriv); - m_pixelReader->readFiltered(color, uv[0], uv[1], deriv[0], deriv[1]); - add_v4_v4(output, color); - } - mul_v4_fl(output, 1.0f / (float)this->m_motion_blur_samples); - } -} - -bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest( - rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - float min[2], max[2]; - INIT_MINMAX2(min, max); - - for (int sample = 0; sample < this->m_motion_blur_samples; sample++) { - float UVs[4][2]; - float deriv[2][2]; - MotionSample *sample_data = &this->m_samples[sample]; - /* TODO(sergey): figure out proper way to do this. */ - warpCoord(input->xmin - 2, input->ymin - 2, sample_data->perspectiveMatrix, UVs[0], deriv); - warpCoord(input->xmax + 2, input->ymin - 2, sample_data->perspectiveMatrix, UVs[1], deriv); - warpCoord(input->xmax + 2, input->ymax + 2, sample_data->perspectiveMatrix, UVs[2], deriv); - warpCoord(input->xmin - 2, input->ymax + 2, sample_data->perspectiveMatrix, UVs[3], deriv); - for (int i = 0; i < 4; i++) { - minmax_v2v2_v2(min, max, UVs[i]); - } - } - - rcti newInput; - - newInput.xmin = min[0] - 1; - newInput.ymin = min[1] - 1; - newInput.xmax = max[0] + 1; - newInput.ymax = max[1] + 1; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -/* ******** PlaneDistort Mask ******** */ - -PlaneDistortMaskOperation::PlaneDistortMaskOperation() -{ - addOutputSocket(COM_DT_VALUE); - - /* Currently hardcoded to 8 samples. */ - m_osa = 8; - this->m_motion_blur_samples = 1; - this->m_motion_blur_shutter = 0.5f; -} - -void PlaneDistortMaskOperation::calculateCorners(const float corners[4][2], - bool normalized, - int sample) -{ - BLI_assert(sample < this->m_motion_blur_samples); - MotionSample *sample_data = &this->m_samples[sample]; - if (normalized) { - for (int i = 0; i < 4; i++) { - sample_data->frameSpaceCorners[i][0] = corners[i][0] * this->getWidth(); - sample_data->frameSpaceCorners[i][1] = corners[i][1] * this->getHeight(); - } - } - else { - for (int i = 0; i < 4; i++) { - sample_data->frameSpaceCorners[i][0] = corners[i][0]; - sample_data->frameSpaceCorners[i][1] = corners[i][1]; - } - } -} - -void PlaneDistortMaskOperation::initExecution() -{ - BLI_jitter_init(m_jitter, m_osa); -} - -void PlaneDistortMaskOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - float point[2]; - int inside_counter = 0; - if (this->m_motion_blur_samples == 1) { - MotionSample *sample_data = &this->m_samples[0]; - for (int sample = 0; sample < this->m_osa; sample++) { - point[0] = x + this->m_jitter[sample][0]; - point[1] = y + this->m_jitter[sample][1]; - if (isect_point_tri_v2(point, - sample_data->frameSpaceCorners[0], - sample_data->frameSpaceCorners[1], - sample_data->frameSpaceCorners[2]) || - isect_point_tri_v2(point, - sample_data->frameSpaceCorners[0], - sample_data->frameSpaceCorners[2], - sample_data->frameSpaceCorners[3])) { - inside_counter++; - } - } - output[0] = (float)inside_counter / this->m_osa; - } - else { - for (int motion_sample = 0; motion_sample < this->m_motion_blur_samples; motion_sample++) { - MotionSample *sample_data = &this->m_samples[motion_sample]; - for (int osa_sample = 0; osa_sample < this->m_osa; osa_sample++) { - point[0] = x + this->m_jitter[osa_sample][0]; - point[1] = y + this->m_jitter[osa_sample][1]; - if (isect_point_tri_v2(point, - sample_data->frameSpaceCorners[0], - sample_data->frameSpaceCorners[1], - sample_data->frameSpaceCorners[2]) || - isect_point_tri_v2(point, - sample_data->frameSpaceCorners[0], - sample_data->frameSpaceCorners[2], - sample_data->frameSpaceCorners[3])) { - inside_counter++; - } - } - } - output[0] = (float)inside_counter / (this->m_osa * this->m_motion_blur_samples); - } -} diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc new file mode 100644 index 00000000000..81a598e937b --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc @@ -0,0 +1,123 @@ +/* + * 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. + * + * Copyright 2013, Blender Foundation. + */ + +#include "COM_PlaneTrackOperation.h" +#include "COM_ReadBufferOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" + +#include "BKE_movieclip.h" +#include "BKE_node.h" +#include "BKE_tracking.h" + +/* ******** PlaneTrackCommon ******** */ + +PlaneTrackCommon::PlaneTrackCommon() +{ + this->m_movieClip = nullptr; + this->m_framenumber = 0; + this->m_trackingObjectName[0] = '\0'; + this->m_planeTrackName[0] = '\0'; +} + +void PlaneTrackCommon::readCornersFromTrack(float corners[4][2], float frame) +{ + MovieTracking *tracking; + MovieTrackingObject *object; + + if (!this->m_movieClip) { + return; + } + + tracking = &this->m_movieClip->tracking; + + object = BKE_tracking_object_get_named(tracking, this->m_trackingObjectName); + if (object) { + MovieTrackingPlaneTrack *plane_track; + plane_track = BKE_tracking_plane_track_get_named(tracking, object, this->m_planeTrackName); + if (plane_track) { + float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, frame); + BKE_tracking_plane_marker_get_subframe_corners(plane_track, clip_framenr, corners); + } + } +} + +void PlaneTrackCommon::determineResolution(unsigned int resolution[2], + unsigned int /*preferredResolution*/[2]) +{ + resolution[0] = 0; + resolution[1] = 0; + + if (this->m_movieClip) { + int width, height; + MovieClipUser user = {0}; + BKE_movieclip_user_set_frame(&user, this->m_framenumber); + BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height); + resolution[0] = width; + resolution[1] = height; + } +} + +/* ******** PlaneTrackMaskOperation ******** */ + +void PlaneTrackMaskOperation::initExecution() +{ + PlaneDistortMaskOperation::initExecution(); + float corners[4][2]; + if (this->m_motion_blur_samples == 1) { + readCornersFromTrack(corners, this->m_framenumber); + calculateCorners(corners, true, 0); + } + else { + const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter; + const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples; + float frame_iter = frame; + for (int sample = 0; sample < this->m_motion_blur_samples; sample++) { + readCornersFromTrack(corners, frame_iter); + calculateCorners(corners, true, sample); + frame_iter += frame_step; + } + } +} + +/* ******** PlaneTrackWarpImageOperation ******** */ + +void PlaneTrackWarpImageOperation::initExecution() +{ + PlaneDistortWarpImageOperation::initExecution(); + /* TODO(sergey): De-duplicate with mask operation. */ + float corners[4][2]; + if (this->m_motion_blur_samples == 1) { + readCornersFromTrack(corners, this->m_framenumber); + calculateCorners(corners, true, 0); + } + else { + const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter; + const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples; + float frame_iter = frame; + for (int sample = 0; sample < this->m_motion_blur_samples; sample++) { + readCornersFromTrack(corners, frame_iter); + calculateCorners(corners, true, sample); + frame_iter += frame_step; + } + } +} diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp deleted file mode 100644 index 81a598e937b..00000000000 --- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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. - * - * Copyright 2013, Blender Foundation. - */ - -#include "COM_PlaneTrackOperation.h" -#include "COM_ReadBufferOperation.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_math_color.h" - -#include "BKE_movieclip.h" -#include "BKE_node.h" -#include "BKE_tracking.h" - -/* ******** PlaneTrackCommon ******** */ - -PlaneTrackCommon::PlaneTrackCommon() -{ - this->m_movieClip = nullptr; - this->m_framenumber = 0; - this->m_trackingObjectName[0] = '\0'; - this->m_planeTrackName[0] = '\0'; -} - -void PlaneTrackCommon::readCornersFromTrack(float corners[4][2], float frame) -{ - MovieTracking *tracking; - MovieTrackingObject *object; - - if (!this->m_movieClip) { - return; - } - - tracking = &this->m_movieClip->tracking; - - object = BKE_tracking_object_get_named(tracking, this->m_trackingObjectName); - if (object) { - MovieTrackingPlaneTrack *plane_track; - plane_track = BKE_tracking_plane_track_get_named(tracking, object, this->m_planeTrackName); - if (plane_track) { - float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, frame); - BKE_tracking_plane_marker_get_subframe_corners(plane_track, clip_framenr, corners); - } - } -} - -void PlaneTrackCommon::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) -{ - resolution[0] = 0; - resolution[1] = 0; - - if (this->m_movieClip) { - int width, height; - MovieClipUser user = {0}; - BKE_movieclip_user_set_frame(&user, this->m_framenumber); - BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height); - resolution[0] = width; - resolution[1] = height; - } -} - -/* ******** PlaneTrackMaskOperation ******** */ - -void PlaneTrackMaskOperation::initExecution() -{ - PlaneDistortMaskOperation::initExecution(); - float corners[4][2]; - if (this->m_motion_blur_samples == 1) { - readCornersFromTrack(corners, this->m_framenumber); - calculateCorners(corners, true, 0); - } - else { - const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter; - const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples; - float frame_iter = frame; - for (int sample = 0; sample < this->m_motion_blur_samples; sample++) { - readCornersFromTrack(corners, frame_iter); - calculateCorners(corners, true, sample); - frame_iter += frame_step; - } - } -} - -/* ******** PlaneTrackWarpImageOperation ******** */ - -void PlaneTrackWarpImageOperation::initExecution() -{ - PlaneDistortWarpImageOperation::initExecution(); - /* TODO(sergey): De-duplicate with mask operation. */ - float corners[4][2]; - if (this->m_motion_blur_samples == 1) { - readCornersFromTrack(corners, this->m_framenumber); - calculateCorners(corners, true, 0); - } - else { - const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter; - const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples; - float frame_iter = frame; - for (int sample = 0; sample < this->m_motion_blur_samples; sample++) { - readCornersFromTrack(corners, frame_iter); - calculateCorners(corners, true, sample); - frame_iter += frame_step; - } - } -} diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cc b/source/blender/compositor/operations/COM_PreviewOperation.cc new file mode 100644 index 00000000000..063421f6525 --- /dev/null +++ b/source/blender/compositor/operations/COM_PreviewOperation.cc @@ -0,0 +1,161 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_PreviewOperation.h" +#include "BKE_image.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" +#include "BLI_utildefines.h" +#include "COM_defines.h" +#include "MEM_guardedalloc.h" +#include "PIL_time.h" +#include "WM_api.h" +#include "WM_types.h" + +#include "BKE_node.h" +#include "IMB_colormanagement.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +PreviewOperation::PreviewOperation(const ColorManagedViewSettings *viewSettings, + const ColorManagedDisplaySettings *displaySettings) + +{ + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); + this->m_preview = nullptr; + this->m_outputBuffer = nullptr; + this->m_input = nullptr; + this->m_divider = 1.0f; + this->m_viewSettings = viewSettings; + this->m_displaySettings = displaySettings; +} + +void PreviewOperation::verifyPreview(bNodeInstanceHash *previews, bNodeInstanceKey key) +{ + /* Size (0, 0) ensures the preview rect is not allocated in advance, + * this is set later in initExecution once the resolution is determined. + */ + this->m_preview = BKE_node_preview_verify(previews, key, 0, 0, true); +} + +void PreviewOperation::initExecution() +{ + this->m_input = getInputSocketReader(0); + + if (this->getWidth() == (unsigned int)this->m_preview->xsize && + this->getHeight() == (unsigned int)this->m_preview->ysize) { + this->m_outputBuffer = this->m_preview->rect; + } + + if (this->m_outputBuffer == nullptr) { + this->m_outputBuffer = (unsigned char *)MEM_callocN( + sizeof(unsigned char) * 4 * getWidth() * getHeight(), "PreviewOperation"); + if (this->m_preview->rect) { + MEM_freeN(this->m_preview->rect); + } + this->m_preview->xsize = getWidth(); + this->m_preview->ysize = getHeight(); + this->m_preview->rect = this->m_outputBuffer; + } +} + +void PreviewOperation::deinitExecution() +{ + this->m_outputBuffer = nullptr; + this->m_input = nullptr; +} + +void PreviewOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) +{ + int offset; + float color[4]; + struct ColormanageProcessor *cm_processor; + + cm_processor = IMB_colormanagement_display_processor_new(this->m_viewSettings, + this->m_displaySettings); + + for (int y = rect->ymin; y < rect->ymax; y++) { + offset = (y * getWidth() + rect->xmin) * 4; + for (int x = rect->xmin; x < rect->xmax; x++) { + float rx = floor(x / this->m_divider); + float ry = floor(y / this->m_divider); + + color[0] = 0.0f; + color[1] = 0.0f; + color[2] = 0.0f; + color[3] = 1.0f; + this->m_input->readSampled(color, rx, ry, COM_PS_NEAREST); + IMB_colormanagement_processor_apply_v4(cm_processor, color); + rgba_float_to_uchar(this->m_outputBuffer + offset, color); + offset += 4; + } + } + + IMB_colormanagement_processor_free(cm_processor); +} +bool PreviewOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + + newInput.xmin = input->xmin / this->m_divider; + newInput.xmax = input->xmax / this->m_divider; + newInput.ymin = input->ymin / this->m_divider; + newInput.ymax = input->ymax / this->m_divider; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} +void PreviewOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + NodeOperation::determineResolution(resolution, preferredResolution); + + /* If resolution is 0 there are two possible scenarios: + * - Either node is not connected at all + * - It is connected to input which doesn't have own resolution (i.e. color input). + * + * In the former case we rely on the execution system to not evaluate this node. + * + * For the latter case we use 1 pixel preview, so that it's possible to see preview color in the + * preview. This is how final F12 render will behave (flood-fill final frame with the color). + * + * Having things consistent in terms that node preview is scaled down F12 render is a very + * natural thing to do. */ + int width = max_ii(1, resolution[0]); + int height = max_ii(1, resolution[1]); + + this->m_divider = 0.0f; + if (width > height) { + this->m_divider = (float)COM_PREVIEW_SIZE / (width); + } + else { + this->m_divider = (float)COM_PREVIEW_SIZE / (height); + } + width = width * this->m_divider; + height = height * this->m_divider; + + resolution[0] = width; + resolution[1] = height; +} + +CompositorPriority PreviewOperation::getRenderPriority() const +{ + return COM_PRIORITY_LOW; +} diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cpp b/source/blender/compositor/operations/COM_PreviewOperation.cpp deleted file mode 100644 index 063421f6525..00000000000 --- a/source/blender/compositor/operations/COM_PreviewOperation.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_PreviewOperation.h" -#include "BKE_image.h" -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_math_color.h" -#include "BLI_utildefines.h" -#include "COM_defines.h" -#include "MEM_guardedalloc.h" -#include "PIL_time.h" -#include "WM_api.h" -#include "WM_types.h" - -#include "BKE_node.h" -#include "IMB_colormanagement.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -PreviewOperation::PreviewOperation(const ColorManagedViewSettings *viewSettings, - const ColorManagedDisplaySettings *displaySettings) - -{ - this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); - this->m_preview = nullptr; - this->m_outputBuffer = nullptr; - this->m_input = nullptr; - this->m_divider = 1.0f; - this->m_viewSettings = viewSettings; - this->m_displaySettings = displaySettings; -} - -void PreviewOperation::verifyPreview(bNodeInstanceHash *previews, bNodeInstanceKey key) -{ - /* Size (0, 0) ensures the preview rect is not allocated in advance, - * this is set later in initExecution once the resolution is determined. - */ - this->m_preview = BKE_node_preview_verify(previews, key, 0, 0, true); -} - -void PreviewOperation::initExecution() -{ - this->m_input = getInputSocketReader(0); - - if (this->getWidth() == (unsigned int)this->m_preview->xsize && - this->getHeight() == (unsigned int)this->m_preview->ysize) { - this->m_outputBuffer = this->m_preview->rect; - } - - if (this->m_outputBuffer == nullptr) { - this->m_outputBuffer = (unsigned char *)MEM_callocN( - sizeof(unsigned char) * 4 * getWidth() * getHeight(), "PreviewOperation"); - if (this->m_preview->rect) { - MEM_freeN(this->m_preview->rect); - } - this->m_preview->xsize = getWidth(); - this->m_preview->ysize = getHeight(); - this->m_preview->rect = this->m_outputBuffer; - } -} - -void PreviewOperation::deinitExecution() -{ - this->m_outputBuffer = nullptr; - this->m_input = nullptr; -} - -void PreviewOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) -{ - int offset; - float color[4]; - struct ColormanageProcessor *cm_processor; - - cm_processor = IMB_colormanagement_display_processor_new(this->m_viewSettings, - this->m_displaySettings); - - for (int y = rect->ymin; y < rect->ymax; y++) { - offset = (y * getWidth() + rect->xmin) * 4; - for (int x = rect->xmin; x < rect->xmax; x++) { - float rx = floor(x / this->m_divider); - float ry = floor(y / this->m_divider); - - color[0] = 0.0f; - color[1] = 0.0f; - color[2] = 0.0f; - color[3] = 1.0f; - this->m_input->readSampled(color, rx, ry, COM_PS_NEAREST); - IMB_colormanagement_processor_apply_v4(cm_processor, color); - rgba_float_to_uchar(this->m_outputBuffer + offset, color); - offset += 4; - } - } - - IMB_colormanagement_processor_free(cm_processor); -} -bool PreviewOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - - newInput.xmin = input->xmin / this->m_divider; - newInput.xmax = input->xmax / this->m_divider; - newInput.ymin = input->ymin / this->m_divider; - newInput.ymax = input->ymax / this->m_divider; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} -void PreviewOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - NodeOperation::determineResolution(resolution, preferredResolution); - - /* If resolution is 0 there are two possible scenarios: - * - Either node is not connected at all - * - It is connected to input which doesn't have own resolution (i.e. color input). - * - * In the former case we rely on the execution system to not evaluate this node. - * - * For the latter case we use 1 pixel preview, so that it's possible to see preview color in the - * preview. This is how final F12 render will behave (flood-fill final frame with the color). - * - * Having things consistent in terms that node preview is scaled down F12 render is a very - * natural thing to do. */ - int width = max_ii(1, resolution[0]); - int height = max_ii(1, resolution[1]); - - this->m_divider = 0.0f; - if (width > height) { - this->m_divider = (float)COM_PREVIEW_SIZE / (width); - } - else { - this->m_divider = (float)COM_PREVIEW_SIZE / (height); - } - width = width * this->m_divider; - height = height * this->m_divider; - - resolution[0] = width; - resolution[1] = height; -} - -CompositorPriority PreviewOperation::getRenderPriority() const -{ - return COM_PRIORITY_LOW; -} diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc new file mode 100644 index 00000000000..7d459b76cb9 --- /dev/null +++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc @@ -0,0 +1,113 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ProjectorLensDistortionOperation.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +ProjectorLensDistortionOperation::ProjectorLensDistortionOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setComplex(true); + this->m_inputProgram = nullptr; + this->m_dispersionAvailable = false; + this->m_dispersion = 0.0f; +} +void ProjectorLensDistortionOperation::initExecution() +{ + this->initMutex(); + this->m_inputProgram = this->getInputSocketReader(0); +} + +void *ProjectorLensDistortionOperation::initializeTileData(rcti * /*rect*/) +{ + updateDispersion(); + void *buffer = this->m_inputProgram->initializeTileData(nullptr); + return buffer; +} + +void ProjectorLensDistortionOperation::executePixel(float output[4], int x, int y, void *data) +{ + float inputValue[4]; + const float height = this->getHeight(); + const float width = this->getWidth(); + const float v = (y + 0.5f) / height; + const float u = (x + 0.5f) / width; + MemoryBuffer *inputBuffer = (MemoryBuffer *)data; + inputBuffer->readBilinear(inputValue, (u * width + this->m_kr2) - 0.5f, v * height - 0.5f); + output[0] = inputValue[0]; + inputBuffer->read(inputValue, x, y); + output[1] = inputValue[1]; + inputBuffer->readBilinear(inputValue, (u * width - this->m_kr2) - 0.5f, v * height - 0.5f); + output[2] = inputValue[2]; + output[3] = 1.0f; +} + +void ProjectorLensDistortionOperation::deinitExecution() +{ + this->deinitMutex(); + this->m_inputProgram = nullptr; +} + +bool ProjectorLensDistortionOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + if (this->m_dispersionAvailable) { + newInput.ymax = input->ymax; + newInput.ymin = input->ymin; + newInput.xmin = input->xmin - this->m_kr2 - 2; + newInput.xmax = input->xmax + this->m_kr2 + 2; + } + else { + rcti dispInput; + BLI_rcti_init(&dispInput, 0, 5, 0, 5); + if (this->getInputOperation(1)->determineDependingAreaOfInterest( + &dispInput, readOperation, output)) { + return true; + } + newInput.xmin = input->xmin - 7; /* (0.25f * 20 * 1) + 2 == worse case dispersion */ + newInput.ymin = input->ymin; + newInput.ymax = input->ymax; + newInput.xmax = input->xmax + 7; /* (0.25f * 20 * 1) + 2 == worse case dispersion */ + } + if (this->getInputOperation(0)->determineDependingAreaOfInterest( + &newInput, readOperation, output)) { + return true; + } + return false; +} + +void ProjectorLensDistortionOperation::updateDispersion() +{ + if (this->m_dispersionAvailable) { + return; + } + this->lockMutex(); + if (!this->m_dispersionAvailable) { + float result[4]; + this->getInputSocketReader(1)->readSampled(result, 1, 1, COM_PS_NEAREST); + this->m_dispersion = result[0]; + this->m_kr = 0.25f * max_ff(min_ff(this->m_dispersion, 1.0f), 0.0f); + this->m_kr2 = this->m_kr * 20; + this->m_dispersionAvailable = true; + } + this->unlockMutex(); +} diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp deleted file mode 100644 index 7d459b76cb9..00000000000 --- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ProjectorLensDistortionOperation.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -ProjectorLensDistortionOperation::ProjectorLensDistortionOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setComplex(true); - this->m_inputProgram = nullptr; - this->m_dispersionAvailable = false; - this->m_dispersion = 0.0f; -} -void ProjectorLensDistortionOperation::initExecution() -{ - this->initMutex(); - this->m_inputProgram = this->getInputSocketReader(0); -} - -void *ProjectorLensDistortionOperation::initializeTileData(rcti * /*rect*/) -{ - updateDispersion(); - void *buffer = this->m_inputProgram->initializeTileData(nullptr); - return buffer; -} - -void ProjectorLensDistortionOperation::executePixel(float output[4], int x, int y, void *data) -{ - float inputValue[4]; - const float height = this->getHeight(); - const float width = this->getWidth(); - const float v = (y + 0.5f) / height; - const float u = (x + 0.5f) / width; - MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - inputBuffer->readBilinear(inputValue, (u * width + this->m_kr2) - 0.5f, v * height - 0.5f); - output[0] = inputValue[0]; - inputBuffer->read(inputValue, x, y); - output[1] = inputValue[1]; - inputBuffer->readBilinear(inputValue, (u * width - this->m_kr2) - 0.5f, v * height - 0.5f); - output[2] = inputValue[2]; - output[3] = 1.0f; -} - -void ProjectorLensDistortionOperation::deinitExecution() -{ - this->deinitMutex(); - this->m_inputProgram = nullptr; -} - -bool ProjectorLensDistortionOperation::determineDependingAreaOfInterest( - rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInput; - if (this->m_dispersionAvailable) { - newInput.ymax = input->ymax; - newInput.ymin = input->ymin; - newInput.xmin = input->xmin - this->m_kr2 - 2; - newInput.xmax = input->xmax + this->m_kr2 + 2; - } - else { - rcti dispInput; - BLI_rcti_init(&dispInput, 0, 5, 0, 5); - if (this->getInputOperation(1)->determineDependingAreaOfInterest( - &dispInput, readOperation, output)) { - return true; - } - newInput.xmin = input->xmin - 7; /* (0.25f * 20 * 1) + 2 == worse case dispersion */ - newInput.ymin = input->ymin; - newInput.ymax = input->ymax; - newInput.xmax = input->xmax + 7; /* (0.25f * 20 * 1) + 2 == worse case dispersion */ - } - if (this->getInputOperation(0)->determineDependingAreaOfInterest( - &newInput, readOperation, output)) { - return true; - } - return false; -} - -void ProjectorLensDistortionOperation::updateDispersion() -{ - if (this->m_dispersionAvailable) { - return; - } - this->lockMutex(); - if (!this->m_dispersionAvailable) { - float result[4]; - this->getInputSocketReader(1)->readSampled(result, 1, 1, COM_PS_NEAREST); - this->m_dispersion = result[0]; - this->m_kr = 0.25f * max_ff(min_ff(this->m_dispersion, 1.0f), 0.0f); - this->m_kr2 = this->m_kr * 20; - this->m_dispersionAvailable = true; - } - this->unlockMutex(); -} diff --git a/source/blender/compositor/operations/COM_QualityStepHelper.cc b/source/blender/compositor/operations/COM_QualityStepHelper.cc new file mode 100644 index 00000000000..3eb8d528f7a --- /dev/null +++ b/source/blender/compositor/operations/COM_QualityStepHelper.cc @@ -0,0 +1,66 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_QualityStepHelper.h" + +QualityStepHelper::QualityStepHelper() +{ + this->m_quality = COM_QUALITY_HIGH; + this->m_step = 1; + this->m_offsetadd = 4; +} + +void QualityStepHelper::initExecution(QualityHelper helper) +{ + switch (helper) { + case COM_QH_INCREASE: + switch (this->m_quality) { + case COM_QUALITY_HIGH: + default: + this->m_step = 1; + this->m_offsetadd = 1; + break; + case COM_QUALITY_MEDIUM: + this->m_step = 2; + this->m_offsetadd = 2; + break; + case COM_QUALITY_LOW: + this->m_step = 3; + this->m_offsetadd = 3; + break; + } + break; + case COM_QH_MULTIPLY: + switch (this->m_quality) { + case COM_QUALITY_HIGH: + default: + this->m_step = 1; + this->m_offsetadd = 4; + break; + case COM_QUALITY_MEDIUM: + this->m_step = 2; + this->m_offsetadd = 8; + break; + case COM_QUALITY_LOW: + this->m_step = 4; + this->m_offsetadd = 16; + break; + } + break; + } +} diff --git a/source/blender/compositor/operations/COM_QualityStepHelper.cpp b/source/blender/compositor/operations/COM_QualityStepHelper.cpp deleted file mode 100644 index 3eb8d528f7a..00000000000 --- a/source/blender/compositor/operations/COM_QualityStepHelper.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_QualityStepHelper.h" - -QualityStepHelper::QualityStepHelper() -{ - this->m_quality = COM_QUALITY_HIGH; - this->m_step = 1; - this->m_offsetadd = 4; -} - -void QualityStepHelper::initExecution(QualityHelper helper) -{ - switch (helper) { - case COM_QH_INCREASE: - switch (this->m_quality) { - case COM_QUALITY_HIGH: - default: - this->m_step = 1; - this->m_offsetadd = 1; - break; - case COM_QUALITY_MEDIUM: - this->m_step = 2; - this->m_offsetadd = 2; - break; - case COM_QUALITY_LOW: - this->m_step = 3; - this->m_offsetadd = 3; - break; - } - break; - case COM_QH_MULTIPLY: - switch (this->m_quality) { - case COM_QUALITY_HIGH: - default: - this->m_step = 1; - this->m_offsetadd = 4; - break; - case COM_QUALITY_MEDIUM: - this->m_step = 2; - this->m_offsetadd = 8; - break; - case COM_QUALITY_LOW: - this->m_step = 4; - this->m_offsetadd = 16; - break; - } - break; - } -} diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cc b/source/blender/compositor/operations/COM_ReadBufferOperation.cc new file mode 100644 index 00000000000..2977e6685d2 --- /dev/null +++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cc @@ -0,0 +1,133 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ReadBufferOperation.h" +#include "COM_WriteBufferOperation.h" +#include "COM_defines.h" + +ReadBufferOperation::ReadBufferOperation(DataType datatype) +{ + this->addOutputSocket(datatype); + this->m_single_value = false; + this->m_offset = 0; + this->m_buffer = nullptr; +} + +void *ReadBufferOperation::initializeTileData(rcti * /*rect*/) +{ + return m_buffer; +} + +void ReadBufferOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + if (this->m_memoryProxy != nullptr) { + WriteBufferOperation *operation = this->m_memoryProxy->getWriteBufferOperation(); + operation->determineResolution(resolution, preferredResolution); + operation->setResolution(resolution); + + /** \todo: may not occur!, but does with blur node */ + if (this->m_memoryProxy->getExecutor()) { + this->m_memoryProxy->getExecutor()->setResolution(resolution); + } + + m_single_value = operation->isSingleValue(); + } +} +void ReadBufferOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + if (m_single_value) { + /* write buffer has a single value stored at (0,0) */ + m_buffer->read(output, 0, 0); + } + else { + switch (sampler) { + case COM_PS_NEAREST: + m_buffer->read(output, x, y); + break; + case COM_PS_BILINEAR: + default: + m_buffer->readBilinear(output, x, y); + break; + case COM_PS_BICUBIC: + m_buffer->readBilinear(output, x, y); + break; + } + } +} + +void ReadBufferOperation::executePixelExtend(float output[4], + float x, + float y, + PixelSampler sampler, + MemoryBufferExtend extend_x, + MemoryBufferExtend extend_y) +{ + if (m_single_value) { + /* write buffer has a single value stored at (0,0) */ + m_buffer->read(output, 0, 0); + } + else if (sampler == COM_PS_NEAREST) { + m_buffer->read(output, x, y, extend_x, extend_y); + } + else { + m_buffer->readBilinear(output, x, y, extend_x, extend_y); + } +} + +void ReadBufferOperation::executePixelFiltered( + float output[4], float x, float y, float dx[2], float dy[2]) +{ + if (m_single_value) { + /* write buffer has a single value stored at (0,0) */ + m_buffer->read(output, 0, 0); + } + else { + const float uv[2] = {x, y}; + const float deriv[2][2] = {{dx[0], dx[1]}, {dy[0], dy[1]}}; + m_buffer->readEWA(output, uv, deriv); + } +} + +bool ReadBufferOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + if (this == readOperation) { + BLI_rcti_init(output, input->xmin, input->xmax, input->ymin, input->ymax); + return true; + } + return false; +} + +void ReadBufferOperation::readResolutionFromWriteBuffer() +{ + if (this->m_memoryProxy != nullptr) { + WriteBufferOperation *operation = this->m_memoryProxy->getWriteBufferOperation(); + this->setWidth(operation->getWidth()); + this->setHeight(operation->getHeight()); + } +} + +void ReadBufferOperation::updateMemoryBuffer() +{ + this->m_buffer = this->getMemoryProxy()->getBuffer(); +} diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp b/source/blender/compositor/operations/COM_ReadBufferOperation.cpp deleted file mode 100644 index 2977e6685d2..00000000000 --- a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ReadBufferOperation.h" -#include "COM_WriteBufferOperation.h" -#include "COM_defines.h" - -ReadBufferOperation::ReadBufferOperation(DataType datatype) -{ - this->addOutputSocket(datatype); - this->m_single_value = false; - this->m_offset = 0; - this->m_buffer = nullptr; -} - -void *ReadBufferOperation::initializeTileData(rcti * /*rect*/) -{ - return m_buffer; -} - -void ReadBufferOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - if (this->m_memoryProxy != nullptr) { - WriteBufferOperation *operation = this->m_memoryProxy->getWriteBufferOperation(); - operation->determineResolution(resolution, preferredResolution); - operation->setResolution(resolution); - - /** \todo: may not occur!, but does with blur node */ - if (this->m_memoryProxy->getExecutor()) { - this->m_memoryProxy->getExecutor()->setResolution(resolution); - } - - m_single_value = operation->isSingleValue(); - } -} -void ReadBufferOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - if (m_single_value) { - /* write buffer has a single value stored at (0,0) */ - m_buffer->read(output, 0, 0); - } - else { - switch (sampler) { - case COM_PS_NEAREST: - m_buffer->read(output, x, y); - break; - case COM_PS_BILINEAR: - default: - m_buffer->readBilinear(output, x, y); - break; - case COM_PS_BICUBIC: - m_buffer->readBilinear(output, x, y); - break; - } - } -} - -void ReadBufferOperation::executePixelExtend(float output[4], - float x, - float y, - PixelSampler sampler, - MemoryBufferExtend extend_x, - MemoryBufferExtend extend_y) -{ - if (m_single_value) { - /* write buffer has a single value stored at (0,0) */ - m_buffer->read(output, 0, 0); - } - else if (sampler == COM_PS_NEAREST) { - m_buffer->read(output, x, y, extend_x, extend_y); - } - else { - m_buffer->readBilinear(output, x, y, extend_x, extend_y); - } -} - -void ReadBufferOperation::executePixelFiltered( - float output[4], float x, float y, float dx[2], float dy[2]) -{ - if (m_single_value) { - /* write buffer has a single value stored at (0,0) */ - m_buffer->read(output, 0, 0); - } - else { - const float uv[2] = {x, y}; - const float deriv[2][2] = {{dx[0], dx[1]}, {dy[0], dy[1]}}; - m_buffer->readEWA(output, uv, deriv); - } -} - -bool ReadBufferOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - if (this == readOperation) { - BLI_rcti_init(output, input->xmin, input->xmax, input->ymin, input->ymax); - return true; - } - return false; -} - -void ReadBufferOperation::readResolutionFromWriteBuffer() -{ - if (this->m_memoryProxy != nullptr) { - WriteBufferOperation *operation = this->m_memoryProxy->getWriteBufferOperation(); - this->setWidth(operation->getWidth()); - this->setHeight(operation->getHeight()); - } -} - -void ReadBufferOperation::updateMemoryBuffer() -{ - this->m_buffer = this->getMemoryProxy()->getBuffer(); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cc b/source/blender/compositor/operations/COM_RenderLayersProg.cc new file mode 100644 index 00000000000..73de60f4c34 --- /dev/null +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc @@ -0,0 +1,308 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_RenderLayersProg.h" + +#include "COM_MetaData.h" + +#include "BKE_image.h" +#include "BKE_scene.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_ref.hh" + +#include "DNA_scene_types.h" + +#include "RE_pipeline.h" +#include "RE_texture.h" + +/* ******** Render Layers Base Prog ******** */ + +RenderLayersProg::RenderLayersProg(const char *passName, DataType type, int elementsize) + : m_passName(passName) +{ + this->setScene(nullptr); + this->m_inputBuffer = nullptr; + this->m_elementsize = elementsize; + this->m_rd = nullptr; + + this->addOutputSocket(type); +} + +void RenderLayersProg::initExecution() +{ + Scene *scene = this->getScene(); + Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr; + RenderResult *rr = nullptr; + + if (re) { + rr = RE_AcquireResultRead(re); + } + + if (rr) { + ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, getLayerId()); + if (view_layer) { + + RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name); + if (rl) { + this->m_inputBuffer = RE_RenderLayerGetPass( + rl, this->m_passName.c_str(), this->m_viewName); + } + } + } + if (re) { + RE_ReleaseResult(re); + re = nullptr; + } +} + +void RenderLayersProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler) +{ + unsigned int offset; + int width = this->getWidth(), height = this->getHeight(); + + int ix = x, iy = y; + if (ix < 0 || iy < 0 || ix >= width || iy >= height) { + if (this->m_elementsize == 1) { + output[0] = 0.0f; + } + else if (this->m_elementsize == 3) { + zero_v3(output); + } + else { + zero_v4(output); + } + return; + } + + switch (sampler) { + case COM_PS_NEAREST: { + offset = (iy * width + ix) * this->m_elementsize; + + if (this->m_elementsize == 1) { + output[0] = this->m_inputBuffer[offset]; + } + else if (this->m_elementsize == 3) { + copy_v3_v3(output, &this->m_inputBuffer[offset]); + } + else { + copy_v4_v4(output, &this->m_inputBuffer[offset]); + } + break; + } + + case COM_PS_BILINEAR: + BLI_bilinear_interpolation_fl( + this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); + break; + + case COM_PS_BICUBIC: + BLI_bicubic_interpolation_fl( + this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); + break; + } +} + +void RenderLayersProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ +#if 0 + const RenderData *rd = this->m_rd; + + int dx = 0, dy = 0; + + if (rd->mode & R_BORDER && rd->mode & R_CROP) { + /* see comment in executeRegion describing coordinate mapping, + * here it simply goes other way around + */ + int full_width = rd->xsch * rd->size / 100; + int full_height = rd->ysch * rd->size / 100; + + dx = rd->border.xmin * full_width - (full_width - this->getWidth()) / 2.0f; + dy = rd->border.ymin * full_height - (full_height - this->getHeight()) / 2.0f; + } + + int ix = x - dx; + int iy = y - dy; +#endif + +#ifndef NDEBUG + { + const DataType data_type = this->getOutputSocket()->getDataType(); + int actual_element_size = this->m_elementsize; + int expected_element_size; + if (data_type == COM_DT_VALUE) { + expected_element_size = 1; + } + else if (data_type == COM_DT_VECTOR) { + expected_element_size = 3; + } + else if (data_type == COM_DT_COLOR) { + expected_element_size = 4; + } + else { + expected_element_size = 0; + BLI_assert(!"Something horribly wrong just happened"); + } + BLI_assert(expected_element_size == actual_element_size); + } +#endif + + if (this->m_inputBuffer == nullptr) { + int elemsize = this->m_elementsize; + if (elemsize == 1) { + output[0] = 0.0f; + } + else if (elemsize == 3) { + zero_v3(output); + } + else { + BLI_assert(elemsize == 4); + zero_v4(output); + } + } + else { + doInterpolation(output, x, y, sampler); + } +} + +void RenderLayersProg::deinitExecution() +{ + this->m_inputBuffer = nullptr; +} + +void RenderLayersProg::determineResolution(unsigned int resolution[2], + unsigned int /*preferredResolution*/[2]) +{ + Scene *sce = this->getScene(); + Render *re = (sce) ? RE_GetSceneRender(sce) : nullptr; + RenderResult *rr = nullptr; + + resolution[0] = 0; + resolution[1] = 0; + + if (re) { + rr = RE_AcquireResultRead(re); + } + + if (rr) { + ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&sce->view_layers, getLayerId()); + if (view_layer) { + RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name); + if (rl) { + resolution[0] = rl->rectx; + resolution[1] = rl->recty; + } + } + } + + if (re) { + RE_ReleaseResult(re); + } +} + +std::unique_ptr RenderLayersProg::getMetaData() const +{ + Scene *scene = this->getScene(); + Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr; + RenderResult *render_result = nullptr; + MetaDataExtractCallbackData callback_data = {nullptr}; + + if (re) { + render_result = RE_AcquireResultRead(re); + } + + if (render_result && render_result->stamp_data) { + ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, getLayerId()); + if (view_layer) { + std::string full_layer_name = std::string( + view_layer->name, + BLI_strnlen(view_layer->name, sizeof(view_layer->name))) + + "." + m_passName; + blender::StringRef cryptomatte_layer_name = + blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name(full_layer_name); + callback_data.setCryptomatteKeys(cryptomatte_layer_name); + + BKE_stamp_info_callback(&callback_data, + render_result->stamp_data, + MetaDataExtractCallbackData::extract_cryptomatte_meta_data, + false); + } + } + + if (re) { + RE_ReleaseResult(re); + re = nullptr; + } + + return std::move(callback_data.meta_data); +} + +/* ******** Render Layers AO Operation ******** */ +void RenderLayersAOOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float *inputBuffer = this->getInputBuffer(); + if (inputBuffer == nullptr) { + zero_v3(output); + } + else { + doInterpolation(output, x, y, sampler); + } + output[3] = 1.0f; +} + +/* ******** Render Layers Alpha Operation ******** */ +void RenderLayersAlphaProg::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float *inputBuffer = this->getInputBuffer(); + + if (inputBuffer == nullptr) { + output[0] = 0.0f; + } + else { + float temp[4]; + doInterpolation(temp, x, y, sampler); + output[0] = temp[3]; + } +} + +/* ******** Render Layers Depth Operation ******** */ +void RenderLayersDepthProg::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + int ix = x; + int iy = y; + float *inputBuffer = this->getInputBuffer(); + + if (inputBuffer == nullptr || ix < 0 || iy < 0 || ix >= (int)this->getWidth() || + iy >= (int)this->getHeight()) { + output[0] = 10e10f; + } + else { + unsigned int offset = (iy * this->getWidth() + ix); + output[0] = inputBuffer[offset]; + } +} diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp deleted file mode 100644 index 73de60f4c34..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_RenderLayersProg.h" - -#include "COM_MetaData.h" - -#include "BKE_image.h" -#include "BKE_scene.h" - -#include "BLI_listbase.h" -#include "BLI_string.h" -#include "BLI_string_ref.hh" - -#include "DNA_scene_types.h" - -#include "RE_pipeline.h" -#include "RE_texture.h" - -/* ******** Render Layers Base Prog ******** */ - -RenderLayersProg::RenderLayersProg(const char *passName, DataType type, int elementsize) - : m_passName(passName) -{ - this->setScene(nullptr); - this->m_inputBuffer = nullptr; - this->m_elementsize = elementsize; - this->m_rd = nullptr; - - this->addOutputSocket(type); -} - -void RenderLayersProg::initExecution() -{ - Scene *scene = this->getScene(); - Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr; - RenderResult *rr = nullptr; - - if (re) { - rr = RE_AcquireResultRead(re); - } - - if (rr) { - ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, getLayerId()); - if (view_layer) { - - RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name); - if (rl) { - this->m_inputBuffer = RE_RenderLayerGetPass( - rl, this->m_passName.c_str(), this->m_viewName); - } - } - } - if (re) { - RE_ReleaseResult(re); - re = nullptr; - } -} - -void RenderLayersProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler) -{ - unsigned int offset; - int width = this->getWidth(), height = this->getHeight(); - - int ix = x, iy = y; - if (ix < 0 || iy < 0 || ix >= width || iy >= height) { - if (this->m_elementsize == 1) { - output[0] = 0.0f; - } - else if (this->m_elementsize == 3) { - zero_v3(output); - } - else { - zero_v4(output); - } - return; - } - - switch (sampler) { - case COM_PS_NEAREST: { - offset = (iy * width + ix) * this->m_elementsize; - - if (this->m_elementsize == 1) { - output[0] = this->m_inputBuffer[offset]; - } - else if (this->m_elementsize == 3) { - copy_v3_v3(output, &this->m_inputBuffer[offset]); - } - else { - copy_v4_v4(output, &this->m_inputBuffer[offset]); - } - break; - } - - case COM_PS_BILINEAR: - BLI_bilinear_interpolation_fl( - this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); - break; - - case COM_PS_BICUBIC: - BLI_bicubic_interpolation_fl( - this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); - break; - } -} - -void RenderLayersProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ -#if 0 - const RenderData *rd = this->m_rd; - - int dx = 0, dy = 0; - - if (rd->mode & R_BORDER && rd->mode & R_CROP) { - /* see comment in executeRegion describing coordinate mapping, - * here it simply goes other way around - */ - int full_width = rd->xsch * rd->size / 100; - int full_height = rd->ysch * rd->size / 100; - - dx = rd->border.xmin * full_width - (full_width - this->getWidth()) / 2.0f; - dy = rd->border.ymin * full_height - (full_height - this->getHeight()) / 2.0f; - } - - int ix = x - dx; - int iy = y - dy; -#endif - -#ifndef NDEBUG - { - const DataType data_type = this->getOutputSocket()->getDataType(); - int actual_element_size = this->m_elementsize; - int expected_element_size; - if (data_type == COM_DT_VALUE) { - expected_element_size = 1; - } - else if (data_type == COM_DT_VECTOR) { - expected_element_size = 3; - } - else if (data_type == COM_DT_COLOR) { - expected_element_size = 4; - } - else { - expected_element_size = 0; - BLI_assert(!"Something horribly wrong just happened"); - } - BLI_assert(expected_element_size == actual_element_size); - } -#endif - - if (this->m_inputBuffer == nullptr) { - int elemsize = this->m_elementsize; - if (elemsize == 1) { - output[0] = 0.0f; - } - else if (elemsize == 3) { - zero_v3(output); - } - else { - BLI_assert(elemsize == 4); - zero_v4(output); - } - } - else { - doInterpolation(output, x, y, sampler); - } -} - -void RenderLayersProg::deinitExecution() -{ - this->m_inputBuffer = nullptr; -} - -void RenderLayersProg::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) -{ - Scene *sce = this->getScene(); - Render *re = (sce) ? RE_GetSceneRender(sce) : nullptr; - RenderResult *rr = nullptr; - - resolution[0] = 0; - resolution[1] = 0; - - if (re) { - rr = RE_AcquireResultRead(re); - } - - if (rr) { - ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&sce->view_layers, getLayerId()); - if (view_layer) { - RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name); - if (rl) { - resolution[0] = rl->rectx; - resolution[1] = rl->recty; - } - } - } - - if (re) { - RE_ReleaseResult(re); - } -} - -std::unique_ptr RenderLayersProg::getMetaData() const -{ - Scene *scene = this->getScene(); - Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr; - RenderResult *render_result = nullptr; - MetaDataExtractCallbackData callback_data = {nullptr}; - - if (re) { - render_result = RE_AcquireResultRead(re); - } - - if (render_result && render_result->stamp_data) { - ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, getLayerId()); - if (view_layer) { - std::string full_layer_name = std::string( - view_layer->name, - BLI_strnlen(view_layer->name, sizeof(view_layer->name))) + - "." + m_passName; - blender::StringRef cryptomatte_layer_name = - blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name(full_layer_name); - callback_data.setCryptomatteKeys(cryptomatte_layer_name); - - BKE_stamp_info_callback(&callback_data, - render_result->stamp_data, - MetaDataExtractCallbackData::extract_cryptomatte_meta_data, - false); - } - } - - if (re) { - RE_ReleaseResult(re); - re = nullptr; - } - - return std::move(callback_data.meta_data); -} - -/* ******** Render Layers AO Operation ******** */ -void RenderLayersAOOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float *inputBuffer = this->getInputBuffer(); - if (inputBuffer == nullptr) { - zero_v3(output); - } - else { - doInterpolation(output, x, y, sampler); - } - output[3] = 1.0f; -} - -/* ******** Render Layers Alpha Operation ******** */ -void RenderLayersAlphaProg::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float *inputBuffer = this->getInputBuffer(); - - if (inputBuffer == nullptr) { - output[0] = 0.0f; - } - else { - float temp[4]; - doInterpolation(temp, x, y, sampler); - output[0] = temp[3]; - } -} - -/* ******** Render Layers Depth Operation ******** */ -void RenderLayersDepthProg::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - int ix = x; - int iy = y; - float *inputBuffer = this->getInputBuffer(); - - if (inputBuffer == nullptr || ix < 0 || iy < 0 || ix >= (int)this->getWidth() || - iy >= (int)this->getHeight()) { - output[0] = 10e10f; - } - else { - unsigned int offset = (iy * this->getWidth() + ix); - output[0] = inputBuffer[offset]; - } -} diff --git a/source/blender/compositor/operations/COM_RotateOperation.cc b/source/blender/compositor/operations/COM_RotateOperation.cc new file mode 100644 index 00000000000..9a1f54a6e10 --- /dev/null +++ b/source/blender/compositor/operations/COM_RotateOperation.cc @@ -0,0 +1,107 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_RotateOperation.h" +#include "BLI_math.h" + +RotateOperation::RotateOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + this->m_imageSocket = nullptr; + this->m_degreeSocket = nullptr; + this->m_doDegree2RadConversion = false; + this->m_isDegreeSet = false; +} +void RotateOperation::initExecution() +{ + this->m_imageSocket = this->getInputSocketReader(0); + this->m_degreeSocket = this->getInputSocketReader(1); + this->m_centerX = (getWidth() - 1) / 2.0; + this->m_centerY = (getHeight() - 1) / 2.0; +} + +void RotateOperation::deinitExecution() +{ + this->m_imageSocket = nullptr; + this->m_degreeSocket = nullptr; +} + +inline void RotateOperation::ensureDegree() +{ + if (!this->m_isDegreeSet) { + float degree[4]; + this->m_degreeSocket->readSampled(degree, 0, 0, COM_PS_NEAREST); + double rad; + if (this->m_doDegree2RadConversion) { + rad = DEG2RAD((double)degree[0]); + } + else { + rad = degree[0]; + } + this->m_cosine = cos(rad); + this->m_sine = sin(rad); + + this->m_isDegreeSet = true; + } +} + +void RotateOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + ensureDegree(); + const float dy = y - this->m_centerY; + const float dx = x - this->m_centerX; + const float nx = this->m_centerX + (this->m_cosine * dx + this->m_sine * dy); + const float ny = this->m_centerY + (-this->m_sine * dx + this->m_cosine * dy); + this->m_imageSocket->readSampled(output, nx, ny, sampler); +} + +bool RotateOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + ensureDegree(); + rcti newInput; + + const float dxmin = input->xmin - this->m_centerX; + const float dymin = input->ymin - this->m_centerY; + const float dxmax = input->xmax - this->m_centerX; + const float dymax = input->ymax - this->m_centerY; + + const float x1 = this->m_centerX + (this->m_cosine * dxmin + this->m_sine * dymin); + const float x2 = this->m_centerX + (this->m_cosine * dxmax + this->m_sine * dymin); + const float x3 = this->m_centerX + (this->m_cosine * dxmin + this->m_sine * dymax); + const float x4 = this->m_centerX + (this->m_cosine * dxmax + this->m_sine * dymax); + const float y1 = this->m_centerY + (-this->m_sine * dxmin + this->m_cosine * dymin); + const float y2 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymin); + const float y3 = this->m_centerY + (-this->m_sine * dxmin + this->m_cosine * dymax); + const float y4 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymax); + const float minx = MIN2(x1, MIN2(x2, MIN2(x3, x4))); + const float maxx = MAX2(x1, MAX2(x2, MAX2(x3, x4))); + const float miny = MIN2(y1, MIN2(y2, MIN2(y3, y4))); + const float maxy = MAX2(y1, MAX2(y2, MAX2(y3, y4))); + + newInput.xmax = ceil(maxx) + 1; + newInput.xmin = floor(minx) - 1; + newInput.ymax = ceil(maxy) + 1; + newInput.ymin = floor(miny) - 1; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_RotateOperation.cpp b/source/blender/compositor/operations/COM_RotateOperation.cpp deleted file mode 100644 index 9a1f54a6e10..00000000000 --- a/source/blender/compositor/operations/COM_RotateOperation.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_RotateOperation.h" -#include "BLI_math.h" - -RotateOperation::RotateOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_imageSocket = nullptr; - this->m_degreeSocket = nullptr; - this->m_doDegree2RadConversion = false; - this->m_isDegreeSet = false; -} -void RotateOperation::initExecution() -{ - this->m_imageSocket = this->getInputSocketReader(0); - this->m_degreeSocket = this->getInputSocketReader(1); - this->m_centerX = (getWidth() - 1) / 2.0; - this->m_centerY = (getHeight() - 1) / 2.0; -} - -void RotateOperation::deinitExecution() -{ - this->m_imageSocket = nullptr; - this->m_degreeSocket = nullptr; -} - -inline void RotateOperation::ensureDegree() -{ - if (!this->m_isDegreeSet) { - float degree[4]; - this->m_degreeSocket->readSampled(degree, 0, 0, COM_PS_NEAREST); - double rad; - if (this->m_doDegree2RadConversion) { - rad = DEG2RAD((double)degree[0]); - } - else { - rad = degree[0]; - } - this->m_cosine = cos(rad); - this->m_sine = sin(rad); - - this->m_isDegreeSet = true; - } -} - -void RotateOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - ensureDegree(); - const float dy = y - this->m_centerY; - const float dx = x - this->m_centerX; - const float nx = this->m_centerX + (this->m_cosine * dx + this->m_sine * dy); - const float ny = this->m_centerY + (-this->m_sine * dx + this->m_cosine * dy); - this->m_imageSocket->readSampled(output, nx, ny, sampler); -} - -bool RotateOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - ensureDegree(); - rcti newInput; - - const float dxmin = input->xmin - this->m_centerX; - const float dymin = input->ymin - this->m_centerY; - const float dxmax = input->xmax - this->m_centerX; - const float dymax = input->ymax - this->m_centerY; - - const float x1 = this->m_centerX + (this->m_cosine * dxmin + this->m_sine * dymin); - const float x2 = this->m_centerX + (this->m_cosine * dxmax + this->m_sine * dymin); - const float x3 = this->m_centerX + (this->m_cosine * dxmin + this->m_sine * dymax); - const float x4 = this->m_centerX + (this->m_cosine * dxmax + this->m_sine * dymax); - const float y1 = this->m_centerY + (-this->m_sine * dxmin + this->m_cosine * dymin); - const float y2 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymin); - const float y3 = this->m_centerY + (-this->m_sine * dxmin + this->m_cosine * dymax); - const float y4 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymax); - const float minx = MIN2(x1, MIN2(x2, MIN2(x3, x4))); - const float maxx = MAX2(x1, MAX2(x2, MAX2(x3, x4))); - const float miny = MIN2(y1, MIN2(y2, MIN2(y3, y4))); - const float maxy = MAX2(y1, MAX2(y2, MAX2(y3, y4))); - - newInput.xmax = ceil(maxx) + 1; - newInput.xmin = floor(minx) - 1; - newInput.ymax = ceil(maxy) + 1; - newInput.ymin = floor(miny) - 1; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cc b/source/blender/compositor/operations/COM_ScaleOperation.cc new file mode 100644 index 00000000000..9ec4e474ccd --- /dev/null +++ b/source/blender/compositor/operations/COM_ScaleOperation.cc @@ -0,0 +1,310 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ScaleOperation.h" + +#define USE_FORCE_BILINEAR +/* XXX - ignore input and use default from old compositor, + * could become an option like the transform node - campbell + * + * note: use bilinear because bicubic makes fuzzy even when not scaling at all (1:1) + */ + +BaseScaleOperation::BaseScaleOperation() +{ +#ifdef USE_FORCE_BILINEAR + m_sampler = (int)COM_PS_BILINEAR; +#else + m_sampler = -1; +#endif + m_variable_size = false; +} + +ScaleOperation::ScaleOperation() : BaseScaleOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + this->m_inputOperation = nullptr; + this->m_inputXOperation = nullptr; + this->m_inputYOperation = nullptr; +} +void ScaleOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); + this->m_inputXOperation = this->getInputSocketReader(1); + this->m_inputYOperation = this->getInputSocketReader(2); + this->m_centerX = this->getWidth() / 2.0; + this->m_centerY = this->getHeight() / 2.0; +} + +void ScaleOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; + this->m_inputXOperation = nullptr; + this->m_inputYOperation = nullptr; +} + +void ScaleOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + PixelSampler effective_sampler = getEffectiveSampler(sampler); + + float scaleX[4]; + float scaleY[4]; + + this->m_inputXOperation->readSampled(scaleX, x, y, effective_sampler); + this->m_inputYOperation->readSampled(scaleY, x, y, effective_sampler); + + const float scx = scaleX[0]; + const float scy = scaleY[0]; + + float nx = this->m_centerX + (x - this->m_centerX) / scx; + float ny = this->m_centerY + (y - this->m_centerY) / scy; + this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); +} + +bool ScaleOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + if (!m_variable_size) { + float scaleX[4]; + float scaleY[4]; + + this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST); + this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST); + + const float scx = scaleX[0]; + const float scy = scaleY[0]; + + newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / scx + 1; + newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / scx - 1; + newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / scy + 1; + newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / scy - 1; + } + else { + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + } + return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +// SCALE ABSOLUTE +ScaleAbsoluteOperation::ScaleAbsoluteOperation() : BaseScaleOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + this->m_inputOperation = nullptr; + this->m_inputXOperation = nullptr; + this->m_inputYOperation = nullptr; +} +void ScaleAbsoluteOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); + this->m_inputXOperation = this->getInputSocketReader(1); + this->m_inputYOperation = this->getInputSocketReader(2); + this->m_centerX = this->getWidth() / 2.0; + this->m_centerY = this->getHeight() / 2.0; +} + +void ScaleAbsoluteOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; + this->m_inputXOperation = nullptr; + this->m_inputYOperation = nullptr; +} + +void ScaleAbsoluteOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + PixelSampler effective_sampler = getEffectiveSampler(sampler); + + float scaleX[4]; + float scaleY[4]; + + this->m_inputXOperation->readSampled(scaleX, x, y, effective_sampler); + this->m_inputYOperation->readSampled(scaleY, x, y, effective_sampler); + + const float scx = scaleX[0]; // target absolute scale + const float scy = scaleY[0]; // target absolute scale + + const float width = this->getWidth(); + const float height = this->getHeight(); + // div + float relativeXScale = scx / width; + float relativeYScale = scy / height; + + float nx = this->m_centerX + (x - this->m_centerX) / relativeXScale; + float ny = this->m_centerY + (y - this->m_centerY) / relativeYScale; + + this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); +} + +bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + if (!m_variable_size) { + float scaleX[4]; + float scaleY[4]; + + this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST); + this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST); + + const float scx = scaleX[0]; + const float scy = scaleY[0]; + const float width = this->getWidth(); + const float height = this->getHeight(); + // div + float relateveXScale = scx / width; + float relateveYScale = scy / height; + + newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / relateveXScale; + newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / relateveXScale; + newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / relateveYScale; + newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / relateveYScale; + } + else { + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + } + + return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +// Absolute fixed size +ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation() +{ + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + this->m_inputOperation = nullptr; + this->m_is_offset = false; +} +void ScaleFixedSizeOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); + this->m_relX = this->m_inputOperation->getWidth() / (float)this->m_newWidth; + this->m_relY = this->m_inputOperation->getHeight() / (float)this->m_newHeight; + + /* *** all the options below are for a fairly special case - camera framing *** */ + if (this->m_offsetX != 0.0f || this->m_offsetY != 0.0f) { + this->m_is_offset = true; + + if (this->m_newWidth > this->m_newHeight) { + this->m_offsetX *= this->m_newWidth; + this->m_offsetY *= this->m_newWidth; + } + else { + this->m_offsetX *= this->m_newHeight; + this->m_offsetY *= this->m_newHeight; + } + } + + if (this->m_is_aspect) { + /* apply aspect from clip */ + const float w_src = this->m_inputOperation->getWidth(); + const float h_src = this->m_inputOperation->getHeight(); + + /* destination aspect is already applied from the camera frame */ + const float w_dst = this->m_newWidth; + const float h_dst = this->m_newHeight; + + const float asp_src = w_src / h_src; + const float asp_dst = w_dst / h_dst; + + if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) { + if ((asp_src > asp_dst) == (this->m_is_crop == true)) { + /* fit X */ + const float div = asp_src / asp_dst; + this->m_relX /= div; + this->m_offsetX += ((w_src - (w_src * div)) / (w_src / w_dst)) / 2.0f; + } + else { + /* fit Y */ + const float div = asp_dst / asp_src; + this->m_relY /= div; + this->m_offsetY += ((h_src - (h_src * div)) / (h_src / h_dst)) / 2.0f; + } + + this->m_is_offset = true; + } + } + /* *** end framing options *** */ +} + +void ScaleFixedSizeOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; +} + +void ScaleFixedSizeOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + PixelSampler effective_sampler = getEffectiveSampler(sampler); + + if (this->m_is_offset) { + float nx = ((x - this->m_offsetX) * this->m_relX); + float ny = ((y - this->m_offsetY) * this->m_relY); + this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); + } + else { + this->m_inputOperation->readSampled( + output, x * this->m_relX, y * this->m_relY, effective_sampler); + } +} + +bool ScaleFixedSizeOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + + newInput.xmax = (input->xmax - m_offsetX) * this->m_relX + 1; + newInput.xmin = (input->xmin - m_offsetX) * this->m_relX; + newInput.ymax = (input->ymax - m_offsetY) * this->m_relY + 1; + newInput.ymin = (input->ymin - m_offsetY) * this->m_relY; + + return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], + unsigned int /*preferredResolution*/[2]) +{ + unsigned int nr[2]; + nr[0] = this->m_newWidth; + nr[1] = this->m_newHeight; + BaseScaleOperation::determineResolution(resolution, nr); + resolution[0] = this->m_newWidth; + resolution[1] = this->m_newHeight; +} diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cpp b/source/blender/compositor/operations/COM_ScaleOperation.cpp deleted file mode 100644 index 9ec4e474ccd..00000000000 --- a/source/blender/compositor/operations/COM_ScaleOperation.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ScaleOperation.h" - -#define USE_FORCE_BILINEAR -/* XXX - ignore input and use default from old compositor, - * could become an option like the transform node - campbell - * - * note: use bilinear because bicubic makes fuzzy even when not scaling at all (1:1) - */ - -BaseScaleOperation::BaseScaleOperation() -{ -#ifdef USE_FORCE_BILINEAR - m_sampler = (int)COM_PS_BILINEAR; -#else - m_sampler = -1; -#endif - m_variable_size = false; -} - -ScaleOperation::ScaleOperation() : BaseScaleOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = nullptr; - this->m_inputXOperation = nullptr; - this->m_inputYOperation = nullptr; -} -void ScaleOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); - this->m_inputXOperation = this->getInputSocketReader(1); - this->m_inputYOperation = this->getInputSocketReader(2); - this->m_centerX = this->getWidth() / 2.0; - this->m_centerY = this->getHeight() / 2.0; -} - -void ScaleOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; - this->m_inputXOperation = nullptr; - this->m_inputYOperation = nullptr; -} - -void ScaleOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - PixelSampler effective_sampler = getEffectiveSampler(sampler); - - float scaleX[4]; - float scaleY[4]; - - this->m_inputXOperation->readSampled(scaleX, x, y, effective_sampler); - this->m_inputYOperation->readSampled(scaleY, x, y, effective_sampler); - - const float scx = scaleX[0]; - const float scy = scaleY[0]; - - float nx = this->m_centerX + (x - this->m_centerX) / scx; - float ny = this->m_centerY + (y - this->m_centerY) / scy; - this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); -} - -bool ScaleOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - if (!m_variable_size) { - float scaleX[4]; - float scaleY[4]; - - this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST); - this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST); - - const float scx = scaleX[0]; - const float scy = scaleY[0]; - - newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / scx + 1; - newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / scx - 1; - newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / scy + 1; - newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / scy - 1; - } - else { - newInput.xmax = this->getWidth(); - newInput.xmin = 0; - newInput.ymax = this->getHeight(); - newInput.ymin = 0; - } - return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -// SCALE ABSOLUTE -ScaleAbsoluteOperation::ScaleAbsoluteOperation() : BaseScaleOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = nullptr; - this->m_inputXOperation = nullptr; - this->m_inputYOperation = nullptr; -} -void ScaleAbsoluteOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); - this->m_inputXOperation = this->getInputSocketReader(1); - this->m_inputYOperation = this->getInputSocketReader(2); - this->m_centerX = this->getWidth() / 2.0; - this->m_centerY = this->getHeight() / 2.0; -} - -void ScaleAbsoluteOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; - this->m_inputXOperation = nullptr; - this->m_inputYOperation = nullptr; -} - -void ScaleAbsoluteOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - PixelSampler effective_sampler = getEffectiveSampler(sampler); - - float scaleX[4]; - float scaleY[4]; - - this->m_inputXOperation->readSampled(scaleX, x, y, effective_sampler); - this->m_inputYOperation->readSampled(scaleY, x, y, effective_sampler); - - const float scx = scaleX[0]; // target absolute scale - const float scy = scaleY[0]; // target absolute scale - - const float width = this->getWidth(); - const float height = this->getHeight(); - // div - float relativeXScale = scx / width; - float relativeYScale = scy / height; - - float nx = this->m_centerX + (x - this->m_centerX) / relativeXScale; - float ny = this->m_centerY + (y - this->m_centerY) / relativeYScale; - - this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); -} - -bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - if (!m_variable_size) { - float scaleX[4]; - float scaleY[4]; - - this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST); - this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST); - - const float scx = scaleX[0]; - const float scy = scaleY[0]; - const float width = this->getWidth(); - const float height = this->getHeight(); - // div - float relateveXScale = scx / width; - float relateveYScale = scy / height; - - newInput.xmax = this->m_centerX + (input->xmax - this->m_centerX) / relateveXScale; - newInput.xmin = this->m_centerX + (input->xmin - this->m_centerX) / relateveXScale; - newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / relateveYScale; - newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / relateveYScale; - } - else { - newInput.xmax = this->getWidth(); - newInput.xmin = 0; - newInput.ymax = this->getHeight(); - newInput.ymin = 0; - } - - return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -// Absolute fixed size -ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation() -{ - this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = nullptr; - this->m_is_offset = false; -} -void ScaleFixedSizeOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); - this->m_relX = this->m_inputOperation->getWidth() / (float)this->m_newWidth; - this->m_relY = this->m_inputOperation->getHeight() / (float)this->m_newHeight; - - /* *** all the options below are for a fairly special case - camera framing *** */ - if (this->m_offsetX != 0.0f || this->m_offsetY != 0.0f) { - this->m_is_offset = true; - - if (this->m_newWidth > this->m_newHeight) { - this->m_offsetX *= this->m_newWidth; - this->m_offsetY *= this->m_newWidth; - } - else { - this->m_offsetX *= this->m_newHeight; - this->m_offsetY *= this->m_newHeight; - } - } - - if (this->m_is_aspect) { - /* apply aspect from clip */ - const float w_src = this->m_inputOperation->getWidth(); - const float h_src = this->m_inputOperation->getHeight(); - - /* destination aspect is already applied from the camera frame */ - const float w_dst = this->m_newWidth; - const float h_dst = this->m_newHeight; - - const float asp_src = w_src / h_src; - const float asp_dst = w_dst / h_dst; - - if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) { - if ((asp_src > asp_dst) == (this->m_is_crop == true)) { - /* fit X */ - const float div = asp_src / asp_dst; - this->m_relX /= div; - this->m_offsetX += ((w_src - (w_src * div)) / (w_src / w_dst)) / 2.0f; - } - else { - /* fit Y */ - const float div = asp_dst / asp_src; - this->m_relY /= div; - this->m_offsetY += ((h_src - (h_src * div)) / (h_src / h_dst)) / 2.0f; - } - - this->m_is_offset = true; - } - } - /* *** end framing options *** */ -} - -void ScaleFixedSizeOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; -} - -void ScaleFixedSizeOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - PixelSampler effective_sampler = getEffectiveSampler(sampler); - - if (this->m_is_offset) { - float nx = ((x - this->m_offsetX) * this->m_relX); - float ny = ((y - this->m_offsetY) * this->m_relY); - this->m_inputOperation->readSampled(output, nx, ny, effective_sampler); - } - else { - this->m_inputOperation->readSampled( - output, x * this->m_relX, y * this->m_relY, effective_sampler); - } -} - -bool ScaleFixedSizeOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - - newInput.xmax = (input->xmax - m_offsetX) * this->m_relX + 1; - newInput.xmin = (input->xmin - m_offsetX) * this->m_relX; - newInput.ymax = (input->ymax - m_offsetY) * this->m_relY + 1; - newInput.ymin = (input->ymin - m_offsetY) * this->m_relY; - - return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], - unsigned int /*preferredResolution*/[2]) -{ - unsigned int nr[2]; - nr[0] = this->m_newWidth; - nr[1] = this->m_newHeight; - BaseScaleOperation::determineResolution(resolution, nr); - resolution[0] = this->m_newWidth; - resolution[1] = this->m_newHeight; -} diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc new file mode 100644 index 00000000000..158ffd4a8c0 --- /dev/null +++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc @@ -0,0 +1,353 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ScreenLensDistortionOperation.h" + +#include "BLI_math.h" +#include "BLI_rand.h" +#include "BLI_utildefines.h" + +#include "PIL_time.h" + +ScreenLensDistortionOperation::ScreenLensDistortionOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setComplex(true); + this->m_inputProgram = nullptr; + this->m_distortion = 0.0f; + this->m_dispersion = 0.0f; + this->m_distortion_const = false; + this->m_dispersion_const = false; + this->m_variables_ready = false; +} + +void ScreenLensDistortionOperation::setDistortion(float distortion) +{ + m_distortion = distortion; + m_distortion_const = true; +} + +void ScreenLensDistortionOperation::setDispersion(float dispersion) +{ + m_dispersion = dispersion; + m_dispersion_const = true; +} + +void ScreenLensDistortionOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); + this->initMutex(); + + uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX); + rng_seed ^= (uint)POINTER_AS_INT(m_inputProgram); + this->m_rng = BLI_rng_new(rng_seed); + + this->m_cx = 0.5f * (float)getWidth(); + this->m_cy = 0.5f * (float)getHeight(); + + /* if both are constant, init variables once */ + if (m_distortion_const && m_dispersion_const) { + updateVariables(m_distortion, m_dispersion); + m_variables_ready = true; + } +} + +void *ScreenLensDistortionOperation::initializeTileData(rcti * /*rect*/) +{ + void *buffer = this->m_inputProgram->initializeTileData(nullptr); + + /* get distortion/dispersion values once, by reading inputs at (0,0) + * XXX this assumes invariable values (no image inputs), + * we don't have a nice generic system for that yet + */ + if (!m_variables_ready) { + this->lockMutex(); + + if (!m_distortion_const) { + float result[4]; + getInputSocketReader(1)->readSampled(result, 0, 0, COM_PS_NEAREST); + m_distortion = result[0]; + } + if (!m_dispersion_const) { + float result[4]; + getInputSocketReader(2)->readSampled(result, 0, 0, COM_PS_NEAREST); + m_dispersion = result[0]; + } + + updateVariables(m_distortion, m_dispersion); + m_variables_ready = true; + + this->unlockMutex(); + } + + return buffer; +} + +void ScreenLensDistortionOperation::get_uv(const float xy[2], float uv[2]) const +{ + uv[0] = m_sc * ((xy[0] + 0.5f) - m_cx) / m_cx; + uv[1] = m_sc * ((xy[1] + 0.5f) - m_cy) / m_cy; +} + +void ScreenLensDistortionOperation::distort_uv(const float uv[2], float t, float xy[2]) const +{ + float d = 1.0f / (1.0f + sqrtf(t)); + xy[0] = (uv[0] * d + 0.5f) * getWidth() - 0.5f; + xy[1] = (uv[1] * d + 0.5f) * getHeight() - 0.5f; +} + +bool ScreenLensDistortionOperation::get_delta(float r_sq, + float k4, + const float uv[2], + float delta[2]) const +{ + float t = 1.0f - k4 * r_sq; + if (t >= 0.0f) { + distort_uv(uv, t, delta); + return true; + } + + return false; +} + +void ScreenLensDistortionOperation::accumulate(MemoryBuffer *buffer, + int a, + int b, + float r_sq, + const float uv[2], + const float delta[3][2], + float sum[4], + int count[3]) const +{ + float color[4]; + + float dsf = len_v2v2(delta[a], delta[b]) + 1.0f; + int ds = m_jitter ? (dsf < 4.0f ? 2 : (int)sqrtf(dsf)) : (int)dsf; + float sd = 1.0f / (float)ds; + + float k4 = m_k4[a]; + float dk4 = m_dk4[a]; + + for (float z = 0; z < ds; z++) { + float tz = (z + (m_jitter ? BLI_rng_get_float(m_rng) : 0.5f)) * sd; + float t = 1.0f - (k4 + tz * dk4) * r_sq; + + float xy[2]; + distort_uv(uv, t, xy); + buffer->readBilinear(color, xy[0], xy[1]); + + sum[a] += (1.0f - tz) * color[a]; + sum[b] += (tz)*color[b]; + count[a]++; + count[b]++; + } +} + +void ScreenLensDistortionOperation::executePixel(float output[4], int x, int y, void *data) +{ + MemoryBuffer *buffer = (MemoryBuffer *)data; + float xy[2] = {(float)x, (float)y}; + float uv[2]; + get_uv(xy, uv); + float uv_dot = len_squared_v2(uv); + + int count[3] = {0, 0, 0}; + float delta[3][2]; + float sum[4] = {0, 0, 0, 0}; + + bool valid_r = get_delta(uv_dot, m_k4[0], uv, delta[0]); + bool valid_g = get_delta(uv_dot, m_k4[1], uv, delta[1]); + bool valid_b = get_delta(uv_dot, m_k4[2], uv, delta[2]); + + if (valid_r && valid_g && valid_b) { + accumulate(buffer, 0, 1, uv_dot, uv, delta, sum, count); + accumulate(buffer, 1, 2, uv_dot, uv, delta, sum, count); + + if (count[0]) { + output[0] = 2.0f * sum[0] / (float)count[0]; + } + if (count[1]) { + output[1] = 2.0f * sum[1] / (float)count[1]; + } + if (count[2]) { + output[2] = 2.0f * sum[2] / (float)count[2]; + } + + /* set alpha */ + output[3] = 1.0f; + } + else { + zero_v4(output); + } +} + +void ScreenLensDistortionOperation::deinitExecution() +{ + this->deinitMutex(); + this->m_inputProgram = nullptr; + BLI_rng_free(this->m_rng); +} + +void ScreenLensDistortionOperation::determineUV(float result[6], float x, float y) const +{ + const float xy[2] = {x, y}; + float uv[2]; + get_uv(xy, uv); + float uv_dot = len_squared_v2(uv); + + copy_v2_v2(result + 0, xy); + copy_v2_v2(result + 2, xy); + copy_v2_v2(result + 4, xy); + get_delta(uv_dot, m_k4[0], uv, result + 0); + get_delta(uv_dot, m_k4[1], uv, result + 2); + get_delta(uv_dot, m_k4[2], uv, result + 4); +} + +bool ScreenLensDistortionOperation::determineDependingAreaOfInterest( + rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInputValue; + newInputValue.xmin = 0; + newInputValue.ymin = 0; + newInputValue.xmax = 2; + newInputValue.ymax = 2; + + NodeOperation *operation = getInputOperation(1); + if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output)) { + return true; + } + + operation = getInputOperation(2); + if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output)) { + return true; + } + + /* XXX the original method of estimating the area-of-interest does not work + * it assumes a linear increase/decrease of mapped coordinates, which does not + * yield correct results for the area and leaves uninitialized buffer areas. + * So now just use the full image area, which may not be as efficient but works at least ... + */ +#if 1 + rcti imageInput; + + operation = getInputOperation(0); + imageInput.xmax = operation->getWidth(); + imageInput.xmin = 0; + imageInput.ymax = operation->getHeight(); + imageInput.ymin = 0; + + if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) { + return true; + } + return false; +#else + rcti newInput; + const float margin = 2; + + BLI_rcti_init_minmax(&newInput); + + if (m_dispersion_const && m_distortion_const) { + /* update from fixed distortion/dispersion */ +# define UPDATE_INPUT(x, y) \ + { \ + float coords[6]; \ + determineUV(coords, x, y); \ + newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \ + newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \ + newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \ + newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \ + } \ + (void)0 + + UPDATE_INPUT(input->xmin, input->xmax); + UPDATE_INPUT(input->xmin, input->ymax); + UPDATE_INPUT(input->xmax, input->ymax); + UPDATE_INPUT(input->xmax, input->ymin); + +# undef UPDATE_INPUT + } + else { + /* use maximum dispersion 1.0 if not const */ + float dispersion = m_dispersion_const ? m_dispersion : 1.0f; + +# define UPDATE_INPUT(x, y, distortion) \ + { \ + float coords[6]; \ + updateVariables(distortion, dispersion); \ + determineUV(coords, x, y); \ + newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \ + newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \ + newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \ + newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \ + } \ + (void)0 + + if (m_distortion_const) { + /* update from fixed distortion */ + UPDATE_INPUT(input->xmin, input->xmax, m_distortion); + UPDATE_INPUT(input->xmin, input->ymax, m_distortion); + UPDATE_INPUT(input->xmax, input->ymax, m_distortion); + UPDATE_INPUT(input->xmax, input->ymin, m_distortion); + } + else { + /* update from min/max distortion (-1..1) */ + UPDATE_INPUT(input->xmin, input->xmax, -1.0f); + UPDATE_INPUT(input->xmin, input->ymax, -1.0f); + UPDATE_INPUT(input->xmax, input->ymax, -1.0f); + UPDATE_INPUT(input->xmax, input->ymin, -1.0f); + + UPDATE_INPUT(input->xmin, input->xmax, 1.0f); + UPDATE_INPUT(input->xmin, input->ymax, 1.0f); + UPDATE_INPUT(input->xmax, input->ymax, 1.0f); + UPDATE_INPUT(input->xmax, input->ymin, 1.0f); + +# undef UPDATE_INPUT + } + } + + newInput.xmin -= margin; + newInput.ymin -= margin; + newInput.xmax += margin; + newInput.ymax += margin; + + operation = getInputOperation(0); + if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) { + return true; + } + return false; +#endif +} + +void ScreenLensDistortionOperation::updateVariables(float distortion, float dispersion) +{ + m_k[1] = max_ff(min_ff(distortion, 1.0f), -0.999f); + // smaller dispersion range for somewhat more control + float d = 0.25f * max_ff(min_ff(dispersion, 1.0f), 0.0f); + m_k[0] = max_ff(min_ff((m_k[1] + d), 1.0f), -0.999f); + m_k[2] = max_ff(min_ff((m_k[1] - d), 1.0f), -0.999f); + m_maxk = max_fff(m_k[0], m_k[1], m_k[2]); + m_sc = (m_fit && (m_maxk > 0.0f)) ? (1.0f / (1.0f + 2.0f * m_maxk)) : (1.0f / (1.0f + m_maxk)); + m_dk4[0] = 4.0f * (m_k[1] - m_k[0]); + m_dk4[1] = 4.0f * (m_k[2] - m_k[1]); + m_dk4[2] = 0.0f; /* unused */ + + mul_v3_v3fl(m_k4, m_k, 4.0f); +} diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp deleted file mode 100644 index 158ffd4a8c0..00000000000 --- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp +++ /dev/null @@ -1,353 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ScreenLensDistortionOperation.h" - -#include "BLI_math.h" -#include "BLI_rand.h" -#include "BLI_utildefines.h" - -#include "PIL_time.h" - -ScreenLensDistortionOperation::ScreenLensDistortionOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setComplex(true); - this->m_inputProgram = nullptr; - this->m_distortion = 0.0f; - this->m_dispersion = 0.0f; - this->m_distortion_const = false; - this->m_dispersion_const = false; - this->m_variables_ready = false; -} - -void ScreenLensDistortionOperation::setDistortion(float distortion) -{ - m_distortion = distortion; - m_distortion_const = true; -} - -void ScreenLensDistortionOperation::setDispersion(float dispersion) -{ - m_dispersion = dispersion; - m_dispersion_const = true; -} - -void ScreenLensDistortionOperation::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); - this->initMutex(); - - uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX); - rng_seed ^= (uint)POINTER_AS_INT(m_inputProgram); - this->m_rng = BLI_rng_new(rng_seed); - - this->m_cx = 0.5f * (float)getWidth(); - this->m_cy = 0.5f * (float)getHeight(); - - /* if both are constant, init variables once */ - if (m_distortion_const && m_dispersion_const) { - updateVariables(m_distortion, m_dispersion); - m_variables_ready = true; - } -} - -void *ScreenLensDistortionOperation::initializeTileData(rcti * /*rect*/) -{ - void *buffer = this->m_inputProgram->initializeTileData(nullptr); - - /* get distortion/dispersion values once, by reading inputs at (0,0) - * XXX this assumes invariable values (no image inputs), - * we don't have a nice generic system for that yet - */ - if (!m_variables_ready) { - this->lockMutex(); - - if (!m_distortion_const) { - float result[4]; - getInputSocketReader(1)->readSampled(result, 0, 0, COM_PS_NEAREST); - m_distortion = result[0]; - } - if (!m_dispersion_const) { - float result[4]; - getInputSocketReader(2)->readSampled(result, 0, 0, COM_PS_NEAREST); - m_dispersion = result[0]; - } - - updateVariables(m_distortion, m_dispersion); - m_variables_ready = true; - - this->unlockMutex(); - } - - return buffer; -} - -void ScreenLensDistortionOperation::get_uv(const float xy[2], float uv[2]) const -{ - uv[0] = m_sc * ((xy[0] + 0.5f) - m_cx) / m_cx; - uv[1] = m_sc * ((xy[1] + 0.5f) - m_cy) / m_cy; -} - -void ScreenLensDistortionOperation::distort_uv(const float uv[2], float t, float xy[2]) const -{ - float d = 1.0f / (1.0f + sqrtf(t)); - xy[0] = (uv[0] * d + 0.5f) * getWidth() - 0.5f; - xy[1] = (uv[1] * d + 0.5f) * getHeight() - 0.5f; -} - -bool ScreenLensDistortionOperation::get_delta(float r_sq, - float k4, - const float uv[2], - float delta[2]) const -{ - float t = 1.0f - k4 * r_sq; - if (t >= 0.0f) { - distort_uv(uv, t, delta); - return true; - } - - return false; -} - -void ScreenLensDistortionOperation::accumulate(MemoryBuffer *buffer, - int a, - int b, - float r_sq, - const float uv[2], - const float delta[3][2], - float sum[4], - int count[3]) const -{ - float color[4]; - - float dsf = len_v2v2(delta[a], delta[b]) + 1.0f; - int ds = m_jitter ? (dsf < 4.0f ? 2 : (int)sqrtf(dsf)) : (int)dsf; - float sd = 1.0f / (float)ds; - - float k4 = m_k4[a]; - float dk4 = m_dk4[a]; - - for (float z = 0; z < ds; z++) { - float tz = (z + (m_jitter ? BLI_rng_get_float(m_rng) : 0.5f)) * sd; - float t = 1.0f - (k4 + tz * dk4) * r_sq; - - float xy[2]; - distort_uv(uv, t, xy); - buffer->readBilinear(color, xy[0], xy[1]); - - sum[a] += (1.0f - tz) * color[a]; - sum[b] += (tz)*color[b]; - count[a]++; - count[b]++; - } -} - -void ScreenLensDistortionOperation::executePixel(float output[4], int x, int y, void *data) -{ - MemoryBuffer *buffer = (MemoryBuffer *)data; - float xy[2] = {(float)x, (float)y}; - float uv[2]; - get_uv(xy, uv); - float uv_dot = len_squared_v2(uv); - - int count[3] = {0, 0, 0}; - float delta[3][2]; - float sum[4] = {0, 0, 0, 0}; - - bool valid_r = get_delta(uv_dot, m_k4[0], uv, delta[0]); - bool valid_g = get_delta(uv_dot, m_k4[1], uv, delta[1]); - bool valid_b = get_delta(uv_dot, m_k4[2], uv, delta[2]); - - if (valid_r && valid_g && valid_b) { - accumulate(buffer, 0, 1, uv_dot, uv, delta, sum, count); - accumulate(buffer, 1, 2, uv_dot, uv, delta, sum, count); - - if (count[0]) { - output[0] = 2.0f * sum[0] / (float)count[0]; - } - if (count[1]) { - output[1] = 2.0f * sum[1] / (float)count[1]; - } - if (count[2]) { - output[2] = 2.0f * sum[2] / (float)count[2]; - } - - /* set alpha */ - output[3] = 1.0f; - } - else { - zero_v4(output); - } -} - -void ScreenLensDistortionOperation::deinitExecution() -{ - this->deinitMutex(); - this->m_inputProgram = nullptr; - BLI_rng_free(this->m_rng); -} - -void ScreenLensDistortionOperation::determineUV(float result[6], float x, float y) const -{ - const float xy[2] = {x, y}; - float uv[2]; - get_uv(xy, uv); - float uv_dot = len_squared_v2(uv); - - copy_v2_v2(result + 0, xy); - copy_v2_v2(result + 2, xy); - copy_v2_v2(result + 4, xy); - get_delta(uv_dot, m_k4[0], uv, result + 0); - get_delta(uv_dot, m_k4[1], uv, result + 2); - get_delta(uv_dot, m_k4[2], uv, result + 4); -} - -bool ScreenLensDistortionOperation::determineDependingAreaOfInterest( - rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInputValue; - newInputValue.xmin = 0; - newInputValue.ymin = 0; - newInputValue.xmax = 2; - newInputValue.ymax = 2; - - NodeOperation *operation = getInputOperation(1); - if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output)) { - return true; - } - - operation = getInputOperation(2); - if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output)) { - return true; - } - - /* XXX the original method of estimating the area-of-interest does not work - * it assumes a linear increase/decrease of mapped coordinates, which does not - * yield correct results for the area and leaves uninitialized buffer areas. - * So now just use the full image area, which may not be as efficient but works at least ... - */ -#if 1 - rcti imageInput; - - operation = getInputOperation(0); - imageInput.xmax = operation->getWidth(); - imageInput.xmin = 0; - imageInput.ymax = operation->getHeight(); - imageInput.ymin = 0; - - if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) { - return true; - } - return false; -#else - rcti newInput; - const float margin = 2; - - BLI_rcti_init_minmax(&newInput); - - if (m_dispersion_const && m_distortion_const) { - /* update from fixed distortion/dispersion */ -# define UPDATE_INPUT(x, y) \ - { \ - float coords[6]; \ - determineUV(coords, x, y); \ - newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \ - newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \ - newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \ - newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \ - } \ - (void)0 - - UPDATE_INPUT(input->xmin, input->xmax); - UPDATE_INPUT(input->xmin, input->ymax); - UPDATE_INPUT(input->xmax, input->ymax); - UPDATE_INPUT(input->xmax, input->ymin); - -# undef UPDATE_INPUT - } - else { - /* use maximum dispersion 1.0 if not const */ - float dispersion = m_dispersion_const ? m_dispersion : 1.0f; - -# define UPDATE_INPUT(x, y, distortion) \ - { \ - float coords[6]; \ - updateVariables(distortion, dispersion); \ - determineUV(coords, x, y); \ - newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \ - newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \ - newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \ - newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \ - } \ - (void)0 - - if (m_distortion_const) { - /* update from fixed distortion */ - UPDATE_INPUT(input->xmin, input->xmax, m_distortion); - UPDATE_INPUT(input->xmin, input->ymax, m_distortion); - UPDATE_INPUT(input->xmax, input->ymax, m_distortion); - UPDATE_INPUT(input->xmax, input->ymin, m_distortion); - } - else { - /* update from min/max distortion (-1..1) */ - UPDATE_INPUT(input->xmin, input->xmax, -1.0f); - UPDATE_INPUT(input->xmin, input->ymax, -1.0f); - UPDATE_INPUT(input->xmax, input->ymax, -1.0f); - UPDATE_INPUT(input->xmax, input->ymin, -1.0f); - - UPDATE_INPUT(input->xmin, input->xmax, 1.0f); - UPDATE_INPUT(input->xmin, input->ymax, 1.0f); - UPDATE_INPUT(input->xmax, input->ymax, 1.0f); - UPDATE_INPUT(input->xmax, input->ymin, 1.0f); - -# undef UPDATE_INPUT - } - } - - newInput.xmin -= margin; - newInput.ymin -= margin; - newInput.xmax += margin; - newInput.ymax += margin; - - operation = getInputOperation(0); - if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) { - return true; - } - return false; -#endif -} - -void ScreenLensDistortionOperation::updateVariables(float distortion, float dispersion) -{ - m_k[1] = max_ff(min_ff(distortion, 1.0f), -0.999f); - // smaller dispersion range for somewhat more control - float d = 0.25f * max_ff(min_ff(dispersion, 1.0f), 0.0f); - m_k[0] = max_ff(min_ff((m_k[1] + d), 1.0f), -0.999f); - m_k[2] = max_ff(min_ff((m_k[1] - d), 1.0f), -0.999f); - m_maxk = max_fff(m_k[0], m_k[1], m_k[2]); - m_sc = (m_fit && (m_maxk > 0.0f)) ? (1.0f / (1.0f + 2.0f * m_maxk)) : (1.0f / (1.0f + m_maxk)); - m_dk4[0] = 4.0f * (m_k[1] - m_k[0]); - m_dk4[1] = 4.0f * (m_k[2] - m_k[1]); - m_dk4[2] = 0.0f; /* unused */ - - mul_v3_v3fl(m_k4, m_k, 4.0f); -} diff --git a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc new file mode 100644 index 00000000000..17029cb3049 --- /dev/null +++ b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc @@ -0,0 +1,55 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SetAlphaMultiplyOperation.h" + +SetAlphaMultiplyOperation::SetAlphaMultiplyOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + + this->m_inputColor = nullptr; + this->m_inputAlpha = nullptr; +} + +void SetAlphaMultiplyOperation::initExecution() +{ + this->m_inputColor = getInputSocketReader(0); + this->m_inputAlpha = getInputSocketReader(1); +} + +void SetAlphaMultiplyOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float color_input[4]; + float alpha_input[4]; + + this->m_inputColor->readSampled(color_input, x, y, sampler); + this->m_inputAlpha->readSampled(alpha_input, x, y, sampler); + + mul_v4_v4fl(output, color_input, alpha_input[0]); +} + +void SetAlphaMultiplyOperation::deinitExecution() +{ + this->m_inputColor = nullptr; + this->m_inputAlpha = nullptr; +} diff --git a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp deleted file mode 100644 index 17029cb3049..00000000000 --- a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SetAlphaMultiplyOperation.h" - -SetAlphaMultiplyOperation::SetAlphaMultiplyOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - - this->m_inputColor = nullptr; - this->m_inputAlpha = nullptr; -} - -void SetAlphaMultiplyOperation::initExecution() -{ - this->m_inputColor = getInputSocketReader(0); - this->m_inputAlpha = getInputSocketReader(1); -} - -void SetAlphaMultiplyOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float color_input[4]; - float alpha_input[4]; - - this->m_inputColor->readSampled(color_input, x, y, sampler); - this->m_inputAlpha->readSampled(alpha_input, x, y, sampler); - - mul_v4_v4fl(output, color_input, alpha_input[0]); -} - -void SetAlphaMultiplyOperation::deinitExecution() -{ - this->m_inputColor = nullptr; - this->m_inputAlpha = nullptr; -} diff --git a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc new file mode 100644 index 00000000000..cd6e82902cc --- /dev/null +++ b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc @@ -0,0 +1,53 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SetAlphaReplaceOperation.h" + +SetAlphaReplaceOperation::SetAlphaReplaceOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + + this->m_inputColor = nullptr; + this->m_inputAlpha = nullptr; +} + +void SetAlphaReplaceOperation::initExecution() +{ + this->m_inputColor = getInputSocketReader(0); + this->m_inputAlpha = getInputSocketReader(1); +} + +void SetAlphaReplaceOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float alpha_input[4]; + + this->m_inputColor->readSampled(output, x, y, sampler); + this->m_inputAlpha->readSampled(alpha_input, x, y, sampler); + output[3] = alpha_input[0]; +} + +void SetAlphaReplaceOperation::deinitExecution() +{ + this->m_inputColor = nullptr; + this->m_inputAlpha = nullptr; +} diff --git a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp deleted file mode 100644 index cd6e82902cc..00000000000 --- a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SetAlphaReplaceOperation.h" - -SetAlphaReplaceOperation::SetAlphaReplaceOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - - this->m_inputColor = nullptr; - this->m_inputAlpha = nullptr; -} - -void SetAlphaReplaceOperation::initExecution() -{ - this->m_inputColor = getInputSocketReader(0); - this->m_inputAlpha = getInputSocketReader(1); -} - -void SetAlphaReplaceOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float alpha_input[4]; - - this->m_inputColor->readSampled(output, x, y, sampler); - this->m_inputAlpha->readSampled(alpha_input, x, y, sampler); - output[3] = alpha_input[0]; -} - -void SetAlphaReplaceOperation::deinitExecution() -{ - this->m_inputColor = nullptr; - this->m_inputAlpha = nullptr; -} diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cc b/source/blender/compositor/operations/COM_SetColorOperation.cc new file mode 100644 index 00000000000..ffbc20fde9c --- /dev/null +++ b/source/blender/compositor/operations/COM_SetColorOperation.cc @@ -0,0 +1,39 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SetColorOperation.h" + +SetColorOperation::SetColorOperation() +{ + this->addOutputSocket(COM_DT_COLOR); +} + +void SetColorOperation::executePixelSampled(float output[4], + float /*x*/, + float /*y*/, + PixelSampler /*sampler*/) +{ + copy_v4_v4(output, this->m_color); +} + +void SetColorOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + resolution[0] = preferredResolution[0]; + resolution[1] = preferredResolution[1]; +} diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cpp b/source/blender/compositor/operations/COM_SetColorOperation.cpp deleted file mode 100644 index ffbc20fde9c..00000000000 --- a/source/blender/compositor/operations/COM_SetColorOperation.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SetColorOperation.h" - -SetColorOperation::SetColorOperation() -{ - this->addOutputSocket(COM_DT_COLOR); -} - -void SetColorOperation::executePixelSampled(float output[4], - float /*x*/, - float /*y*/, - PixelSampler /*sampler*/) -{ - copy_v4_v4(output, this->m_color); -} - -void SetColorOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; -} diff --git a/source/blender/compositor/operations/COM_SetSamplerOperation.cc b/source/blender/compositor/operations/COM_SetSamplerOperation.cc new file mode 100644 index 00000000000..942d717d19c --- /dev/null +++ b/source/blender/compositor/operations/COM_SetSamplerOperation.cc @@ -0,0 +1,42 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SetSamplerOperation.h" + +SetSamplerOperation::SetSamplerOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void SetSamplerOperation::initExecution() +{ + this->m_reader = this->getInputSocketReader(0); +} +void SetSamplerOperation::deinitExecution() +{ + this->m_reader = nullptr; +} + +void SetSamplerOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + this->m_reader->readSampled(output, x, y, this->m_sampler); +} diff --git a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp b/source/blender/compositor/operations/COM_SetSamplerOperation.cpp deleted file mode 100644 index 942d717d19c..00000000000 --- a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SetSamplerOperation.h" - -SetSamplerOperation::SetSamplerOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); -} - -void SetSamplerOperation::initExecution() -{ - this->m_reader = this->getInputSocketReader(0); -} -void SetSamplerOperation::deinitExecution() -{ - this->m_reader = nullptr; -} - -void SetSamplerOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - this->m_reader->readSampled(output, x, y, this->m_sampler); -} diff --git a/source/blender/compositor/operations/COM_SetValueOperation.cc b/source/blender/compositor/operations/COM_SetValueOperation.cc new file mode 100644 index 00000000000..d72a2dfe23d --- /dev/null +++ b/source/blender/compositor/operations/COM_SetValueOperation.cc @@ -0,0 +1,39 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SetValueOperation.h" + +SetValueOperation::SetValueOperation() +{ + this->addOutputSocket(COM_DT_VALUE); +} + +void SetValueOperation::executePixelSampled(float output[4], + float /*x*/, + float /*y*/, + PixelSampler /*sampler*/) +{ + output[0] = this->m_value; +} + +void SetValueOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + resolution[0] = preferredResolution[0]; + resolution[1] = preferredResolution[1]; +} diff --git a/source/blender/compositor/operations/COM_SetValueOperation.cpp b/source/blender/compositor/operations/COM_SetValueOperation.cpp deleted file mode 100644 index d72a2dfe23d..00000000000 --- a/source/blender/compositor/operations/COM_SetValueOperation.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SetValueOperation.h" - -SetValueOperation::SetValueOperation() -{ - this->addOutputSocket(COM_DT_VALUE); -} - -void SetValueOperation::executePixelSampled(float output[4], - float /*x*/, - float /*y*/, - PixelSampler /*sampler*/) -{ - output[0] = this->m_value; -} - -void SetValueOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; -} diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cc b/source/blender/compositor/operations/COM_SetVectorOperation.cc new file mode 100644 index 00000000000..a0341dbc4df --- /dev/null +++ b/source/blender/compositor/operations/COM_SetVectorOperation.cc @@ -0,0 +1,42 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SetVectorOperation.h" +#include "COM_defines.h" + +SetVectorOperation::SetVectorOperation() +{ + this->addOutputSocket(COM_DT_VECTOR); +} + +void SetVectorOperation::executePixelSampled(float output[4], + float /*x*/, + float /*y*/, + PixelSampler /*sampler*/) +{ + output[0] = this->m_x; + output[1] = this->m_y; + output[2] = this->m_z; +} + +void SetVectorOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + resolution[0] = preferredResolution[0]; + resolution[1] = preferredResolution[1]; +} diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cpp b/source/blender/compositor/operations/COM_SetVectorOperation.cpp deleted file mode 100644 index a0341dbc4df..00000000000 --- a/source/blender/compositor/operations/COM_SetVectorOperation.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SetVectorOperation.h" -#include "COM_defines.h" - -SetVectorOperation::SetVectorOperation() -{ - this->addOutputSocket(COM_DT_VECTOR); -} - -void SetVectorOperation::executePixelSampled(float output[4], - float /*x*/, - float /*y*/, - PixelSampler /*sampler*/) -{ - output[0] = this->m_x; - output[1] = this->m_y; - output[2] = this->m_z; -} - -void SetVectorOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; -} diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.cc b/source/blender/compositor/operations/COM_SocketProxyOperation.cc new file mode 100644 index 00000000000..53f5fea8795 --- /dev/null +++ b/source/blender/compositor/operations/COM_SocketProxyOperation.cc @@ -0,0 +1,31 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SocketProxyOperation.h" + +SocketProxyOperation::SocketProxyOperation(DataType type, bool use_conversion) + : m_use_conversion(use_conversion) +{ + this->addInputSocket(type); + this->addOutputSocket(type); +} + +std::unique_ptr SocketProxyOperation::getMetaData() const +{ + return this->getInputSocket(0)->getReader()->getMetaData(); +} diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp b/source/blender/compositor/operations/COM_SocketProxyOperation.cpp deleted file mode 100644 index 53f5fea8795..00000000000 --- a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SocketProxyOperation.h" - -SocketProxyOperation::SocketProxyOperation(DataType type, bool use_conversion) - : m_use_conversion(use_conversion) -{ - this->addInputSocket(type); - this->addOutputSocket(type); -} - -std::unique_ptr SocketProxyOperation::getMetaData() const -{ - return this->getInputSocket(0)->getReader()->getMetaData(); -} diff --git a/source/blender/compositor/operations/COM_SplitOperation.cc b/source/blender/compositor/operations/COM_SplitOperation.cc new file mode 100644 index 00000000000..fb6214c7522 --- /dev/null +++ b/source/blender/compositor/operations/COM_SplitOperation.cc @@ -0,0 +1,78 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_SplitOperation.h" +#include "BKE_image.h" +#include "BLI_listbase.h" +#include "BLI_math_color.h" +#include "BLI_math_vector.h" +#include "BLI_utildefines.h" +#include "MEM_guardedalloc.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +SplitOperation::SplitOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_image1Input = nullptr; + this->m_image2Input = nullptr; +} + +void SplitOperation::initExecution() +{ + // When initializing the tree during initial load the width and height can be zero. + this->m_image1Input = getInputSocketReader(0); + this->m_image2Input = getInputSocketReader(1); +} + +void SplitOperation::deinitExecution() +{ + this->m_image1Input = nullptr; + this->m_image2Input = nullptr; +} + +void SplitOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + int perc = this->m_xSplit ? this->m_splitPercentage * this->getWidth() / 100.0f : + this->m_splitPercentage * this->getHeight() / 100.0f; + bool image1 = this->m_xSplit ? x > perc : y > perc; + if (image1) { + this->m_image1Input->readSampled(output, x, y, COM_PS_NEAREST); + } + else { + this->m_image2Input->readSampled(output, x, y, COM_PS_NEAREST); + } +} + +void SplitOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + unsigned int tempPreferredResolution[2] = {0, 0}; + unsigned int tempResolution[2]; + + this->getInputSocket(0)->determineResolution(tempResolution, tempPreferredResolution); + this->setResolutionInputSocketIndex((tempResolution[0] && tempResolution[1]) ? 0 : 1); + + NodeOperation::determineResolution(resolution, preferredResolution); +} diff --git a/source/blender/compositor/operations/COM_SplitOperation.cpp b/source/blender/compositor/operations/COM_SplitOperation.cpp deleted file mode 100644 index fb6214c7522..00000000000 --- a/source/blender/compositor/operations/COM_SplitOperation.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_SplitOperation.h" -#include "BKE_image.h" -#include "BLI_listbase.h" -#include "BLI_math_color.h" -#include "BLI_math_vector.h" -#include "BLI_utildefines.h" -#include "MEM_guardedalloc.h" - -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -SplitOperation::SplitOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_image1Input = nullptr; - this->m_image2Input = nullptr; -} - -void SplitOperation::initExecution() -{ - // When initializing the tree during initial load the width and height can be zero. - this->m_image1Input = getInputSocketReader(0); - this->m_image2Input = getInputSocketReader(1); -} - -void SplitOperation::deinitExecution() -{ - this->m_image1Input = nullptr; - this->m_image2Input = nullptr; -} - -void SplitOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - int perc = this->m_xSplit ? this->m_splitPercentage * this->getWidth() / 100.0f : - this->m_splitPercentage * this->getHeight() / 100.0f; - bool image1 = this->m_xSplit ? x > perc : y > perc; - if (image1) { - this->m_image1Input->readSampled(output, x, y, COM_PS_NEAREST); - } - else { - this->m_image2Input->readSampled(output, x, y, COM_PS_NEAREST); - } -} - -void SplitOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - unsigned int tempPreferredResolution[2] = {0, 0}; - unsigned int tempResolution[2]; - - this->getInputSocket(0)->determineResolution(tempResolution, tempPreferredResolution); - this->setResolutionInputSocketIndex((tempResolution[0] && tempResolution[1]) ? 0 : 1); - - NodeOperation::determineResolution(resolution, preferredResolution); -} diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cc b/source/blender/compositor/operations/COM_SunBeamsOperation.cc new file mode 100644 index 00000000000..28811d479a5 --- /dev/null +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cc @@ -0,0 +1,355 @@ +/* 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. + * + * Copyright 2014, Blender Foundation. + */ + +#include "MEM_guardedalloc.h" + +#include "COM_SunBeamsOperation.h" + +SunBeamsOperation::SunBeamsOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + + this->setComplex(true); +} + +void SunBeamsOperation::initExecution() +{ + /* convert to pixels */ + this->m_source_px[0] = this->m_data.source[0] * this->getWidth(); + this->m_source_px[1] = this->m_data.source[1] * this->getHeight(); + this->m_ray_length_px = this->m_data.ray_length * MAX2(this->getWidth(), this->getHeight()); +} + +/** + * Defines a line accumulator for a specific sector, + * given by the four matrix entries that rotate from buffer space into the sector + * + * (x,y) is used to designate buffer space coordinates + * (u,v) is used to designate sector space coordinates + * + * For a target point (x,y) the sector should be chosen such that + * ``u >= v >= 0`` + * This removes the need to handle all sorts of special cases. + * + * Template parameters: + * fxu : buffer increment in x for sector u+1 + * fxv : buffer increment in x for sector v+1 + * fyu : buffer increment in y for sector u+1 + * fyv : buffer increment in y for sector v+1 + */ +template struct BufferLineAccumulator { + + /* utility functions implementing the matrix transform to/from sector space */ + + static inline void buffer_to_sector(const float source[2], int x, int y, int &u, int &v) + { + int x0 = (int)source[0]; + int y0 = (int)source[1]; + x -= x0; + y -= y0; + u = x * fxu + y * fyu; + v = x * fxv + y * fyv; + } + + static inline void buffer_to_sector(const float source[2], float x, float y, float &u, float &v) + { + int x0 = (int)source[0]; + int y0 = (int)source[1]; + x -= (float)x0; + y -= (float)y0; + u = x * fxu + y * fyu; + v = x * fxv + y * fyv; + } + + static inline void sector_to_buffer(const float source[2], int u, int v, int &x, int &y) + { + int x0 = (int)source[0]; + int y0 = (int)source[1]; + x = x0 + u * fxu + v * fxv; + y = y0 + u * fyu + v * fyv; + } + + static inline void sector_to_buffer(const float source[2], float u, float v, float &x, float &y) + { + int x0 = (int)source[0]; + int y0 = (int)source[1]; + x = (float)x0 + u * fxu + v * fxv; + y = (float)y0 + u * fyu + v * fyv; + } + + /** + * Set up the initial buffer pointer and calculate necessary variables for looping. + * + * Note that sector space is centered around the "source" point while the loop starts + * at dist_min from the target pt. This way the loop can be canceled as soon as it runs + * out of the buffer rect, because no pixels further along the line can contribute. + * + * \param x, y: Start location in the buffer + * \param num: Total steps in the loop + * \param v, dv: Vertical offset in sector space, for line offset perpendicular to the loop axis + */ + static float *init_buffer_iterator(MemoryBuffer *input, + const float source[2], + const float co[2], + float dist_min, + float dist_max, + int &x, + int &y, + int &num, + float &v, + float &dv, + float &falloff_factor) + { + float pu, pv; + buffer_to_sector(source, co[0], co[1], pu, pv); + + /* line angle */ + float tan_phi = pv / pu; + float dr = sqrtf(tan_phi * tan_phi + 1.0f); + float cos_phi = 1.0f / dr; + + /* clamp u range to avoid influence of pixels "behind" the source */ + float umin = max_ff(pu - cos_phi * dist_min, 0.0f); + float umax = max_ff(pu - cos_phi * dist_max, 0.0f); + v = umin * tan_phi; + dv = tan_phi; + + int start = (int)floorf(umax); + int end = (int)ceilf(umin); + num = end - start; + + sector_to_buffer(source, end, (int)ceilf(v), x, y); + + falloff_factor = dist_max > dist_min ? dr / (float)(dist_max - dist_min) : 0.0f; + + float *iter = input->getBuffer() + COM_NUM_CHANNELS_COLOR * (x + input->getWidth() * y); + return iter; + } + + /** + * Perform the actual accumulation along a ray segment from source to pt. + * Only pixels within dist_min..dist_max contribute. + * + * The loop runs backwards(!) over the primary sector space axis u, i.e. increasing distance to + * pt. After each step it decrements v by dv < 1, adding a buffer shift when necessary. + */ + static void eval(MemoryBuffer *input, + float output[4], + const float co[2], + const float source[2], + float dist_min, + float dist_max) + { + rcti rect = *input->getRect(); + int buffer_width = input->getWidth(); + int x, y, num; + float v, dv; + float falloff_factor; + float border[4]; + + zero_v4(output); + + if ((int)(co[0] - source[0]) == 0 && (int)(co[1] - source[1]) == 0) { + copy_v4_v4(output, + input->getBuffer() + COM_NUM_CHANNELS_COLOR * + ((int)source[0] + input->getWidth() * (int)source[1])); + return; + } + + /* Initialize the iteration variables. */ + float *buffer = init_buffer_iterator( + input, source, co, dist_min, dist_max, x, y, num, v, dv, falloff_factor); + zero_v3(border); + border[3] = 1.0f; + + /* v_local keeps track of when to decrement v (see below) */ + float v_local = v - floorf(v); + + for (int i = 0; i < num; i++) { + float weight = 1.0f - (float)i * falloff_factor; + weight *= weight; + + /* range check, use last valid color when running beyond the image border */ + if (x >= rect.xmin && x < rect.xmax && y >= rect.ymin && y < rect.ymax) { + madd_v4_v4fl(output, buffer, buffer[3] * weight); + /* use as border color in case subsequent pixels are out of bounds */ + copy_v4_v4(border, buffer); + } + else { + madd_v4_v4fl(output, border, border[3] * weight); + } + + /* TODO implement proper filtering here, see + * https://en.wikipedia.org/wiki/Lanczos_resampling + * https://en.wikipedia.org/wiki/Sinc_function + * + * using lanczos with x = distance from the line segment, + * normalized to a == 0.5f, could give a good result + * + * for now just divide equally at the end ... + */ + + /* decrement u */ + x -= fxu; + y -= fyu; + buffer -= (fxu + fyu * buffer_width) * COM_NUM_CHANNELS_COLOR; + + /* decrement v (in steps of dv < 1) */ + v_local -= dv; + if (v_local < 0.0f) { + v_local += 1.0f; + + x -= fxv; + y -= fyv; + buffer -= (fxv + fyv * buffer_width) * COM_NUM_CHANNELS_COLOR; + } + } + + /* normalize */ + if (num > 0) { + mul_v4_fl(output, 1.0f / (float)num); + } + } +}; + +/** + * Dispatch function which selects an appropriate accumulator based on the sector of the target + * point, relative to the source. + * + * The BufferLineAccumulator defines the actual loop over the buffer, with an efficient inner loop + * due to using compile time constants instead of a local matrix variable defining the sector + * space. + */ +static void accumulate_line(MemoryBuffer *input, + float output[4], + const float co[2], + const float source[2], + float dist_min, + float dist_max) +{ + /* coordinates relative to source */ + float pt_ofs[2] = {co[0] - source[0], co[1] - source[1]}; + + /* The source sectors are defined like so: + * + * \ 3 | 2 / + * \ | / + * 4 \ | / 1 + * \|/ + * ----------- + * /|\ + * 5 / | \ 8 + * / | \ + * / 6 | 7 \ + * + * The template arguments encode the transformation into "sector space", + * by means of rotation/mirroring matrix elements. + */ + + if (fabsf(pt_ofs[1]) > fabsf(pt_ofs[0])) { + if (pt_ofs[0] > 0.0f) { + if (pt_ofs[1] > 0.0f) { + /* 2 */ + BufferLineAccumulator<0, 1, 1, 0>::eval(input, output, co, source, dist_min, dist_max); + } + else { + /* 7 */ + BufferLineAccumulator<0, 1, -1, 0>::eval(input, output, co, source, dist_min, dist_max); + } + } + else { + if (pt_ofs[1] > 0.0f) { + /* 3 */ + BufferLineAccumulator<0, -1, 1, 0>::eval(input, output, co, source, dist_min, dist_max); + } + else { + /* 6 */ + BufferLineAccumulator<0, -1, -1, 0>::eval(input, output, co, source, dist_min, dist_max); + } + } + } + else { + if (pt_ofs[0] > 0.0f) { + if (pt_ofs[1] > 0.0f) { + /* 1 */ + BufferLineAccumulator<1, 0, 0, 1>::eval(input, output, co, source, dist_min, dist_max); + } + else { + /* 8 */ + BufferLineAccumulator<1, 0, 0, -1>::eval(input, output, co, source, dist_min, dist_max); + } + } + else { + if (pt_ofs[1] > 0.0f) { + /* 4 */ + BufferLineAccumulator<-1, 0, 0, 1>::eval(input, output, co, source, dist_min, dist_max); + } + else { + /* 5 */ + BufferLineAccumulator<-1, 0, 0, -1>::eval(input, output, co, source, dist_min, dist_max); + } + } + } +} + +void *SunBeamsOperation::initializeTileData(rcti * /*rect*/) +{ + void *buffer = getInputOperation(0)->initializeTileData(nullptr); + return buffer; +} + +void SunBeamsOperation::executePixel(float output[4], int x, int y, void *data) +{ + const float co[2] = {(float)x, (float)y}; + + accumulate_line( + (MemoryBuffer *)data, output, co, this->m_source_px, 0.0f, this->m_ray_length_px); +} + +static void calc_ray_shift(rcti *rect, float x, float y, const float source[2], float ray_length) +{ + float co[2] = {(float)x, (float)y}; + float dir[2], dist; + + /* move (x,y) vector toward the source by ray_length distance */ + sub_v2_v2v2(dir, co, source); + dist = normalize_v2(dir); + mul_v2_fl(dir, min_ff(dist, ray_length)); + sub_v2_v2(co, dir); + + int ico[2] = {(int)co[0], (int)co[1]}; + BLI_rcti_do_minmax_v(rect, ico); +} + +bool SunBeamsOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + /* Enlarges the rect by moving each corner toward the source. + * This is the maximum distance that pixels can influence each other + * and gives a rect that contains all possible accumulated pixels. + */ + rcti rect = *input; + calc_ray_shift(&rect, input->xmin, input->ymin, this->m_source_px, this->m_ray_length_px); + calc_ray_shift(&rect, input->xmin, input->ymax, this->m_source_px, this->m_ray_length_px); + calc_ray_shift(&rect, input->xmax, input->ymin, this->m_source_px, this->m_ray_length_px); + calc_ray_shift(&rect, input->xmax, input->ymax, this->m_source_px, this->m_ray_length_px); + + return NodeOperation::determineDependingAreaOfInterest(&rect, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp deleted file mode 100644 index 28811d479a5..00000000000 --- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp +++ /dev/null @@ -1,355 +0,0 @@ -/* 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. - * - * Copyright 2014, Blender Foundation. - */ - -#include "MEM_guardedalloc.h" - -#include "COM_SunBeamsOperation.h" - -SunBeamsOperation::SunBeamsOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - - this->setComplex(true); -} - -void SunBeamsOperation::initExecution() -{ - /* convert to pixels */ - this->m_source_px[0] = this->m_data.source[0] * this->getWidth(); - this->m_source_px[1] = this->m_data.source[1] * this->getHeight(); - this->m_ray_length_px = this->m_data.ray_length * MAX2(this->getWidth(), this->getHeight()); -} - -/** - * Defines a line accumulator for a specific sector, - * given by the four matrix entries that rotate from buffer space into the sector - * - * (x,y) is used to designate buffer space coordinates - * (u,v) is used to designate sector space coordinates - * - * For a target point (x,y) the sector should be chosen such that - * ``u >= v >= 0`` - * This removes the need to handle all sorts of special cases. - * - * Template parameters: - * fxu : buffer increment in x for sector u+1 - * fxv : buffer increment in x for sector v+1 - * fyu : buffer increment in y for sector u+1 - * fyv : buffer increment in y for sector v+1 - */ -template struct BufferLineAccumulator { - - /* utility functions implementing the matrix transform to/from sector space */ - - static inline void buffer_to_sector(const float source[2], int x, int y, int &u, int &v) - { - int x0 = (int)source[0]; - int y0 = (int)source[1]; - x -= x0; - y -= y0; - u = x * fxu + y * fyu; - v = x * fxv + y * fyv; - } - - static inline void buffer_to_sector(const float source[2], float x, float y, float &u, float &v) - { - int x0 = (int)source[0]; - int y0 = (int)source[1]; - x -= (float)x0; - y -= (float)y0; - u = x * fxu + y * fyu; - v = x * fxv + y * fyv; - } - - static inline void sector_to_buffer(const float source[2], int u, int v, int &x, int &y) - { - int x0 = (int)source[0]; - int y0 = (int)source[1]; - x = x0 + u * fxu + v * fxv; - y = y0 + u * fyu + v * fyv; - } - - static inline void sector_to_buffer(const float source[2], float u, float v, float &x, float &y) - { - int x0 = (int)source[0]; - int y0 = (int)source[1]; - x = (float)x0 + u * fxu + v * fxv; - y = (float)y0 + u * fyu + v * fyv; - } - - /** - * Set up the initial buffer pointer and calculate necessary variables for looping. - * - * Note that sector space is centered around the "source" point while the loop starts - * at dist_min from the target pt. This way the loop can be canceled as soon as it runs - * out of the buffer rect, because no pixels further along the line can contribute. - * - * \param x, y: Start location in the buffer - * \param num: Total steps in the loop - * \param v, dv: Vertical offset in sector space, for line offset perpendicular to the loop axis - */ - static float *init_buffer_iterator(MemoryBuffer *input, - const float source[2], - const float co[2], - float dist_min, - float dist_max, - int &x, - int &y, - int &num, - float &v, - float &dv, - float &falloff_factor) - { - float pu, pv; - buffer_to_sector(source, co[0], co[1], pu, pv); - - /* line angle */ - float tan_phi = pv / pu; - float dr = sqrtf(tan_phi * tan_phi + 1.0f); - float cos_phi = 1.0f / dr; - - /* clamp u range to avoid influence of pixels "behind" the source */ - float umin = max_ff(pu - cos_phi * dist_min, 0.0f); - float umax = max_ff(pu - cos_phi * dist_max, 0.0f); - v = umin * tan_phi; - dv = tan_phi; - - int start = (int)floorf(umax); - int end = (int)ceilf(umin); - num = end - start; - - sector_to_buffer(source, end, (int)ceilf(v), x, y); - - falloff_factor = dist_max > dist_min ? dr / (float)(dist_max - dist_min) : 0.0f; - - float *iter = input->getBuffer() + COM_NUM_CHANNELS_COLOR * (x + input->getWidth() * y); - return iter; - } - - /** - * Perform the actual accumulation along a ray segment from source to pt. - * Only pixels within dist_min..dist_max contribute. - * - * The loop runs backwards(!) over the primary sector space axis u, i.e. increasing distance to - * pt. After each step it decrements v by dv < 1, adding a buffer shift when necessary. - */ - static void eval(MemoryBuffer *input, - float output[4], - const float co[2], - const float source[2], - float dist_min, - float dist_max) - { - rcti rect = *input->getRect(); - int buffer_width = input->getWidth(); - int x, y, num; - float v, dv; - float falloff_factor; - float border[4]; - - zero_v4(output); - - if ((int)(co[0] - source[0]) == 0 && (int)(co[1] - source[1]) == 0) { - copy_v4_v4(output, - input->getBuffer() + COM_NUM_CHANNELS_COLOR * - ((int)source[0] + input->getWidth() * (int)source[1])); - return; - } - - /* Initialize the iteration variables. */ - float *buffer = init_buffer_iterator( - input, source, co, dist_min, dist_max, x, y, num, v, dv, falloff_factor); - zero_v3(border); - border[3] = 1.0f; - - /* v_local keeps track of when to decrement v (see below) */ - float v_local = v - floorf(v); - - for (int i = 0; i < num; i++) { - float weight = 1.0f - (float)i * falloff_factor; - weight *= weight; - - /* range check, use last valid color when running beyond the image border */ - if (x >= rect.xmin && x < rect.xmax && y >= rect.ymin && y < rect.ymax) { - madd_v4_v4fl(output, buffer, buffer[3] * weight); - /* use as border color in case subsequent pixels are out of bounds */ - copy_v4_v4(border, buffer); - } - else { - madd_v4_v4fl(output, border, border[3] * weight); - } - - /* TODO implement proper filtering here, see - * https://en.wikipedia.org/wiki/Lanczos_resampling - * https://en.wikipedia.org/wiki/Sinc_function - * - * using lanczos with x = distance from the line segment, - * normalized to a == 0.5f, could give a good result - * - * for now just divide equally at the end ... - */ - - /* decrement u */ - x -= fxu; - y -= fyu; - buffer -= (fxu + fyu * buffer_width) * COM_NUM_CHANNELS_COLOR; - - /* decrement v (in steps of dv < 1) */ - v_local -= dv; - if (v_local < 0.0f) { - v_local += 1.0f; - - x -= fxv; - y -= fyv; - buffer -= (fxv + fyv * buffer_width) * COM_NUM_CHANNELS_COLOR; - } - } - - /* normalize */ - if (num > 0) { - mul_v4_fl(output, 1.0f / (float)num); - } - } -}; - -/** - * Dispatch function which selects an appropriate accumulator based on the sector of the target - * point, relative to the source. - * - * The BufferLineAccumulator defines the actual loop over the buffer, with an efficient inner loop - * due to using compile time constants instead of a local matrix variable defining the sector - * space. - */ -static void accumulate_line(MemoryBuffer *input, - float output[4], - const float co[2], - const float source[2], - float dist_min, - float dist_max) -{ - /* coordinates relative to source */ - float pt_ofs[2] = {co[0] - source[0], co[1] - source[1]}; - - /* The source sectors are defined like so: - * - * \ 3 | 2 / - * \ | / - * 4 \ | / 1 - * \|/ - * ----------- - * /|\ - * 5 / | \ 8 - * / | \ - * / 6 | 7 \ - * - * The template arguments encode the transformation into "sector space", - * by means of rotation/mirroring matrix elements. - */ - - if (fabsf(pt_ofs[1]) > fabsf(pt_ofs[0])) { - if (pt_ofs[0] > 0.0f) { - if (pt_ofs[1] > 0.0f) { - /* 2 */ - BufferLineAccumulator<0, 1, 1, 0>::eval(input, output, co, source, dist_min, dist_max); - } - else { - /* 7 */ - BufferLineAccumulator<0, 1, -1, 0>::eval(input, output, co, source, dist_min, dist_max); - } - } - else { - if (pt_ofs[1] > 0.0f) { - /* 3 */ - BufferLineAccumulator<0, -1, 1, 0>::eval(input, output, co, source, dist_min, dist_max); - } - else { - /* 6 */ - BufferLineAccumulator<0, -1, -1, 0>::eval(input, output, co, source, dist_min, dist_max); - } - } - } - else { - if (pt_ofs[0] > 0.0f) { - if (pt_ofs[1] > 0.0f) { - /* 1 */ - BufferLineAccumulator<1, 0, 0, 1>::eval(input, output, co, source, dist_min, dist_max); - } - else { - /* 8 */ - BufferLineAccumulator<1, 0, 0, -1>::eval(input, output, co, source, dist_min, dist_max); - } - } - else { - if (pt_ofs[1] > 0.0f) { - /* 4 */ - BufferLineAccumulator<-1, 0, 0, 1>::eval(input, output, co, source, dist_min, dist_max); - } - else { - /* 5 */ - BufferLineAccumulator<-1, 0, 0, -1>::eval(input, output, co, source, dist_min, dist_max); - } - } - } -} - -void *SunBeamsOperation::initializeTileData(rcti * /*rect*/) -{ - void *buffer = getInputOperation(0)->initializeTileData(nullptr); - return buffer; -} - -void SunBeamsOperation::executePixel(float output[4], int x, int y, void *data) -{ - const float co[2] = {(float)x, (float)y}; - - accumulate_line( - (MemoryBuffer *)data, output, co, this->m_source_px, 0.0f, this->m_ray_length_px); -} - -static void calc_ray_shift(rcti *rect, float x, float y, const float source[2], float ray_length) -{ - float co[2] = {(float)x, (float)y}; - float dir[2], dist; - - /* move (x,y) vector toward the source by ray_length distance */ - sub_v2_v2v2(dir, co, source); - dist = normalize_v2(dir); - mul_v2_fl(dir, min_ff(dist, ray_length)); - sub_v2_v2(co, dir); - - int ico[2] = {(int)co[0], (int)co[1]}; - BLI_rcti_do_minmax_v(rect, ico); -} - -bool SunBeamsOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - /* Enlarges the rect by moving each corner toward the source. - * This is the maximum distance that pixels can influence each other - * and gives a rect that contains all possible accumulated pixels. - */ - rcti rect = *input; - calc_ray_shift(&rect, input->xmin, input->ymin, this->m_source_px, this->m_ray_length_px); - calc_ray_shift(&rect, input->xmin, input->ymax, this->m_source_px, this->m_ray_length_px); - calc_ray_shift(&rect, input->xmax, input->ymin, this->m_source_px, this->m_ray_length_px); - calc_ray_shift(&rect, input->xmax, input->ymax, this->m_source_px, this->m_ray_length_px); - - return NodeOperation::determineDependingAreaOfInterest(&rect, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc new file mode 100644 index 00000000000..e66cd57cb3f --- /dev/null +++ b/source/blender/compositor/operations/COM_TextureOperation.cc @@ -0,0 +1,157 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_TextureOperation.h" +#include "COM_WorkScheduler.h" + +#include "BKE_image.h" +#include "BKE_node.h" + +#include "BLI_listbase.h" +#include "BLI_threads.h" + +TextureBaseOperation::TextureBaseOperation() +{ + this->addInputSocket(COM_DT_VECTOR); // offset + this->addInputSocket(COM_DT_VECTOR); // size + this->m_texture = nullptr; + this->m_inputSize = nullptr; + this->m_inputOffset = nullptr; + this->m_rd = nullptr; + this->m_pool = nullptr; + this->m_sceneColorManage = false; + setComplex(true); +} +TextureOperation::TextureOperation() : TextureBaseOperation() +{ + this->addOutputSocket(COM_DT_COLOR); +} +TextureAlphaOperation::TextureAlphaOperation() : TextureBaseOperation() +{ + this->addOutputSocket(COM_DT_VALUE); +} + +void TextureBaseOperation::initExecution() +{ + this->m_inputOffset = getInputSocketReader(0); + this->m_inputSize = getInputSocketReader(1); + this->m_pool = BKE_image_pool_new(); + if (this->m_texture != nullptr && this->m_texture->nodetree != nullptr && + this->m_texture->use_nodes) { + ntreeTexBeginExecTree(this->m_texture->nodetree); + } + NodeOperation::initExecution(); +} +void TextureBaseOperation::deinitExecution() +{ + this->m_inputSize = nullptr; + this->m_inputOffset = nullptr; + BKE_image_pool_free(this->m_pool); + this->m_pool = nullptr; + if (this->m_texture != nullptr && this->m_texture->use_nodes && + this->m_texture->nodetree != nullptr && this->m_texture->nodetree->execdata != nullptr) { + ntreeTexEndExecTree(this->m_texture->nodetree->execdata); + } + NodeOperation::deinitExecution(); +} + +void TextureBaseOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + if (preferredResolution[0] == 0 || preferredResolution[1] == 0) { + int width = this->m_rd->xsch * this->m_rd->size / 100; + int height = this->m_rd->ysch * this->m_rd->size / 100; + resolution[0] = width; + resolution[1] = height; + } + else { + resolution[0] = preferredResolution[0]; + resolution[1] = preferredResolution[1]; + } +} + +void TextureAlphaOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float color[4]; + TextureBaseOperation::executePixelSampled(color, x, y, sampler); + output[0] = color[3]; +} + +void TextureBaseOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + TexResult texres = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, nullptr}; + float textureSize[4]; + float textureOffset[4]; + float vec[3]; + int retval; + const float cx = this->getWidth() / 2; + const float cy = this->getHeight() / 2; + float u = (x - cx) / this->getWidth() * 2; + float v = (y - cy) / this->getHeight() * 2; + + /* When no interpolation/filtering happens in multitex() force nearest interpolation. + * We do it here because (a) we can't easily say multitex() that we want nearest + * interpolation and (b) in such configuration multitex() simply floor's the value + * which often produces artifacts. + */ + if (m_texture != nullptr && (m_texture->imaflag & TEX_INTERPOL) == 0) { + u += 0.5f / cx; + v += 0.5f / cy; + } + + this->m_inputSize->readSampled(textureSize, x, y, sampler); + this->m_inputOffset->readSampled(textureOffset, x, y, sampler); + + vec[0] = textureSize[0] * (u + textureOffset[0]); + vec[1] = textureSize[1] * (v + textureOffset[1]); + vec[2] = textureSize[2] * textureOffset[2]; + + const int thread_id = WorkScheduler::current_thread_id(); + retval = multitex_ext(this->m_texture, + vec, + nullptr, + nullptr, + 0, + &texres, + thread_id, + m_pool, + m_sceneColorManage, + false); + + if (texres.talpha) { + output[3] = texres.ta; + } + else { + output[3] = texres.tin; + } + + if ((retval & TEX_RGB)) { + output[0] = texres.tr; + output[1] = texres.tg; + output[2] = texres.tb; + } + else { + output[0] = output[1] = output[2] = output[3]; + } +} diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp deleted file mode 100644 index e66cd57cb3f..00000000000 --- a/source/blender/compositor/operations/COM_TextureOperation.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_TextureOperation.h" -#include "COM_WorkScheduler.h" - -#include "BKE_image.h" -#include "BKE_node.h" - -#include "BLI_listbase.h" -#include "BLI_threads.h" - -TextureBaseOperation::TextureBaseOperation() -{ - this->addInputSocket(COM_DT_VECTOR); // offset - this->addInputSocket(COM_DT_VECTOR); // size - this->m_texture = nullptr; - this->m_inputSize = nullptr; - this->m_inputOffset = nullptr; - this->m_rd = nullptr; - this->m_pool = nullptr; - this->m_sceneColorManage = false; - setComplex(true); -} -TextureOperation::TextureOperation() : TextureBaseOperation() -{ - this->addOutputSocket(COM_DT_COLOR); -} -TextureAlphaOperation::TextureAlphaOperation() : TextureBaseOperation() -{ - this->addOutputSocket(COM_DT_VALUE); -} - -void TextureBaseOperation::initExecution() -{ - this->m_inputOffset = getInputSocketReader(0); - this->m_inputSize = getInputSocketReader(1); - this->m_pool = BKE_image_pool_new(); - if (this->m_texture != nullptr && this->m_texture->nodetree != nullptr && - this->m_texture->use_nodes) { - ntreeTexBeginExecTree(this->m_texture->nodetree); - } - NodeOperation::initExecution(); -} -void TextureBaseOperation::deinitExecution() -{ - this->m_inputSize = nullptr; - this->m_inputOffset = nullptr; - BKE_image_pool_free(this->m_pool); - this->m_pool = nullptr; - if (this->m_texture != nullptr && this->m_texture->use_nodes && - this->m_texture->nodetree != nullptr && this->m_texture->nodetree->execdata != nullptr) { - ntreeTexEndExecTree(this->m_texture->nodetree->execdata); - } - NodeOperation::deinitExecution(); -} - -void TextureBaseOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - if (preferredResolution[0] == 0 || preferredResolution[1] == 0) { - int width = this->m_rd->xsch * this->m_rd->size / 100; - int height = this->m_rd->ysch * this->m_rd->size / 100; - resolution[0] = width; - resolution[1] = height; - } - else { - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; - } -} - -void TextureAlphaOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float color[4]; - TextureBaseOperation::executePixelSampled(color, x, y, sampler); - output[0] = color[3]; -} - -void TextureBaseOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - TexResult texres = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, nullptr}; - float textureSize[4]; - float textureOffset[4]; - float vec[3]; - int retval; - const float cx = this->getWidth() / 2; - const float cy = this->getHeight() / 2; - float u = (x - cx) / this->getWidth() * 2; - float v = (y - cy) / this->getHeight() * 2; - - /* When no interpolation/filtering happens in multitex() force nearest interpolation. - * We do it here because (a) we can't easily say multitex() that we want nearest - * interpolation and (b) in such configuration multitex() simply floor's the value - * which often produces artifacts. - */ - if (m_texture != nullptr && (m_texture->imaflag & TEX_INTERPOL) == 0) { - u += 0.5f / cx; - v += 0.5f / cy; - } - - this->m_inputSize->readSampled(textureSize, x, y, sampler); - this->m_inputOffset->readSampled(textureOffset, x, y, sampler); - - vec[0] = textureSize[0] * (u + textureOffset[0]); - vec[1] = textureSize[1] * (v + textureOffset[1]); - vec[2] = textureSize[2] * textureOffset[2]; - - const int thread_id = WorkScheduler::current_thread_id(); - retval = multitex_ext(this->m_texture, - vec, - nullptr, - nullptr, - 0, - &texres, - thread_id, - m_pool, - m_sceneColorManage, - false); - - if (texres.talpha) { - output[3] = texres.ta; - } - else { - output[3] = texres.tin; - } - - if ((retval & TEX_RGB)) { - output[0] = texres.tr; - output[1] = texres.tg; - output[2] = texres.tb; - } - else { - output[0] = output[1] = output[2] = output[3]; - } -} diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cc b/source/blender/compositor/operations/COM_TonemapOperation.cc new file mode 100644 index 00000000000..4c1d285a69f --- /dev/null +++ b/source/blender/compositor/operations/COM_TonemapOperation.cc @@ -0,0 +1,152 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_TonemapOperation.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "IMB_colormanagement.h" + +TonemapOperation::TonemapOperation() +{ + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); + this->addOutputSocket(COM_DT_COLOR); + this->m_imageReader = nullptr; + this->m_data = nullptr; + this->m_cachedInstance = nullptr; + this->setComplex(true); +} +void TonemapOperation::initExecution() +{ + this->m_imageReader = this->getInputSocketReader(0); + NodeOperation::initMutex(); +} + +void TonemapOperation::executePixel(float output[4], int x, int y, void *data) +{ + AvgLogLum *avg = (AvgLogLum *)data; + + this->m_imageReader->read(output, x, y, nullptr); + mul_v3_fl(output, avg->al); + float dr = output[0] + this->m_data->offset; + float dg = output[1] + this->m_data->offset; + float db = output[2] + this->m_data->offset; + output[0] /= ((dr == 0.0f) ? 1.0f : dr); + output[1] /= ((dg == 0.0f) ? 1.0f : dg); + output[2] /= ((db == 0.0f) ? 1.0f : db); + const float igm = avg->igm; + if (igm != 0.0f) { + output[0] = powf(MAX2(output[0], 0.0f), igm); + output[1] = powf(MAX2(output[1], 0.0f), igm); + output[2] = powf(MAX2(output[2], 0.0f), igm); + } +} +void PhotoreceptorTonemapOperation::executePixel(float output[4], int x, int y, void *data) +{ + AvgLogLum *avg = (AvgLogLum *)data; + NodeTonemap *ntm = this->m_data; + + const float f = expf(-this->m_data->f); + const float m = (ntm->m > 0.0f) ? ntm->m : (0.3f + 0.7f * powf(avg->auto_key, 1.4f)); + const float ic = 1.0f - ntm->c, ia = 1.0f - ntm->a; + + this->m_imageReader->read(output, x, y, nullptr); + + const float L = IMB_colormanagement_get_luminance(output); + float I_l = output[0] + ic * (L - output[0]); + float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]); + float I_a = I_l + ia * (I_g - I_l); + output[0] /= (output[0] + powf(f * I_a, m)); + I_l = output[1] + ic * (L - output[1]); + I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]); + I_a = I_l + ia * (I_g - I_l); + output[1] /= (output[1] + powf(f * I_a, m)); + I_l = output[2] + ic * (L - output[2]); + I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]); + I_a = I_l + ia * (I_g - I_l); + output[2] /= (output[2] + powf(f * I_a, m)); +} + +void TonemapOperation::deinitExecution() +{ + this->m_imageReader = nullptr; + delete this->m_cachedInstance; + NodeOperation::deinitMutex(); +} + +bool TonemapOperation::determineDependingAreaOfInterest(rcti * /*input*/, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti imageInput; + + NodeOperation *operation = getInputOperation(0); + imageInput.xmax = operation->getWidth(); + imageInput.xmin = 0; + imageInput.ymax = operation->getHeight(); + imageInput.ymin = 0; + if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) { + return true; + } + return false; +} + +void *TonemapOperation::initializeTileData(rcti *rect) +{ + lockMutex(); + if (this->m_cachedInstance == nullptr) { + MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect); + AvgLogLum *data = new AvgLogLum(); + + float *buffer = tile->getBuffer(); + + float lsum = 0.0f; + int p = tile->getWidth() * tile->getHeight(); + float *bc = buffer; + float avl, maxl = -1e10f, minl = 1e10f; + const float sc = 1.0f / p; + float Lav = 0.0f; + float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + while (p--) { + float L = IMB_colormanagement_get_luminance(bc); + Lav += L; + add_v3_v3(cav, bc); + lsum += logf(MAX2(L, 0.0f) + 1e-5f); + maxl = (L > maxl) ? L : maxl; + minl = (L < minl) ? L : minl; + bc += 4; + } + data->lav = Lav * sc; + mul_v3_v3fl(data->cav, cav, sc); + maxl = log((double)maxl + 1e-5); + minl = log((double)minl + 1e-5); + avl = lsum * sc; + data->auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f; + float al = exp((double)avl); + data->al = (al == 0.0f) ? 0.0f : (this->m_data->key / al); + data->igm = (this->m_data->gamma == 0.0f) ? 1 : (1.0f / this->m_data->gamma); + this->m_cachedInstance = data; + } + unlockMutex(); + return this->m_cachedInstance; +} + +void TonemapOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/) +{ + /* pass */ +} diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cpp b/source/blender/compositor/operations/COM_TonemapOperation.cpp deleted file mode 100644 index 4c1d285a69f..00000000000 --- a/source/blender/compositor/operations/COM_TonemapOperation.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_TonemapOperation.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -#include "IMB_colormanagement.h" - -TonemapOperation::TonemapOperation() -{ - this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); - this->addOutputSocket(COM_DT_COLOR); - this->m_imageReader = nullptr; - this->m_data = nullptr; - this->m_cachedInstance = nullptr; - this->setComplex(true); -} -void TonemapOperation::initExecution() -{ - this->m_imageReader = this->getInputSocketReader(0); - NodeOperation::initMutex(); -} - -void TonemapOperation::executePixel(float output[4], int x, int y, void *data) -{ - AvgLogLum *avg = (AvgLogLum *)data; - - this->m_imageReader->read(output, x, y, nullptr); - mul_v3_fl(output, avg->al); - float dr = output[0] + this->m_data->offset; - float dg = output[1] + this->m_data->offset; - float db = output[2] + this->m_data->offset; - output[0] /= ((dr == 0.0f) ? 1.0f : dr); - output[1] /= ((dg == 0.0f) ? 1.0f : dg); - output[2] /= ((db == 0.0f) ? 1.0f : db); - const float igm = avg->igm; - if (igm != 0.0f) { - output[0] = powf(MAX2(output[0], 0.0f), igm); - output[1] = powf(MAX2(output[1], 0.0f), igm); - output[2] = powf(MAX2(output[2], 0.0f), igm); - } -} -void PhotoreceptorTonemapOperation::executePixel(float output[4], int x, int y, void *data) -{ - AvgLogLum *avg = (AvgLogLum *)data; - NodeTonemap *ntm = this->m_data; - - const float f = expf(-this->m_data->f); - const float m = (ntm->m > 0.0f) ? ntm->m : (0.3f + 0.7f * powf(avg->auto_key, 1.4f)); - const float ic = 1.0f - ntm->c, ia = 1.0f - ntm->a; - - this->m_imageReader->read(output, x, y, nullptr); - - const float L = IMB_colormanagement_get_luminance(output); - float I_l = output[0] + ic * (L - output[0]); - float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]); - float I_a = I_l + ia * (I_g - I_l); - output[0] /= (output[0] + powf(f * I_a, m)); - I_l = output[1] + ic * (L - output[1]); - I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]); - I_a = I_l + ia * (I_g - I_l); - output[1] /= (output[1] + powf(f * I_a, m)); - I_l = output[2] + ic * (L - output[2]); - I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]); - I_a = I_l + ia * (I_g - I_l); - output[2] /= (output[2] + powf(f * I_a, m)); -} - -void TonemapOperation::deinitExecution() -{ - this->m_imageReader = nullptr; - delete this->m_cachedInstance; - NodeOperation::deinitMutex(); -} - -bool TonemapOperation::determineDependingAreaOfInterest(rcti * /*input*/, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti imageInput; - - NodeOperation *operation = getInputOperation(0); - imageInput.xmax = operation->getWidth(); - imageInput.xmin = 0; - imageInput.ymax = operation->getHeight(); - imageInput.ymin = 0; - if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output)) { - return true; - } - return false; -} - -void *TonemapOperation::initializeTileData(rcti *rect) -{ - lockMutex(); - if (this->m_cachedInstance == nullptr) { - MemoryBuffer *tile = (MemoryBuffer *)this->m_imageReader->initializeTileData(rect); - AvgLogLum *data = new AvgLogLum(); - - float *buffer = tile->getBuffer(); - - float lsum = 0.0f; - int p = tile->getWidth() * tile->getHeight(); - float *bc = buffer; - float avl, maxl = -1e10f, minl = 1e10f; - const float sc = 1.0f / p; - float Lav = 0.0f; - float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - while (p--) { - float L = IMB_colormanagement_get_luminance(bc); - Lav += L; - add_v3_v3(cav, bc); - lsum += logf(MAX2(L, 0.0f) + 1e-5f); - maxl = (L > maxl) ? L : maxl; - minl = (L < minl) ? L : minl; - bc += 4; - } - data->lav = Lav * sc; - mul_v3_v3fl(data->cav, cav, sc); - maxl = log((double)maxl + 1e-5); - minl = log((double)minl + 1e-5); - avl = lsum * sc; - data->auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f; - float al = exp((double)avl); - data->al = (al == 0.0f) ? 0.0f : (this->m_data->key / al); - data->igm = (this->m_data->gamma == 0.0f) ? 1 : (1.0f / this->m_data->gamma); - this->m_cachedInstance = data; - } - unlockMutex(); - return this->m_cachedInstance; -} - -void TonemapOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/) -{ - /* pass */ -} diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cc b/source/blender/compositor/operations/COM_TrackPositionOperation.cc new file mode 100644 index 00000000000..ddabfb7cf6c --- /dev/null +++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cc @@ -0,0 +1,136 @@ +/* + * 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. + * + * Copyright 2012, Blender Foundation. + */ + +#include "COM_TrackPositionOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" + +#include "BKE_movieclip.h" +#include "BKE_node.h" +#include "BKE_tracking.h" + +TrackPositionOperation::TrackPositionOperation() +{ + this->addOutputSocket(COM_DT_VALUE); + this->m_movieClip = nullptr; + this->m_framenumber = 0; + this->m_trackingObjectName[0] = 0; + this->m_trackName[0] = 0; + this->m_axis = 0; + this->m_position = CMP_TRACKPOS_ABSOLUTE; + this->m_relativeFrame = 0; + this->m_speed_output = false; +} + +void TrackPositionOperation::initExecution() +{ + MovieTracking *tracking = nullptr; + MovieClipUser user = {0}; + MovieTrackingObject *object; + + zero_v2(this->m_markerPos); + zero_v2(this->m_relativePos); + + if (!this->m_movieClip) { + return; + } + + tracking = &this->m_movieClip->tracking; + + BKE_movieclip_user_set_frame(&user, this->m_framenumber); + BKE_movieclip_get_size(this->m_movieClip, &user, &this->m_width, &this->m_height); + + object = BKE_tracking_object_get_named(tracking, this->m_trackingObjectName); + if (object) { + MovieTrackingTrack *track; + + track = BKE_tracking_track_get_named(tracking, object, this->m_trackName); + + if (track) { + MovieTrackingMarker *marker; + int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, + this->m_framenumber); + + marker = BKE_tracking_marker_get(track, clip_framenr); + + copy_v2_v2(this->m_markerPos, marker->pos); + + if (this->m_speed_output) { + int relative_clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, + this->m_relativeFrame); + + marker = BKE_tracking_marker_get_exact(track, relative_clip_framenr); + if (marker != nullptr && (marker->flag & MARKER_DISABLED) == 0) { + copy_v2_v2(this->m_relativePos, marker->pos); + } + else { + copy_v2_v2(this->m_relativePos, this->m_markerPos); + } + if (this->m_relativeFrame < this->m_framenumber) { + swap_v2_v2(this->m_relativePos, this->m_markerPos); + } + } + else if (this->m_position == CMP_TRACKPOS_RELATIVE_START) { + int i; + + for (i = 0; i < track->markersnr; i++) { + marker = &track->markers[i]; + + if ((marker->flag & MARKER_DISABLED) == 0) { + copy_v2_v2(this->m_relativePos, marker->pos); + + break; + } + } + } + else if (this->m_position == CMP_TRACKPOS_RELATIVE_FRAME) { + int relative_clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, + this->m_relativeFrame); + + marker = BKE_tracking_marker_get(track, relative_clip_framenr); + copy_v2_v2(this->m_relativePos, marker->pos); + } + } + } +} + +void TrackPositionOperation::executePixelSampled(float output[4], + float /*x*/, + float /*y*/, + PixelSampler /*sampler*/) +{ + output[0] = this->m_markerPos[this->m_axis] - this->m_relativePos[this->m_axis]; + + if (this->m_axis == 0) { + output[0] *= this->m_width; + } + else { + output[0] *= this->m_height; + } +} + +void TrackPositionOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + resolution[0] = preferredResolution[0]; + resolution[1] = preferredResolution[1]; +} diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp b/source/blender/compositor/operations/COM_TrackPositionOperation.cpp deleted file mode 100644 index ddabfb7cf6c..00000000000 --- a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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. - * - * Copyright 2012, Blender Foundation. - */ - -#include "COM_TrackPositionOperation.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_math_color.h" - -#include "BKE_movieclip.h" -#include "BKE_node.h" -#include "BKE_tracking.h" - -TrackPositionOperation::TrackPositionOperation() -{ - this->addOutputSocket(COM_DT_VALUE); - this->m_movieClip = nullptr; - this->m_framenumber = 0; - this->m_trackingObjectName[0] = 0; - this->m_trackName[0] = 0; - this->m_axis = 0; - this->m_position = CMP_TRACKPOS_ABSOLUTE; - this->m_relativeFrame = 0; - this->m_speed_output = false; -} - -void TrackPositionOperation::initExecution() -{ - MovieTracking *tracking = nullptr; - MovieClipUser user = {0}; - MovieTrackingObject *object; - - zero_v2(this->m_markerPos); - zero_v2(this->m_relativePos); - - if (!this->m_movieClip) { - return; - } - - tracking = &this->m_movieClip->tracking; - - BKE_movieclip_user_set_frame(&user, this->m_framenumber); - BKE_movieclip_get_size(this->m_movieClip, &user, &this->m_width, &this->m_height); - - object = BKE_tracking_object_get_named(tracking, this->m_trackingObjectName); - if (object) { - MovieTrackingTrack *track; - - track = BKE_tracking_track_get_named(tracking, object, this->m_trackName); - - if (track) { - MovieTrackingMarker *marker; - int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, - this->m_framenumber); - - marker = BKE_tracking_marker_get(track, clip_framenr); - - copy_v2_v2(this->m_markerPos, marker->pos); - - if (this->m_speed_output) { - int relative_clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, - this->m_relativeFrame); - - marker = BKE_tracking_marker_get_exact(track, relative_clip_framenr); - if (marker != nullptr && (marker->flag & MARKER_DISABLED) == 0) { - copy_v2_v2(this->m_relativePos, marker->pos); - } - else { - copy_v2_v2(this->m_relativePos, this->m_markerPos); - } - if (this->m_relativeFrame < this->m_framenumber) { - swap_v2_v2(this->m_relativePos, this->m_markerPos); - } - } - else if (this->m_position == CMP_TRACKPOS_RELATIVE_START) { - int i; - - for (i = 0; i < track->markersnr; i++) { - marker = &track->markers[i]; - - if ((marker->flag & MARKER_DISABLED) == 0) { - copy_v2_v2(this->m_relativePos, marker->pos); - - break; - } - } - } - else if (this->m_position == CMP_TRACKPOS_RELATIVE_FRAME) { - int relative_clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, - this->m_relativeFrame); - - marker = BKE_tracking_marker_get(track, relative_clip_framenr); - copy_v2_v2(this->m_relativePos, marker->pos); - } - } - } -} - -void TrackPositionOperation::executePixelSampled(float output[4], - float /*x*/, - float /*y*/, - PixelSampler /*sampler*/) -{ - output[0] = this->m_markerPos[this->m_axis] - this->m_relativePos[this->m_axis]; - - if (this->m_axis == 0) { - output[0] *= this->m_width; - } - else { - output[0] *= this->m_height; - } -} - -void TrackPositionOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - resolution[0] = preferredResolution[0]; - resolution[1] = preferredResolution[1]; -} diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cc b/source/blender/compositor/operations/COM_TranslateOperation.cc new file mode 100644 index 00000000000..286004cd49b --- /dev/null +++ b/source/blender/compositor/operations/COM_TranslateOperation.cc @@ -0,0 +1,82 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_TranslateOperation.h" + +TranslateOperation::TranslateOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + this->m_inputOperation = nullptr; + this->m_inputXOperation = nullptr; + this->m_inputYOperation = nullptr; + this->m_isDeltaSet = false; + this->m_factorX = 1.0f; + this->m_factorY = 1.0f; +} +void TranslateOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); + this->m_inputXOperation = this->getInputSocketReader(1); + this->m_inputYOperation = this->getInputSocketReader(2); +} + +void TranslateOperation::deinitExecution() +{ + this->m_inputOperation = nullptr; + this->m_inputXOperation = nullptr; + this->m_inputYOperation = nullptr; +} + +void TranslateOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler /*sampler*/) +{ + ensureDelta(); + + float originalXPos = x - this->getDeltaX(); + float originalYPos = y - this->getDeltaY(); + + this->m_inputOperation->readSampled(output, originalXPos, originalYPos, COM_PS_BILINEAR); +} + +bool TranslateOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + + ensureDelta(); + + newInput.xmin = input->xmin - this->getDeltaX(); + newInput.xmax = input->xmax - this->getDeltaX(); + newInput.ymin = input->ymin - this->getDeltaY(); + newInput.ymax = input->ymax - this->getDeltaY(); + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +void TranslateOperation::setFactorXY(float factorX, float factorY) +{ + m_factorX = factorX; + m_factorY = factorY; +} diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cpp b/source/blender/compositor/operations/COM_TranslateOperation.cpp deleted file mode 100644 index 286004cd49b..00000000000 --- a/source/blender/compositor/operations/COM_TranslateOperation.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_TranslateOperation.h" - -TranslateOperation::TranslateOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = nullptr; - this->m_inputXOperation = nullptr; - this->m_inputYOperation = nullptr; - this->m_isDeltaSet = false; - this->m_factorX = 1.0f; - this->m_factorY = 1.0f; -} -void TranslateOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); - this->m_inputXOperation = this->getInputSocketReader(1); - this->m_inputYOperation = this->getInputSocketReader(2); -} - -void TranslateOperation::deinitExecution() -{ - this->m_inputOperation = nullptr; - this->m_inputXOperation = nullptr; - this->m_inputYOperation = nullptr; -} - -void TranslateOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler /*sampler*/) -{ - ensureDelta(); - - float originalXPos = x - this->getDeltaX(); - float originalYPos = y - this->getDeltaY(); - - this->m_inputOperation->readSampled(output, originalXPos, originalYPos, COM_PS_BILINEAR); -} - -bool TranslateOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - - ensureDelta(); - - newInput.xmin = input->xmin - this->getDeltaX(); - newInput.xmax = input->xmax - this->getDeltaX(); - newInput.ymin = input->ymin - this->getDeltaY(); - newInput.ymax = input->ymax - this->getDeltaY(); - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -void TranslateOperation::setFactorXY(float factorX, float factorY) -{ - m_factorX = factorX; - m_factorY = factorY; -} diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc new file mode 100644 index 00000000000..909a2f73d25 --- /dev/null +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc @@ -0,0 +1,383 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_VariableSizeBokehBlurOperation.h" +#include "BLI_math.h" +#include "COM_OpenCLDevice.h" + +#include "RE_pipeline.h" + +VariableSizeBokehBlurOperation::VariableSizeBokehBlurOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); // do not resize the bokeh image. + this->addInputSocket(COM_DT_VALUE); // radius +#ifdef COM_DEFOCUS_SEARCH + this->addInputSocket(COM_DT_COLOR, + COM_SC_NO_RESIZE); // inverse search radius optimization structure. +#endif + this->addOutputSocket(COM_DT_COLOR); + this->setComplex(true); + this->setOpenCL(true); + + this->m_inputProgram = nullptr; + this->m_inputBokehProgram = nullptr; + this->m_inputSizeProgram = nullptr; + this->m_maxBlur = 32.0f; + this->m_threshold = 1.0f; + this->m_do_size_scale = false; +#ifdef COM_DEFOCUS_SEARCH + this->m_inputSearchProgram = NULL; +#endif +} + +void VariableSizeBokehBlurOperation::initExecution() +{ + this->m_inputProgram = getInputSocketReader(0); + this->m_inputBokehProgram = getInputSocketReader(1); + this->m_inputSizeProgram = getInputSocketReader(2); +#ifdef COM_DEFOCUS_SEARCH + this->m_inputSearchProgram = getInputSocketReader(3); +#endif + QualityStepHelper::initExecution(COM_QH_INCREASE); +} +struct VariableSizeBokehBlurTileData { + MemoryBuffer *color; + MemoryBuffer *bokeh; + MemoryBuffer *size; + int maxBlurScalar; +}; + +void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect) +{ + VariableSizeBokehBlurTileData *data = new VariableSizeBokehBlurTileData(); + data->color = (MemoryBuffer *)this->m_inputProgram->initializeTileData(rect); + data->bokeh = (MemoryBuffer *)this->m_inputBokehProgram->initializeTileData(rect); + data->size = (MemoryBuffer *)this->m_inputSizeProgram->initializeTileData(rect); + + rcti rect2; + this->determineDependingAreaOfInterest( + rect, (ReadBufferOperation *)this->m_inputSizeProgram, &rect2); + + const float max_dim = MAX2(m_width, m_height); + const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; + + data->maxBlurScalar = (int)(data->size->getMaximumValue(&rect2) * scalar); + CLAMP(data->maxBlurScalar, 1.0f, this->m_maxBlur); + return data; +} + +void VariableSizeBokehBlurOperation::deinitializeTileData(rcti * /*rect*/, void *data) +{ + VariableSizeBokehBlurTileData *result = (VariableSizeBokehBlurTileData *)data; + delete result; +} + +void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, void *data) +{ + VariableSizeBokehBlurTileData *tileData = (VariableSizeBokehBlurTileData *)data; + MemoryBuffer *inputProgramBuffer = tileData->color; + MemoryBuffer *inputBokehBuffer = tileData->bokeh; + MemoryBuffer *inputSizeBuffer = tileData->size; + float *inputSizeFloatBuffer = inputSizeBuffer->getBuffer(); + float *inputProgramFloatBuffer = inputProgramBuffer->getBuffer(); + float readColor[4]; + float bokeh[4]; + float tempSize[4]; + float multiplier_accum[4]; + float color_accum[4]; + + const float max_dim = MAX2(m_width, m_height); + const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; + int maxBlurScalar = tileData->maxBlurScalar; + + BLI_assert(inputBokehBuffer->getWidth() == COM_BLUR_BOKEH_PIXELS); + BLI_assert(inputBokehBuffer->getHeight() == COM_BLUR_BOKEH_PIXELS); + +#ifdef COM_DEFOCUS_SEARCH + float search[4]; + this->m_inputSearchProgram->read(search, + x / InverseSearchRadiusOperation::DIVIDER, + y / InverseSearchRadiusOperation::DIVIDER, + NULL); + int minx = search[0]; + int miny = search[1]; + int maxx = search[2]; + int maxy = search[3]; +#else + int minx = MAX2(x - maxBlurScalar, 0); + int miny = MAX2(y - maxBlurScalar, 0); + int maxx = MIN2(x + maxBlurScalar, (int)m_width); + int maxy = MIN2(y + maxBlurScalar, (int)m_height); +#endif + { + inputSizeBuffer->readNoCheck(tempSize, x, y); + inputProgramBuffer->readNoCheck(readColor, x, y); + + copy_v4_v4(color_accum, readColor); + copy_v4_fl(multiplier_accum, 1.0f); + float size_center = tempSize[0] * scalar; + + const int addXStepValue = QualityStepHelper::getStep(); + const int addYStepValue = addXStepValue; + const int addXStepColor = addXStepValue * COM_NUM_CHANNELS_COLOR; + + if (size_center > this->m_threshold) { + for (int ny = miny; ny < maxy; ny += addYStepValue) { + float dy = ny - y; + int offsetValueNy = ny * inputSizeBuffer->getWidth(); + int offsetValueNxNy = offsetValueNy + (minx); + int offsetColorNxNy = offsetValueNxNy * COM_NUM_CHANNELS_COLOR; + for (int nx = minx; nx < maxx; nx += addXStepValue) { + if (nx != x || ny != y) { + float size = MIN2(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center); + if (size > this->m_threshold) { + float dx = nx - x; + if (size > fabsf(dx) && size > fabsf(dy)) { + float uv[2] = { + (float)(COM_BLUR_BOKEH_PIXELS / 2) + + (dx / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1), + (float)(COM_BLUR_BOKEH_PIXELS / 2) + + (dy / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1), + }; + inputBokehBuffer->read(bokeh, uv[0], uv[1]); + madd_v4_v4v4(color_accum, bokeh, &inputProgramFloatBuffer[offsetColorNxNy]); + add_v4_v4(multiplier_accum, bokeh); + } + } + } + offsetColorNxNy += addXStepColor; + offsetValueNxNy += addXStepValue; + } + } + } + + output[0] = color_accum[0] / multiplier_accum[0]; + output[1] = color_accum[1] / multiplier_accum[1]; + output[2] = color_accum[2] / multiplier_accum[2]; + output[3] = color_accum[3] / multiplier_accum[3]; + + /* blend in out values over the threshold, otherwise we get sharp, ugly transitions */ + if ((size_center > this->m_threshold) && (size_center < this->m_threshold * 2.0f)) { + /* factor from 0-1 */ + float fac = (size_center - this->m_threshold) / this->m_threshold; + interp_v4_v4v4(output, readColor, output, fac); + } + } +} + +void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device, + MemoryBuffer *outputMemoryBuffer, + cl_mem clOutputBuffer, + MemoryBuffer **inputMemoryBuffers, + std::list *clMemToCleanUp, + std::list * /*clKernelsToCleanUp*/) +{ + cl_kernel defocusKernel = device->COM_clCreateKernel("defocusKernel", nullptr); + + cl_int step = this->getStep(); + cl_int maxBlur; + cl_float threshold = this->m_threshold; + + MemoryBuffer *sizeMemoryBuffer = this->m_inputSizeProgram->getInputMemoryBuffer( + inputMemoryBuffers); + + const float max_dim = MAX2(m_width, m_height); + cl_float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; + + maxBlur = (cl_int)min_ff(sizeMemoryBuffer->getMaximumValue() * scalar, (float)this->m_maxBlur); + + device->COM_clAttachMemoryBufferToKernelParameter( + defocusKernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram); + device->COM_clAttachMemoryBufferToKernelParameter( + defocusKernel, 1, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBokehProgram); + device->COM_clAttachMemoryBufferToKernelParameter( + defocusKernel, 2, 4, clMemToCleanUp, inputMemoryBuffers, this->m_inputSizeProgram); + device->COM_clAttachOutputMemoryBufferToKernelParameter(defocusKernel, 3, clOutputBuffer); + device->COM_clAttachMemoryBufferOffsetToKernelParameter(defocusKernel, 5, outputMemoryBuffer); + clSetKernelArg(defocusKernel, 6, sizeof(cl_int), &step); + clSetKernelArg(defocusKernel, 7, sizeof(cl_int), &maxBlur); + clSetKernelArg(defocusKernel, 8, sizeof(cl_float), &threshold); + clSetKernelArg(defocusKernel, 9, sizeof(cl_float), &scalar); + device->COM_clAttachSizeToKernelParameter(defocusKernel, 10, this); + + device->COM_clEnqueueRange(defocusKernel, outputMemoryBuffer, 11, this); +} + +void VariableSizeBokehBlurOperation::deinitExecution() +{ + this->m_inputProgram = nullptr; + this->m_inputBokehProgram = nullptr; + this->m_inputSizeProgram = nullptr; +#ifdef COM_DEFOCUS_SEARCH + this->m_inputSearchProgram = NULL; +#endif +} + +bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + rcti bokehInput; + + const float max_dim = MAX2(m_width, m_height); + const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; + int maxBlurScalar = this->m_maxBlur * scalar; + + newInput.xmax = input->xmax + maxBlurScalar + 2; + newInput.xmin = input->xmin - maxBlurScalar + 2; + newInput.ymax = input->ymax + maxBlurScalar - 2; + newInput.ymin = input->ymin - maxBlurScalar - 2; + bokehInput.xmax = COM_BLUR_BOKEH_PIXELS; + bokehInput.xmin = 0; + bokehInput.ymax = COM_BLUR_BOKEH_PIXELS; + bokehInput.ymin = 0; + + NodeOperation *operation = getInputOperation(2); + if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) { + return true; + } + operation = getInputOperation(1); + if (operation->determineDependingAreaOfInterest(&bokehInput, readOperation, output)) { + return true; + } +#ifdef COM_DEFOCUS_SEARCH + rcti searchInput; + searchInput.xmax = (input->xmax / InverseSearchRadiusOperation::DIVIDER) + 1; + searchInput.xmin = (input->xmin / InverseSearchRadiusOperation::DIVIDER) - 1; + searchInput.ymax = (input->ymax / InverseSearchRadiusOperation::DIVIDER) + 1; + searchInput.ymin = (input->ymin / InverseSearchRadiusOperation::DIVIDER) - 1; + operation = getInputOperation(3); + if (operation->determineDependingAreaOfInterest(&searchInput, readOperation, output)) { + return true; + } +#endif + operation = getInputOperation(0); + if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) { + return true; + } + return false; +} + +#ifdef COM_DEFOCUS_SEARCH +// InverseSearchRadiusOperation +InverseSearchRadiusOperation::InverseSearchRadiusOperation() +{ + this->addInputSocket(COM_DT_VALUE, COM_SC_NO_RESIZE); // radius + this->addOutputSocket(COM_DT_COLOR); + this->setComplex(true); + this->m_inputRadius = NULL; +} + +void InverseSearchRadiusOperation::initExecution() +{ + this->m_inputRadius = this->getInputSocketReader(0); +} + +void *InverseSearchRadiusOperation::initializeTileData(rcti *rect) +{ + MemoryBuffer *data = new MemoryBuffer(COM_DT_COLOR, rect); + float *buffer = data->getBuffer(); + int x, y; + int width = this->m_inputRadius->getWidth(); + int height = this->m_inputRadius->getHeight(); + float temp[4]; + int offset = 0; + for (y = rect->ymin; y < rect->ymax; y++) { + for (x = rect->xmin; x < rect->xmax; x++) { + int rx = x * DIVIDER; + int ry = y * DIVIDER; + buffer[offset] = MAX2(rx - m_maxBlur, 0); + buffer[offset + 1] = MAX2(ry - m_maxBlur, 0); + buffer[offset + 2] = MIN2(rx + DIVIDER + m_maxBlur, width); + buffer[offset + 3] = MIN2(ry + DIVIDER + m_maxBlur, height); + offset += 4; + } + } + // for (x = rect->xmin; x < rect->xmax ; x++) { + // for (y = rect->ymin; y < rect->ymax ; y++) { + // int rx = x * DIVIDER; + // int ry = y * DIVIDER; + // float radius = 0.0f; + // float maxx = x; + // float maxy = y; + + // for (int x2 = 0 ; x2 < DIVIDER ; x2 ++) { + // for (int y2 = 0 ; y2 < DIVIDER ; y2 ++) { + // this->m_inputRadius->read(temp, rx+x2, ry+y2, COM_PS_NEAREST); + // if (radius < temp[0]) { + // radius = temp[0]; + // maxx = x2; + // maxy = y2; + // } + // } + // } + // int impactRadius = ceil(radius / DIVIDER); + // for (int x2 = x - impactRadius ; x2 < x + impactRadius ; x2 ++) { + // for (int y2 = y - impactRadius ; y2 < y + impactRadius ; y2 ++) { + // data->read(temp, x2, y2); + // temp[0] = MIN2(temp[0], maxx); + // temp[1] = MIN2(temp[1], maxy); + // temp[2] = MAX2(temp[2], maxx); + // temp[3] = MAX2(temp[3], maxy); + // data->writePixel(x2, y2, temp); + // } + // } + // } + // } + return data; +} + +void InverseSearchRadiusOperation::executePixelChunk(float output[4], int x, int y, void *data) +{ + MemoryBuffer *buffer = (MemoryBuffer *)data; + buffer->readNoCheck(output, x, y); +} + +void InverseSearchRadiusOperation::deinitializeTileData(rcti *rect, void *data) +{ + if (data) { + MemoryBuffer *mb = (MemoryBuffer *)data; + delete mb; + } +} + +void InverseSearchRadiusOperation::deinitExecution() +{ + this->m_inputRadius = NULL; +} + +void InverseSearchRadiusOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + NodeOperation::determineResolution(resolution, preferredResolution); + resolution[0] = resolution[0] / DIVIDER; + resolution[1] = resolution[1] / DIVIDER; +} + +bool InverseSearchRadiusOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newRect; + newRect.ymin = input->ymin * DIVIDER - m_maxBlur; + newRect.ymax = input->ymax * DIVIDER + m_maxBlur; + newRect.xmin = input->xmin * DIVIDER - m_maxBlur; + newRect.xmax = input->xmax * DIVIDER + m_maxBlur; + return NodeOperation::determineDependingAreaOfInterest(&newRect, readOperation, output); +} +#endif diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp deleted file mode 100644 index 909a2f73d25..00000000000 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_VariableSizeBokehBlurOperation.h" -#include "BLI_math.h" -#include "COM_OpenCLDevice.h" - -#include "RE_pipeline.h" - -VariableSizeBokehBlurOperation::VariableSizeBokehBlurOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); // do not resize the bokeh image. - this->addInputSocket(COM_DT_VALUE); // radius -#ifdef COM_DEFOCUS_SEARCH - this->addInputSocket(COM_DT_COLOR, - COM_SC_NO_RESIZE); // inverse search radius optimization structure. -#endif - this->addOutputSocket(COM_DT_COLOR); - this->setComplex(true); - this->setOpenCL(true); - - this->m_inputProgram = nullptr; - this->m_inputBokehProgram = nullptr; - this->m_inputSizeProgram = nullptr; - this->m_maxBlur = 32.0f; - this->m_threshold = 1.0f; - this->m_do_size_scale = false; -#ifdef COM_DEFOCUS_SEARCH - this->m_inputSearchProgram = NULL; -#endif -} - -void VariableSizeBokehBlurOperation::initExecution() -{ - this->m_inputProgram = getInputSocketReader(0); - this->m_inputBokehProgram = getInputSocketReader(1); - this->m_inputSizeProgram = getInputSocketReader(2); -#ifdef COM_DEFOCUS_SEARCH - this->m_inputSearchProgram = getInputSocketReader(3); -#endif - QualityStepHelper::initExecution(COM_QH_INCREASE); -} -struct VariableSizeBokehBlurTileData { - MemoryBuffer *color; - MemoryBuffer *bokeh; - MemoryBuffer *size; - int maxBlurScalar; -}; - -void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect) -{ - VariableSizeBokehBlurTileData *data = new VariableSizeBokehBlurTileData(); - data->color = (MemoryBuffer *)this->m_inputProgram->initializeTileData(rect); - data->bokeh = (MemoryBuffer *)this->m_inputBokehProgram->initializeTileData(rect); - data->size = (MemoryBuffer *)this->m_inputSizeProgram->initializeTileData(rect); - - rcti rect2; - this->determineDependingAreaOfInterest( - rect, (ReadBufferOperation *)this->m_inputSizeProgram, &rect2); - - const float max_dim = MAX2(m_width, m_height); - const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; - - data->maxBlurScalar = (int)(data->size->getMaximumValue(&rect2) * scalar); - CLAMP(data->maxBlurScalar, 1.0f, this->m_maxBlur); - return data; -} - -void VariableSizeBokehBlurOperation::deinitializeTileData(rcti * /*rect*/, void *data) -{ - VariableSizeBokehBlurTileData *result = (VariableSizeBokehBlurTileData *)data; - delete result; -} - -void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, void *data) -{ - VariableSizeBokehBlurTileData *tileData = (VariableSizeBokehBlurTileData *)data; - MemoryBuffer *inputProgramBuffer = tileData->color; - MemoryBuffer *inputBokehBuffer = tileData->bokeh; - MemoryBuffer *inputSizeBuffer = tileData->size; - float *inputSizeFloatBuffer = inputSizeBuffer->getBuffer(); - float *inputProgramFloatBuffer = inputProgramBuffer->getBuffer(); - float readColor[4]; - float bokeh[4]; - float tempSize[4]; - float multiplier_accum[4]; - float color_accum[4]; - - const float max_dim = MAX2(m_width, m_height); - const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; - int maxBlurScalar = tileData->maxBlurScalar; - - BLI_assert(inputBokehBuffer->getWidth() == COM_BLUR_BOKEH_PIXELS); - BLI_assert(inputBokehBuffer->getHeight() == COM_BLUR_BOKEH_PIXELS); - -#ifdef COM_DEFOCUS_SEARCH - float search[4]; - this->m_inputSearchProgram->read(search, - x / InverseSearchRadiusOperation::DIVIDER, - y / InverseSearchRadiusOperation::DIVIDER, - NULL); - int minx = search[0]; - int miny = search[1]; - int maxx = search[2]; - int maxy = search[3]; -#else - int minx = MAX2(x - maxBlurScalar, 0); - int miny = MAX2(y - maxBlurScalar, 0); - int maxx = MIN2(x + maxBlurScalar, (int)m_width); - int maxy = MIN2(y + maxBlurScalar, (int)m_height); -#endif - { - inputSizeBuffer->readNoCheck(tempSize, x, y); - inputProgramBuffer->readNoCheck(readColor, x, y); - - copy_v4_v4(color_accum, readColor); - copy_v4_fl(multiplier_accum, 1.0f); - float size_center = tempSize[0] * scalar; - - const int addXStepValue = QualityStepHelper::getStep(); - const int addYStepValue = addXStepValue; - const int addXStepColor = addXStepValue * COM_NUM_CHANNELS_COLOR; - - if (size_center > this->m_threshold) { - for (int ny = miny; ny < maxy; ny += addYStepValue) { - float dy = ny - y; - int offsetValueNy = ny * inputSizeBuffer->getWidth(); - int offsetValueNxNy = offsetValueNy + (minx); - int offsetColorNxNy = offsetValueNxNy * COM_NUM_CHANNELS_COLOR; - for (int nx = minx; nx < maxx; nx += addXStepValue) { - if (nx != x || ny != y) { - float size = MIN2(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center); - if (size > this->m_threshold) { - float dx = nx - x; - if (size > fabsf(dx) && size > fabsf(dy)) { - float uv[2] = { - (float)(COM_BLUR_BOKEH_PIXELS / 2) + - (dx / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1), - (float)(COM_BLUR_BOKEH_PIXELS / 2) + - (dy / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1), - }; - inputBokehBuffer->read(bokeh, uv[0], uv[1]); - madd_v4_v4v4(color_accum, bokeh, &inputProgramFloatBuffer[offsetColorNxNy]); - add_v4_v4(multiplier_accum, bokeh); - } - } - } - offsetColorNxNy += addXStepColor; - offsetValueNxNy += addXStepValue; - } - } - } - - output[0] = color_accum[0] / multiplier_accum[0]; - output[1] = color_accum[1] / multiplier_accum[1]; - output[2] = color_accum[2] / multiplier_accum[2]; - output[3] = color_accum[3] / multiplier_accum[3]; - - /* blend in out values over the threshold, otherwise we get sharp, ugly transitions */ - if ((size_center > this->m_threshold) && (size_center < this->m_threshold * 2.0f)) { - /* factor from 0-1 */ - float fac = (size_center - this->m_threshold) / this->m_threshold; - interp_v4_v4v4(output, readColor, output, fac); - } - } -} - -void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device, - MemoryBuffer *outputMemoryBuffer, - cl_mem clOutputBuffer, - MemoryBuffer **inputMemoryBuffers, - std::list *clMemToCleanUp, - std::list * /*clKernelsToCleanUp*/) -{ - cl_kernel defocusKernel = device->COM_clCreateKernel("defocusKernel", nullptr); - - cl_int step = this->getStep(); - cl_int maxBlur; - cl_float threshold = this->m_threshold; - - MemoryBuffer *sizeMemoryBuffer = this->m_inputSizeProgram->getInputMemoryBuffer( - inputMemoryBuffers); - - const float max_dim = MAX2(m_width, m_height); - cl_float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; - - maxBlur = (cl_int)min_ff(sizeMemoryBuffer->getMaximumValue() * scalar, (float)this->m_maxBlur); - - device->COM_clAttachMemoryBufferToKernelParameter( - defocusKernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram); - device->COM_clAttachMemoryBufferToKernelParameter( - defocusKernel, 1, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBokehProgram); - device->COM_clAttachMemoryBufferToKernelParameter( - defocusKernel, 2, 4, clMemToCleanUp, inputMemoryBuffers, this->m_inputSizeProgram); - device->COM_clAttachOutputMemoryBufferToKernelParameter(defocusKernel, 3, clOutputBuffer); - device->COM_clAttachMemoryBufferOffsetToKernelParameter(defocusKernel, 5, outputMemoryBuffer); - clSetKernelArg(defocusKernel, 6, sizeof(cl_int), &step); - clSetKernelArg(defocusKernel, 7, sizeof(cl_int), &maxBlur); - clSetKernelArg(defocusKernel, 8, sizeof(cl_float), &threshold); - clSetKernelArg(defocusKernel, 9, sizeof(cl_float), &scalar); - device->COM_clAttachSizeToKernelParameter(defocusKernel, 10, this); - - device->COM_clEnqueueRange(defocusKernel, outputMemoryBuffer, 11, this); -} - -void VariableSizeBokehBlurOperation::deinitExecution() -{ - this->m_inputProgram = nullptr; - this->m_inputBokehProgram = nullptr; - this->m_inputSizeProgram = nullptr; -#ifdef COM_DEFOCUS_SEARCH - this->m_inputSearchProgram = NULL; -#endif -} - -bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest( - rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInput; - rcti bokehInput; - - const float max_dim = MAX2(m_width, m_height); - const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; - int maxBlurScalar = this->m_maxBlur * scalar; - - newInput.xmax = input->xmax + maxBlurScalar + 2; - newInput.xmin = input->xmin - maxBlurScalar + 2; - newInput.ymax = input->ymax + maxBlurScalar - 2; - newInput.ymin = input->ymin - maxBlurScalar - 2; - bokehInput.xmax = COM_BLUR_BOKEH_PIXELS; - bokehInput.xmin = 0; - bokehInput.ymax = COM_BLUR_BOKEH_PIXELS; - bokehInput.ymin = 0; - - NodeOperation *operation = getInputOperation(2); - if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) { - return true; - } - operation = getInputOperation(1); - if (operation->determineDependingAreaOfInterest(&bokehInput, readOperation, output)) { - return true; - } -#ifdef COM_DEFOCUS_SEARCH - rcti searchInput; - searchInput.xmax = (input->xmax / InverseSearchRadiusOperation::DIVIDER) + 1; - searchInput.xmin = (input->xmin / InverseSearchRadiusOperation::DIVIDER) - 1; - searchInput.ymax = (input->ymax / InverseSearchRadiusOperation::DIVIDER) + 1; - searchInput.ymin = (input->ymin / InverseSearchRadiusOperation::DIVIDER) - 1; - operation = getInputOperation(3); - if (operation->determineDependingAreaOfInterest(&searchInput, readOperation, output)) { - return true; - } -#endif - operation = getInputOperation(0); - if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) { - return true; - } - return false; -} - -#ifdef COM_DEFOCUS_SEARCH -// InverseSearchRadiusOperation -InverseSearchRadiusOperation::InverseSearchRadiusOperation() -{ - this->addInputSocket(COM_DT_VALUE, COM_SC_NO_RESIZE); // radius - this->addOutputSocket(COM_DT_COLOR); - this->setComplex(true); - this->m_inputRadius = NULL; -} - -void InverseSearchRadiusOperation::initExecution() -{ - this->m_inputRadius = this->getInputSocketReader(0); -} - -void *InverseSearchRadiusOperation::initializeTileData(rcti *rect) -{ - MemoryBuffer *data = new MemoryBuffer(COM_DT_COLOR, rect); - float *buffer = data->getBuffer(); - int x, y; - int width = this->m_inputRadius->getWidth(); - int height = this->m_inputRadius->getHeight(); - float temp[4]; - int offset = 0; - for (y = rect->ymin; y < rect->ymax; y++) { - for (x = rect->xmin; x < rect->xmax; x++) { - int rx = x * DIVIDER; - int ry = y * DIVIDER; - buffer[offset] = MAX2(rx - m_maxBlur, 0); - buffer[offset + 1] = MAX2(ry - m_maxBlur, 0); - buffer[offset + 2] = MIN2(rx + DIVIDER + m_maxBlur, width); - buffer[offset + 3] = MIN2(ry + DIVIDER + m_maxBlur, height); - offset += 4; - } - } - // for (x = rect->xmin; x < rect->xmax ; x++) { - // for (y = rect->ymin; y < rect->ymax ; y++) { - // int rx = x * DIVIDER; - // int ry = y * DIVIDER; - // float radius = 0.0f; - // float maxx = x; - // float maxy = y; - - // for (int x2 = 0 ; x2 < DIVIDER ; x2 ++) { - // for (int y2 = 0 ; y2 < DIVIDER ; y2 ++) { - // this->m_inputRadius->read(temp, rx+x2, ry+y2, COM_PS_NEAREST); - // if (radius < temp[0]) { - // radius = temp[0]; - // maxx = x2; - // maxy = y2; - // } - // } - // } - // int impactRadius = ceil(radius / DIVIDER); - // for (int x2 = x - impactRadius ; x2 < x + impactRadius ; x2 ++) { - // for (int y2 = y - impactRadius ; y2 < y + impactRadius ; y2 ++) { - // data->read(temp, x2, y2); - // temp[0] = MIN2(temp[0], maxx); - // temp[1] = MIN2(temp[1], maxy); - // temp[2] = MAX2(temp[2], maxx); - // temp[3] = MAX2(temp[3], maxy); - // data->writePixel(x2, y2, temp); - // } - // } - // } - // } - return data; -} - -void InverseSearchRadiusOperation::executePixelChunk(float output[4], int x, int y, void *data) -{ - MemoryBuffer *buffer = (MemoryBuffer *)data; - buffer->readNoCheck(output, x, y); -} - -void InverseSearchRadiusOperation::deinitializeTileData(rcti *rect, void *data) -{ - if (data) { - MemoryBuffer *mb = (MemoryBuffer *)data; - delete mb; - } -} - -void InverseSearchRadiusOperation::deinitExecution() -{ - this->m_inputRadius = NULL; -} - -void InverseSearchRadiusOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - NodeOperation::determineResolution(resolution, preferredResolution); - resolution[0] = resolution[0] / DIVIDER; - resolution[1] = resolution[1] / DIVIDER; -} - -bool InverseSearchRadiusOperation::determineDependingAreaOfInterest( - rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newRect; - newRect.ymin = input->ymin * DIVIDER - m_maxBlur; - newRect.ymax = input->ymax * DIVIDER + m_maxBlur; - newRect.xmin = input->xmin * DIVIDER - m_maxBlur; - newRect.xmax = input->xmax * DIVIDER + m_maxBlur; - return NodeOperation::determineDependingAreaOfInterest(&newRect, readOperation, output); -} -#endif diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cc b/source/blender/compositor/operations/COM_VectorBlurOperation.cc new file mode 100644 index 00000000000..d6894dfc8ad --- /dev/null +++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cc @@ -0,0 +1,899 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_jitter_2d.h" +#include "BLI_math.h" + +#include "COM_VectorBlurOperation.h" + +/* Defined */ +#define PASS_VECTOR_MAX 10000.0f + +/* Forward declarations */ +struct DrawBufPixel; +struct ZSpan; +void zbuf_accumulate_vecblur(NodeBlurData *nbd, + int xsize, + int ysize, + float *newrect, + const float *imgrect, + float *vecbufrect, + const float *zbufrect); +void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty, float clipcrop); +void zbuf_free_span(ZSpan *zspan); +void antialias_tagbuf(int xsize, int ysize, char *rectmove); + +/* VectorBlurOperation */ +VectorBlurOperation::VectorBlurOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); // ZBUF + this->addInputSocket(COM_DT_COLOR); // SPEED + this->addOutputSocket(COM_DT_COLOR); + this->m_settings = nullptr; + this->m_cachedInstance = nullptr; + this->m_inputImageProgram = nullptr; + this->m_inputSpeedProgram = nullptr; + this->m_inputZProgram = nullptr; + setComplex(true); +} +void VectorBlurOperation::initExecution() +{ + initMutex(); + this->m_inputImageProgram = getInputSocketReader(0); + this->m_inputZProgram = getInputSocketReader(1); + this->m_inputSpeedProgram = getInputSocketReader(2); + this->m_cachedInstance = nullptr; + QualityStepHelper::initExecution(COM_QH_INCREASE); +} + +void VectorBlurOperation::executePixel(float output[4], int x, int y, void *data) +{ + float *buffer = (float *)data; + int index = (y * this->getWidth() + x) * COM_NUM_CHANNELS_COLOR; + copy_v4_v4(output, &buffer[index]); +} + +void VectorBlurOperation::deinitExecution() +{ + deinitMutex(); + this->m_inputImageProgram = nullptr; + this->m_inputSpeedProgram = nullptr; + this->m_inputZProgram = nullptr; + if (this->m_cachedInstance) { + MEM_freeN(this->m_cachedInstance); + this->m_cachedInstance = nullptr; + } +} +void *VectorBlurOperation::initializeTileData(rcti *rect) +{ + if (this->m_cachedInstance) { + return this->m_cachedInstance; + } + + lockMutex(); + if (this->m_cachedInstance == nullptr) { + MemoryBuffer *tile = (MemoryBuffer *)this->m_inputImageProgram->initializeTileData(rect); + MemoryBuffer *speed = (MemoryBuffer *)this->m_inputSpeedProgram->initializeTileData(rect); + MemoryBuffer *z = (MemoryBuffer *)this->m_inputZProgram->initializeTileData(rect); + float *data = (float *)MEM_dupallocN(tile->getBuffer()); + this->generateVectorBlur(data, tile, speed, z); + this->m_cachedInstance = data; + } + unlockMutex(); + return this->m_cachedInstance; +} + +bool VectorBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/, + ReadBufferOperation *readOperation, + rcti *output) +{ + if (this->m_cachedInstance == nullptr) { + rcti newInput; + newInput.xmax = this->getWidth(); + newInput.xmin = 0; + newInput.ymax = this->getHeight(); + newInput.ymin = 0; + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + } + + return false; +} + +void VectorBlurOperation::generateVectorBlur(float *data, + MemoryBuffer *inputImage, + MemoryBuffer *inputSpeed, + MemoryBuffer *inputZ) +{ + NodeBlurData blurdata; + blurdata.samples = this->m_settings->samples / QualityStepHelper::getStep(); + blurdata.maxspeed = this->m_settings->maxspeed; + blurdata.minspeed = this->m_settings->minspeed; + blurdata.curved = this->m_settings->curved; + blurdata.fac = this->m_settings->fac; + zbuf_accumulate_vecblur(&blurdata, + this->getWidth(), + this->getHeight(), + data, + inputImage->getBuffer(), + inputSpeed->getBuffer(), + inputZ->getBuffer()); +} + +/* ****************** Spans ******************************* */ +/* span fill in method, is also used to localize data for zbuffering */ +struct ZSpan { + /* range for clipping */ + int rectx, recty; + + /* actual filled in range */ + int miny1, maxy1, miny2, maxy2; + /* vertex pointers detect min/max range in */ + const float *minp1, *maxp1, *minp2, *maxp2; + float *span1, *span2; + + /* transform from hoco to zbuf co */ + float zmulx, zmuly, zofsx, zofsy; + + int *rectz; + DrawBufPixel *rectdraw; + float clipcrop; +}; + +/* each zbuffer has coordinates transformed to local rect coordinates, so we can simply clip */ +void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty, float clipcrop) +{ + memset(zspan, 0, sizeof(ZSpan)); + + zspan->rectx = rectx; + zspan->recty = recty; + + zspan->span1 = (float *)MEM_mallocN(recty * sizeof(float), "zspan"); + zspan->span2 = (float *)MEM_mallocN(recty * sizeof(float), "zspan"); + + zspan->clipcrop = clipcrop; +} + +void zbuf_free_span(ZSpan *zspan) +{ + if (zspan) { + if (zspan->span1) { + MEM_freeN(zspan->span1); + } + if (zspan->span2) { + MEM_freeN(zspan->span2); + } + zspan->span1 = zspan->span2 = nullptr; + } +} + +/* reset range for clipping */ +static void zbuf_init_span(ZSpan *zspan) +{ + zspan->miny1 = zspan->miny2 = zspan->recty + 1; + zspan->maxy1 = zspan->maxy2 = -1; + zspan->minp1 = zspan->maxp1 = zspan->minp2 = zspan->maxp2 = nullptr; +} + +static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2]) +{ + const float *minv, *maxv; + float *span; + float xx1, dx0, xs0; + int y, my0, my2; + + if (v1[1] < v2[1]) { + minv = v1; + maxv = v2; + } + else { + minv = v2; + maxv = v1; + } + + my0 = ceil(minv[1]); + my2 = floor(maxv[1]); + + if (my2 < 0 || my0 >= zspan->recty) { + return; + } + + /* clip top */ + if (my2 >= zspan->recty) { + my2 = zspan->recty - 1; + } + /* clip bottom */ + if (my0 < 0) { + my0 = 0; + } + + if (my0 > my2) { + return; + } + /* if (my0>my2) should still fill in, that way we get spans that skip nicely */ + + xx1 = maxv[1] - minv[1]; + if (xx1 > FLT_EPSILON) { + dx0 = (minv[0] - maxv[0]) / xx1; + xs0 = dx0 * (minv[1] - my2) + minv[0]; + } + else { + dx0 = 0.0f; + xs0 = min_ff(minv[0], maxv[0]); + } + + /* empty span */ + if (zspan->maxp1 == nullptr) { + span = zspan->span1; + } + else { /* does it complete left span? */ + if (maxv == zspan->minp1 || minv == zspan->maxp1) { + span = zspan->span1; + } + else { + span = zspan->span2; + } + } + + if (span == zspan->span1) { + // printf("left span my0 %d my2 %d\n", my0, my2); + if (zspan->minp1 == nullptr || zspan->minp1[1] > minv[1]) { + zspan->minp1 = minv; + } + if (zspan->maxp1 == nullptr || zspan->maxp1[1] < maxv[1]) { + zspan->maxp1 = maxv; + } + if (my0 < zspan->miny1) { + zspan->miny1 = my0; + } + if (my2 > zspan->maxy1) { + zspan->maxy1 = my2; + } + } + else { + // printf("right span my0 %d my2 %d\n", my0, my2); + if (zspan->minp2 == nullptr || zspan->minp2[1] > minv[1]) { + zspan->minp2 = minv; + } + if (zspan->maxp2 == nullptr || zspan->maxp2[1] < maxv[1]) { + zspan->maxp2 = maxv; + } + if (my0 < zspan->miny2) { + zspan->miny2 = my0; + } + if (my2 > zspan->maxy2) { + zspan->maxy2 = my2; + } + } + + for (y = my2; y >= my0; y--, xs0 += dx0) { + /* xs0 is the xcoord! */ + span[y] = xs0; + } +} + +/* ******************** VECBLUR ACCUM BUF ************************* */ + +struct DrawBufPixel { + const float *colpoin; + float alpha; +}; + +static void zbuf_fill_in_rgba( + ZSpan *zspan, DrawBufPixel *col, float *v1, float *v2, float *v3, float *v4) +{ + DrawBufPixel *rectpofs, *rp; + double zxd, zyd, zy0, zverg; + float x0, y0, z0; + float x1, y1, z1, x2, y2, z2, xx1; + const float *span1, *span2; + float *rectzofs, *rz; + int x, y; + int sn1, sn2, rectx, my0, my2; + + /* init */ + zbuf_init_span(zspan); + + /* set spans */ + zbuf_add_to_span(zspan, v1, v2); + zbuf_add_to_span(zspan, v2, v3); + zbuf_add_to_span(zspan, v3, v4); + zbuf_add_to_span(zspan, v4, v1); + + /* clipped */ + if (zspan->minp2 == nullptr || zspan->maxp2 == nullptr) { + return; + } + + my0 = max_ii(zspan->miny1, zspan->miny2); + my2 = min_ii(zspan->maxy1, zspan->maxy2); + + // printf("my %d %d\n", my0, my2); + if (my2 < my0) { + return; + } + + /* ZBUF DX DY, in floats still */ + x1 = v1[0] - v2[0]; + x2 = v2[0] - v3[0]; + y1 = v1[1] - v2[1]; + y2 = v2[1] - v3[1]; + z1 = v1[2] - v2[2]; + z2 = v2[2] - v3[2]; + x0 = y1 * z2 - z1 * y2; + y0 = z1 * x2 - x1 * z2; + z0 = x1 * y2 - y1 * x2; + + if (z0 == 0.0f) { + return; + } + + xx1 = (x0 * v1[0] + y0 * v1[1]) / z0 + v1[2]; + + zxd = -(double)x0 / (double)z0; + zyd = -(double)y0 / (double)z0; + zy0 = ((double)my2) * zyd + (double)xx1; + + /* start-offset in rect */ + rectx = zspan->rectx; + rectzofs = (float *)(zspan->rectz + rectx * my2); + rectpofs = ((DrawBufPixel *)zspan->rectdraw) + rectx * my2; + + /* correct span */ + sn1 = (my0 + my2) / 2; + if (zspan->span1[sn1] < zspan->span2[sn1]) { + span1 = zspan->span1 + my2; + span2 = zspan->span2 + my2; + } + else { + span1 = zspan->span2 + my2; + span2 = zspan->span1 + my2; + } + + for (y = my2; y >= my0; y--, span1--, span2--) { + + sn1 = floor(*span1); + sn2 = floor(*span2); + sn1++; + + if (sn2 >= rectx) { + sn2 = rectx - 1; + } + if (sn1 < 0) { + sn1 = 0; + } + + if (sn2 >= sn1) { + zverg = (double)sn1 * zxd + zy0; + rz = rectzofs + sn1; + rp = rectpofs + sn1; + x = sn2 - sn1; + + while (x >= 0) { + if (zverg < (double)*rz) { + *rz = zverg; + *rp = *col; + } + zverg += zxd; + rz++; + rp++; + x--; + } + } + + zy0 -= zyd; + rectzofs -= rectx; + rectpofs -= rectx; + } +} + +/* char value==255 is filled in, rest should be zero */ +/* returns alpha values, + * but sets alpha to 1 for zero alpha pixels that have an alpha value as neighbor. */ +void antialias_tagbuf(int xsize, int ysize, char *rectmove) +{ + char *row1, *row2, *row3; + char prev, next; + int a, x, y, step; + + /* 1: tag pixels to be candidate for AA */ + for (y = 2; y < ysize; y++) { + /* setup rows */ + row1 = rectmove + (y - 2) * xsize; + row2 = row1 + xsize; + row3 = row2 + xsize; + for (x = 2; x < xsize; x++, row1++, row2++, row3++) { + if (row2[1]) { + if (row2[0] == 0 || row2[2] == 0 || row1[1] == 0 || row3[1] == 0) { + row2[1] = 128; + } + } + } + } + + /* 2: evaluate horizontal scanlines and calculate alphas */ + row1 = rectmove; + for (y = 0; y < ysize; y++) { + row1++; + for (x = 1; x < xsize; x++, row1++) { + if (row1[0] == 128 && row1[1] == 128) { + /* find previous color and next color and amount of steps to blend */ + prev = row1[-1]; + step = 1; + while (x + step < xsize && row1[step] == 128) { + step++; + } + + if (x + step != xsize) { + /* now we can blend values */ + next = row1[step]; + + /* note, prev value can be next value, but we do this loop to clear 128 then */ + for (a = 0; a < step; a++) { + int fac, mfac; + + fac = ((a + 1) << 8) / (step + 1); + mfac = 255 - fac; + + row1[a] = (prev * mfac + next * fac) >> 8; + } + } + } + } + } + + /* 3: evaluate vertical scanlines and calculate alphas */ + /* use for reading a copy of the original tagged buffer */ + for (x = 0; x < xsize; x++) { + row1 = rectmove + x + xsize; + + for (y = 1; y < ysize; y++, row1 += xsize) { + if (row1[0] == 128 && row1[xsize] == 128) { + /* find previous color and next color and amount of steps to blend */ + prev = row1[-xsize]; + step = 1; + while (y + step < ysize && row1[step * xsize] == 128) { + step++; + } + + if (y + step != ysize) { + /* now we can blend values */ + next = row1[step * xsize]; + /* note, prev value can be next value, but we do this loop to clear 128 then */ + for (a = 0; a < step; a++) { + int fac, mfac; + + fac = ((a + 1) << 8) / (step + 1); + mfac = 255 - fac; + + row1[a * xsize] = (prev * mfac + next * fac) >> 8; + } + } + } + } + } + + /* last: pixels with 0 we fill in zbuffer, with 1 we skip for mask */ + for (y = 2; y < ysize; y++) { + /* setup rows */ + row1 = rectmove + (y - 2) * xsize; + row2 = row1 + xsize; + row3 = row2 + xsize; + for (x = 2; x < xsize; x++, row1++, row2++, row3++) { + if (row2[1] == 0) { + if (row2[0] > 1 || row2[2] > 1 || row1[1] > 1 || row3[1] > 1) { + row2[1] = 1; + } + } + } + } +} + +/* in: two vectors, first vector points from origin back in time, 2nd vector points to future */ +/* we make this into 3 points, center point is (0, 0) */ +/* and offset the center point just enough to make curve go through midpoint */ + +static void quad_bezier_2d(float *result, const float *v1, const float *v2, const float *ipodata) +{ + float p1[2], p2[2], p3[2]; + + p3[0] = -v2[0]; + p3[1] = -v2[1]; + + p1[0] = v1[0]; + p1[1] = v1[1]; + + /* official formula 2*p2 - 0.5*p1 - 0.5*p3 */ + p2[0] = -0.5f * p1[0] - 0.5f * p3[0]; + p2[1] = -0.5f * p1[1] - 0.5f * p3[1]; + + result[0] = ipodata[0] * p1[0] + ipodata[1] * p2[0] + ipodata[2] * p3[0]; + result[1] = ipodata[0] * p1[1] + ipodata[1] * p2[1] + ipodata[2] * p3[1]; +} + +static void set_quad_bezier_ipo(float fac, float *data) +{ + float mfac = (1.0f - fac); + + data[0] = mfac * mfac; + data[1] = 2.0f * mfac * fac; + data[2] = fac * fac; +} + +void zbuf_accumulate_vecblur(NodeBlurData *nbd, + int xsize, + int ysize, + float *newrect, + const float *imgrect, + float *vecbufrect, + const float *zbufrect) +{ + ZSpan zspan; + DrawBufPixel *rectdraw, *dr; + static float jit[256][2]; + float v1[3], v2[3], v3[3], v4[3], fx, fy; + const float *dimg, *dz, *ro; + float *rectvz, *dvz, *dvec1, *dvec2, *dz1, *dz2, *rectz; + float *minvecbufrect = nullptr, *rectweight, *rw, *rectmax, *rm; + float maxspeedsq = (float)nbd->maxspeed * nbd->maxspeed; + int y, x, step, maxspeed = nbd->maxspeed, samples = nbd->samples; + int tsktsk = 0; + static int firsttime = 1; + char *rectmove, *dm; + + zbuf_alloc_span(&zspan, xsize, ysize, 1.0f); + zspan.zmulx = ((float)xsize) / 2.0f; + zspan.zmuly = ((float)ysize) / 2.0f; + zspan.zofsx = 0.0f; + zspan.zofsy = 0.0f; + + /* the buffers */ + rectz = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "zbuf accum"); + zspan.rectz = (int *)rectz; + + rectmove = (char *)MEM_callocN(xsize * ysize, "rectmove"); + rectdraw = (DrawBufPixel *)MEM_callocN(sizeof(DrawBufPixel) * xsize * ysize, "rect draw"); + zspan.rectdraw = rectdraw; + + rectweight = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "rect weight"); + rectmax = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "rect max"); + + /* debug... check if PASS_VECTOR_MAX still is in buffers */ + dvec1 = vecbufrect; + for (x = 4 * xsize * ysize; x > 0; x--, dvec1++) { + if (dvec1[0] == PASS_VECTOR_MAX) { + dvec1[0] = 0.0f; + tsktsk = 1; + } + } + if (tsktsk) { + printf("Found uninitialized speed in vector buffer... fixed.\n"); + } + + /* Min speed? then copy speed-buffer to recalculate speed vectors. */ + if (nbd->minspeed) { + float minspeed = (float)nbd->minspeed; + float minspeedsq = minspeed * minspeed; + + minvecbufrect = (float *)MEM_callocN(sizeof(float[4]) * xsize * ysize, "minspeed buf"); + + dvec1 = vecbufrect; + dvec2 = minvecbufrect; + for (x = 2 * xsize * ysize; x > 0; x--, dvec1 += 2, dvec2 += 2) { + if (dvec1[0] == 0.0f && dvec1[1] == 0.0f) { + dvec2[0] = dvec1[0]; + dvec2[1] = dvec1[1]; + } + else { + float speedsq = dvec1[0] * dvec1[0] + dvec1[1] * dvec1[1]; + if (speedsq <= minspeedsq) { + dvec2[0] = 0.0f; + dvec2[1] = 0.0f; + } + else { + speedsq = 1.0f - minspeed / sqrtf(speedsq); + dvec2[0] = speedsq * dvec1[0]; + dvec2[1] = speedsq * dvec1[1]; + } + } + } + SWAP(float *, minvecbufrect, vecbufrect); + } + + /* Make vertex buffer with averaged speed and Z-values. */ + rectvz = (float *)MEM_callocN(sizeof(float[4]) * (xsize + 1) * (ysize + 1), "vertices"); + dvz = rectvz; + for (y = 0; y <= ysize; y++) { + + if (y == 0) { + dvec1 = vecbufrect + 4 * y * xsize; + } + else { + dvec1 = vecbufrect + 4 * (y - 1) * xsize; + } + + if (y == ysize) { + dvec2 = vecbufrect + 4 * (y - 1) * xsize; + } + else { + dvec2 = vecbufrect + 4 * y * xsize; + } + + for (x = 0; x <= xsize; x++) { + + /* two vectors, so a step loop */ + for (step = 0; step < 2; step++, dvec1 += 2, dvec2 += 2, dvz += 2) { + /* average on minimal speed */ + int div = 0; + + if (x != 0) { + if (dvec1[-4] != 0.0f || dvec1[-3] != 0.0f) { + dvz[0] = dvec1[-4]; + dvz[1] = dvec1[-3]; + div++; + } + if (dvec2[-4] != 0.0f || dvec2[-3] != 0.0f) { + if (div == 0) { + dvz[0] = dvec2[-4]; + dvz[1] = dvec2[-3]; + div++; + } + else if ((fabsf(dvec2[-4]) + fabsf(dvec2[-3])) < (fabsf(dvz[0]) + fabsf(dvz[1]))) { + dvz[0] = dvec2[-4]; + dvz[1] = dvec2[-3]; + } + } + } + + if (x != xsize) { + if (dvec1[0] != 0.0f || dvec1[1] != 0.0f) { + if (div == 0) { + dvz[0] = dvec1[0]; + dvz[1] = dvec1[1]; + div++; + } + else if ((fabsf(dvec1[0]) + fabsf(dvec1[1])) < (fabsf(dvz[0]) + fabsf(dvz[1]))) { + dvz[0] = dvec1[0]; + dvz[1] = dvec1[1]; + } + } + if (dvec2[0] != 0.0f || dvec2[1] != 0.0f) { + if (div == 0) { + dvz[0] = dvec2[0]; + dvz[1] = dvec2[1]; + } + else if ((fabsf(dvec2[0]) + fabsf(dvec2[1])) < (fabsf(dvz[0]) + fabsf(dvz[1]))) { + dvz[0] = dvec2[0]; + dvz[1] = dvec2[1]; + } + } + } + if (maxspeed) { + float speedsq = dvz[0] * dvz[0] + dvz[1] * dvz[1]; + if (speedsq > maxspeedsq) { + speedsq = (float)maxspeed / sqrtf(speedsq); + dvz[0] *= speedsq; + dvz[1] *= speedsq; + } + } + } + } + } + + /* set border speeds to keep border speeds on border */ + dz1 = rectvz; + dz2 = rectvz + 4 * (ysize) * (xsize + 1); + for (x = 0; x <= xsize; x++, dz1 += 4, dz2 += 4) { + dz1[1] = 0.0f; + dz2[1] = 0.0f; + dz1[3] = 0.0f; + dz2[3] = 0.0f; + } + dz1 = rectvz; + dz2 = rectvz + 4 * (xsize); + for (y = 0; y <= ysize; y++, dz1 += 4 * (xsize + 1), dz2 += 4 * (xsize + 1)) { + dz1[0] = 0.0f; + dz2[0] = 0.0f; + dz1[2] = 0.0f; + dz2[2] = 0.0f; + } + + /* tag moving pixels, only these faces we draw */ + dm = rectmove; + dvec1 = vecbufrect; + for (x = xsize * ysize; x > 0; x--, dm++, dvec1 += 4) { + if ((dvec1[0] != 0.0f || dvec1[1] != 0.0f || dvec1[2] != 0.0f || dvec1[3] != 0.0f)) { + *dm = 255; + } + } + + antialias_tagbuf(xsize, ysize, rectmove); + + /* Has to become static, the jitter initialization calls a random-seed, + * screwing up texture noise node. */ + if (firsttime) { + firsttime = 0; + BLI_jitter_init(jit, 256); + } + + memset(newrect, 0, sizeof(float) * xsize * ysize * 4); + + /* accumulate */ + samples /= 2; + for (step = 1; step <= samples; step++) { + float speedfac = 0.5f * nbd->fac * (float)step / (float)(samples + 1); + int side; + + for (side = 0; side < 2; side++) { + float blendfac, ipodata[4]; + + /* clear zbuf, if we draw future we fill in not moving pixels */ + if (false) { + for (x = xsize * ysize - 1; x >= 0; x--) { + rectz[x] = 10e16; + } + } + else { + for (x = xsize * ysize - 1; x >= 0; x--) { + if (rectmove[x] == 0) { + rectz[x] = zbufrect[x]; + } + else { + rectz[x] = 10e16; + } + } + } + + /* clear drawing buffer */ + for (x = xsize * ysize - 1; x >= 0; x--) { + rectdraw[x].colpoin = nullptr; + } + + dimg = imgrect; + dm = rectmove; + dz = zbufrect; + dz1 = rectvz; + dz2 = rectvz + 4 * (xsize + 1); + + if (side) { + if (nbd->curved == 0) { + dz1 += 2; + dz2 += 2; + } + speedfac = -speedfac; + } + + set_quad_bezier_ipo(0.5f + 0.5f * speedfac, ipodata); + + for (fy = -0.5f + jit[step & 255][0], y = 0; y < ysize; y++, fy += 1.0f) { + for (fx = -0.5f + jit[step & 255][1], x = 0; x < xsize; + x++, fx += 1.0f, dimg += 4, dz1 += 4, dz2 += 4, dm++, dz++) { + if (*dm > 1) { + float jfx = fx + 0.5f; + float jfy = fy + 0.5f; + DrawBufPixel col; + + /* make vertices */ + if (nbd->curved) { /* curved */ + quad_bezier_2d(v1, dz1, dz1 + 2, ipodata); + v1[0] += jfx; + v1[1] += jfy; + v1[2] = *dz; + + quad_bezier_2d(v2, dz1 + 4, dz1 + 4 + 2, ipodata); + v2[0] += jfx + 1.0f; + v2[1] += jfy; + v2[2] = *dz; + + quad_bezier_2d(v3, dz2 + 4, dz2 + 4 + 2, ipodata); + v3[0] += jfx + 1.0f; + v3[1] += jfy + 1.0f; + v3[2] = *dz; + + quad_bezier_2d(v4, dz2, dz2 + 2, ipodata); + v4[0] += jfx; + v4[1] += jfy + 1.0f; + v4[2] = *dz; + } + else { + ARRAY_SET_ITEMS(v1, speedfac * dz1[0] + jfx, speedfac * dz1[1] + jfy, *dz); + ARRAY_SET_ITEMS(v2, speedfac * dz1[4] + jfx + 1.0f, speedfac * dz1[5] + jfy, *dz); + ARRAY_SET_ITEMS( + v3, speedfac * dz2[4] + jfx + 1.0f, speedfac * dz2[5] + jfy + 1.0f, *dz); + ARRAY_SET_ITEMS(v4, speedfac * dz2[0] + jfx, speedfac * dz2[1] + jfy + 1.0f, *dz); + } + if (*dm == 255) { + col.alpha = 1.0f; + } + else if (*dm < 2) { + col.alpha = 0.0f; + } + else { + col.alpha = ((float)*dm) / 255.0f; + } + col.colpoin = dimg; + + zbuf_fill_in_rgba(&zspan, &col, v1, v2, v3, v4); + } + } + dz1 += 4; + dz2 += 4; + } + + /* blend with a falloff. this fixes the ugly effect you get with + * a fast moving object. then it looks like a solid object overlaid + * over a very transparent moving version of itself. in reality, the + * whole object should become transparent if it is moving fast, be + * we don't know what is behind it so we don't do that. this hack + * overestimates the contribution of foreground pixels but looks a + * bit better without a sudden cutoff. */ + blendfac = ((samples - step) / (float)samples); + /* smoothstep to make it look a bit nicer as well */ + blendfac = 3.0f * pow(blendfac, 2.0f) - 2.0f * pow(blendfac, 3.0f); + + /* accum */ + rw = rectweight; + rm = rectmax; + for (dr = rectdraw, dz2 = newrect, x = xsize * ysize - 1; x >= 0; + x--, dr++, dz2 += 4, rw++, rm++) { + if (dr->colpoin) { + float bfac = dr->alpha * blendfac; + + dz2[0] += bfac * dr->colpoin[0]; + dz2[1] += bfac * dr->colpoin[1]; + dz2[2] += bfac * dr->colpoin[2]; + dz2[3] += bfac * dr->colpoin[3]; + + *rw += bfac; + *rm = MAX2(*rm, bfac); + } + } + } + } + + /* blend between original images and accumulated image */ + rw = rectweight; + rm = rectmax; + ro = imgrect; + dm = rectmove; + for (dz2 = newrect, x = xsize * ysize - 1; x >= 0; x--, dz2 += 4, ro += 4, rw++, rm++, dm++) { + float mfac = *rm; + float fac = (*rw == 0.0f) ? 0.0f : mfac / (*rw); + float nfac = 1.0f - mfac; + + dz2[0] = fac * dz2[0] + nfac * ro[0]; + dz2[1] = fac * dz2[1] + nfac * ro[1]; + dz2[2] = fac * dz2[2] + nfac * ro[2]; + dz2[3] = fac * dz2[3] + nfac * ro[3]; + } + + MEM_freeN(rectz); + MEM_freeN(rectmove); + MEM_freeN(rectdraw); + MEM_freeN(rectvz); + MEM_freeN(rectweight); + MEM_freeN(rectmax); + if (minvecbufrect) { + MEM_freeN(vecbufrect); /* rects were swapped! */ + } + zbuf_free_span(&zspan); +} diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp deleted file mode 100644 index d6894dfc8ad..00000000000 --- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp +++ /dev/null @@ -1,899 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include - -#include "MEM_guardedalloc.h" - -#include "BLI_jitter_2d.h" -#include "BLI_math.h" - -#include "COM_VectorBlurOperation.h" - -/* Defined */ -#define PASS_VECTOR_MAX 10000.0f - -/* Forward declarations */ -struct DrawBufPixel; -struct ZSpan; -void zbuf_accumulate_vecblur(NodeBlurData *nbd, - int xsize, - int ysize, - float *newrect, - const float *imgrect, - float *vecbufrect, - const float *zbufrect); -void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty, float clipcrop); -void zbuf_free_span(ZSpan *zspan); -void antialias_tagbuf(int xsize, int ysize, char *rectmove); - -/* VectorBlurOperation */ -VectorBlurOperation::VectorBlurOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); // ZBUF - this->addInputSocket(COM_DT_COLOR); // SPEED - this->addOutputSocket(COM_DT_COLOR); - this->m_settings = nullptr; - this->m_cachedInstance = nullptr; - this->m_inputImageProgram = nullptr; - this->m_inputSpeedProgram = nullptr; - this->m_inputZProgram = nullptr; - setComplex(true); -} -void VectorBlurOperation::initExecution() -{ - initMutex(); - this->m_inputImageProgram = getInputSocketReader(0); - this->m_inputZProgram = getInputSocketReader(1); - this->m_inputSpeedProgram = getInputSocketReader(2); - this->m_cachedInstance = nullptr; - QualityStepHelper::initExecution(COM_QH_INCREASE); -} - -void VectorBlurOperation::executePixel(float output[4], int x, int y, void *data) -{ - float *buffer = (float *)data; - int index = (y * this->getWidth() + x) * COM_NUM_CHANNELS_COLOR; - copy_v4_v4(output, &buffer[index]); -} - -void VectorBlurOperation::deinitExecution() -{ - deinitMutex(); - this->m_inputImageProgram = nullptr; - this->m_inputSpeedProgram = nullptr; - this->m_inputZProgram = nullptr; - if (this->m_cachedInstance) { - MEM_freeN(this->m_cachedInstance); - this->m_cachedInstance = nullptr; - } -} -void *VectorBlurOperation::initializeTileData(rcti *rect) -{ - if (this->m_cachedInstance) { - return this->m_cachedInstance; - } - - lockMutex(); - if (this->m_cachedInstance == nullptr) { - MemoryBuffer *tile = (MemoryBuffer *)this->m_inputImageProgram->initializeTileData(rect); - MemoryBuffer *speed = (MemoryBuffer *)this->m_inputSpeedProgram->initializeTileData(rect); - MemoryBuffer *z = (MemoryBuffer *)this->m_inputZProgram->initializeTileData(rect); - float *data = (float *)MEM_dupallocN(tile->getBuffer()); - this->generateVectorBlur(data, tile, speed, z); - this->m_cachedInstance = data; - } - unlockMutex(); - return this->m_cachedInstance; -} - -bool VectorBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/, - ReadBufferOperation *readOperation, - rcti *output) -{ - if (this->m_cachedInstance == nullptr) { - rcti newInput; - newInput.xmax = this->getWidth(); - newInput.xmin = 0; - newInput.ymax = this->getHeight(); - newInput.ymin = 0; - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); - } - - return false; -} - -void VectorBlurOperation::generateVectorBlur(float *data, - MemoryBuffer *inputImage, - MemoryBuffer *inputSpeed, - MemoryBuffer *inputZ) -{ - NodeBlurData blurdata; - blurdata.samples = this->m_settings->samples / QualityStepHelper::getStep(); - blurdata.maxspeed = this->m_settings->maxspeed; - blurdata.minspeed = this->m_settings->minspeed; - blurdata.curved = this->m_settings->curved; - blurdata.fac = this->m_settings->fac; - zbuf_accumulate_vecblur(&blurdata, - this->getWidth(), - this->getHeight(), - data, - inputImage->getBuffer(), - inputSpeed->getBuffer(), - inputZ->getBuffer()); -} - -/* ****************** Spans ******************************* */ -/* span fill in method, is also used to localize data for zbuffering */ -struct ZSpan { - /* range for clipping */ - int rectx, recty; - - /* actual filled in range */ - int miny1, maxy1, miny2, maxy2; - /* vertex pointers detect min/max range in */ - const float *minp1, *maxp1, *minp2, *maxp2; - float *span1, *span2; - - /* transform from hoco to zbuf co */ - float zmulx, zmuly, zofsx, zofsy; - - int *rectz; - DrawBufPixel *rectdraw; - float clipcrop; -}; - -/* each zbuffer has coordinates transformed to local rect coordinates, so we can simply clip */ -void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty, float clipcrop) -{ - memset(zspan, 0, sizeof(ZSpan)); - - zspan->rectx = rectx; - zspan->recty = recty; - - zspan->span1 = (float *)MEM_mallocN(recty * sizeof(float), "zspan"); - zspan->span2 = (float *)MEM_mallocN(recty * sizeof(float), "zspan"); - - zspan->clipcrop = clipcrop; -} - -void zbuf_free_span(ZSpan *zspan) -{ - if (zspan) { - if (zspan->span1) { - MEM_freeN(zspan->span1); - } - if (zspan->span2) { - MEM_freeN(zspan->span2); - } - zspan->span1 = zspan->span2 = nullptr; - } -} - -/* reset range for clipping */ -static void zbuf_init_span(ZSpan *zspan) -{ - zspan->miny1 = zspan->miny2 = zspan->recty + 1; - zspan->maxy1 = zspan->maxy2 = -1; - zspan->minp1 = zspan->maxp1 = zspan->minp2 = zspan->maxp2 = nullptr; -} - -static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2]) -{ - const float *minv, *maxv; - float *span; - float xx1, dx0, xs0; - int y, my0, my2; - - if (v1[1] < v2[1]) { - minv = v1; - maxv = v2; - } - else { - minv = v2; - maxv = v1; - } - - my0 = ceil(minv[1]); - my2 = floor(maxv[1]); - - if (my2 < 0 || my0 >= zspan->recty) { - return; - } - - /* clip top */ - if (my2 >= zspan->recty) { - my2 = zspan->recty - 1; - } - /* clip bottom */ - if (my0 < 0) { - my0 = 0; - } - - if (my0 > my2) { - return; - } - /* if (my0>my2) should still fill in, that way we get spans that skip nicely */ - - xx1 = maxv[1] - minv[1]; - if (xx1 > FLT_EPSILON) { - dx0 = (minv[0] - maxv[0]) / xx1; - xs0 = dx0 * (minv[1] - my2) + minv[0]; - } - else { - dx0 = 0.0f; - xs0 = min_ff(minv[0], maxv[0]); - } - - /* empty span */ - if (zspan->maxp1 == nullptr) { - span = zspan->span1; - } - else { /* does it complete left span? */ - if (maxv == zspan->minp1 || minv == zspan->maxp1) { - span = zspan->span1; - } - else { - span = zspan->span2; - } - } - - if (span == zspan->span1) { - // printf("left span my0 %d my2 %d\n", my0, my2); - if (zspan->minp1 == nullptr || zspan->minp1[1] > minv[1]) { - zspan->minp1 = minv; - } - if (zspan->maxp1 == nullptr || zspan->maxp1[1] < maxv[1]) { - zspan->maxp1 = maxv; - } - if (my0 < zspan->miny1) { - zspan->miny1 = my0; - } - if (my2 > zspan->maxy1) { - zspan->maxy1 = my2; - } - } - else { - // printf("right span my0 %d my2 %d\n", my0, my2); - if (zspan->minp2 == nullptr || zspan->minp2[1] > minv[1]) { - zspan->minp2 = minv; - } - if (zspan->maxp2 == nullptr || zspan->maxp2[1] < maxv[1]) { - zspan->maxp2 = maxv; - } - if (my0 < zspan->miny2) { - zspan->miny2 = my0; - } - if (my2 > zspan->maxy2) { - zspan->maxy2 = my2; - } - } - - for (y = my2; y >= my0; y--, xs0 += dx0) { - /* xs0 is the xcoord! */ - span[y] = xs0; - } -} - -/* ******************** VECBLUR ACCUM BUF ************************* */ - -struct DrawBufPixel { - const float *colpoin; - float alpha; -}; - -static void zbuf_fill_in_rgba( - ZSpan *zspan, DrawBufPixel *col, float *v1, float *v2, float *v3, float *v4) -{ - DrawBufPixel *rectpofs, *rp; - double zxd, zyd, zy0, zverg; - float x0, y0, z0; - float x1, y1, z1, x2, y2, z2, xx1; - const float *span1, *span2; - float *rectzofs, *rz; - int x, y; - int sn1, sn2, rectx, my0, my2; - - /* init */ - zbuf_init_span(zspan); - - /* set spans */ - zbuf_add_to_span(zspan, v1, v2); - zbuf_add_to_span(zspan, v2, v3); - zbuf_add_to_span(zspan, v3, v4); - zbuf_add_to_span(zspan, v4, v1); - - /* clipped */ - if (zspan->minp2 == nullptr || zspan->maxp2 == nullptr) { - return; - } - - my0 = max_ii(zspan->miny1, zspan->miny2); - my2 = min_ii(zspan->maxy1, zspan->maxy2); - - // printf("my %d %d\n", my0, my2); - if (my2 < my0) { - return; - } - - /* ZBUF DX DY, in floats still */ - x1 = v1[0] - v2[0]; - x2 = v2[0] - v3[0]; - y1 = v1[1] - v2[1]; - y2 = v2[1] - v3[1]; - z1 = v1[2] - v2[2]; - z2 = v2[2] - v3[2]; - x0 = y1 * z2 - z1 * y2; - y0 = z1 * x2 - x1 * z2; - z0 = x1 * y2 - y1 * x2; - - if (z0 == 0.0f) { - return; - } - - xx1 = (x0 * v1[0] + y0 * v1[1]) / z0 + v1[2]; - - zxd = -(double)x0 / (double)z0; - zyd = -(double)y0 / (double)z0; - zy0 = ((double)my2) * zyd + (double)xx1; - - /* start-offset in rect */ - rectx = zspan->rectx; - rectzofs = (float *)(zspan->rectz + rectx * my2); - rectpofs = ((DrawBufPixel *)zspan->rectdraw) + rectx * my2; - - /* correct span */ - sn1 = (my0 + my2) / 2; - if (zspan->span1[sn1] < zspan->span2[sn1]) { - span1 = zspan->span1 + my2; - span2 = zspan->span2 + my2; - } - else { - span1 = zspan->span2 + my2; - span2 = zspan->span1 + my2; - } - - for (y = my2; y >= my0; y--, span1--, span2--) { - - sn1 = floor(*span1); - sn2 = floor(*span2); - sn1++; - - if (sn2 >= rectx) { - sn2 = rectx - 1; - } - if (sn1 < 0) { - sn1 = 0; - } - - if (sn2 >= sn1) { - zverg = (double)sn1 * zxd + zy0; - rz = rectzofs + sn1; - rp = rectpofs + sn1; - x = sn2 - sn1; - - while (x >= 0) { - if (zverg < (double)*rz) { - *rz = zverg; - *rp = *col; - } - zverg += zxd; - rz++; - rp++; - x--; - } - } - - zy0 -= zyd; - rectzofs -= rectx; - rectpofs -= rectx; - } -} - -/* char value==255 is filled in, rest should be zero */ -/* returns alpha values, - * but sets alpha to 1 for zero alpha pixels that have an alpha value as neighbor. */ -void antialias_tagbuf(int xsize, int ysize, char *rectmove) -{ - char *row1, *row2, *row3; - char prev, next; - int a, x, y, step; - - /* 1: tag pixels to be candidate for AA */ - for (y = 2; y < ysize; y++) { - /* setup rows */ - row1 = rectmove + (y - 2) * xsize; - row2 = row1 + xsize; - row3 = row2 + xsize; - for (x = 2; x < xsize; x++, row1++, row2++, row3++) { - if (row2[1]) { - if (row2[0] == 0 || row2[2] == 0 || row1[1] == 0 || row3[1] == 0) { - row2[1] = 128; - } - } - } - } - - /* 2: evaluate horizontal scanlines and calculate alphas */ - row1 = rectmove; - for (y = 0; y < ysize; y++) { - row1++; - for (x = 1; x < xsize; x++, row1++) { - if (row1[0] == 128 && row1[1] == 128) { - /* find previous color and next color and amount of steps to blend */ - prev = row1[-1]; - step = 1; - while (x + step < xsize && row1[step] == 128) { - step++; - } - - if (x + step != xsize) { - /* now we can blend values */ - next = row1[step]; - - /* note, prev value can be next value, but we do this loop to clear 128 then */ - for (a = 0; a < step; a++) { - int fac, mfac; - - fac = ((a + 1) << 8) / (step + 1); - mfac = 255 - fac; - - row1[a] = (prev * mfac + next * fac) >> 8; - } - } - } - } - } - - /* 3: evaluate vertical scanlines and calculate alphas */ - /* use for reading a copy of the original tagged buffer */ - for (x = 0; x < xsize; x++) { - row1 = rectmove + x + xsize; - - for (y = 1; y < ysize; y++, row1 += xsize) { - if (row1[0] == 128 && row1[xsize] == 128) { - /* find previous color and next color and amount of steps to blend */ - prev = row1[-xsize]; - step = 1; - while (y + step < ysize && row1[step * xsize] == 128) { - step++; - } - - if (y + step != ysize) { - /* now we can blend values */ - next = row1[step * xsize]; - /* note, prev value can be next value, but we do this loop to clear 128 then */ - for (a = 0; a < step; a++) { - int fac, mfac; - - fac = ((a + 1) << 8) / (step + 1); - mfac = 255 - fac; - - row1[a * xsize] = (prev * mfac + next * fac) >> 8; - } - } - } - } - } - - /* last: pixels with 0 we fill in zbuffer, with 1 we skip for mask */ - for (y = 2; y < ysize; y++) { - /* setup rows */ - row1 = rectmove + (y - 2) * xsize; - row2 = row1 + xsize; - row3 = row2 + xsize; - for (x = 2; x < xsize; x++, row1++, row2++, row3++) { - if (row2[1] == 0) { - if (row2[0] > 1 || row2[2] > 1 || row1[1] > 1 || row3[1] > 1) { - row2[1] = 1; - } - } - } - } -} - -/* in: two vectors, first vector points from origin back in time, 2nd vector points to future */ -/* we make this into 3 points, center point is (0, 0) */ -/* and offset the center point just enough to make curve go through midpoint */ - -static void quad_bezier_2d(float *result, const float *v1, const float *v2, const float *ipodata) -{ - float p1[2], p2[2], p3[2]; - - p3[0] = -v2[0]; - p3[1] = -v2[1]; - - p1[0] = v1[0]; - p1[1] = v1[1]; - - /* official formula 2*p2 - 0.5*p1 - 0.5*p3 */ - p2[0] = -0.5f * p1[0] - 0.5f * p3[0]; - p2[1] = -0.5f * p1[1] - 0.5f * p3[1]; - - result[0] = ipodata[0] * p1[0] + ipodata[1] * p2[0] + ipodata[2] * p3[0]; - result[1] = ipodata[0] * p1[1] + ipodata[1] * p2[1] + ipodata[2] * p3[1]; -} - -static void set_quad_bezier_ipo(float fac, float *data) -{ - float mfac = (1.0f - fac); - - data[0] = mfac * mfac; - data[1] = 2.0f * mfac * fac; - data[2] = fac * fac; -} - -void zbuf_accumulate_vecblur(NodeBlurData *nbd, - int xsize, - int ysize, - float *newrect, - const float *imgrect, - float *vecbufrect, - const float *zbufrect) -{ - ZSpan zspan; - DrawBufPixel *rectdraw, *dr; - static float jit[256][2]; - float v1[3], v2[3], v3[3], v4[3], fx, fy; - const float *dimg, *dz, *ro; - float *rectvz, *dvz, *dvec1, *dvec2, *dz1, *dz2, *rectz; - float *minvecbufrect = nullptr, *rectweight, *rw, *rectmax, *rm; - float maxspeedsq = (float)nbd->maxspeed * nbd->maxspeed; - int y, x, step, maxspeed = nbd->maxspeed, samples = nbd->samples; - int tsktsk = 0; - static int firsttime = 1; - char *rectmove, *dm; - - zbuf_alloc_span(&zspan, xsize, ysize, 1.0f); - zspan.zmulx = ((float)xsize) / 2.0f; - zspan.zmuly = ((float)ysize) / 2.0f; - zspan.zofsx = 0.0f; - zspan.zofsy = 0.0f; - - /* the buffers */ - rectz = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "zbuf accum"); - zspan.rectz = (int *)rectz; - - rectmove = (char *)MEM_callocN(xsize * ysize, "rectmove"); - rectdraw = (DrawBufPixel *)MEM_callocN(sizeof(DrawBufPixel) * xsize * ysize, "rect draw"); - zspan.rectdraw = rectdraw; - - rectweight = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "rect weight"); - rectmax = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "rect max"); - - /* debug... check if PASS_VECTOR_MAX still is in buffers */ - dvec1 = vecbufrect; - for (x = 4 * xsize * ysize; x > 0; x--, dvec1++) { - if (dvec1[0] == PASS_VECTOR_MAX) { - dvec1[0] = 0.0f; - tsktsk = 1; - } - } - if (tsktsk) { - printf("Found uninitialized speed in vector buffer... fixed.\n"); - } - - /* Min speed? then copy speed-buffer to recalculate speed vectors. */ - if (nbd->minspeed) { - float minspeed = (float)nbd->minspeed; - float minspeedsq = minspeed * minspeed; - - minvecbufrect = (float *)MEM_callocN(sizeof(float[4]) * xsize * ysize, "minspeed buf"); - - dvec1 = vecbufrect; - dvec2 = minvecbufrect; - for (x = 2 * xsize * ysize; x > 0; x--, dvec1 += 2, dvec2 += 2) { - if (dvec1[0] == 0.0f && dvec1[1] == 0.0f) { - dvec2[0] = dvec1[0]; - dvec2[1] = dvec1[1]; - } - else { - float speedsq = dvec1[0] * dvec1[0] + dvec1[1] * dvec1[1]; - if (speedsq <= minspeedsq) { - dvec2[0] = 0.0f; - dvec2[1] = 0.0f; - } - else { - speedsq = 1.0f - minspeed / sqrtf(speedsq); - dvec2[0] = speedsq * dvec1[0]; - dvec2[1] = speedsq * dvec1[1]; - } - } - } - SWAP(float *, minvecbufrect, vecbufrect); - } - - /* Make vertex buffer with averaged speed and Z-values. */ - rectvz = (float *)MEM_callocN(sizeof(float[4]) * (xsize + 1) * (ysize + 1), "vertices"); - dvz = rectvz; - for (y = 0; y <= ysize; y++) { - - if (y == 0) { - dvec1 = vecbufrect + 4 * y * xsize; - } - else { - dvec1 = vecbufrect + 4 * (y - 1) * xsize; - } - - if (y == ysize) { - dvec2 = vecbufrect + 4 * (y - 1) * xsize; - } - else { - dvec2 = vecbufrect + 4 * y * xsize; - } - - for (x = 0; x <= xsize; x++) { - - /* two vectors, so a step loop */ - for (step = 0; step < 2; step++, dvec1 += 2, dvec2 += 2, dvz += 2) { - /* average on minimal speed */ - int div = 0; - - if (x != 0) { - if (dvec1[-4] != 0.0f || dvec1[-3] != 0.0f) { - dvz[0] = dvec1[-4]; - dvz[1] = dvec1[-3]; - div++; - } - if (dvec2[-4] != 0.0f || dvec2[-3] != 0.0f) { - if (div == 0) { - dvz[0] = dvec2[-4]; - dvz[1] = dvec2[-3]; - div++; - } - else if ((fabsf(dvec2[-4]) + fabsf(dvec2[-3])) < (fabsf(dvz[0]) + fabsf(dvz[1]))) { - dvz[0] = dvec2[-4]; - dvz[1] = dvec2[-3]; - } - } - } - - if (x != xsize) { - if (dvec1[0] != 0.0f || dvec1[1] != 0.0f) { - if (div == 0) { - dvz[0] = dvec1[0]; - dvz[1] = dvec1[1]; - div++; - } - else if ((fabsf(dvec1[0]) + fabsf(dvec1[1])) < (fabsf(dvz[0]) + fabsf(dvz[1]))) { - dvz[0] = dvec1[0]; - dvz[1] = dvec1[1]; - } - } - if (dvec2[0] != 0.0f || dvec2[1] != 0.0f) { - if (div == 0) { - dvz[0] = dvec2[0]; - dvz[1] = dvec2[1]; - } - else if ((fabsf(dvec2[0]) + fabsf(dvec2[1])) < (fabsf(dvz[0]) + fabsf(dvz[1]))) { - dvz[0] = dvec2[0]; - dvz[1] = dvec2[1]; - } - } - } - if (maxspeed) { - float speedsq = dvz[0] * dvz[0] + dvz[1] * dvz[1]; - if (speedsq > maxspeedsq) { - speedsq = (float)maxspeed / sqrtf(speedsq); - dvz[0] *= speedsq; - dvz[1] *= speedsq; - } - } - } - } - } - - /* set border speeds to keep border speeds on border */ - dz1 = rectvz; - dz2 = rectvz + 4 * (ysize) * (xsize + 1); - for (x = 0; x <= xsize; x++, dz1 += 4, dz2 += 4) { - dz1[1] = 0.0f; - dz2[1] = 0.0f; - dz1[3] = 0.0f; - dz2[3] = 0.0f; - } - dz1 = rectvz; - dz2 = rectvz + 4 * (xsize); - for (y = 0; y <= ysize; y++, dz1 += 4 * (xsize + 1), dz2 += 4 * (xsize + 1)) { - dz1[0] = 0.0f; - dz2[0] = 0.0f; - dz1[2] = 0.0f; - dz2[2] = 0.0f; - } - - /* tag moving pixels, only these faces we draw */ - dm = rectmove; - dvec1 = vecbufrect; - for (x = xsize * ysize; x > 0; x--, dm++, dvec1 += 4) { - if ((dvec1[0] != 0.0f || dvec1[1] != 0.0f || dvec1[2] != 0.0f || dvec1[3] != 0.0f)) { - *dm = 255; - } - } - - antialias_tagbuf(xsize, ysize, rectmove); - - /* Has to become static, the jitter initialization calls a random-seed, - * screwing up texture noise node. */ - if (firsttime) { - firsttime = 0; - BLI_jitter_init(jit, 256); - } - - memset(newrect, 0, sizeof(float) * xsize * ysize * 4); - - /* accumulate */ - samples /= 2; - for (step = 1; step <= samples; step++) { - float speedfac = 0.5f * nbd->fac * (float)step / (float)(samples + 1); - int side; - - for (side = 0; side < 2; side++) { - float blendfac, ipodata[4]; - - /* clear zbuf, if we draw future we fill in not moving pixels */ - if (false) { - for (x = xsize * ysize - 1; x >= 0; x--) { - rectz[x] = 10e16; - } - } - else { - for (x = xsize * ysize - 1; x >= 0; x--) { - if (rectmove[x] == 0) { - rectz[x] = zbufrect[x]; - } - else { - rectz[x] = 10e16; - } - } - } - - /* clear drawing buffer */ - for (x = xsize * ysize - 1; x >= 0; x--) { - rectdraw[x].colpoin = nullptr; - } - - dimg = imgrect; - dm = rectmove; - dz = zbufrect; - dz1 = rectvz; - dz2 = rectvz + 4 * (xsize + 1); - - if (side) { - if (nbd->curved == 0) { - dz1 += 2; - dz2 += 2; - } - speedfac = -speedfac; - } - - set_quad_bezier_ipo(0.5f + 0.5f * speedfac, ipodata); - - for (fy = -0.5f + jit[step & 255][0], y = 0; y < ysize; y++, fy += 1.0f) { - for (fx = -0.5f + jit[step & 255][1], x = 0; x < xsize; - x++, fx += 1.0f, dimg += 4, dz1 += 4, dz2 += 4, dm++, dz++) { - if (*dm > 1) { - float jfx = fx + 0.5f; - float jfy = fy + 0.5f; - DrawBufPixel col; - - /* make vertices */ - if (nbd->curved) { /* curved */ - quad_bezier_2d(v1, dz1, dz1 + 2, ipodata); - v1[0] += jfx; - v1[1] += jfy; - v1[2] = *dz; - - quad_bezier_2d(v2, dz1 + 4, dz1 + 4 + 2, ipodata); - v2[0] += jfx + 1.0f; - v2[1] += jfy; - v2[2] = *dz; - - quad_bezier_2d(v3, dz2 + 4, dz2 + 4 + 2, ipodata); - v3[0] += jfx + 1.0f; - v3[1] += jfy + 1.0f; - v3[2] = *dz; - - quad_bezier_2d(v4, dz2, dz2 + 2, ipodata); - v4[0] += jfx; - v4[1] += jfy + 1.0f; - v4[2] = *dz; - } - else { - ARRAY_SET_ITEMS(v1, speedfac * dz1[0] + jfx, speedfac * dz1[1] + jfy, *dz); - ARRAY_SET_ITEMS(v2, speedfac * dz1[4] + jfx + 1.0f, speedfac * dz1[5] + jfy, *dz); - ARRAY_SET_ITEMS( - v3, speedfac * dz2[4] + jfx + 1.0f, speedfac * dz2[5] + jfy + 1.0f, *dz); - ARRAY_SET_ITEMS(v4, speedfac * dz2[0] + jfx, speedfac * dz2[1] + jfy + 1.0f, *dz); - } - if (*dm == 255) { - col.alpha = 1.0f; - } - else if (*dm < 2) { - col.alpha = 0.0f; - } - else { - col.alpha = ((float)*dm) / 255.0f; - } - col.colpoin = dimg; - - zbuf_fill_in_rgba(&zspan, &col, v1, v2, v3, v4); - } - } - dz1 += 4; - dz2 += 4; - } - - /* blend with a falloff. this fixes the ugly effect you get with - * a fast moving object. then it looks like a solid object overlaid - * over a very transparent moving version of itself. in reality, the - * whole object should become transparent if it is moving fast, be - * we don't know what is behind it so we don't do that. this hack - * overestimates the contribution of foreground pixels but looks a - * bit better without a sudden cutoff. */ - blendfac = ((samples - step) / (float)samples); - /* smoothstep to make it look a bit nicer as well */ - blendfac = 3.0f * pow(blendfac, 2.0f) - 2.0f * pow(blendfac, 3.0f); - - /* accum */ - rw = rectweight; - rm = rectmax; - for (dr = rectdraw, dz2 = newrect, x = xsize * ysize - 1; x >= 0; - x--, dr++, dz2 += 4, rw++, rm++) { - if (dr->colpoin) { - float bfac = dr->alpha * blendfac; - - dz2[0] += bfac * dr->colpoin[0]; - dz2[1] += bfac * dr->colpoin[1]; - dz2[2] += bfac * dr->colpoin[2]; - dz2[3] += bfac * dr->colpoin[3]; - - *rw += bfac; - *rm = MAX2(*rm, bfac); - } - } - } - } - - /* blend between original images and accumulated image */ - rw = rectweight; - rm = rectmax; - ro = imgrect; - dm = rectmove; - for (dz2 = newrect, x = xsize * ysize - 1; x >= 0; x--, dz2 += 4, ro += 4, rw++, rm++, dm++) { - float mfac = *rm; - float fac = (*rw == 0.0f) ? 0.0f : mfac / (*rw); - float nfac = 1.0f - mfac; - - dz2[0] = fac * dz2[0] + nfac * ro[0]; - dz2[1] = fac * dz2[1] + nfac * ro[1]; - dz2[2] = fac * dz2[2] + nfac * ro[2]; - dz2[3] = fac * dz2[3] + nfac * ro[3]; - } - - MEM_freeN(rectz); - MEM_freeN(rectmove); - MEM_freeN(rectdraw); - MEM_freeN(rectvz); - MEM_freeN(rectweight); - MEM_freeN(rectmax); - if (minvecbufrect) { - MEM_freeN(vecbufrect); /* rects were swapped! */ - } - zbuf_free_span(&zspan); -} diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.cc b/source/blender/compositor/operations/COM_VectorCurveOperation.cc new file mode 100644 index 00000000000..a883237f870 --- /dev/null +++ b/source/blender/compositor/operations/COM_VectorCurveOperation.cc @@ -0,0 +1,52 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_VectorCurveOperation.h" + +#include "BKE_colortools.h" + +VectorCurveOperation::VectorCurveOperation() +{ + this->addInputSocket(COM_DT_VECTOR); + this->addOutputSocket(COM_DT_VECTOR); + + this->m_inputProgram = nullptr; +} +void VectorCurveOperation::initExecution() +{ + CurveBaseOperation::initExecution(); + this->m_inputProgram = this->getInputSocketReader(0); +} + +void VectorCurveOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float input[4]; + + this->m_inputProgram->readSampled(input, x, y, sampler); + + BKE_curvemapping_evaluate_premulRGBF(this->m_curveMapping, output, input); +} + +void VectorCurveOperation::deinitExecution() +{ + CurveBaseOperation::deinitExecution(); + this->m_inputProgram = nullptr; +} diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp b/source/blender/compositor/operations/COM_VectorCurveOperation.cpp deleted file mode 100644 index a883237f870..00000000000 --- a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_VectorCurveOperation.h" - -#include "BKE_colortools.h" - -VectorCurveOperation::VectorCurveOperation() -{ - this->addInputSocket(COM_DT_VECTOR); - this->addOutputSocket(COM_DT_VECTOR); - - this->m_inputProgram = nullptr; -} -void VectorCurveOperation::initExecution() -{ - CurveBaseOperation::initExecution(); - this->m_inputProgram = this->getInputSocketReader(0); -} - -void VectorCurveOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float input[4]; - - this->m_inputProgram->readSampled(input, x, y, sampler); - - BKE_curvemapping_evaluate_premulRGBF(this->m_curveMapping, output, input); -} - -void VectorCurveOperation::deinitExecution() -{ - CurveBaseOperation::deinitExecution(); - this->m_inputProgram = nullptr; -} diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cc b/source/blender/compositor/operations/COM_ViewerOperation.cc new file mode 100644 index 00000000000..025dde8e866 --- /dev/null +++ b/source/blender/compositor/operations/COM_ViewerOperation.cc @@ -0,0 +1,204 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ViewerOperation.h" +#include "BKE_image.h" +#include "BKE_scene.h" +#include "BLI_listbase.h" +#include "BLI_math_color.h" +#include "BLI_math_vector.h" +#include "BLI_utildefines.h" +#include "MEM_guardedalloc.h" +#include "PIL_time.h" +#include "WM_api.h" +#include "WM_types.h" + +#include "IMB_colormanagement.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +ViewerOperation::ViewerOperation() +{ + this->setImage(nullptr); + this->setImageUser(nullptr); + this->m_outputBuffer = nullptr; + this->m_depthBuffer = nullptr; + this->m_active = false; + this->m_doDepthBuffer = false; + this->m_viewSettings = nullptr; + this->m_displaySettings = nullptr; + this->m_useAlphaInput = false; + + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + + this->m_imageInput = nullptr; + this->m_alphaInput = nullptr; + this->m_depthInput = nullptr; + this->m_rd = nullptr; + this->m_viewName = nullptr; +} + +void ViewerOperation::initExecution() +{ + // When initializing the tree during initial load the width and height can be zero. + this->m_imageInput = getInputSocketReader(0); + this->m_alphaInput = getInputSocketReader(1); + this->m_depthInput = getInputSocketReader(2); + this->m_doDepthBuffer = (this->m_depthInput != nullptr); + + if (isActiveViewerOutput()) { + initImage(); + } +} + +void ViewerOperation::deinitExecution() +{ + this->m_imageInput = nullptr; + this->m_alphaInput = nullptr; + this->m_depthInput = nullptr; + this->m_outputBuffer = nullptr; +} + +void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) +{ + float *buffer = this->m_outputBuffer; + float *depthbuffer = this->m_depthBuffer; + if (!buffer) { + return; + } + const int x1 = rect->xmin; + const int y1 = rect->ymin; + const int x2 = rect->xmax; + const int y2 = rect->ymax; + const int offsetadd = (this->getWidth() - (x2 - x1)); + const int offsetadd4 = offsetadd * 4; + int offset = (y1 * this->getWidth() + x1); + int offset4 = offset * 4; + float alpha[4], depth[4]; + int x; + int y; + bool breaked = false; + + for (y = y1; y < y2 && (!breaked); y++) { + for (x = x1; x < x2; x++) { + this->m_imageInput->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST); + if (this->m_useAlphaInput) { + this->m_alphaInput->readSampled(alpha, x, y, COM_PS_NEAREST); + buffer[offset4 + 3] = alpha[0]; + } + this->m_depthInput->readSampled(depth, x, y, COM_PS_NEAREST); + depthbuffer[offset] = depth[0]; + + offset++; + offset4 += 4; + } + if (isBraked()) { + breaked = true; + } + offset += offsetadd; + offset4 += offsetadd4; + } + updateImage(rect); +} + +void ViewerOperation::initImage() +{ + Image *ima = this->m_image; + ImageUser iuser = *this->m_imageUser; + void *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_ensure_viewer_views(this->m_rd, ima, this->m_imageUser); + } + + BLI_thread_lock(LOCK_DRAW_IMAGE); + + /* 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) { + BLI_thread_unlock(LOCK_DRAW_IMAGE); + return; + } + if (ibuf->x != (int)getWidth() || ibuf->y != (int)getHeight()) { + + imb_freerectImBuf(ibuf); + imb_freerectfloatImBuf(ibuf); + IMB_freezbuffloatImBuf(ibuf); + ibuf->x = getWidth(); + ibuf->y = getHeight(); + /* zero size can happen if no image buffers exist to define a sensible resolution */ + if (ibuf->x > 0 && ibuf->y > 0) { + imb_addrectfloatImBuf(ibuf); + } + ImageTile *tile = BKE_image_get_tile(ima, 0); + tile->ok = IMA_OK_LOADED; + + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + } + + if (m_doDepthBuffer) { + addzbuffloatImBuf(ibuf); + } + + /* now we combine the input with ibuf */ + this->m_outputBuffer = ibuf->rect_float; + + /* needed for display buffer update */ + this->m_ibuf = ibuf; + + if (m_doDepthBuffer) { + this->m_depthBuffer = ibuf->zbuf_float; + } + + BKE_image_release_ibuf(this->m_image, this->m_ibuf, lock); + + BLI_thread_unlock(LOCK_DRAW_IMAGE); +} + +void ViewerOperation::updateImage(rcti *rect) +{ + IMB_partial_display_buffer_update(this->m_ibuf, + this->m_outputBuffer, + nullptr, + getWidth(), + 0, + 0, + this->m_viewSettings, + this->m_displaySettings, + rect->xmin, + rect->ymin, + rect->xmax, + rect->ymax); + this->m_image->gpuflag |= IMA_GPU_REFRESH; + this->updateDraw(); +} + +CompositorPriority ViewerOperation::getRenderPriority() const +{ + if (this->isActiveViewerOutput()) { + return COM_PRIORITY_HIGH; + } + + return COM_PRIORITY_LOW; +} diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cpp deleted file mode 100644 index 025dde8e866..00000000000 --- a/source/blender/compositor/operations/COM_ViewerOperation.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ViewerOperation.h" -#include "BKE_image.h" -#include "BKE_scene.h" -#include "BLI_listbase.h" -#include "BLI_math_color.h" -#include "BLI_math_vector.h" -#include "BLI_utildefines.h" -#include "MEM_guardedalloc.h" -#include "PIL_time.h" -#include "WM_api.h" -#include "WM_types.h" - -#include "IMB_colormanagement.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -ViewerOperation::ViewerOperation() -{ - this->setImage(nullptr); - this->setImageUser(nullptr); - this->m_outputBuffer = nullptr; - this->m_depthBuffer = nullptr; - this->m_active = false; - this->m_doDepthBuffer = false; - this->m_viewSettings = nullptr; - this->m_displaySettings = nullptr; - this->m_useAlphaInput = false; - - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - - this->m_imageInput = nullptr; - this->m_alphaInput = nullptr; - this->m_depthInput = nullptr; - this->m_rd = nullptr; - this->m_viewName = nullptr; -} - -void ViewerOperation::initExecution() -{ - // When initializing the tree during initial load the width and height can be zero. - this->m_imageInput = getInputSocketReader(0); - this->m_alphaInput = getInputSocketReader(1); - this->m_depthInput = getInputSocketReader(2); - this->m_doDepthBuffer = (this->m_depthInput != nullptr); - - if (isActiveViewerOutput()) { - initImage(); - } -} - -void ViewerOperation::deinitExecution() -{ - this->m_imageInput = nullptr; - this->m_alphaInput = nullptr; - this->m_depthInput = nullptr; - this->m_outputBuffer = nullptr; -} - -void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) -{ - float *buffer = this->m_outputBuffer; - float *depthbuffer = this->m_depthBuffer; - if (!buffer) { - return; - } - const int x1 = rect->xmin; - const int y1 = rect->ymin; - const int x2 = rect->xmax; - const int y2 = rect->ymax; - const int offsetadd = (this->getWidth() - (x2 - x1)); - const int offsetadd4 = offsetadd * 4; - int offset = (y1 * this->getWidth() + x1); - int offset4 = offset * 4; - float alpha[4], depth[4]; - int x; - int y; - bool breaked = false; - - for (y = y1; y < y2 && (!breaked); y++) { - for (x = x1; x < x2; x++) { - this->m_imageInput->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST); - if (this->m_useAlphaInput) { - this->m_alphaInput->readSampled(alpha, x, y, COM_PS_NEAREST); - buffer[offset4 + 3] = alpha[0]; - } - this->m_depthInput->readSampled(depth, x, y, COM_PS_NEAREST); - depthbuffer[offset] = depth[0]; - - offset++; - offset4 += 4; - } - if (isBraked()) { - breaked = true; - } - offset += offsetadd; - offset4 += offsetadd4; - } - updateImage(rect); -} - -void ViewerOperation::initImage() -{ - Image *ima = this->m_image; - ImageUser iuser = *this->m_imageUser; - void *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_ensure_viewer_views(this->m_rd, ima, this->m_imageUser); - } - - BLI_thread_lock(LOCK_DRAW_IMAGE); - - /* 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) { - BLI_thread_unlock(LOCK_DRAW_IMAGE); - return; - } - if (ibuf->x != (int)getWidth() || ibuf->y != (int)getHeight()) { - - imb_freerectImBuf(ibuf); - imb_freerectfloatImBuf(ibuf); - IMB_freezbuffloatImBuf(ibuf); - ibuf->x = getWidth(); - ibuf->y = getHeight(); - /* zero size can happen if no image buffers exist to define a sensible resolution */ - if (ibuf->x > 0 && ibuf->y > 0) { - imb_addrectfloatImBuf(ibuf); - } - ImageTile *tile = BKE_image_get_tile(ima, 0); - tile->ok = IMA_OK_LOADED; - - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - } - - if (m_doDepthBuffer) { - addzbuffloatImBuf(ibuf); - } - - /* now we combine the input with ibuf */ - this->m_outputBuffer = ibuf->rect_float; - - /* needed for display buffer update */ - this->m_ibuf = ibuf; - - if (m_doDepthBuffer) { - this->m_depthBuffer = ibuf->zbuf_float; - } - - BKE_image_release_ibuf(this->m_image, this->m_ibuf, lock); - - BLI_thread_unlock(LOCK_DRAW_IMAGE); -} - -void ViewerOperation::updateImage(rcti *rect) -{ - IMB_partial_display_buffer_update(this->m_ibuf, - this->m_outputBuffer, - nullptr, - getWidth(), - 0, - 0, - this->m_viewSettings, - this->m_displaySettings, - rect->xmin, - rect->ymin, - rect->xmax, - rect->ymax); - this->m_image->gpuflag |= IMA_GPU_REFRESH; - this->updateDraw(); -} - -CompositorPriority ViewerOperation::getRenderPriority() const -{ - if (this->isActiveViewerOutput()) { - return COM_PRIORITY_HIGH; - } - - return COM_PRIORITY_LOW; -} diff --git a/source/blender/compositor/operations/COM_WrapOperation.cc b/source/blender/compositor/operations/COM_WrapOperation.cc new file mode 100644 index 00000000000..37b7d68d495 --- /dev/null +++ b/source/blender/compositor/operations/COM_WrapOperation.cc @@ -0,0 +1,117 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include + +#include "COM_WrapOperation.h" + +WrapOperation::WrapOperation(DataType datatype) : ReadBufferOperation(datatype) +{ + this->m_wrappingType = CMP_NODE_WRAP_NONE; +} + +inline float WrapOperation::getWrappedOriginalXPos(float x) +{ + if (this->getWidth() == 0) { + return 0; + } + while (x < 0) { + x += this->m_width; + } + return fmodf(x, this->getWidth()); +} + +inline float WrapOperation::getWrappedOriginalYPos(float y) +{ + if (this->getHeight() == 0) { + return 0; + } + while (y < 0) { + y += this->m_height; + } + return fmodf(y, this->getHeight()); +} + +void WrapOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) +{ + float nx, ny; + nx = x; + ny = y; + MemoryBufferExtend extend_x = COM_MB_CLIP, extend_y = COM_MB_CLIP; + switch (m_wrappingType) { + case CMP_NODE_WRAP_NONE: + // Intentionally empty, originalXPos and originalYPos have been set before + break; + case CMP_NODE_WRAP_X: + // wrap only on the x-axis + nx = this->getWrappedOriginalXPos(x); + extend_x = COM_MB_REPEAT; + break; + case CMP_NODE_WRAP_Y: + // wrap only on the y-axis + ny = this->getWrappedOriginalYPos(y); + extend_y = COM_MB_REPEAT; + break; + case CMP_NODE_WRAP_XY: + // wrap on both + nx = this->getWrappedOriginalXPos(x); + ny = this->getWrappedOriginalYPos(y); + extend_x = COM_MB_REPEAT; + extend_y = COM_MB_REPEAT; + break; + } + + executePixelExtend(output, nx, ny, sampler, extend_x, extend_y); +} + +bool WrapOperation::determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) +{ + rcti newInput; + newInput.xmin = input->xmin; + newInput.xmax = input->xmax; + newInput.ymin = input->ymin; + newInput.ymax = input->ymax; + + if (ELEM(m_wrappingType, CMP_NODE_WRAP_X, CMP_NODE_WRAP_XY)) { + // wrap only on the x-axis if tile is wrapping + newInput.xmin = getWrappedOriginalXPos(input->xmin); + newInput.xmax = roundf(getWrappedOriginalXPos(input->xmax)); + if (newInput.xmin >= newInput.xmax) { + newInput.xmin = 0; + newInput.xmax = this->getWidth(); + } + } + if (ELEM(m_wrappingType, CMP_NODE_WRAP_Y, CMP_NODE_WRAP_XY)) { + // wrap only on the y-axis if tile is wrapping + newInput.ymin = getWrappedOriginalYPos(input->ymin); + newInput.ymax = roundf(getWrappedOriginalYPos(input->ymax)); + if (newInput.ymin >= newInput.ymax) { + newInput.ymin = 0; + newInput.ymax = this->getHeight(); + } + } + + return ReadBufferOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +void WrapOperation::setWrapping(int wrapping_type) +{ + m_wrappingType = wrapping_type; +} diff --git a/source/blender/compositor/operations/COM_WrapOperation.cpp b/source/blender/compositor/operations/COM_WrapOperation.cpp deleted file mode 100644 index 37b7d68d495..00000000000 --- a/source/blender/compositor/operations/COM_WrapOperation.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include - -#include "COM_WrapOperation.h" - -WrapOperation::WrapOperation(DataType datatype) : ReadBufferOperation(datatype) -{ - this->m_wrappingType = CMP_NODE_WRAP_NONE; -} - -inline float WrapOperation::getWrappedOriginalXPos(float x) -{ - if (this->getWidth() == 0) { - return 0; - } - while (x < 0) { - x += this->m_width; - } - return fmodf(x, this->getWidth()); -} - -inline float WrapOperation::getWrappedOriginalYPos(float y) -{ - if (this->getHeight() == 0) { - return 0; - } - while (y < 0) { - y += this->m_height; - } - return fmodf(y, this->getHeight()); -} - -void WrapOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) -{ - float nx, ny; - nx = x; - ny = y; - MemoryBufferExtend extend_x = COM_MB_CLIP, extend_y = COM_MB_CLIP; - switch (m_wrappingType) { - case CMP_NODE_WRAP_NONE: - // Intentionally empty, originalXPos and originalYPos have been set before - break; - case CMP_NODE_WRAP_X: - // wrap only on the x-axis - nx = this->getWrappedOriginalXPos(x); - extend_x = COM_MB_REPEAT; - break; - case CMP_NODE_WRAP_Y: - // wrap only on the y-axis - ny = this->getWrappedOriginalYPos(y); - extend_y = COM_MB_REPEAT; - break; - case CMP_NODE_WRAP_XY: - // wrap on both - nx = this->getWrappedOriginalXPos(x); - ny = this->getWrappedOriginalYPos(y); - extend_x = COM_MB_REPEAT; - extend_y = COM_MB_REPEAT; - break; - } - - executePixelExtend(output, nx, ny, sampler, extend_x, extend_y); -} - -bool WrapOperation::determineDependingAreaOfInterest(rcti *input, - ReadBufferOperation *readOperation, - rcti *output) -{ - rcti newInput; - newInput.xmin = input->xmin; - newInput.xmax = input->xmax; - newInput.ymin = input->ymin; - newInput.ymax = input->ymax; - - if (ELEM(m_wrappingType, CMP_NODE_WRAP_X, CMP_NODE_WRAP_XY)) { - // wrap only on the x-axis if tile is wrapping - newInput.xmin = getWrappedOriginalXPos(input->xmin); - newInput.xmax = roundf(getWrappedOriginalXPos(input->xmax)); - if (newInput.xmin >= newInput.xmax) { - newInput.xmin = 0; - newInput.xmax = this->getWidth(); - } - } - if (ELEM(m_wrappingType, CMP_NODE_WRAP_Y, CMP_NODE_WRAP_XY)) { - // wrap only on the y-axis if tile is wrapping - newInput.ymin = getWrappedOriginalYPos(input->ymin); - newInput.ymax = roundf(getWrappedOriginalYPos(input->ymax)); - if (newInput.ymin >= newInput.ymax) { - newInput.ymin = 0; - newInput.ymax = this->getHeight(); - } - } - - return ReadBufferOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} - -void WrapOperation::setWrapping(int wrapping_type) -{ - m_wrappingType = wrapping_type; -} diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cc b/source/blender/compositor/operations/COM_WriteBufferOperation.cc new file mode 100644 index 00000000000..8d38dbfe180 --- /dev/null +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cc @@ -0,0 +1,228 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_WriteBufferOperation.h" +#include "COM_OpenCLDevice.h" +#include "COM_defines.h" +#include + +WriteBufferOperation::WriteBufferOperation(DataType datatype) +{ + this->addInputSocket(datatype); + this->m_memoryProxy = new MemoryProxy(datatype); + this->m_memoryProxy->setWriteBufferOperation(this); + this->m_memoryProxy->setExecutor(nullptr); +} +WriteBufferOperation::~WriteBufferOperation() +{ + if (this->m_memoryProxy) { + delete this->m_memoryProxy; + this->m_memoryProxy = nullptr; + } +} + +void WriteBufferOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + this->m_input->readSampled(output, x, y, sampler); +} + +void WriteBufferOperation::initExecution() +{ + this->m_input = this->getInputOperation(0); + this->m_memoryProxy->allocate(this->m_width, this->m_height); +} + +void WriteBufferOperation::deinitExecution() +{ + this->m_input = nullptr; + this->m_memoryProxy->free(); +} + +void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) +{ + MemoryBuffer *memoryBuffer = this->m_memoryProxy->getBuffer(); + float *buffer = memoryBuffer->getBuffer(); + const int num_channels = memoryBuffer->get_num_channels(); + if (this->m_input->isComplex()) { + void *data = this->m_input->initializeTileData(rect); + int x1 = rect->xmin; + int y1 = rect->ymin; + int x2 = rect->xmax; + int y2 = rect->ymax; + int x; + int y; + bool breaked = false; + for (y = y1; y < y2 && (!breaked); y++) { + int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels; + for (x = x1; x < x2; x++) { + this->m_input->read(&(buffer[offset4]), x, y, data); + offset4 += num_channels; + } + if (isBraked()) { + breaked = true; + } + } + if (data) { + this->m_input->deinitializeTileData(rect, data); + data = nullptr; + } + } + else { + int x1 = rect->xmin; + int y1 = rect->ymin; + int x2 = rect->xmax; + int y2 = rect->ymax; + + int x; + int y; + bool breaked = false; + for (y = y1; y < y2 && (!breaked); y++) { + int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels; + for (x = x1; x < x2; x++) { + this->m_input->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST); + offset4 += num_channels; + } + if (isBraked()) { + breaked = true; + } + } + } + memoryBuffer->setCreatedState(); +} + +void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, + rcti * /*rect*/, + unsigned int /*chunkNumber*/, + MemoryBuffer **inputMemoryBuffers, + MemoryBuffer *outputBuffer) +{ + float *outputFloatBuffer = outputBuffer->getBuffer(); + cl_int error; + /* + * 1. create cl_mem from outputbuffer + * 2. call NodeOperation (input) executeOpenCLChunk(.....) + * 3. schedule read back from opencl to main device (outputbuffer) + * 4. schedule native callback + * + * note: list of cl_mem will be filled by 2, and needs to be cleaned up by 4 + */ + // STEP 1 + const unsigned int outputBufferWidth = outputBuffer->getWidth(); + const unsigned int outputBufferHeight = outputBuffer->getHeight(); + + const cl_image_format *imageFormat = OpenCLDevice::determineImageFormat(outputBuffer); + + cl_mem clOutputBuffer = clCreateImage2D(device->getContext(), + CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, + imageFormat, + outputBufferWidth, + outputBufferHeight, + 0, + outputFloatBuffer, + &error); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + + // STEP 2 + std::list *clMemToCleanUp = new std::list(); + clMemToCleanUp->push_back(clOutputBuffer); + std::list *clKernelsToCleanUp = new std::list(); + + this->m_input->executeOpenCL(device, + outputBuffer, + clOutputBuffer, + inputMemoryBuffers, + clMemToCleanUp, + clKernelsToCleanUp); + + // STEP 3 + + size_t origin[3] = {0, 0, 0}; + size_t region[3] = {outputBufferWidth, outputBufferHeight, 1}; + + // clFlush(queue); + // clFinish(queue); + + error = clEnqueueBarrier(device->getQueue()); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + error = clEnqueueReadImage(device->getQueue(), + clOutputBuffer, + CL_TRUE, + origin, + region, + 0, + 0, + outputFloatBuffer, + 0, + nullptr, + nullptr); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + + this->getMemoryProxy()->getBuffer()->copyContentFrom(outputBuffer); + + // STEP 4 + while (!clMemToCleanUp->empty()) { + cl_mem mem = clMemToCleanUp->front(); + error = clReleaseMemObject(mem); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + clMemToCleanUp->pop_front(); + } + + while (!clKernelsToCleanUp->empty()) { + cl_kernel kernel = clKernelsToCleanUp->front(); + error = clReleaseKernel(kernel); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + clKernelsToCleanUp->pop_front(); + } + delete clKernelsToCleanUp; +} + +void WriteBufferOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + NodeOperation::determineResolution(resolution, preferredResolution); + /* make sure there is at least one pixel stored in case the input is a single value */ + m_single_value = false; + if (resolution[0] == 0) { + resolution[0] = 1; + m_single_value = true; + } + if (resolution[1] == 0) { + resolution[1] = 1; + m_single_value = true; + } +} + +void WriteBufferOperation::readResolutionFromInputSocket() +{ + NodeOperation *inputOperation = this->getInputOperation(0); + this->setWidth(inputOperation->getWidth()); + this->setHeight(inputOperation->getHeight()); +} diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp deleted file mode 100644 index 8d38dbfe180..00000000000 --- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_WriteBufferOperation.h" -#include "COM_OpenCLDevice.h" -#include "COM_defines.h" -#include - -WriteBufferOperation::WriteBufferOperation(DataType datatype) -{ - this->addInputSocket(datatype); - this->m_memoryProxy = new MemoryProxy(datatype); - this->m_memoryProxy->setWriteBufferOperation(this); - this->m_memoryProxy->setExecutor(nullptr); -} -WriteBufferOperation::~WriteBufferOperation() -{ - if (this->m_memoryProxy) { - delete this->m_memoryProxy; - this->m_memoryProxy = nullptr; - } -} - -void WriteBufferOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - this->m_input->readSampled(output, x, y, sampler); -} - -void WriteBufferOperation::initExecution() -{ - this->m_input = this->getInputOperation(0); - this->m_memoryProxy->allocate(this->m_width, this->m_height); -} - -void WriteBufferOperation::deinitExecution() -{ - this->m_input = nullptr; - this->m_memoryProxy->free(); -} - -void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) -{ - MemoryBuffer *memoryBuffer = this->m_memoryProxy->getBuffer(); - float *buffer = memoryBuffer->getBuffer(); - const int num_channels = memoryBuffer->get_num_channels(); - if (this->m_input->isComplex()) { - void *data = this->m_input->initializeTileData(rect); - int x1 = rect->xmin; - int y1 = rect->ymin; - int x2 = rect->xmax; - int y2 = rect->ymax; - int x; - int y; - bool breaked = false; - for (y = y1; y < y2 && (!breaked); y++) { - int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels; - for (x = x1; x < x2; x++) { - this->m_input->read(&(buffer[offset4]), x, y, data); - offset4 += num_channels; - } - if (isBraked()) { - breaked = true; - } - } - if (data) { - this->m_input->deinitializeTileData(rect, data); - data = nullptr; - } - } - else { - int x1 = rect->xmin; - int y1 = rect->ymin; - int x2 = rect->xmax; - int y2 = rect->ymax; - - int x; - int y; - bool breaked = false; - for (y = y1; y < y2 && (!breaked); y++) { - int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels; - for (x = x1; x < x2; x++) { - this->m_input->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST); - offset4 += num_channels; - } - if (isBraked()) { - breaked = true; - } - } - } - memoryBuffer->setCreatedState(); -} - -void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, - rcti * /*rect*/, - unsigned int /*chunkNumber*/, - MemoryBuffer **inputMemoryBuffers, - MemoryBuffer *outputBuffer) -{ - float *outputFloatBuffer = outputBuffer->getBuffer(); - cl_int error; - /* - * 1. create cl_mem from outputbuffer - * 2. call NodeOperation (input) executeOpenCLChunk(.....) - * 3. schedule read back from opencl to main device (outputbuffer) - * 4. schedule native callback - * - * note: list of cl_mem will be filled by 2, and needs to be cleaned up by 4 - */ - // STEP 1 - const unsigned int outputBufferWidth = outputBuffer->getWidth(); - const unsigned int outputBufferHeight = outputBuffer->getHeight(); - - const cl_image_format *imageFormat = OpenCLDevice::determineImageFormat(outputBuffer); - - cl_mem clOutputBuffer = clCreateImage2D(device->getContext(), - CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, - imageFormat, - outputBufferWidth, - outputBufferHeight, - 0, - outputFloatBuffer, - &error); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - - // STEP 2 - std::list *clMemToCleanUp = new std::list(); - clMemToCleanUp->push_back(clOutputBuffer); - std::list *clKernelsToCleanUp = new std::list(); - - this->m_input->executeOpenCL(device, - outputBuffer, - clOutputBuffer, - inputMemoryBuffers, - clMemToCleanUp, - clKernelsToCleanUp); - - // STEP 3 - - size_t origin[3] = {0, 0, 0}; - size_t region[3] = {outputBufferWidth, outputBufferHeight, 1}; - - // clFlush(queue); - // clFinish(queue); - - error = clEnqueueBarrier(device->getQueue()); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - error = clEnqueueReadImage(device->getQueue(), - clOutputBuffer, - CL_TRUE, - origin, - region, - 0, - 0, - outputFloatBuffer, - 0, - nullptr, - nullptr); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - - this->getMemoryProxy()->getBuffer()->copyContentFrom(outputBuffer); - - // STEP 4 - while (!clMemToCleanUp->empty()) { - cl_mem mem = clMemToCleanUp->front(); - error = clReleaseMemObject(mem); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - clMemToCleanUp->pop_front(); - } - - while (!clKernelsToCleanUp->empty()) { - cl_kernel kernel = clKernelsToCleanUp->front(); - error = clReleaseKernel(kernel); - if (error != CL_SUCCESS) { - printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); - } - clKernelsToCleanUp->pop_front(); - } - delete clKernelsToCleanUp; -} - -void WriteBufferOperation::determineResolution(unsigned int resolution[2], - unsigned int preferredResolution[2]) -{ - NodeOperation::determineResolution(resolution, preferredResolution); - /* make sure there is at least one pixel stored in case the input is a single value */ - m_single_value = false; - if (resolution[0] == 0) { - resolution[0] = 1; - m_single_value = true; - } - if (resolution[1] == 0) { - resolution[1] = 1; - m_single_value = true; - } -} - -void WriteBufferOperation::readResolutionFromInputSocket() -{ - NodeOperation *inputOperation = this->getInputOperation(0); - this->setWidth(inputOperation->getWidth()); - this->setHeight(inputOperation->getHeight()); -} diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cc b/source/blender/compositor/operations/COM_ZCombineOperation.cc new file mode 100644 index 00000000000..26d3f2c7dc4 --- /dev/null +++ b/source/blender/compositor/operations/COM_ZCombineOperation.cc @@ -0,0 +1,160 @@ +/* + * 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. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_ZCombineOperation.h" +#include "BLI_utildefines.h" + +ZCombineOperation::ZCombineOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + + this->m_image1Reader = nullptr; + this->m_depth1Reader = nullptr; + this->m_image2Reader = nullptr; + this->m_depth2Reader = nullptr; +} + +void ZCombineOperation::initExecution() +{ + this->m_image1Reader = this->getInputSocketReader(0); + this->m_depth1Reader = this->getInputSocketReader(1); + this->m_image2Reader = this->getInputSocketReader(2); + this->m_depth2Reader = this->getInputSocketReader(3); +} + +void ZCombineOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float depth1[4]; + float depth2[4]; + + this->m_depth1Reader->readSampled(depth1, x, y, sampler); + this->m_depth2Reader->readSampled(depth2, x, y, sampler); + if (depth1[0] < depth2[0]) { + this->m_image1Reader->readSampled(output, x, y, sampler); + } + else { + this->m_image2Reader->readSampled(output, x, y, sampler); + } +} +void ZCombineAlphaOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float depth1[4]; + float depth2[4]; + float color1[4]; + float color2[4]; + + this->m_depth1Reader->readSampled(depth1, x, y, sampler); + this->m_depth2Reader->readSampled(depth2, x, y, sampler); + if (depth1[0] <= depth2[0]) { + this->m_image1Reader->readSampled(color1, x, y, sampler); + this->m_image2Reader->readSampled(color2, x, y, sampler); + } + else { + this->m_image1Reader->readSampled(color2, x, y, sampler); + this->m_image2Reader->readSampled(color1, x, y, sampler); + } + float fac = color1[3]; + float ifac = 1.0f - fac; + output[0] = fac * color1[0] + ifac * color2[0]; + output[1] = fac * color1[1] + ifac * color2[1]; + output[2] = fac * color1[2] + ifac * color2[2]; + output[3] = MAX2(color1[3], color2[3]); +} + +void ZCombineOperation::deinitExecution() +{ + this->m_image1Reader = nullptr; + this->m_depth1Reader = nullptr; + this->m_image2Reader = nullptr; + this->m_depth2Reader = nullptr; +} + +// MASK combine +ZCombineMaskOperation::ZCombineMaskOperation() +{ + this->addInputSocket(COM_DT_VALUE); // mask + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + + this->m_maskReader = nullptr; + this->m_image1Reader = nullptr; + this->m_image2Reader = nullptr; +} + +void ZCombineMaskOperation::initExecution() +{ + this->m_maskReader = this->getInputSocketReader(0); + this->m_image1Reader = this->getInputSocketReader(1); + this->m_image2Reader = this->getInputSocketReader(2); +} + +void ZCombineMaskOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float mask[4]; + float color1[4]; + float color2[4]; + + this->m_maskReader->readSampled(mask, x, y, sampler); + this->m_image1Reader->readSampled(color1, x, y, sampler); + this->m_image2Reader->readSampled(color2, x, y, sampler); + + interp_v4_v4v4(output, color1, color2, 1.0f - mask[0]); +} + +void ZCombineMaskAlphaOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float mask[4]; + float color1[4]; + float color2[4]; + + this->m_maskReader->readSampled(mask, x, y, sampler); + this->m_image1Reader->readSampled(color1, x, y, sampler); + this->m_image2Reader->readSampled(color2, x, y, sampler); + + float fac = (1.0f - mask[0]) * (1.0f - color1[3]) + mask[0] * color2[3]; + float mfac = 1.0f - fac; + + output[0] = color1[0] * mfac + color2[0] * fac; + output[1] = color1[1] * mfac + color2[1] * fac; + output[2] = color1[2] * mfac + color2[2] * fac; + output[3] = MAX2(color1[3], color2[3]); +} + +void ZCombineMaskOperation::deinitExecution() +{ + this->m_image1Reader = nullptr; + this->m_maskReader = nullptr; + this->m_image2Reader = nullptr; +} diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cpp b/source/blender/compositor/operations/COM_ZCombineOperation.cpp deleted file mode 100644 index 26d3f2c7dc4..00000000000 --- a/source/blender/compositor/operations/COM_ZCombineOperation.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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. - * - * Copyright 2011, Blender Foundation. - */ - -#include "COM_ZCombineOperation.h" -#include "BLI_utildefines.h" - -ZCombineOperation::ZCombineOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - - this->m_image1Reader = nullptr; - this->m_depth1Reader = nullptr; - this->m_image2Reader = nullptr; - this->m_depth2Reader = nullptr; -} - -void ZCombineOperation::initExecution() -{ - this->m_image1Reader = this->getInputSocketReader(0); - this->m_depth1Reader = this->getInputSocketReader(1); - this->m_image2Reader = this->getInputSocketReader(2); - this->m_depth2Reader = this->getInputSocketReader(3); -} - -void ZCombineOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float depth1[4]; - float depth2[4]; - - this->m_depth1Reader->readSampled(depth1, x, y, sampler); - this->m_depth2Reader->readSampled(depth2, x, y, sampler); - if (depth1[0] < depth2[0]) { - this->m_image1Reader->readSampled(output, x, y, sampler); - } - else { - this->m_image2Reader->readSampled(output, x, y, sampler); - } -} -void ZCombineAlphaOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float depth1[4]; - float depth2[4]; - float color1[4]; - float color2[4]; - - this->m_depth1Reader->readSampled(depth1, x, y, sampler); - this->m_depth2Reader->readSampled(depth2, x, y, sampler); - if (depth1[0] <= depth2[0]) { - this->m_image1Reader->readSampled(color1, x, y, sampler); - this->m_image2Reader->readSampled(color2, x, y, sampler); - } - else { - this->m_image1Reader->readSampled(color2, x, y, sampler); - this->m_image2Reader->readSampled(color1, x, y, sampler); - } - float fac = color1[3]; - float ifac = 1.0f - fac; - output[0] = fac * color1[0] + ifac * color2[0]; - output[1] = fac * color1[1] + ifac * color2[1]; - output[2] = fac * color1[2] + ifac * color2[2]; - output[3] = MAX2(color1[3], color2[3]); -} - -void ZCombineOperation::deinitExecution() -{ - this->m_image1Reader = nullptr; - this->m_depth1Reader = nullptr; - this->m_image2Reader = nullptr; - this->m_depth2Reader = nullptr; -} - -// MASK combine -ZCombineMaskOperation::ZCombineMaskOperation() -{ - this->addInputSocket(COM_DT_VALUE); // mask - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - - this->m_maskReader = nullptr; - this->m_image1Reader = nullptr; - this->m_image2Reader = nullptr; -} - -void ZCombineMaskOperation::initExecution() -{ - this->m_maskReader = this->getInputSocketReader(0); - this->m_image1Reader = this->getInputSocketReader(1); - this->m_image2Reader = this->getInputSocketReader(2); -} - -void ZCombineMaskOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float mask[4]; - float color1[4]; - float color2[4]; - - this->m_maskReader->readSampled(mask, x, y, sampler); - this->m_image1Reader->readSampled(color1, x, y, sampler); - this->m_image2Reader->readSampled(color2, x, y, sampler); - - interp_v4_v4v4(output, color1, color2, 1.0f - mask[0]); -} - -void ZCombineMaskAlphaOperation::executePixelSampled(float output[4], - float x, - float y, - PixelSampler sampler) -{ - float mask[4]; - float color1[4]; - float color2[4]; - - this->m_maskReader->readSampled(mask, x, y, sampler); - this->m_image1Reader->readSampled(color1, x, y, sampler); - this->m_image2Reader->readSampled(color2, x, y, sampler); - - float fac = (1.0f - mask[0]) * (1.0f - color1[3]) + mask[0] * color2[3]; - float mfac = 1.0f - fac; - - output[0] = color1[0] * mfac + color2[0] * fac; - output[1] = color1[1] * mfac + color2[1] * fac; - output[2] = color1[2] * mfac + color2[2] * fac; - output[3] = MAX2(color1[3], color2[3]); -} - -void ZCombineMaskOperation::deinitExecution() -{ - this->m_image1Reader = nullptr; - this->m_maskReader = nullptr; - this->m_image2Reader = nullptr; -} -- cgit v1.2.3 From 9ba1ff1c6322cbacaaf7fad057cc507673dcd92d Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Mon, 8 Mar 2021 13:38:42 +0100 Subject: Fix T86373: crash picking colors in geometry nodesockets Caused by {rB85421c4fab02}. Above commit treated `SOCK_RGBA` and `SOCK_STRING` the same in `std_node_socket_draw`. That would turn a RGBA button into a text button (for attribute search), leading to trouble. Note these were just treated the same prior to above commit because both were doing the layout split. Now just give RGBA sockets their own case. Maniphest Tasks: T86373 Differential Revision: https://developer.blender.org/D10646 --- source/blender/editors/space_node/drawnode.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 977c2053187..a9a7ef5a0a2 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3385,7 +3385,12 @@ static void std_node_socket_draw( } } break; - case SOCK_RGBA: + case SOCK_RGBA: { + uiLayout *row = uiLayoutSplit(layout, 0.5f, false); + uiItemL(row, text, 0); + uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0); + break; + } case SOCK_STRING: { uiLayout *row = uiLayoutSplit(layout, 0.5f, false); uiItemL(row, text, 0); -- cgit v1.2.3 From 240e721dd363dd894f585f33bfe6a9971cd7660a Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 3 Mar 2021 12:46:09 +0100 Subject: Fix T86210: No preview icons for non-8bit images It looks like we never generated correct icon previews for images with float_rects (non-8bit-images). Images from the report were 16bit pngs. In this case, `icon_preview_startjob` would return early (it only checked if the ImBuf `rect` was NULL -- which is the case if it has a `rect_float` instead). This is not neccessary since `icon_copy_rect` is perfectly capable of taking float rects. Now correct the check and only return early if both `rect` & `rect_float` are NULL. note: this will not refresh icon previews from existing files automatically. For this, use File > Data Previews > Clear Data-Block Previews. Maniphest Tasks: T86210 Differential Revision: https://developer.blender.org/D10601 --- source/blender/editors/render/render_preview.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 9811b7caa38..1b7209b164b 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -1342,7 +1342,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat * already there. Very expensive for large images. Need to find a way to * only get existing ibuf */ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); - if (ibuf == NULL || ibuf->rect == NULL) { + if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) { BKE_image_release_ibuf(ima, ibuf, NULL); return; } -- cgit v1.2.3 From 3669a3e2e95ca0dc63afec69e49a4b99cc2ab5c2 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 8 Mar 2021 13:59:16 +0100 Subject: Fix Cycles CUDA build error with Visual Studio 2019 v16.9 Something in this update broke the floor() function in CUDA, instead use floorf() like we do everywhere else in the kernel code. Thanks to Ray Molenkamp for identifying the solution. --- intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h b/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h index 82ad9225fc3..132653fa7ca 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h +++ b/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h @@ -68,8 +68,8 @@ ccl_device T kernel_tex_image_interp_bicubic(const TextureInfo &info, float x, f x = (x * info.width) - 0.5f; y = (y * info.height) - 0.5f; - float px = floor(x); - float py = floor(y); + float px = floorf(x); + float py = floorf(y); float fx = x - px; float fy = y - py; @@ -95,9 +95,9 @@ ccl_device T kernel_tex_image_interp_tricubic(const TextureInfo &info, float x, y = (y * info.height) - 0.5f; z = (z * info.depth) - 0.5f; - float px = floor(x); - float py = floor(y); - float pz = floor(z); + float px = floorf(x); + float py = floorf(y); + float pz = floorf(z); float fx = x - px; float fy = y - py; float fz = z - pz; @@ -127,9 +127,9 @@ ccl_device T kernel_tex_image_interp_tricubic(const TextureInfo &info, float x, template ccl_device T kernel_tex_image_interp_tricubic_nanovdb(S &s, float x, float y, float z) { - float px = floor(x); - float py = floor(y); - float pz = floor(z); + float px = floorf(x); + float py = floorf(y); + float pz = floorf(z); float fx = x - px; float fy = y - py; float fz = z - pz; -- cgit v1.2.3 From 171ba4243941770351e8190a1690e4ba61d25abf Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 9 Mar 2021 00:24:51 +1100 Subject: Fix error in unused argument cleanup Bad keyword argument rename from 9dc0c44aa102b5a7dae1fe92fd9105231ab1798c --- release/scripts/startup/bl_ui/space_toolsystem_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py index 25f2a740f7c..12ec863327c 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_common.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py @@ -1022,7 +1022,7 @@ def activate_by_id(context, space_type, idname, *, as_fallback=False): return True -def activate_by_id_or_cycle(context, space_type, idname, *, offset=1, _as_fallback=False): +def activate_by_id_or_cycle(context, space_type, idname, *, offset=1, as_fallback=False): # Only cycle when the active tool is activated again. cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) -- cgit v1.2.3 From b6c07d69e2f022f024c6ec2ff92925dbc6bbd79e Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Mon, 8 Mar 2021 10:29:57 -0300 Subject: Fix T86106: bpy.types.SpaceView3D.draw_handler_remove(...) causes Blender to crash The handle of a drawing callback can be removed within the drawing function itself. This causes `var = (type)(((Link *)(var))->next` to read an invalid memory value in C. --- source/blender/editors/space_api/spacetypes.c | 2 +- source/blender/windowmanager/intern/wm_draw.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 1bd8d13b25b..ff05fb3bad6 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -262,7 +262,7 @@ void ED_region_draw_cb_exit(ARegionType *art, void *handle) void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type) { - LISTBASE_FOREACH (RegionDrawCB *, rdc, ®ion->type->drawcalls) { + LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, ®ion->type->drawcalls) { if (rdc->type == type) { rdc->draw(C, region, rdc->customdata); diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 071bce822a5..e0c4ab8eaf3 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -98,7 +98,7 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region) return; } - LISTBASE_FOREACH (wmPaintCursor *, pc, &wm->paintcursors) { + LISTBASE_FOREACH_MUTABLE (wmPaintCursor *, pc, &wm->paintcursors) { if ((pc->space_type != SPACE_TYPE_ANY) && (area->spacetype != pc->space_type)) { continue; } -- cgit v1.2.3 From 09a8f5ebcab446758b37d5359dff77ea4edcf7d6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 9 Mar 2021 00:42:56 +1100 Subject: Fix T86384: Click detection fails in some cases with modifiers Regression in b5d154f400e46ba322f0e08a231bb2557bf51a1e --- source/blender/windowmanager/intern/wm_event_system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 4c4523c80bc..470952956c8 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -3002,7 +3002,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) * wasn't handled, the KM_RELEASE will become a KM_CLICK */ if (event->val == KM_PRESS) { - if (event->prevval != KM_PRESS) { + if (event->is_repeat == false) { win->event_queue_check_click = true; win->event_queue_check_drag = true; } -- cgit v1.2.3 From cfd11af9819433c5b83359b72f002fcd59fdc1ab Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 9 Mar 2021 00:53:13 +1100 Subject: readfile: add id_tag_extra argument This allows adding ID tags when linking/loading data. This is needed to implement loading non 'G.main' ID data-blocks, see D10612. --- .../blender/blenkernel/intern/blender_copybuffer.c | 7 ++++-- source/blender/blenloader/BLO_readfile.h | 6 +++++- source/blender/blenloader/intern/readfile.c | 25 ++++++++++++++++------ source/blender/blenloader/intern/readfile.h | 8 +++++++ source/blender/python/intern/bpy_library_load.c | 2 +- .../blender/windowmanager/intern/wm_files_link.c | 3 ++- 6 files changed, 39 insertions(+), 12 deletions(-) diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index 9f5e038fb82..ec8962d5f6d 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -94,8 +94,9 @@ bool BKE_copybuffer_read(Main *bmain_dst, } /* Here appending/linking starts. */ const int flag = 0; + const int id_tag_extra = 0; struct LibraryLink_Params liblink_params; - BLO_library_link_params_init(&liblink_params, bmain_dst, flag); + BLO_library_link_params_init(&liblink_params, bmain_dst, flag, id_tag_extra); Main *mainl = BLO_library_link_begin(&bh, libname, &liblink_params); BLO_library_link_copypaste(mainl, bh, id_types_mask); BLO_library_link_end(mainl, &bh, &liblink_params); @@ -130,6 +131,7 @@ int BKE_copybuffer_paste(bContext *C, Main *mainl = NULL; Library *lib; BlendHandle *bh; + const int id_tag_extra = 0; bh = BLO_blendhandle_from_file(libname, reports); @@ -148,7 +150,8 @@ int BKE_copybuffer_paste(bContext *C, /* here appending/linking starts */ struct LibraryLink_Params liblink_params; - BLO_library_link_params_init_with_context(&liblink_params, bmain, flag, scene, view_layer, v3d); + BLO_library_link_params_init_with_context( + &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d); mainl = BLO_library_link_begin(&bh, libname, &liblink_params); const int num_pasted = BLO_library_link_copypaste(mainl, bh, id_types_mask); diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index c7f02de21ea..09f4c405613 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -182,6 +182,8 @@ struct LibraryLink_Params { struct Main *bmain; /** Options for linking, used for instantiating. */ int flag; + /** Additional tag for #ID.tag. */ + int id_tag_extra; /** Context for instancing objects (optional, no instantiation will be performed when NULL). */ struct { /** The scene in which to instantiate objects/collections. */ @@ -195,10 +197,12 @@ struct LibraryLink_Params { void BLO_library_link_params_init(struct LibraryLink_Params *params, struct Main *bmain, - const int flag); + const int flag, + const int id_tag_extra); void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params, struct Main *bmain, const int flag, + const int id_tag_extra, struct Scene *scene, struct ViewLayer *view_layer, const struct View3D *v3d); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 2eba9af233c..aa3362aa211 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4411,7 +4411,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) if (id == NULL) { /* ID has not been read yet, add placeholder to the main of the * library it belongs to, so that it will be read later. */ - read_libblock(fd, libmain, bhead, LIB_TAG_INDIRECT, false, NULL); + read_libblock(fd, libmain, bhead, fd->id_tag_extra | LIB_TAG_INDIRECT, false, NULL); /* commented because this can print way too much */ // if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->filepath); @@ -4466,7 +4466,12 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) ID *id = is_yet_read(fd, mainvar, bhead); if (id == NULL) { - read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, NULL); + read_libblock(fd, + mainvar, + bhead, + fd->id_tag_extra | LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, + false, + NULL); } else { /* Convert any previously read weak link to regular link @@ -4847,7 +4852,7 @@ static ID *link_named_part( id = is_yet_read(fd, mainl, bhead); if (id == NULL) { /* not read yet */ - const int tag = force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN; + const int tag = ((force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN) | fd->id_tag_extra); read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, false, &id); if (id) { @@ -4988,10 +4993,13 @@ static void library_link_clear_tag(Main *mainvar, const int flag) } } -static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepath, const int flag) +static Main *library_link_begin( + Main *mainvar, FileData **fd, const char *filepath, const int flag, const int id_tag_extra) { Main *mainl; + (*fd)->id_tag_extra = id_tag_extra; + (*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist"); if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) { @@ -5017,22 +5025,25 @@ static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepa void BLO_library_link_params_init(struct LibraryLink_Params *params, struct Main *bmain, - const int flag) + const int flag, + const int id_tag_extra) { memset(params, 0, sizeof(*params)); params->bmain = bmain; params->flag = flag; + params->id_tag_extra = id_tag_extra; } void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params, struct Main *bmain, const int flag, + const int id_tag_extra, /* Context arguments. */ struct Scene *scene, struct ViewLayer *view_layer, const struct View3D *v3d) { - BLO_library_link_params_init(params, bmain, flag); + BLO_library_link_params_init(params, bmain, flag, id_tag_extra); if (scene != NULL) { /* Tagging is needed for instancing. */ params->flag |= BLO_LIBLINK_NEEDS_ID_TAG_DOIT; @@ -5057,7 +5068,7 @@ Main *BLO_library_link_begin(BlendHandle **bh, const struct LibraryLink_Params *params) { FileData *fd = (FileData *)(*bh); - return library_link_begin(params->bmain, &fd, filepath, params->flag); + return library_link_begin(params->bmain, &fd, filepath, params->flag, params->id_tag_extra); } static void split_main_newid(Main *mainptr, Main *main_newid) diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index 7c14c7a19bf..9682b5456d2 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -120,6 +120,14 @@ typedef struct FileData { /** Optionally skip some data-blocks when they're not needed. */ eBLOReadSkip skip_flags; + /** + * Tag to apply to all loaded ID data-blocks. + * + * \note This is initialized from #LibraryLink_Params.id_tag_extra since passing it as an + * argument would need an additional argument to be passed around when expanding library data. + */ + int id_tag_extra; + struct OldNewMap *datamap; struct OldNewMap *globmap; struct OldNewMap *libmap; diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 03771a8c294..5d9adb08f3d 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -345,7 +345,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) /* here appending/linking starts */ struct LibraryLink_Params liblink_params; - BLO_library_link_params_init(&liblink_params, bmain, self->flag); + BLO_library_link_params_init(&liblink_params, bmain, self->flag, 0); mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params); diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 6a1fc84774c..bf7cf81f0a9 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -229,6 +229,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data, Library *lib; const int flag = lapp_data->flag; + const int id_tag_extra = 0; LinkNode *liblink, *itemlink; int lib_idx, item_idx; @@ -255,7 +256,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data, /* here appending/linking starts */ struct LibraryLink_Params liblink_params; BLO_library_link_params_init_with_context( - &liblink_params, bmain, flag, scene, view_layer, v3d); + &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d); mainl = BLO_library_link_begin(&bh, libname, &liblink_params); lib = mainl->curlib; -- cgit v1.2.3 From 9e0921497912cbfe9846358d1cb1220f88315f80 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 9 Mar 2021 01:01:31 +1100 Subject: PyAPI: add bpy.types.BlendFile.temp_data for temporary library loading This adds support for creating a `BlendFile` (internally called `Main`), which is limited to a context. Temporary data can now be created which can then use `.libraries.load()` the same as with `bpy.data`. To prevent errors caused by mixing the temporary ID's with data in `bpy.data` they are tagged as temporary so they can't be assigned to properties, however they can be passed as arguments to functions. Reviewed By: mont29, sybren Ref D10612 --- source/blender/blenkernel/intern/lib_id.c | 1 + source/blender/blenloader/intern/readfile.c | 13 +- source/blender/blenloader/intern/versioning_250.c | 4 +- source/blender/makesdna/DNA_ID.h | 6 + source/blender/python/intern/CMakeLists.txt | 2 + source/blender/python/intern/bpy.c | 3 + source/blender/python/intern/bpy_library_load.c | 16 +- source/blender/python/intern/bpy_rna.c | 13 ++ source/blender/python/intern/bpy_rna_data.c | 219 ++++++++++++++++++++++ source/blender/python/intern/bpy_rna_data.h | 29 +++ source/blender/python/intern/bpy_rna_types_capi.c | 7 +- 11 files changed, 306 insertions(+), 7 deletions(-) create mode 100644 source/blender/python/intern/bpy_rna_data.c create mode 100644 source/blender/python/intern/bpy_rna_data.h diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index a511c1f9c4c..f3a1c01ad26 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -1139,6 +1139,7 @@ static uint global_session_uuid = 0; void BKE_lib_libblock_session_uuid_ensure(ID *id) { if (id->session_uuid == MAIN_ID_SESSION_UUID_UNSET) { + BLI_assert((id->tag & LIB_TAG_TEMP_MAIN) == 0); /* Caller must ensure this. */ id->session_uuid = atomic_add_and_fetch_uint32(&global_session_uuid, 1); /* In case overflow happens, still assign a valid ID. This way opening files many times works * correctly. */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index aa3362aa211..de7353d827a 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2424,7 +2424,9 @@ static void direct_link_id_common( id->session_uuid = MAIN_ID_SESSION_UUID_UNSET; } - BKE_lib_libblock_session_uuid_ensure(id); + if ((tag & LIB_TAG_TEMP_MAIN) == 0) { + BKE_lib_libblock_session_uuid_ensure(id); + } id->lib = current_library; id->us = ID_FAKE_USERS(id); @@ -3168,7 +3170,9 @@ static ID *create_placeholder(Main *mainvar, const short idcode, const char *idn BLI_addtail(lb, ph_id); id_sort_by_name(lb, ph_id, NULL); - BKE_lib_libblock_session_uuid_ensure(ph_id); + if ((tag & LIB_TAG_TEMP_MAIN) == 0) { + BKE_lib_libblock_session_uuid_ensure(ph_id); + } return ph_id; } @@ -4998,6 +5002,11 @@ static Main *library_link_begin( { Main *mainl; + /* Only allow specific tags to be set as extra, + * otherwise this could conflict with library loading logic. + * Other flags can be added here, as long as they are safe. */ + BLI_assert((id_tag_extra & ~LIB_TAG_TEMP_MAIN) == 0); + (*fd)->id_tag_extra = id_tag_extra; (*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist"); diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 983fdce15f1..467fd8b0399 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -449,7 +449,9 @@ static void versions_gpencil_add_main(ListBase *lb, ID *id, const char *name) BKE_id_new_name_validate(lb, id, name); /* alphabetic insertion: is in BKE_id_new_name_validate */ - BKE_lib_libblock_session_uuid_ensure(id); + if ((id->tag & LIB_TAG_TEMP_MAIN) == 0) { + BKE_lib_libblock_session_uuid_ensure(id); + } if (G.debug & G_DEBUG) { printf("Converted GPencil to ID: %s\n", id->name + 2); diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 14f0fef5270..c708219cfe8 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -566,6 +566,12 @@ enum { /* RESET_AFTER_USE Used by undo system to tag unchanged IDs re-used from old Main (instead of * read from memfile). */ LIB_TAG_UNDO_OLD_ID_REUSED = 1 << 19, + + /* This ID is part of a temporary #Main which is expected to be freed in a short time-frame. + * Don't allow assigning this to non-temporary members (since it's likely to cause errors). + * When set #ID.session_uuid isn't initialized, since the data isn't part of the session. */ + LIB_TAG_TEMP_MAIN = 1 << 20, + }; /* Tag given ID for an update in all the dependency graphs. */ diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 5d8330e368d..56ef5c8187a 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -75,6 +75,7 @@ set(SRC bpy_rna_anim.c bpy_rna_array.c bpy_rna_callback.c + bpy_rna_data.c bpy_rna_driver.c bpy_rna_gizmo.c bpy_rna_id_collection.c @@ -113,6 +114,7 @@ set(SRC bpy_rna.h bpy_rna_anim.h bpy_rna_callback.h + bpy_rna_data.h bpy_rna_driver.h bpy_rna_gizmo.h bpy_rna_id_collection.h diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 74fc8bcfec9..547cf2ad38f 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -44,6 +44,7 @@ #include "bpy_operator.h" #include "bpy_props.h" #include "bpy_rna.h" +#include "bpy_rna_data.h" #include "bpy_rna_gizmo.h" #include "bpy_rna_id_collection.h" #include "bpy_rna_types_capi.h" @@ -425,6 +426,8 @@ void BPy_init_modules(struct bContext *C) /* needs to be first so bpy_types can run */ BPY_library_load_type_ready(); + BPY_rna_data_context_type_ready(); + BPY_rna_gizmo_module(mod); bpy_import_test("bpy_types"); diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 5d9adb08f3d..1ee14df24cf 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -34,6 +34,7 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_context.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -67,8 +68,10 @@ typedef struct { BlendHandle *blo_handle; int flag; PyObject *dict; - /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries. */ + /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries. + * Defaults to #G.main, Otherwise use a temporary #Main when `bmain_is_temp` is true. */ Main *bmain; + bool bmain_is_temp; } BPy_Library; static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kwds); @@ -185,6 +188,7 @@ PyDoc_STRVAR( " :type assets_only: bool\n"); static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kw) { + Main *bmain_base = CTX_data_main(BPY_context_get()); Main *bmain = self->ptr.data; /* Typically #G_MAIN */ BPy_Library *ret; const char *filename = NULL; @@ -212,6 +216,7 @@ static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *k BLI_path_abs(ret->abspath, BKE_main_blendfile_path(bmain)); ret->bmain = bmain; + ret->bmain_is_temp = (bmain != bmain_base); ret->blo_handle = NULL; ret->flag = ((is_link ? FILE_LINK : 0) | (is_rel ? FILE_RELPATH : 0) | @@ -344,8 +349,9 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); /* here appending/linking starts */ + const int id_tag_extra = self->bmain_is_temp ? LIB_TAG_TEMP_MAIN : 0; struct LibraryLink_Params liblink_params; - BLO_library_link_params_init(&liblink_params, bmain, self->flag, 0); + BLO_library_link_params_init(&liblink_params, bmain, self->flag, id_tag_extra); mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params); @@ -372,6 +378,12 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) ID *id = BLO_library_link_named_part( mainl, &(self->blo_handle), idcode, item_idname, &liblink_params); if (id) { + + if (self->bmain_is_temp) { + /* If this fails, #LibraryLink_Params.id_tag_extra is not being applied. */ + BLI_assert(id->tag & LIB_TAG_TEMP_MAIN); + } + #ifdef USE_RNA_DATABLOCKS /* swap name for pointer to the id */ item_dst = PyCapsule_New((void *)id, NULL, NULL); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index ecaa5791e38..7a43c9cb997 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -2061,6 +2061,19 @@ static int pyrna_py_to_prop( Py_XDECREF(value_new); return -1; } + + if (value_owner_id->tag & LIB_TAG_TEMP_MAIN) { + /* Allow passing temporary ID's to functions, but not attribute assignment. */ + if (ptr->type != &RNA_Function) { + PyErr_Format(PyExc_TypeError, + "%.200s %.200s.%.200s ID type assignment is temporary, can't assign", + error_prefix, + RNA_struct_identifier(ptr->type), + RNA_property_identifier(prop)); + Py_XDECREF(value_new); + return -1; + } + } } } diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c new file mode 100644 index 00000000000..3771cc05490 --- /dev/null +++ b/source/blender/python/intern/bpy_rna_data.c @@ -0,0 +1,219 @@ +/* + * 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. + */ + +/** \file + * \ingroup pythonintern + * + * This file defines the API to support temporarily creating #Main data. + * The only use case for this is currently to support temporarily loading data-blocks + * which can be freed, without them polluting the current #G_MAIN. + * + * This is exposed via a context manager `bpy.types.BlendData.temp_data(...)` + * which returns a new `bpy.types.BlendData` that is freed once the context manager exits. + */ + +#include +#include + +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BKE_global.h" +#include "BKE_main.h" + +#include "RNA_access.h" + +#include "bpy_rna.h" +#include "bpy_rna_data.h" + +typedef struct { + PyObject_HEAD /* required python macro */ + BPy_StructRNA *data_rna; + char filepath[1024]; +} BPy_DataContext; + +static PyObject *bpy_rna_data_temp_data(PyObject *self, PyObject *args, PyObject *kwds); +static PyObject *bpy_rna_data_context_enter(BPy_DataContext *self); +static PyObject *bpy_rna_data_context_exit(BPy_DataContext *self, PyObject *args); + +static PyMethodDef bpy_rna_data_context_methods[] = { + {"__enter__", (PyCFunction)bpy_rna_data_context_enter, METH_NOARGS}, + {"__exit__", (PyCFunction)bpy_rna_data_context_exit, METH_VARARGS}, + {NULL} /* sentinel */ +}; + +static int bpy_rna_data_context_traverse(BPy_DataContext *self, visitproc visit, void *arg) +{ + Py_VISIT(self->data_rna); + return 0; +} + +static int bpy_rna_data_context_clear(BPy_DataContext *self) +{ + Py_CLEAR(self->data_rna); + return 0; +} + +static void bpy_rna_data_context_dealloc(BPy_DataContext *self) +{ + PyObject_GC_UnTrack(self); + Py_CLEAR(self->data_rna); + PyObject_GC_Del(self); +} + +static PyTypeObject bpy_rna_data_context_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "bpy_rna_data_context", /* tp_name */ + sizeof(BPy_DataContext), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)bpy_rna_data_context_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, + /* tp_compare */ /* DEPRECATED in python 3.0! */ + NULL, /* tp_repr */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + + /* will only use these if this is a subtype of a py class */ + NULL /*PyObject_GenericGetAttr is assigned later */, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + (traverseproc)bpy_rna_data_context_traverse, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + (inquiry)bpy_rna_data_context_clear, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons (subclassed) ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + bpy_rna_data_context_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL, +}; + +PyDoc_STRVAR(bpy_rna_data_context_load_doc, + ".. method:: temp_data(filepath=None)\n" + "\n" + " A context manager that temporarily creates blender file data.\n" + "\n" + " :arg filepath: The file path for the newly temporary data. " + "When None, the path of the currently open file is used.\n" + " :type filepath: str or NoneType\n" + "\n" + " :return: Blend file data which is freed once the context exists.\n" + " :rtype: :class:`bpy.types.BlendData`\n"); + +static PyObject *bpy_rna_data_temp_data(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + BPy_DataContext *ret; + const char *filepath = NULL; + static const char *_keywords[] = {"filepath", NULL}; + static _PyArg_Parser _parser = {"|$z:temp_data", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filepath)) { + return NULL; + } + + ret = PyObject_GC_New(BPy_DataContext, &bpy_rna_data_context_Type); + + STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->name); + + return (PyObject *)ret; +} + +static PyObject *bpy_rna_data_context_enter(BPy_DataContext *self) +{ + Main *bmain_temp = BKE_main_new(); + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_BlendData, bmain_temp, &ptr); + + self->data_rna = (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr); + + PyObject_GC_Track(self); + + return (PyObject *)self->data_rna; +} + +static PyObject *bpy_rna_data_context_exit(BPy_DataContext *self, PyObject *UNUSED(args)) +{ + BKE_main_free(self->data_rna->ptr.data); + RNA_POINTER_INVALIDATE(&self->data_rna->ptr); + Py_RETURN_NONE; +} + +PyMethodDef BPY_rna_data_context_method_def = { + "temp_data", + (PyCFunction)bpy_rna_data_temp_data, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_rna_data_context_load_doc, +}; + +int BPY_rna_data_context_type_ready(void) +{ + if (PyType_Ready(&bpy_rna_data_context_Type) < 0) { + return -1; + } + + return 0; +} diff --git a/source/blender/python/intern/bpy_rna_data.h b/source/blender/python/intern/bpy_rna_data.h new file mode 100644 index 00000000000..b1d226d9dc4 --- /dev/null +++ b/source/blender/python/intern/bpy_rna_data.h @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/** \file + * \ingroup pythonintern + */ + +#pragma once + +int BPY_rna_data_context_type_ready(void); + +extern PyMethodDef BPY_rna_data_context_method_def; + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c index 042f7b6fd67..9b15e84663d 100644 --- a/source/blender/python/intern/bpy_rna_types_capi.c +++ b/source/blender/python/intern/bpy_rna_types_capi.c @@ -36,6 +36,7 @@ #include "bpy_library.h" #include "bpy_rna.h" #include "bpy_rna_callback.h" +#include "bpy_rna_data.h" #include "bpy_rna_id_collection.h" #include "bpy_rna_types_capi.h" #include "bpy_rna_ui.h" @@ -56,6 +57,7 @@ static struct PyMethodDef pyrna_blenddata_methods[] = { {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_user_map_method_def */ {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_batch_remove_method_def */ {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_orphans_purge_method_def */ + {NULL, NULL, 0, NULL}, /* #BPY_rna_data_context_method_def */ {NULL, NULL, 0, NULL}, }; @@ -207,8 +209,9 @@ void BPY_rna_types_extend_capi(void) ARRAY_SET_ITEMS(pyrna_blenddata_methods, BPY_rna_id_collection_user_map_method_def, BPY_rna_id_collection_batch_remove_method_def, - BPY_rna_id_collection_orphans_purge_method_def); - BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 4); + BPY_rna_id_collection_orphans_purge_method_def, + BPY_rna_data_context_method_def); + BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 5); pyrna_struct_type_extend_capi(&RNA_BlendData, pyrna_blenddata_methods, NULL); /* BlendDataLibraries */ -- cgit v1.2.3 From 91825ebfe2cb8ecf6d5c02e11783e44aaa1add84 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Sun, 7 Mar 2021 15:12:49 +0100 Subject: UI: UVProject modifier: clarify aspect & scale are only for camera projectors Make this clear in property UI descriptions and deactivate aspect & scale fields if no camera projectors are present. ref T86268 Maniphest Tasks: T86268 Differential Revision: https://developer.blender.org/D10634 --- source/blender/makesrna/intern/rna_modifier.c | 8 ++++---- source/blender/modifiers/intern/MOD_uvproject.c | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 4f53a1e6c2b..8624384e3ec 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -3139,7 +3139,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 1, FLT_MAX); RNA_def_property_ui_range(prop, 1, 1000, 1, 3); - RNA_def_property_ui_text(prop, "Horizontal Aspect Ratio", ""); + RNA_def_property_ui_text(prop, "Aspect X", "Horizontal aspect ratio (only used for camera projectors)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "aspect_y", PROP_FLOAT, PROP_NONE); @@ -3147,7 +3147,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 1, FLT_MAX); RNA_def_property_ui_range(prop, 1, 1000, 1, 3); - RNA_def_property_ui_text(prop, "Vertical Aspect Ratio", ""); + RNA_def_property_ui_text(prop, "Aspect Y", "Vertical aspect ratio (only used for camera projectors)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "scale_x", PROP_FLOAT, PROP_NONE); @@ -3155,7 +3155,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 0, FLT_MAX); RNA_def_property_ui_range(prop, 0, 1000, 1, 3); - RNA_def_property_ui_text(prop, "Horizontal Scale", ""); + RNA_def_property_ui_text(prop, "Scale X", "Horizontal scale (only used for camera projectors)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "scale_y", PROP_FLOAT, PROP_NONE); @@ -3163,7 +3163,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 0, FLT_MAX); RNA_def_property_ui_range(prop, 0, 1000, 1, 3); - RNA_def_property_ui_text(prop, "Vertical Scale", ""); + RNA_def_property_ui_text(prop, "Scale Y", "Vertical scale (only used for camera projectors)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); srna = RNA_def_struct(brna, "UVProjector", NULL); diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index a6b83ed60ea..487250eb4e3 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -331,12 +331,24 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemPointerR(layout, ptr, "uv_layer", &obj_data_ptr, "uv_layers", NULL, ICON_NONE); + /* Aspect and Scale are only used for camera projectors. */ + bool has_camera = false; + RNA_BEGIN (ptr, projector_ptr, "projectors") { + PointerRNA ob_projector = RNA_pointer_get(&projector_ptr, "object"); + if (!RNA_pointer_is_null(&ob_projector) && RNA_enum_get(&ob_projector, "type") == OB_CAMERA) { + has_camera = true; + } + } + RNA_END; + sub = uiLayoutColumn(layout, true); - uiItemR(sub, ptr, "aspect_x", 0, IFACE_("Aspect X"), ICON_NONE); + uiLayoutSetActive(sub, has_camera); + uiItemR(sub, ptr, "aspect_x", 0, NULL, ICON_NONE); uiItemR(sub, ptr, "aspect_y", 0, IFACE_("Y"), ICON_NONE); sub = uiLayoutColumn(layout, true); - uiItemR(sub, ptr, "scale_x", 0, IFACE_("Scale X"), ICON_NONE); + uiLayoutSetActive(sub, has_camera); + uiItemR(sub, ptr, "scale_x", 0, NULL, ICON_NONE); uiItemR(sub, ptr, "scale_y", 0, IFACE_("Y"), ICON_NONE); uiItemR(layout, ptr, "projector_count", 0, IFACE_("Projectors"), ICON_NONE); -- cgit v1.2.3 From e20b31504a2381011e60c5eadffb67f18918bc71 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Sun, 7 Mar 2021 13:05:34 +0100 Subject: Fix T86347: Add Primitive Tool fails for 1x1x1 scale The Tool stores desired dimensions as `scale` and thus had to half the scale again in `make_prim_init()` because by default all primitives are created at a size of 2 in blender. This worked, but: - [1] it logged something like size=2, scale=2,2,2 for a 2x2x2 cube [which does not sound right, it should be size=2 scale=1,1,1] - [2] it had to make an exception for the case scale is exactly 1x1x1 [this happens when the property is not set specifically, e.g. adding primitives from the menu] -- this exception led to double sized primitives being created when the tool asked for exact dimensions of 1x1x1 Now - instead of compensating in `make_prim_init()` - do this earlier in the tool itself, see `view3d_interactive_add_modal`, this fixes the bug and now also correctly logs size=2 scale 0.5,0.5,0.5 for a 1x1x1 cube. Maniphest Tasks: T86347 Differential Revision: https://developer.blender.org/D10632 --- source/blender/editors/mesh/editmesh_add.c | 7 ++----- source/blender/editors/space_view3d/view3d_placement.c | 2 ++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index d60d83850a5..582ff01173a 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -75,11 +75,8 @@ static Object *make_prim_init(bContext *C, ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat); - if (scale && !equals_v3v3(scale, (const float[3]){1.0f, 1.0f, 1.0f})) { - float scale_half[3]; - copy_v3_v3(scale_half, scale); - mul_v3_fl(scale_half, 0.5f); - rescale_m4(r_creation_data->mat, scale_half); + if (scale) { + rescale_m4(r_creation_data->mat, scale); } return obedit; diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index c75d9796265..48f274ca71b 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -1438,6 +1438,8 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve const int cube_verts[3] = {3, 1, 4}; for (int i = 0; i < 3; i++) { scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]); + /* Primitives have size 2 by default, compensate for this here. */ + scale[i] /= 2.0f; } wmOperatorType *ot = NULL; -- cgit v1.2.3 From 5a67407d5aa8800faf78f40811b703d07e8f7300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 8 Mar 2021 13:57:15 +0100 Subject: File Browser: scroll selected files into view Add operator `FILE_OT_view_selected` to the file browser (and thus also to the asset browser) that scrolls selected files into view. This includes the active file, even though it is not selected. In certain cases the active file can loose its selected state (clicking next to it, or refreshing the asset browser), but then it's still shown in the right-hand sidebar. Because of this, I found it important to take it into account when scrolling. This also includes a change to the keymaps: - Blender default: {key NUMPAD_PERIOD} is removed from the "reload" operator, and assigned to the new "view selected files" operator. The reload operator was already doubly bound, and now {key R} is the only remaining hotkey for it. - Industry compatible: {key F} is assigned to the new "view selected files" operator. This is consistent with the other "view selected" operators in other editors. Reviewed By: Severin Differential Revision: https://developer.blender.org/D10583 --- .../keyconfig/keymap_data/blender_default.py | 2 +- .../keymap_data/industry_compatible_data.py | 1 + release/scripts/startup/bl_ui/space_filebrowser.py | 1 + source/blender/editors/space_file/file_intern.h | 1 + source/blender/editors/space_file/file_ops.c | 105 +++++++++++++++++++-- source/blender/editors/space_file/filelist.c | 13 +++ source/blender/editors/space_file/filelist.h | 1 + source/blender/editors/space_file/space_file.c | 1 + 8 files changed, 114 insertions(+), 11 deletions(-) diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 949cfcae2b1..577448554b7 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -2011,7 +2011,6 @@ def km_file_browser_main(params): # operator (i.e. in regular editor mode). ("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, {"properties": [("open", True), ("deselect_all", not params.legacy)]}), - ("file.refresh", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), ("file.select", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": [("open", False), ("deselect_all", not params.legacy)]}), ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True}, @@ -2053,6 +2052,7 @@ def km_file_browser_main(params): {"properties": [("mode", 'SUB')]}), ("file.highlight", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None), ("file.sort_column_ui_context", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ("file.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), ]) return keymap diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py index 234781b7bc8..214b8f98ff6 100644 --- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -1309,6 +1309,7 @@ def km_file_browser_main(params): {"properties": [("mode", 'ADD')]}), ("file.highlight", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None), ("file.sort_column_ui_context", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ("file.view_selected", {"type": 'F', "value": 'PRESS'}, None), ]) return keymap diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index ef4f47c9399..b236b2ee7cf 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -494,6 +494,7 @@ class FILEBROWSER_MT_view(Menu): layout.prop(st, "show_region_toolbar", text="Source List") layout.prop(st, "show_region_ui", text="File Path") + layout.operator("file.view_selected") layout.separator() diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index deb32812f44..309b280177c 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -75,6 +75,7 @@ void FILE_OT_rename(struct wmOperatorType *ot); void FILE_OT_smoothscroll(struct wmOperatorType *ot); void FILE_OT_filepath_drop(struct wmOperatorType *ot); void FILE_OT_start_filter(struct wmOperatorType *ot); +void FILE_OT_view_selected(struct wmOperatorType *ot); void file_directory_enter_handle(bContext *C, void *arg_unused, void *arg_but); void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 985c92f19b6..b82290205c7 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -256,6 +256,33 @@ static bool file_is_any_selected(struct FileList *files) return false; } +static FileSelection file_current_selection_range_get(struct FileList *files) +{ + const int numfiles = filelist_files_ensure(files); + FileSelection selection = {-1, -1}; + + /* Iterate over the files once but in two loops, one to find the first selected file, and the + * other to find the last. */ + + int file_index; + for (file_index = 0; file_index < numfiles; file_index++) { + if (filelist_entry_is_selected(files, file_index)) { + /* First selected entry found. */ + selection.first = file_index; + break; + } + } + + for (; file_index < numfiles; file_index++) { + if (filelist_entry_is_selected(files, file_index)) { + selection.last = file_index; + /* Keep looping, we may find more selected files. */ + } + } + + return selection; +} + /** * If \a file is outside viewbounds, this adjusts view to make sure it's inside */ @@ -299,6 +326,24 @@ static void file_ensure_inside_viewbounds(ARegion *region, SpaceFile *sfile, con } } +static void file_ensure_selection_inside_viewbounds(ARegion *region, + SpaceFile *sfile, + FileSelection *sel) +{ + const FileLayout *layout = ED_fileselect_get_layout(sfile, region); + + if (((layout->flag & FILE_LAYOUT_HOR) && region->winx <= (1.2f * layout->tile_w)) && + ((layout->flag & FILE_LAYOUT_VER) && region->winy <= (2.0f * layout->tile_h))) { + return; + } + + /* Adjust view to display selection. Doing iterations for first and last + * selected item makes view showing as much of the selection possible. + * Not really useful if tiles are (almost) bigger than viewbounds though. */ + file_ensure_inside_viewbounds(region, sfile, sel->last); + file_ensure_inside_viewbounds(region, sfile, sel->first); +} + static FileSelect file_select( bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen) { @@ -330,16 +375,7 @@ static FileSelect file_select( } else if (sel.last >= 0) { ARegion *region = CTX_wm_region(C); - const FileLayout *layout = ED_fileselect_get_layout(sfile, region); - - /* Adjust view to display selection. Doing iterations for first and last - * selected item makes view showing as much of the selection possible. - * Not really useful if tiles are (almost) bigger than viewbounds though. */ - if (((layout->flag & FILE_LAYOUT_HOR) && region->winx > (1.2f * layout->tile_w)) || - ((layout->flag & FILE_LAYOUT_VER) && region->winy > (2.0f * layout->tile_h))) { - file_ensure_inside_viewbounds(region, sfile, sel.last); - file_ensure_inside_viewbounds(region, sfile, sel.first); - } + file_ensure_selection_inside_viewbounds(region, sfile, &sel); } /* update operator for name change event */ @@ -925,6 +961,55 @@ void FILE_OT_select_all(wmOperatorType *ot) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Select All Operator + * \{ */ + +static int file_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelection sel = file_current_selection_range_get(sfile->files); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + + if (sel.first == -1 && sel.last == -1 && params->active_file == -1) { + /* Nothing was selected. */ + return OPERATOR_CANCELLED; + } + + /* Extend the selection area with the active file, as it may not be selected but still is + * important to have in view. */ + if (sel.first == -1 || params->active_file < sel.first) { + sel.first = params->active_file; + } + if (sel.last == -1 || params->active_file > sel.last) { + sel.last = params->active_file; + } + + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + file_ensure_selection_inside_viewbounds(region, sfile, &sel); + + file_draw_check(C); + WM_event_add_mousemove(CTX_wm_window(C)); + ED_area_tag_redraw(area); + + return OPERATOR_FINISHED; +} + +void FILE_OT_view_selected(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Frame Selected"; + ot->description = "Scroll the selected files into view"; + ot->idname = "FILE_OT_view_selected"; + + /* api callbacks */ + ot->exec = file_view_selected_exec; + ot->poll = ED_operator_file_active; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Select Bookmark Operator * \{ */ diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 757ec7c741f..f5ec9a0e8a1 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -2701,6 +2701,19 @@ uint filelist_entry_select_index_get(FileList *filelist, const int index, FileCh return 0; } +bool filelist_entry_is_selected(FileList *filelist, const int index) +{ + BLI_assert(index >= 0 && index < filelist->filelist.nbr_entries_filtered); + FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index]; + + /* BLI_ghash_lookup returns NULL if not found, which gets mapped to 0, which gets mapped to + * "not selected". */ + const uint selection_state = POINTER_AS_UINT( + BLI_ghash_lookup(filelist->selection_state, intern_entry->uuid)); + + return selection_state != 0; +} + /** * Set selection of the '..' parent entry, but only if it's actually visible. */ diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 7eecd7a05de..9eb70dd8437 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -128,6 +128,7 @@ unsigned int filelist_entry_select_get(struct FileList *filelist, unsigned int filelist_entry_select_index_get(struct FileList *filelist, const int index, FileCheckType check); +bool filelist_entry_is_selected(struct FileList *filelist, const int index); void filelist_entry_parent_select_set(struct FileList *filelist, FileSelType select, unsigned int flag, diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 2c9c2688e88..4373bd88473 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -659,6 +659,7 @@ static void file_operatortypes(void) WM_operatortype_append(FILE_OT_smoothscroll); WM_operatortype_append(FILE_OT_filepath_drop); WM_operatortype_append(FILE_OT_start_filter); + WM_operatortype_append(FILE_OT_view_selected); } /* NOTE: do not add .blend file reading on this level */ -- cgit v1.2.3 From d230c9b96c516e718014fb50914fcada1a7ec98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 8 Mar 2021 15:49:16 +0100 Subject: Alembic: avoid red overwrite warning when opening a file Pass `FILE_OPENFILE` instead of `FILE_SAVE` when selecting a file for reading. --- source/blender/editors/io/io_cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index 1e66a86c8fd..ea6606ed066 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -130,7 +130,7 @@ void CACHEFILE_OT_open(wmOperatorType *ot) WM_operator_properties_filesel(ot, FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER, FILE_BLENDER, - FILE_SAVE, + FILE_OPENFILE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); -- cgit v1.2.3 From 9cb5f0a2282a7a84f7f8636b43a32bdc04b51cd5 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 8 Mar 2021 16:23:21 +0100 Subject: Spreadsheet: add boilerplate code for new editor type This adds the initial boilerplate code that is required to introduce the new spreadsheet editor. The editor is still hidden from the ui. It can be made visible by undoing the change in `rna_screen.c`. This patch does not contain any business logic for the spreadsheet editor. Differential Revision: https://developer.blender.org/D10645 Ref T86279. --- release/datafiles/userdef/userdef_default_theme.c | 32 +++ .../presets/interface_theme/Blender_Light.xml | 36 ++++ release/scripts/startup/bl_ui/__init__.py | 1 + release/scripts/startup/bl_ui/space_spreadsheet.py | 39 ++++ source/blender/blenkernel/BKE_context.h | 1 + source/blender/blenkernel/intern/context.c | 9 + source/blender/blenkernel/intern/screen.c | 3 + .../blender/blenloader/intern/versioning_userdef.c | 2 + source/blender/editors/CMakeLists.txt | 1 + source/blender/editors/include/ED_space_api.h | 1 + .../interface/interface_template_search_menu.c | 1 + source/blender/editors/interface/resources.c | 3 + source/blender/editors/space_api/CMakeLists.txt | 1 + source/blender/editors/space_api/spacetypes.c | 1 + .../editors/space_spreadsheet/CMakeLists.txt | 39 ++++ .../editors/space_spreadsheet/space_spreadsheet.cc | 221 +++++++++++++++++++++ .../space_spreadsheet/spreadsheet_intern.hh | 19 ++ .../editors/space_spreadsheet/spreadsheet_ops.cc | 21 ++ source/blender/makesdna/DNA_space_types.h | 19 +- source/blender/makesdna/DNA_userdef_types.h | 3 +- source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_screen.c | 4 + source/blender/makesrna/intern/rna_space.c | 16 ++ source/blender/makesrna/intern/rna_userdef.c | 28 +++ source/blender/windowmanager/WM_types.h | 1 + 25 files changed, 501 insertions(+), 2 deletions(-) create mode 100644 release/scripts/startup/bl_ui/space_spreadsheet.py create mode 100644 source/blender/editors/space_spreadsheet/CMakeLists.txt create mode 100644 source/blender/editors/space_spreadsheet/space_spreadsheet.cc create mode 100644 source/blender/editors/space_spreadsheet/spreadsheet_intern.hh create mode 100644 source/blender/editors/space_spreadsheet/spreadsheet_ops.cc diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c index 0477b0c9f23..5b34515d080 100644 --- a/release/datafiles/userdef/userdef_default_theme.c +++ b/release/datafiles/userdef/userdef_default_theme.c @@ -1009,6 +1009,38 @@ const bTheme U_theme_default = { .facedot_size = 4, .gp_vertex_size = 3, }, + .space_spreadsheet = { + .back = RGBA(0x28282800), + .title = RGBA(0xffffffff), + .text = RGBA(0xc3c3c3ff), + .text_hi = RGBA(0xffffffff), + .header = RGBA(0x454545ff), + .header_text = RGBA(0xeeeeeeff), + .header_text_hi = RGBA(0xffffffff), + .tab_active = RGBA(0x4b4b4bff), + .tab_inactive = RGBA(0x2b2b2bff), + .tab_back = RGBA(0x232323ff), + .tab_outline = RGBA(0x232323ff), + .button = RGBA(0x424242ff), + .button_title = RGBA(0xffffffff), + .button_text = RGBA(0xe5e5e5ff), + .button_text_hi = RGBA(0xffffffff), + .panelcolors = { + .header = RGBA(0x424242cc), + .back = RGBA(0x333333b3), + .sub_back = RGBA(0x0000003e), + }, + .active = RGBA(0x3b5689ff), + .vertex_size = 3, + .outline_width = 1, + .facedot_size = 4, + .match = RGBA(0x337f334c), + .selected_highlight = RGBA(0x223a5bff), + .selected_object = RGBA(0xe96a00ff), + .active_object = RGBA(0xffaf29ff), + .edited_object = RGBA(0x00806266), + .row_alternate = RGBA(0xffffff07), + }, .tarm = { { .solid = RGBA(0x9a0000ff), diff --git a/release/scripts/presets/interface_theme/Blender_Light.xml b/release/scripts/presets/interface_theme/Blender_Light.xml index 77908bb6bbf..9da075ad949 100644 --- a/release/scripts/presets/interface_theme/Blender_Light.xml +++ b/release/scripts/presets/interface_theme/Blender_Light.xml @@ -1316,6 +1316,42 @@ + + + + + + + + + + + + spacetype == SPACE_SPREADSHEET) { + return area->spacedata.first; + } + return NULL; +} + void CTX_wm_manager_set(bContext *C, wmWindowManager *wm) { C->wm.manager = wm; diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 623f3a349d8..aa1a9403908 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -1342,6 +1342,9 @@ static void write_area_regions(BlendWriter *writer, ScrArea *area) else if (sl->spacetype == SPACE_INFO) { BLO_write_struct(writer, SpaceInfo, sl); } + else if (sl->spacetype == SPACE_SPREADSHEET) { + BLO_write_struct(writer, SpaceSpreadsheet, sl); + } } } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 3d39181cd32..ae22c5151cc 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -282,6 +282,8 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) FROM_DEFAULT_V4_UCHAR(space_info.info_property); FROM_DEFAULT_V4_UCHAR(space_info.info_error); FROM_DEFAULT_V4_UCHAR(space_info.info_operator); + + btheme->space_spreadsheet = btheme->space_outliner; } #undef FROM_DEFAULT_V4_UCHAR diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt index a2ae350ce4b..092198cea86 100644 --- a/source/blender/editors/CMakeLists.txt +++ b/source/blender/editors/CMakeLists.txt @@ -53,6 +53,7 @@ if(WITH_BLENDER) add_subdirectory(space_outliner) add_subdirectory(space_script) add_subdirectory(space_sequencer) + add_subdirectory(space_spreadsheet) add_subdirectory(space_statusbar) add_subdirectory(space_text) add_subdirectory(space_topbar) diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h index fc474ea464d..1a3aa7e5496 100644 --- a/source/blender/editors/include/ED_space_api.h +++ b/source/blender/editors/include/ED_space_api.h @@ -55,6 +55,7 @@ void ED_spacetype_userpref(void); void ED_spacetype_clip(void); void ED_spacetype_statusbar(void); void ED_spacetype_topbar(void); +void ED_spacetype_spreadsheet(void); /* calls for instancing and freeing spacetype static data * called in WM_init_exit */ diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c index e1f8f63dcbf..74668b2f3a3 100644 --- a/source/blender/editors/interface/interface_template_search_menu.c +++ b/source/blender/editors/interface/interface_template_search_menu.c @@ -642,6 +642,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( SPACE_MENU_NOP(SPACE_SCRIPT); SPACE_MENU_NOP(SPACE_STATUSBAR); SPACE_MENU_NOP(SPACE_TOPBAR); + SPACE_MENU_NOP(SPACE_SPREADSHEET); } } for (int i = 0; i < idname_array_len; i++) { diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 80e54f4f92f..afac254f542 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -160,6 +160,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case SPACE_STATUSBAR: ts = &btheme->space_statusbar; break; + case SPACE_SPREADSHEET: + ts = &btheme->space_spreadsheet; + break; default: ts = &btheme->space_view3d; break; diff --git a/source/blender/editors/space_api/CMakeLists.txt b/source/blender/editors/space_api/CMakeLists.txt index 573afb76f0e..85c07223f2d 100644 --- a/source/blender/editors/space_api/CMakeLists.txt +++ b/source/blender/editors/space_api/CMakeLists.txt @@ -50,6 +50,7 @@ set(LIB bf_editor_space_outliner bf_editor_space_script bf_editor_space_sequencer + bf_editor_space_spreadsheet bf_editor_space_statusbar bf_editor_space_text bf_editor_space_topbar diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index ff05fb3bad6..adb824b8934 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -95,6 +95,7 @@ void ED_spacetypes_init(void) ED_spacetype_clip(); ED_spacetype_statusbar(); ED_spacetype_topbar(); + ED_spacetype_spreadsheet(); /* Register operator types for screen and all spaces. */ ED_operatortypes_userpref(); diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt new file mode 100644 index 00000000000..8be5f506dd7 --- /dev/null +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -0,0 +1,39 @@ +# ***** 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. +# ***** END GPL LICENSE BLOCK ***** + +set(INC + ../include + ../../blenkernel + ../../blenlib + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/glew-mx + ../../../../intern/guardedalloc +) + +set(SRC + space_spreadsheet.cc + spreadsheet_ops.cc + + spreadsheet_intern.hh +) + +set(LIB +) + +blender_add_lib(bf_editor_space_spreadsheet "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc new file mode 100644 index 00000000000..27276b4bedc --- /dev/null +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -0,0 +1,221 @@ +/* + * 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. + */ + +#include + +#include "BLI_listbase.h" + +#include "BKE_screen.h" + +#include "ED_screen.h" +#include "ED_space_api.h" + +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "MEM_guardedalloc.h" + +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "spreadsheet_intern.hh" + +static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) +{ + SpaceSpreadsheet *spreadsheet_space = (SpaceSpreadsheet *)MEM_callocN(sizeof(SpaceSpreadsheet), + "spreadsheet space"); + spreadsheet_space->spacetype = SPACE_SPREADSHEET; + + { + /* header */ + ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header"); + BLI_addtail(&spreadsheet_space->regionbase, region); + region->regiontype = RGN_TYPE_HEADER; + region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; + } + + { + /* main window */ + ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region"); + BLI_addtail(&spreadsheet_space->regionbase, region); + region->regiontype = RGN_TYPE_WINDOW; + } + + return (SpaceLink *)spreadsheet_space; +} + +static void spreadsheet_free(SpaceLink *UNUSED(sl)) +{ +} + +static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area)) +{ +} + +static SpaceLink *spreadsheet_duplicate(SpaceLink *sl) +{ + return (SpaceLink *)MEM_dupallocN(sl); +} + +static void spreadsheet_keymap(wmKeyConfig *UNUSED(keyconf)) +{ +} + +static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region) +{ + region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM; + region->v2d.align = V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y; + region->v2d.keepzoom = V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT; + region->v2d.keeptot = V2D_KEEPTOT_STRICT; + region->v2d.minzoom = region->v2d.maxzoom = 1.0f; + + UI_view2d_region_reinit(®ion->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy); + + wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D Buttons List", 0, 0); + WM_event_add_keymap_handler(®ion->handlers, keymap); +} + +static void spreadsheet_main_region_draw(const bContext *UNUSED(C), ARegion *UNUSED(region)) +{ + UI_ThemeClearColor(TH_BACK); +} + +static void spreadsheet_main_region_listener(const wmRegionListenerParams *params) +{ + ARegion *region = params->region; + wmNotifier *wmn = params->notifier; + + switch (wmn->category) { + case NC_SCENE: { + switch (wmn->data) { + case ND_MODE: + case ND_OB_ACTIVE: { + ED_region_tag_redraw(region); + break; + } + } + break; + } + case NC_OBJECT: { + ED_region_tag_redraw(region); + break; + } + case NC_SPACE: { + if (wmn->data == ND_SPACE_SPREADSHEET) { + ED_region_tag_redraw(region); + } + break; + } + case NC_GEOM: { + ED_region_tag_redraw(region); + break; + } + } +} + +static void spreadsheet_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region) +{ + ED_region_header_init(region); +} + +static void spreadsheet_header_region_draw(const bContext *C, ARegion *region) +{ + ED_region_header(C, region); +} + +static void spreadsheet_header_region_free(ARegion *UNUSED(region)) +{ +} + +static void spreadsheet_header_region_listener(const wmRegionListenerParams *params) +{ + ARegion *region = params->region; + wmNotifier *wmn = params->notifier; + + switch (wmn->category) { + case NC_SCENE: { + switch (wmn->data) { + case ND_MODE: + case ND_OB_ACTIVE: { + ED_region_tag_redraw(region); + break; + } + } + break; + } + case NC_OBJECT: { + ED_region_tag_redraw(region); + break; + } + case NC_SPACE: { + if (wmn->data == ND_SPACE_SPREADSHEET) { + ED_region_tag_redraw(region); + } + break; + } + case NC_GEOM: { + ED_region_tag_redraw(region); + break; + } + } +} + +void ED_spacetype_spreadsheet(void) +{ + SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet"); + ARegionType *art; + + st->spaceid = SPACE_SPREADSHEET; + strncpy(st->name, "Spreadsheet", BKE_ST_MAXNAME); + + st->create = spreadsheet_create; + st->free = spreadsheet_free; + st->init = spreadsheet_init; + st->duplicate = spreadsheet_duplicate; + st->operatortypes = spreadsheet_operatortypes; + st->keymap = spreadsheet_keymap; + + /* regions: main window */ + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region"); + art->regionid = RGN_TYPE_WINDOW; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; + + art->init = spreadsheet_main_region_init; + art->draw = spreadsheet_main_region_draw; + art->listener = spreadsheet_main_region_listener; + BLI_addhead(&st->regiontypes, art); + + /* regions: header */ + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet header region"); + art->regionid = RGN_TYPE_HEADER; + art->prefsizey = HEADERY; + art->keymapflag = 0; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; + + art->init = spreadsheet_header_region_init; + art->draw = spreadsheet_header_region_draw; + art->free = spreadsheet_header_region_free; + art->listener = spreadsheet_header_region_listener; + BLI_addhead(&st->regiontypes, art); + + BKE_spacetype_register(st); +} diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh new file mode 100644 index 00000000000..10a875e2c14 --- /dev/null +++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh @@ -0,0 +1,19 @@ +/* + * 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. + */ + +#pragma once + +void spreadsheet_operatortypes(void); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc new file mode 100644 index 00000000000..770bd207e8d --- /dev/null +++ b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc @@ -0,0 +1,21 @@ +/* + * 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. + */ + +#include "spreadsheet_intern.hh" + +void spreadsheet_operatortypes() +{ +} diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 856fa569645..81fd7c45baa 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1839,6 +1839,22 @@ typedef struct SpaceStatusBar { /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Spreadsheet + * \{ */ + +typedef struct SpaceSpreadsheet { + SpaceLink *next, *prev; + /** Storage of regions for inactive spaces. */ + ListBase regionbase; + char spacetype; + char link_flag; + char _pad0[6]; + /* End 'SpaceLink' header. */ +} SpaceSpreadsheet; + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Space Defines (eSpace_Type) * \{ */ @@ -1876,8 +1892,9 @@ typedef enum eSpace_Type { SPACE_CLIP = 20, SPACE_TOPBAR = 21, SPACE_STATUSBAR = 22, + SPACE_SPREADSHEET = 23 -#define SPACE_TYPE_LAST SPACE_STATUSBAR +#define SPACE_TYPE_LAST SPACE_SPREADSHEET } eSpace_Type; /* use for function args */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index d304641e112..bd8f3cd95a7 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -492,6 +492,7 @@ typedef struct bTheme { ThemeSpace space_clip; ThemeSpace space_topbar; ThemeSpace space_statusbar; + ThemeSpace space_spreadsheet; /* 20 sets of bone colors for this theme */ ThemeWireColor tarm[20]; @@ -507,7 +508,7 @@ typedef struct bTheme { #define UI_THEMESPACE_START(btheme) \ (CHECK_TYPE_INLINE(btheme, bTheme *), &((btheme)->space_properties)) #define UI_THEMESPACE_END(btheme) \ - (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_statusbar) + 1)) + (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_spreadsheet) + 1)) typedef struct bAddon { struct bAddon *next, *prev; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index eecac8ca19e..74b8517f538 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -601,6 +601,7 @@ extern StructRNA RNA_SpaceOutliner; extern StructRNA RNA_SpacePreferences; extern StructRNA RNA_SpaceProperties; extern StructRNA RNA_SpaceSequenceEditor; +extern StructRNA RNA_SpaceSpreadsheet; extern StructRNA RNA_SpaceTextEditor; extern StructRNA RNA_SpaceUVEditor; extern StructRNA RNA_SpaceView3D; diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 6cf1d7a923b..58e446381ad 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -201,6 +201,10 @@ static const EnumPropertyItem *rna_Area_ui_type_itemf(bContext *C, if (ELEM(item_from->value, SPACE_TOPBAR, SPACE_STATUSBAR)) { continue; } + /* Hide spreadsheet editor until we want to expose it in the ui. */ + if (item_from->value == SPACE_SPREADSHEET) { + continue; + } SpaceType *st = item_from->identifier[0] ? BKE_spacetype_from_id(item_from->value) : NULL; int totitem_prev = totitem; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 5312aea9295..d0f366d6a18 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -145,6 +145,11 @@ const EnumPropertyItem rna_enum_space_type_items[] = { "Properties", "Edit properties of active object and related data-blocks"}, {SPACE_FILE, "FILE_BROWSER", ICON_FILEBROWSER, "File Browser", "Browse for files and assets"}, + {SPACE_SPREADSHEET, + "SPREADSHEET", + ICON_SPREADSHEET, + "Spreadsheet", + "Explore geometry data in a table"}, {SPACE_USERPREF, "PREFERENCES", ICON_PREFERENCES, @@ -571,6 +576,8 @@ static StructRNA *rna_Space_refine(struct PointerRNA *ptr) return &RNA_SpacePreferences; case SPACE_CLIP: return &RNA_SpaceClipEditor; + case SPACE_SPREADSHEET: + return &RNA_SpaceSpreadsheet; /* Currently no type info. */ case SPACE_SCRIPT: @@ -7171,6 +7178,14 @@ static void rna_def_space_clip(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL); } +static void rna_def_space_spreadsheet(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space"); + RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data"); +} + void RNA_def_space(BlenderRNA *brna) { rna_def_space(brna); @@ -7196,6 +7211,7 @@ void RNA_def_space(BlenderRNA *brna) rna_def_node_tree_path(brna); rna_def_space_node(brna); rna_def_space_clip(brna); + rna_def_space_spreadsheet(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b06ec674e81..4097e2dddea 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -3847,6 +3847,26 @@ static void rna_def_userdef_theme_space_statusbar(BlenderRNA *brna) rna_def_userdef_theme_spaces_main(srna); } +static void rna_def_userdef_theme_space_spreadsheet(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* space_spreadsheet */ + + srna = RNA_def_struct(brna, "ThemeSpreadsheet", NULL); + RNA_def_struct_sdna(srna, "ThemeSpace"); + RNA_def_struct_clear_flag(srna, STRUCT_UNDO); + RNA_def_struct_ui_text(srna, "Theme Spreadsheet", "Theme settings for the Spreadsheet"); + + prop = RNA_def_property(srna, "row_alternate", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Alternate Rows", "Overlay color on every other row"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + rna_def_userdef_theme_spaces_main(srna); +} + static void rna_def_userdef_themes(BlenderRNA *brna) { StructRNA *srna; @@ -3873,6 +3893,7 @@ static void rna_def_userdef_themes(BlenderRNA *brna) {20, "CLIP_EDITOR", ICON_TRACKER, "Movie Clip Editor", ""}, {21, "TOPBAR", ICON_TOPBAR, "Top Bar", ""}, {22, "STATUSBAR", ICON_STATUSBAR, "Status Bar", ""}, + {23, "SPREADSHEET", ICON_SPREADSHEET, "Spreadsheet"}, {0, NULL, 0, NULL, NULL}, }; @@ -4001,6 +4022,12 @@ static void rna_def_userdef_themes(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "space_statusbar"); RNA_def_property_struct_type(prop, "ThemeStatusBar"); RNA_def_property_ui_text(prop, "Status Bar", ""); + + prop = RNA_def_property(srna, "spreadsheet", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "space_spreadsheet"); + RNA_def_property_struct_type(prop, "ThemeSpreadsheet"); + RNA_def_property_ui_text(prop, "Spreadsheet", ""); /* end space types */ prop = RNA_def_property(srna, "bone_color_sets", PROP_COLLECTION, PROP_NONE); @@ -4254,6 +4281,7 @@ static void rna_def_userdef_dothemes(BlenderRNA *brna) rna_def_userdef_theme_space_clip(brna); rna_def_userdef_theme_space_topbar(brna); rna_def_userdef_theme_space_statusbar(brna); + rna_def_userdef_theme_space_spreadsheet(brna); rna_def_userdef_theme_colorset(brna); rna_def_userdef_theme_collection_color(brna); rna_def_userdef_themes(brna); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 084ca2d2df5..b46a354c7ae 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -427,6 +427,7 @@ typedef struct wmNotifier { #define ND_SPACE_CHANGED (19 << 16) /*sent to a new editor type after it's replaced an old one*/ #define ND_SPACE_CLIP (20 << 16) #define ND_SPACE_FILE_PREVIEW (21 << 16) +#define ND_SPACE_SPREADSHEET (22 << 16) /* subtype, 256 entries too */ #define NOTE_SUBTYPE 0x0000FF00 -- cgit v1.2.3 From 1aa59464b6ac1b916ac4a878b620cb6e45783e62 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 8 Mar 2021 16:52:49 +0100 Subject: Cleanup: Move LibOverride debug prints to CLOG. --- source/blender/blenkernel/intern/lib_override.c | 12 +-- .../makesrna/intern/rna_access_compare_override.c | 96 +++++++++++----------- 2 files changed, 57 insertions(+), 51 deletions(-) diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 602c560cedd..702d718f2b9 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -24,6 +24,8 @@ #include #include +#include "CLG_log.h" + #include "MEM_guardedalloc.h" #include "DNA_ID.h" @@ -66,6 +68,8 @@ # include "PIL_time_utildefines.h" #endif +static CLG_LogRef LOG = {"bke.liboverride"}; + static void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst, IDOverrideLibraryProperty *op_src); static void lib_override_library_property_operation_copy( @@ -1557,17 +1561,15 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local) created = true; } -#ifndef NDEBUG if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) { - printf("We did restore some properties of %s from its reference.\n", local->name); + CLOG_INFO(&LOG, 2, "We did restore some properties of %s from its reference", local->name); } if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) { - printf("We did generate library override rules for %s\n", local->name); + CLOG_INFO(&LOG, 2, "We did generate library override rules for %s", local->name); } else { - printf("No new library override rules for %s\n", local->name); + CLOG_INFO(&LOG, 2, "No new library override rules for %s", local->name); } -#endif } return created; } diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index d6305388cf9..0f3b0a895db 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -20,6 +20,8 @@ #include +#include + #include "MEM_guardedalloc.h" #include "DNA_ID.h" @@ -53,6 +55,8 @@ #include "rna_access_internal.h" #include "rna_internal.h" +static CLG_LogRef LOG = {"rna.access_compare_override"}; + /** * Find the actual ID owner of the given \a ptr #PointerRNA, in override sense, and generate the * full rna path from it to given \a prop #PropertyRNA if \a rna_path is given. @@ -411,12 +415,11 @@ static int rna_property_override_diff(Main *bmain, } if (override_diff == NULL) { -#ifndef NDEBUG - printf("'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d).\n", - rna_path ? rna_path : prop_a->identifier, - !prop_a->is_idprop, - !prop_b->is_idprop); -#endif + CLOG_ERROR(&LOG, + "'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d)", + rna_path ? rna_path : prop_a->identifier, + !prop_a->is_idprop, + !prop_b->is_idprop); BLI_assert(0); return 1; } @@ -501,12 +504,11 @@ static bool rna_property_override_operation_store(Main *bmain, } if (override_store == NULL) { -#ifndef NDEBUG - printf("'%s' gives unmatching or NULL RNA store callbacks, should not happen (%d vs. %d).\n", - op->rna_path, - prop_local->magic == RNA_MAGIC, - prop_reference->magic == RNA_MAGIC); -#endif + CLOG_ERROR(&LOG, + "'%s' gives unmatching or NULL RNA store callbacks, should not happen (%d vs. %d)", + op->rna_path, + prop_local->magic == RNA_MAGIC, + prop_reference->magic == RNA_MAGIC); BLI_assert(0); return changed; } @@ -590,12 +592,12 @@ static bool rna_property_override_operation_apply(Main *bmain, } if (override_apply == NULL) { -#ifndef NDEBUG - printf("'%s' gives unmatching or NULL RNA copy callbacks, should not happen (%d vs. %d).\n", - prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name : prop_dst->identifier, - prop_dst->magic == RNA_MAGIC, - prop_src->magic == RNA_MAGIC); -#endif + CLOG_ERROR(&LOG, + "'%s' gives unmatching or NULL RNA apply callbacks, should not happen (%d vs. %d)", + prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name : + prop_dst->identifier, + prop_dst->magic == RNA_MAGIC, + prop_src->magic == RNA_MAGIC); BLI_assert(0); return false; } @@ -788,7 +790,7 @@ bool RNA_struct_override_matches(Main *bmain, continue; } - // printf("Override Checking %s\n", rna_path); + CLOG_INFO(&LOG, 5, "Override Checking %s\n", rna_path); IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path); if (ignore_overridden && op != NULL) { @@ -990,11 +992,9 @@ static void rna_property_override_apply_ex(Main *bmain, if (!do_insert != !ELEM(opop->operation, IDOVERRIDE_LIBRARY_OP_INSERT_AFTER, IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE)) { -#ifndef NDEBUG if (!do_insert) { - printf("Skipping insert override operations in first pass (%s)!\n", op->rna_path); + CLOG_INFO(&LOG, 5, "Skipping insert override operations in first pass (%s)", op->rna_path); } -#endif continue; } @@ -1078,22 +1078,25 @@ static void rna_property_override_apply_ex(Main *bmain, ptr_item_src = &private_ptr_item_src; ptr_item_storage = &private_ptr_item_storage; -#ifndef NDEBUG if (ptr_item_dst->type == NULL) { - printf("Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'\n", - opop->subitem_reference_name, - opop->subitem_reference_index, - op->rna_path, - ptr_dst->owner_id->name); + CLOG_INFO( + &LOG, + 2, + "Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'", + opop->subitem_reference_name, + opop->subitem_reference_index, + op->rna_path, + ptr_dst->owner_id->name); } if (ptr_item_src->type == NULL) { - printf("Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'\n", - opop->subitem_local_name, - opop->subitem_local_index, - op->rna_path, - ptr_src->owner_id->name); + CLOG_INFO(&LOG, + 2, + "Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'", + opop->subitem_local_name, + opop->subitem_local_index, + op->rna_path, + ptr_src->owner_id->name); } -#endif } if (!rna_property_override_operation_apply(bmain, @@ -1107,9 +1110,11 @@ static void rna_property_override_apply_ex(Main *bmain, ptr_item_src, ptr_item_storage, opop)) { - printf("Failed to apply '%s' override operation on %s\n", - op->rna_path, - ptr_src->owner_id->name); + CLOG_INFO(&LOG, + 2, + "Failed to apply '%s' override operation on %s\n", + op->rna_path, + ptr_src->owner_id->name); } } } @@ -1166,17 +1171,16 @@ void RNA_struct_override_apply(Main *bmain, op, do_insert); } -#ifndef NDEBUG else { - printf( - "Failed to apply library override operation to '%s.%s' " - "(could not resolve some properties, local: %d, override: %d)\n", - ((ID *)ptr_src->owner_id)->name, - op->rna_path, - RNA_path_resolve_property(ptr_dst, op->rna_path, &data_dst, &prop_dst), - RNA_path_resolve_property(ptr_src, op->rna_path, &data_src, &prop_src)); + CLOG_INFO(&LOG, + 2, + "Failed to apply library override operation to '%s.%s' " + "(could not resolve some properties, local: %d, override: %d)", + ((ID *)ptr_src->owner_id)->name, + op->rna_path, + RNA_path_resolve_property(ptr_dst, op->rna_path, &data_dst, &prop_dst), + RNA_path_resolve_property(ptr_src, op->rna_path, &data_src, &prop_src)); } -#endif } } -- cgit v1.2.3 From a6a8ca9212108de9a2fad2a67a86d81efdf5ada3 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Mon, 1 Mar 2021 16:38:38 +0100 Subject: Fix T86063: support 'Relative Path' setting opening (alembic) caches This was reported as opening alembic caches ignoring the 'use_relative_paths' preference, but this operator just did not have this setting. Fortunately, adding this is just a simple switch. Maniphest Tasks: T86063 Differential Revision: https://developer.blender.org/D10568 --- source/blender/editors/io/io_cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index ea6606ed066..bf20c1f6438 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -131,7 +131,7 @@ void CACHEFILE_OT_open(wmOperatorType *ot) FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER, FILE_BLENDER, FILE_OPENFILE, - WM_FILESEL_FILEPATH, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); } -- cgit v1.2.3 From 6afe2d373a00a49a7a51cafec50d03ada0fe0743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 8 Mar 2021 16:32:32 +0100 Subject: Fix ID preview not updating in Asset Browser Fix ID preview not updating in Asset Browser, by actually sending an explicit `NA_EDITED` along with the `NC_ASSET` notifier. --- source/blender/editors/space_file/space_file.c | 1 + source/blender/editors/util/ed_util_ops.cc | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 4373bd88473..83bb8abf5d8 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -459,6 +459,7 @@ static void file_listener(const wmSpaceTypeListenerParams *params) break; case NA_ADDED: case NA_REMOVED: + case NA_EDITED: if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { /* Full refresh of the file list if local asset data was changed. Refreshing this view * is cheap and users expect this to be updated immediately. */ diff --git a/source/blender/editors/util/ed_util_ops.cc b/source/blender/editors/util/ed_util_ops.cc index 5b2e1a16bc2..06f1b999d58 100644 --- a/source/blender/editors/util/ed_util_ops.cc +++ b/source/blender/editors/util/ed_util_ops.cc @@ -92,7 +92,7 @@ static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op) BKE_previewimg_id_custom_set(id, path); - WM_event_add_notifier(C, NC_ASSET, nullptr); + WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr); return OPERATOR_FINISHED; } @@ -133,7 +133,7 @@ static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op)) } UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true); - WM_event_add_notifier(C, NC_ASSET, nullptr); + WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr); return OPERATOR_FINISHED; } -- cgit v1.2.3 From ba75ea8012084aa84ba8c9ac088b88a8dcf4fb21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 4 Mar 2021 11:59:49 +0100 Subject: EEVEE: Use Fullscreen maxZBuffer instead of halfres This removes the need for per mipmap scalling factor and trilinear interpolation issues. We pad the texture so that all mipmaps have pixels in the next mip. This simplifies the downsampling shader too. This also change the SSR radiance buffer as well in the same fashion. --- source/blender/draw/engines/eevee/eevee_effects.c | 176 ++++++++++----------- .../blender/draw/engines/eevee/eevee_lightprobes.c | 20 +-- .../blender/draw/engines/eevee/eevee_materials.c | 2 +- source/blender/draw/engines/eevee/eevee_private.h | 35 ++-- .../draw/engines/eevee/eevee_screen_raytrace.c | 24 +-- source/blender/draw/engines/eevee/eevee_shaders.c | 16 +- .../eevee/shaders/ambient_occlusion_lib.glsl | 3 +- .../engines/eevee/shaders/common_uniforms_lib.glsl | 12 +- .../draw/engines/eevee/shaders/effect_dof_lib.glsl | 6 - .../eevee/shaders/effect_downsample_frag.glsl | 25 +-- .../engines/eevee/shaders/effect_minmaxz_frag.glsl | 58 ++----- .../engines/eevee/shaders/effect_ssr_frag.glsl | 15 +- .../engines/eevee/shaders/effect_temporal_aa.glsl | 6 - .../draw/engines/eevee/shaders/raytrace_lib.glsl | 20 +-- .../draw/engines/eevee/shaders/ssr_lib.glsl | 5 +- .../draw/intern/shaders/common_math_lib.glsl | 6 + 16 files changed, 184 insertions(+), 245 deletions(-) diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 18d3e453c5d..25aedd2cdde 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -44,7 +44,7 @@ static struct { #define SETUP_BUFFER(tex, fb, fb_color) \ { \ eGPUTextureFormat format = (DRW_state_is_scene_render()) ? GPU_RGBA32F : GPU_RGBA16F; \ - DRW_texture_ensure_fullscreen_2d(&tex, format, DRW_TEX_FILTER | DRW_TEX_MIPMAP); \ + DRW_texture_ensure_fullscreen_2d(&tex, format, DRW_TEX_FILTER); \ GPU_framebuffer_ensure_config(&fb, \ { \ GPU_ATTACHMENT_TEXTURE(dtxl->depth), \ @@ -117,20 +117,27 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, /** * MinMax Pyramid */ - const bool half_res_hiz = true; - int size[2], div; - common_data->hiz_mip_offset = (half_res_hiz) ? 1 : 0; - div = (half_res_hiz) ? 2 : 1; - size[0] = max_ii(size_fs[0] / div, 1); - size[1] = max_ii(size_fs[1] / div, 1); + int div = 1 << MAX_SCREEN_BUFFERS_LOD_LEVEL; + effects->hiz_size[0] = divide_ceil_u(size_fs[0], div) * div; + effects->hiz_size[1] = divide_ceil_u(size_fs[1], div) * div; if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { - /* Intel gpu seems to have problem rendering to only depth format */ - DRW_texture_ensure_2d(&txl->maxzbuffer, size[0], size[1], GPU_R32F, DRW_TEX_MIPMAP); + /* Intel gpu seems to have problem rendering to only depth hiz_format */ + DRW_texture_ensure_2d(&txl->maxzbuffer, UNPACK2(effects->hiz_size), GPU_R32F, DRW_TEX_MIPMAP); + GPU_framebuffer_ensure_config(&fbl->maxzbuffer_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->maxzbuffer), + }); } else { DRW_texture_ensure_2d( - &txl->maxzbuffer, size[0], size[1], GPU_DEPTH_COMPONENT24, DRW_TEX_MIPMAP); + &txl->maxzbuffer, UNPACK2(effects->hiz_size), GPU_DEPTH_COMPONENT24, DRW_TEX_MIPMAP); + GPU_framebuffer_ensure_config(&fbl->maxzbuffer_fb, + { + GPU_ATTACHMENT_TEXTURE(txl->maxzbuffer), + GPU_ATTACHMENT_NONE, + }); } if (fbl->downsample_fb == NULL) { @@ -138,13 +145,35 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, } /** - * Compute Mipmap texel alignment. + * Compute hiZ texel alignment. + */ + common_data->hiz_uv_scale[0] = viewport_size[0] / effects->hiz_size[0]; + common_data->hiz_uv_scale[1] = viewport_size[1] / effects->hiz_size[1]; + common_data->hiz_uv_scale[2] = 1.0f / effects->hiz_size[0]; + common_data->hiz_uv_scale[3] = 1.0f / effects->hiz_size[1]; + + /* Compute pixel size. Size is multiplied by 2 because it is applied in NDC [-1..1] range. */ + sldata->common_data.ssr_pixelsize[0] = 2.0f / size_fs[0]; + sldata->common_data.ssr_pixelsize[1] = 2.0f / size_fs[1]; + + /** + * Color buffer with correct downsampling alignment. + * Used for SSReflections & SSRefractions. */ - for (int i = 0; i < 10; i++) { - int mip_size[3]; - GPU_texture_get_mipmap_size(txl->color, i, mip_size); - common_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, i)); - common_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, i)); + if ((effects->enabled_effects & EFFECT_RADIANCE_BUFFER) != 0) { + DRW_texture_ensure_2d(&txl->filtered_radiance, + UNPACK2(effects->hiz_size), + GPU_R11F_G11F_B10F, + DRW_TEX_FILTER | DRW_TEX_MIPMAP); + + GPU_framebuffer_ensure_config(&fbl->radiance_filtered_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->filtered_radiance), + }); + } + else { + txl->filtered_radiance = NULL; } /** @@ -210,7 +239,7 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_TextureList *txl = vedata->txl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - DRWState downsample_write = DRW_STATE_WRITE_DEPTH; + DRWState downsample_write = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS; DRWShadingGroup *grp; /* Intel gpu seems to have problem rendering to only depth format. @@ -221,12 +250,17 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); - { + if (effects->enabled_effects & EFFECT_RADIANCE_BUFFER) { + DRW_PASS_CREATE(psl->color_copy_ps, DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(EEVEE_shaders_effect_color_copy_sh_get(), psl->color_copy_ps); + DRW_shgroup_uniform_texture_ref_ex(grp, "source", &e_data.color_src, GPU_SAMPLER_DEFAULT); + DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + DRW_PASS_CREATE(psl->color_downsample_ps, DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(EEVEE_shaders_effect_downsample_sh_get(), psl->color_downsample_ps); - DRW_shgroup_uniform_texture_ref(grp, "source", &e_data.color_src); - DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_uniform_texture_ex(grp, "source", txl->filtered_radiance, GPU_SAMPLER_FILTER); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { @@ -241,34 +275,21 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { /* Perform min/max down-sample. */ - DRW_PASS_CREATE(psl->maxz_downlevel_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); + DRW_PASS_CREATE(psl->maxz_downlevel_ps, downsample_write); grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downlevel_sh_get(), psl->maxz_downlevel_ps); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &txl->maxzbuffer); - DRW_shgroup_call(grp, quad, NULL); - - /* Copy depth buffer to halfres top level of HiZ */ - - DRW_PASS_CREATE(psl->maxz_downdepth_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); - grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downdepth_sh_get(), psl->maxz_downdepth_ps); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_call(grp, quad, NULL); - - DRW_PASS_CREATE(psl->maxz_downdepth_layer_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); - grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downdepth_layer_sh_get(), - psl->maxz_downdepth_layer_ps); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1); + DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &txl->maxzbuffer, GPU_SAMPLER_DEFAULT); DRW_shgroup_call(grp, quad, NULL); - DRW_PASS_CREATE(psl->maxz_copydepth_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); + /* Copy depth buffer to top level of HiZ */ + DRW_PASS_CREATE(psl->maxz_copydepth_ps, downsample_write); grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_copydepth_sh_get(), psl->maxz_copydepth_ps); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); + DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &e_data.depth_src, GPU_SAMPLER_DEFAULT); DRW_shgroup_call(grp, quad, NULL); - DRW_PASS_CREATE(psl->maxz_copydepth_layer_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); + DRW_PASS_CREATE(psl->maxz_copydepth_layer_ps, downsample_write); grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_copydepth_layer_sh_get(), psl->maxz_copydepth_layer_ps); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); + DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &e_data.depth_src, GPU_SAMPLER_DEFAULT); DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1); DRW_shgroup_call(grp, quad, NULL); } @@ -331,12 +352,6 @@ static void max_downsample_cb(void *vedata, int UNUSED(level)) DRW_draw_pass(psl->maxz_downlevel_ps); } -static void simple_downsample_cb(void *vedata, int UNUSED(level)) -{ - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; - DRW_draw_pass(psl->color_downsample_ps); -} - static void simple_downsample_cube_cb(void *vedata, int level) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; @@ -348,58 +363,22 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l { EEVEE_PassList *psl = vedata->psl; EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; e_data.depth_src = depth_src; e_data.depth_src_layer = layer; -#if 0 /* Not required for now */ - DRW_stats_group_start("Min buffer"); - /* Copy depth buffer to min texture top level */ - GPU_framebuffer_texture_attach(fbl->downsample_fb, stl->g_data->minzbuffer, 0, 0); - GPU_framebuffer_bind(fbl->downsample_fb); - if (layer >= 0) { - DRW_draw_pass(psl->minz_downdepth_layer_ps); - } - else { - DRW_draw_pass(psl->minz_downdepth_ps); - } - GPU_framebuffer_texture_detach(stl->g_data->minzbuffer); - - /* Create lower levels */ - GPU_framebuffer_recursive_downsample( - fbl->downsample_fb, stl->g_data->minzbuffer, 8, &min_downsample_cb, vedata); - DRW_stats_group_end(); -#endif - int minmax_size[3], depth_size[3]; - GPU_texture_get_mipmap_size(depth_src, 0, depth_size); - GPU_texture_get_mipmap_size(txl->maxzbuffer, 0, minmax_size); - bool is_full_res_minmaxz = equals_v2v2_int(minmax_size, depth_size); - DRW_stats_group_start("Max buffer"); /* Copy depth buffer to max texture top level */ - GPU_framebuffer_texture_attach(fbl->downsample_fb, txl->maxzbuffer, 0, 0); - GPU_framebuffer_bind(fbl->downsample_fb); + GPU_framebuffer_bind(fbl->maxzbuffer_fb); if (layer >= 0) { - if (is_full_res_minmaxz) { - DRW_draw_pass(psl->maxz_copydepth_layer_ps); - } - else { - DRW_draw_pass(psl->maxz_downdepth_layer_ps); - } + DRW_draw_pass(psl->maxz_copydepth_layer_ps); } else { - if (is_full_res_minmaxz) { - DRW_draw_pass(psl->maxz_copydepth_ps); - } - else { - DRW_draw_pass(psl->maxz_downdepth_ps); - } + DRW_draw_pass(psl->maxz_copydepth_ps); } - /* Create lower levels */ - GPU_framebuffer_recursive_downsample(fbl->downsample_fb, 8, &max_downsample_cb, vedata); - GPU_framebuffer_texture_detach(fbl->downsample_fb, txl->maxzbuffer); + GPU_framebuffer_recursive_downsample( + fbl->maxzbuffer_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &max_downsample_cb, vedata); DRW_stats_group_end(); /* Restore */ @@ -412,19 +391,28 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l } } +static void downsample_radiance_cb(void *vedata, int UNUSED(level)) +{ + EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + DRW_draw_pass(psl->color_downsample_ps); +} + /** * Simple down-sampling algorithm. Reconstruct mip chain up to mip level. */ -void EEVEE_downsample_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level) +void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, GPUTexture *texture_src) { + EEVEE_PassList *psl = vedata->psl; EEVEE_FramebufferList *fbl = vedata->fbl; + e_data.color_src = texture_src; + DRW_stats_group_start("Downsample Radiance"); - /* Create lower levels */ - DRW_stats_group_start("Downsample buffer"); - GPU_framebuffer_texture_attach(fbl->downsample_fb, texture_src, 0, 0); - GPU_framebuffer_recursive_downsample(fbl->downsample_fb, level, &simple_downsample_cb, vedata); - GPU_framebuffer_texture_detach(fbl->downsample_fb, texture_src); + GPU_framebuffer_bind(fbl->radiance_filtered_fb); + DRW_draw_pass(psl->color_copy_ps); + + GPU_framebuffer_recursive_downsample( + fbl->radiance_filtered_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &downsample_radiance_cb, vedata); DRW_stats_group_end(); } diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 7688039d0a8..0ce94b8f1b1 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -112,19 +112,20 @@ static struct GPUTexture *create_hammersley_sample_texture(int samples) static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref) { EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *fx = stl->effects; /* XXX TODO OPTIMIZATION: This is a complete waist of texture memory. * Instead of allocating each planar probe for each viewport, * only alloc them once using the biggest viewport resolution. */ - const float *viewport_size = DRW_viewport_size_get(); /* TODO get screen percentage from layer setting */ // const DRWContextState *draw_ctx = DRW_context_state_get(); // ViewLayer *view_layer = draw_ctx->view_layer; - float screen_percentage = 1.0f; + int screen_divider = 1; - int width = max_ii(1, (int)(viewport_size[0] * screen_percentage)); - int height = max_ii(1, (int)(viewport_size[1] * screen_percentage)); + int width = max_ii(1, fx->hiz_size[0] / screen_divider); + int height = max_ii(1, fx->hiz_size[1] / screen_divider); /* Fix case were the pool was allocated width the dummy size (1,1,1). */ if (txl->planar_pool && (num_planar_ref > 0) && @@ -139,12 +140,12 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref) if (num_planar_ref > 0) { txl->planar_pool = DRW_texture_create_2d_array(width, height, - max_ii(1, num_planar_ref), + num_planar_ref, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); txl->planar_depth = DRW_texture_create_2d_array( - width, height, max_ii(1, num_planar_ref), GPU_DEPTH_COMPONENT24, 0, NULL); + width, height, num_planar_ref, GPU_DEPTH_COMPONENT24, 0, NULL); } else if (num_planar_ref == 0) { /* Makes Opengl Happy : Create a placeholder texture that will never be sampled but still @@ -674,10 +675,12 @@ static void lightbake_planar_ensure_view(EEVEE_PlanarReflection *eplanar, const DRWView *main_view, DRWView **r_planar_view) { - float winmat[4][4], viewmat[4][4]; + float winmat[4][4], viewmat[4][4], persmat[4][4]; DRW_view_viewmat_get(main_view, viewmat, false); /* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */ DRW_view_winmat_get(main_view, winmat, false); + DRW_view_persmat_get(main_view, persmat, false); + /* Invert X to avoid flipping the triangle facing direction. */ winmat[0][0] = -winmat[0][0]; winmat[1][0] = -winmat[1][0]; @@ -729,7 +732,6 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved /* For shading, save max level of the octahedron map */ sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len; - sldata->common_data.prb_lod_planar_max = (float)MAX_PLANAR_LOD_LEVEL; sldata->common_data.prb_irradiance_vis_size = light_cache->vis_res; sldata->common_data.prb_irradiance_smooth = square_f(scene_eval->eevee.gi_irradiance_smoothing); sldata->common_data.prb_num_render_cube = max_ii(1, light_cache->cube_len); @@ -1220,7 +1222,7 @@ static void EEVEE_lightbake_filter_planar(EEVEE_Data *vedata) {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->planar_pool)}); GPU_framebuffer_recursive_downsample( - fbl->planar_downsample_fb, MAX_PLANAR_LOD_LEVEL, &downsample_planar, vedata); + fbl->planar_downsample_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &downsample_planar, vedata); DRW_stats_group_end(); } diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 9d74d916265..bc7db4b5df6 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -128,7 +128,7 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp, DRW_shgroup_uniform_float_copy( shgrp, "refractionDepth", (refract_depth) ? *refract_depth : 0.0); if (use_ssrefraction) { - DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->refract_color); + DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->filtered_radiance); } } if (use_alpha_blend) { diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 4e32854dedc..45afee31591 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -161,7 +161,7 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d) ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0)))) #define MIN_CUBE_LOD_LEVEL 3 -#define MAX_PLANAR_LOD_LEVEL 9 +#define MAX_SCREEN_BUFFERS_LOD_LEVEL 6 /* All the renderpasses that use the GPUMaterial for accumulation */ #define EEVEE_RENDERPASSES_MATERIAL \ @@ -308,6 +308,7 @@ typedef struct EEVEE_PassList { struct DRWPass *sss_blur_ps; struct DRWPass *sss_resolve_ps; struct DRWPass *sss_translucency_ps; + struct DRWPass *color_copy_ps; struct DRWPass *color_downsample_ps; struct DRWPass *color_downsample_cube_ps; struct DRWPass *velocity_object; @@ -320,13 +321,7 @@ typedef struct EEVEE_PassList { struct DRWPass *alpha_checker; /* HiZ */ - struct DRWPass *minz_downlevel_ps; struct DRWPass *maxz_downlevel_ps; - struct DRWPass *minz_downdepth_ps; - struct DRWPass *maxz_downdepth_ps; - struct DRWPass *minz_downdepth_layer_ps; - struct DRWPass *maxz_downdepth_layer_ps; - struct DRWPass *minz_copydepth_ps; struct DRWPass *maxz_copydepth_ps; struct DRWPass *maxz_copydepth_layer_ps; @@ -362,6 +357,7 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *gtao_fb; struct GPUFrameBuffer *gtao_debug_fb; struct GPUFrameBuffer *downsample_fb; + struct GPUFrameBuffer *maxzbuffer_fb; struct GPUFrameBuffer *bloom_blit_fb; struct GPUFrameBuffer *bloom_down_fb[MAX_BLOOM_STEP]; struct GPUFrameBuffer *bloom_accum_fb[MAX_BLOOM_STEP - 1]; @@ -394,7 +390,6 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *volumetric_integ_fb; struct GPUFrameBuffer *volumetric_accum_fb; struct GPUFrameBuffer *screen_tracing_fb; - struct GPUFrameBuffer *refract_fb; struct GPUFrameBuffer *mist_accum_fb; struct GPUFrameBuffer *material_accum_fb; struct GPUFrameBuffer *renderpass_fb; @@ -412,6 +407,7 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *main_color_fb; struct GPUFrameBuffer *effect_fb; struct GPUFrameBuffer *effect_color_fb; + struct GPUFrameBuffer *radiance_filtered_fb; struct GPUFrameBuffer *double_buffer_fb; struct GPUFrameBuffer *double_buffer_color_fb; struct GPUFrameBuffer *double_buffer_depth_fb; @@ -436,7 +432,6 @@ typedef struct EEVEE_TextureList { struct GPUTexture *ssr_accum; struct GPUTexture *shadow_accum; struct GPUTexture *cryptomatte; - struct GPUTexture *refract_color; struct GPUTexture *taa_history; /* Could not be pool texture because of mipmapping. */ struct GPUTexture *dof_reduced_color; @@ -460,6 +455,7 @@ typedef struct EEVEE_TextureList { struct GPUTexture *planar_depth; struct GPUTexture *maxzbuffer; + struct GPUTexture *filtered_radiance; struct GPUTexture *renderpass; @@ -618,7 +614,7 @@ typedef struct EEVEE_LightProbesInfo { float roughness; float firefly_fac; float lodfactor; - float lod_rt_max, lod_cube_max, lod_planar_max; + float lod_rt_max, lod_cube_max; float visibility_range; float visibility_blur; float intensity_fac; @@ -708,8 +704,9 @@ typedef enum EEVEE_EffectsFlag { EFFECT_REFRACT = (1 << 6), EFFECT_GTAO = (1 << 7), EFFECT_TAA = (1 << 8), - EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */ - EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */ + EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */ + EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */ + EFFECT_RADIANCE_BUFFER = (1 << 10), /* Not really an effect but a feature */ EFFECT_SSS = (1 << 11), EFFECT_VELOCITY_BUFFER = (1 << 12), /* Not really an effect but a feature */ EFFECT_TAA_REPROJECT = (1 << 13), /* should be mutually exclusive with EFFECT_TAA */ @@ -817,11 +814,10 @@ typedef struct EEVEE_EffectsInfo { struct GPUTexture *dof_scatter_src_tx; struct GPUTexture *dof_reduce_input_coc_tx; /* Just references to actual textures. */ struct GPUTexture *dof_reduce_input_color_tx; - /* Alpha Checker */ - float color_checker_dark[4]; - float color_checker_light[4]; /* Other */ float prev_persmat[4][4]; + /* Size used by all fullscreen buffers using mipmaps. */ + int hiz_size[2]; /* Lookdev */ int sphere_size; eDRWLevelOfDetail sphere_lod; @@ -859,7 +855,7 @@ typedef struct EEVEE_EffectsInfo { * - sizeof(bool) == sizeof(int) in GLSL so use int in C */ typedef struct EEVEE_CommonUniformBuffer { float prev_persmat[4][4]; /* mat4 */ - float mip_ratio[10][4]; /* vec2[10] */ + float hiz_uv_scale[4]; /* vec4 */ /* Ambient Occlusion */ /* -- 16 byte aligned -- */ float ao_dist, pad1, ao_factor, pad2; /* vec4 */ @@ -899,15 +895,15 @@ typedef struct EEVEE_CommonUniformBuffer { int prb_irradiance_vis_size; /* int */ float prb_irradiance_smooth; /* float */ float prb_lod_cube_max; /* float */ - float prb_lod_planar_max; /* float */ /* Misc */ - int hiz_mip_offset; /* int */ int ray_type; /* int */ float ray_depth; /* float */ float alpha_hash_offset; /* float */ float alpha_hash_scale; /* float */ float pad7; /* float */ float pad8; /* float */ + float pad9; /* float */ + float pad10; /* float */ } EEVEE_CommonUniformBuffer; BLI_STATIC_ASSERT_ALIGN(EEVEE_CommonUniformBuffer, 16) @@ -1201,6 +1197,7 @@ struct GPUShader *EEVEE_shaders_depth_of_field_gather_get(EEVEE_DofGatherPass pa struct GPUShader *EEVEE_shaders_depth_of_field_filter_get(void); struct GPUShader *EEVEE_shaders_depth_of_field_scatter_get(bool is_foreground, bool bokeh_tx); struct GPUShader *EEVEE_shaders_depth_of_field_resolve_get(bool use_bokeh_tx, bool use_hq_gather); +struct GPUShader *EEVEE_shaders_effect_color_copy_sh_get(void); struct GPUShader *EEVEE_shaders_effect_downsample_sh_get(void); struct GPUShader *EEVEE_shaders_effect_downsample_cube_sh_get(void); struct GPUShader *EEVEE_shaders_effect_minz_downlevel_sh_get(void); @@ -1472,8 +1469,8 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, const bool minimal); void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src); void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer); -void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level); void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level); void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index f9e22f5c08d..80a1c9fcbe5 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -42,29 +42,15 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; const float *viewport_size = DRW_viewport_size_get(); const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - /* Compute pixel size, (shared with contact shadows) */ - copy_v2_v2(common_data->ssr_pixelsize, viewport_size); - invert_v2(common_data->ssr_pixelsize); - if (scene_eval->eevee.flag & SCE_EEVEE_SSR_ENABLED) { const bool use_refraction = (scene_eval->eevee.flag & SCE_EEVEE_SSR_REFRACTION) != 0; - if (use_refraction) { - /* TODO: Opti: Could be shared. */ - DRW_texture_ensure_fullscreen_2d( - &txl->refract_color, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP); - - GPU_framebuffer_ensure_config( - &fbl->refract_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->refract_color)}); - } - const bool is_persp = DRW_view_is_persp_get(NULL); if (effects->ssr_was_persp != is_persp) { effects->ssr_was_persp = is_persp; @@ -117,8 +103,7 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output), GPU_ATTACHMENT_TEXTURE(effects->ssr_pdf_output)}); - /* Enable double buffering to be able to read previous frame color */ - return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_DOUBLE_BUFFER | + return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_RADIANCE_BUFFER | EFFECT_DOUBLE_BUFFER | ((use_refraction) ? EFFECT_REFRACT : 0); } @@ -189,7 +174,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth); DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output); DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output); - DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->color_double_buffer); + DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->filtered_radiance); DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); @@ -216,8 +201,7 @@ void EEVEE_refraction_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v EEVEE_EffectsInfo *effects = stl->effects; if ((effects->enabled_effects & EFFECT_REFRACT) != 0) { - GPU_framebuffer_blit(fbl->main_fb, 0, fbl->refract_fb, 0, GPU_COLOR_BIT); - EEVEE_downsample_buffer(vedata, txl->refract_color, 9); + EEVEE_effects_downsample_radiance_buffer(vedata, txl->color); /* Restore */ GPU_framebuffer_bind(fbl->main_fb); @@ -242,7 +226,7 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v GPU_framebuffer_bind(fbl->screen_tracing_fb); DRW_draw_pass(psl->ssr_raytrace); - EEVEE_downsample_buffer(vedata, txl->color_double_buffer, 9); + EEVEE_effects_downsample_radiance_buffer(vedata, txl->color_double_buffer); /* Resolve at fullres */ int samp = (DRW_state_is_image_render()) ? effects->taa_render_sample : diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index a3e9236dc79..74c4803928a 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -103,7 +103,8 @@ static struct { struct GPUShader *minz_copydepth_sh; struct GPUShader *maxz_copydepth_sh; - /* Simple Down-sample */ + /* Simple Down-sample. */ + struct GPUShader *color_copy_sh; struct GPUShader *downsample_sh; struct GPUShader *downsample_cube_sh; @@ -452,10 +453,20 @@ GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void) /** \name Down-sampling * \{ */ +GPUShader *EEVEE_shaders_effect_color_copy_sh_get(void) +{ + if (e_data.color_copy_sh == NULL) { + e_data.color_copy_sh = DRW_shader_create_fullscreen_with_shaderlib( + datatoc_effect_downsample_frag_glsl, e_data.lib, "#define COPY_SRC\n"); + } + return e_data.color_copy_sh; +} + GPUShader *EEVEE_shaders_effect_downsample_sh_get(void) { if (e_data.downsample_sh == NULL) { - e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL); + e_data.downsample_sh = DRW_shader_create_fullscreen_with_shaderlib( + datatoc_effect_downsample_frag_glsl, e_data.lib, NULL); } return e_data.downsample_sh; } @@ -1537,6 +1548,7 @@ void EEVEE_shaders_free(void) MEM_SAFE_FREE(e_data.surface_geom_barycentric); DRW_SHADER_FREE_SAFE(e_data.lookdev_background); DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); + DRW_SHADER_FREE_SAFE(e_data.color_copy_sh); DRW_SHADER_FREE_SAFE(e_data.downsample_sh); DRW_SHADER_FREE_SAFE(e_data.downsample_cube_sh); DRW_SHADER_FREE_SAFE(e_data.minz_downlevel_sh); diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 473990e1683..0b01b186b1b 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -94,8 +94,7 @@ float search_horizon(vec3 vI, vec2 uv = uv_start + uv_dir * t; float lod = min(MAX_LOD, max(i - noise, 0.0) * aoQuality); - int mip = int(lod) + hizMipOffset; - float depth = textureLod(depth_tx, uv * mipRatio[mip].xy, floor(lod)).r; + float depth = textureLod(depth_tx, uv * hizUvScale.xy, floor(lod)).r; /* Bias depth a bit to avoid self shadowing issues. */ const float bias = 2.0 * 2.4e-7; diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl index a6c9eebaff2..24de4520207 100644 --- a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl @@ -2,7 +2,7 @@ layout(std140) uniform common_block { mat4 pastViewProjectionMatrix; - vec2 mipRatio[10]; /* To correct mip level texel misalignment */ + vec4 hizUvScale; /* To correct mip level texel misalignment */ /* Ambient Occlusion */ vec4 aoParameters[2]; /* Volumetric */ @@ -37,15 +37,15 @@ layout(std140) uniform common_block int prbIrradianceVisSize; float prbIrradianceSmooth; float prbLodCubeMax; - float prbLodPlanarMax; /* Misc*/ - int hizMipOffset; int rayType; float rayDepth; float alphaHashOffset; float alphaHashScale; + float pad6; float pad7; float pad8; + float pad9; }; /* rayType (keep in sync with ray_type) */ @@ -69,9 +69,3 @@ layout(std140) uniform common_block #define ssrQuality ssrParameters.x #define ssrThickness ssrParameters.y #define ssrPixelSize ssrParameters.zw - -vec2 mip_ratio_interp(float mip) -{ - float low_mip = floor(mip); - return mix(mipRatio[int(low_mip)], mipRatio[int(low_mip + 1.0)], mip - low_mip); -} diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl index 88d83cd913a..3ad3c90d27a 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl @@ -62,12 +62,6 @@ const vec2 quad_offsets[4] = vec2[4]( #define dof_coc_from_zdepth(d) calculate_coc(linear_depth(d)) -vec4 safe_color(vec4 c) -{ - /* Clamp to avoid black square artifacts if a pixel goes NaN. */ - return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */ -} - float dof_hdr_color_weight(vec4 color) { /* From UE4. Very fast "luma" weighting. */ diff --git a/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl index a4637b9df91..5bf850fe229 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl @@ -1,5 +1,9 @@ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + /** - * Simple down-sample shader. Takes the average of the 4 texels of lower mip. + * Simple down-sample shader. + * Do a gaussian filter using 4 bilinear texture samples. */ uniform sampler2D source; @@ -14,24 +18,25 @@ float brightness(vec3 c) void main() { -#if 0 - /* Reconstructing Target uvs like this avoid missing pixels if NPO2 */ - vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0)); + vec2 texel_size = 1.0 / vec2(textureSize(source, 0)); + vec2 uvs = gl_FragCoord.xy * texel_size; +#ifdef COPY_SRC FragColor = textureLod(source, uvs, 0.0); + FragColor = safe_color(FragColor); + + /* Clamped brightness. */ + float luma = max(1e-8, brightness(FragColor.rgb)); + FragColor *= 1.0 - max(0.0, luma - fireflyFactor) / luma; + #else - vec2 texel_size = 1.0 / vec2(textureSize(source, 0)); - vec2 uvs = gl_FragCoord.xy * 2.0 * texel_size; vec4 ofs = texel_size.xyxy * vec4(0.75, 0.75, -0.75, -0.75); + uvs *= 2.0; FragColor = textureLod(source, uvs + ofs.xy, 0.0); FragColor += textureLod(source, uvs + ofs.xw, 0.0); FragColor += textureLod(source, uvs + ofs.zy, 0.0); FragColor += textureLod(source, uvs + ofs.zw, 0.0); FragColor *= 0.25; - - /* Clamped brightness. */ - float luma = max(1e-8, brightness(FragColor.rgb)); - FragColor *= 1.0 - max(0.0, luma - fireflyFactor) / luma; #endif } diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl index b99037b1e80..ccb65d2e5a6 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl @@ -2,6 +2,9 @@ * Shader that down-sample depth buffer, * saving min and max value of each texel in the above mipmaps. * Adapted from http://rastergrid.com/blog/2010/10/hierarchical-z-map-based-occlusion-culling/ + * + * Major simplification has been made since we pad the buffer to always be bigger than input to + * avoid mipmapping misalignement. */ #ifdef LAYERED @@ -12,10 +15,10 @@ uniform sampler2D depthBuffer; #endif #ifdef LAYERED -# define sampleLowerMip(t) texelFetch(depthBuffer, ivec3(t, depthLayer), 0).r +# define sampleLowerMip(t) texture(depthBuffer, vec3(t, depthLayer)).r # define gatherLowerMip(t) textureGather(depthBuffer, vec3(t, depthLayer)) #else -# define sampleLowerMip(t) texelFetch(depthBuffer, t, 0).r +# define sampleLowerMip(t) texture(depthBuffer, t).r # define gatherLowerMip(t) textureGather(depthBuffer, t) #endif @@ -37,54 +40,27 @@ out vec4 fragColor; void main() { - ivec2 texelPos = ivec2(gl_FragCoord.xy); - ivec2 mipsize = textureSize(depthBuffer, 0).xy; - -#ifndef COPY_DEPTH - texelPos *= 2; -#endif + vec2 texel = gl_FragCoord.xy; + vec2 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); #ifdef COPY_DEPTH - float val = sampleLowerMip(texelPos); + vec2 uv = texel * texel_size; + + float val = sampleLowerMip(uv); #else + vec2 uv = texel * 2.0 * texel_size; + vec4 samp; # ifdef GPU_ARB_texture_gather - /* + 1.0 to gather at the center of target 4 texels. */ - samp = gatherLowerMip((vec2(texelPos) + 1.0) / vec2(mipsize)); + samp = gatherLowerMip(uv); # else - samp.x = sampleLowerMip(texelPos); - samp.y = sampleLowerMip(texelPos + ivec2(1, 0)); - samp.z = sampleLowerMip(texelPos + ivec2(1, 1)); - samp.w = sampleLowerMip(texelPos + ivec2(0, 1)); + samp.x = sampleLowerMip(uv + vec2(-0.5, -0.5) * texel_size); + samp.y = sampleLowerMip(uv + vec2(-0.5, 0.5) * texel_size); + samp.z = sampleLowerMip(uv + vec2(0.5, -0.5) * texel_size); + samp.w = sampleLowerMip(uv + vec2(0.5, 0.5) * texel_size); # endif float val = minmax4(samp.x, samp.y, samp.z, samp.w); - - /* if we are reducing an odd-width texture then fetch the edge texels */ - if (((mipsize.x & 1) != 0) && (texelPos.x == mipsize.x - 3)) { - /* if both edges are odd, fetch the top-left corner texel */ - if (((mipsize.y & 1) != 0) && (texelPos.y == mipsize.y - 3)) { - samp.x = sampleLowerMip(texelPos + ivec2(2, 2)); - val = minmax2(val, samp.x); - } -# ifdef GPU_ARB_texture_gather - samp = gatherLowerMip((vec2(texelPos) + vec2(2.0, 1.0)) / vec2(mipsize)); -# else - samp.y = sampleLowerMip(texelPos + ivec2(2, 0)); - samp.z = sampleLowerMip(texelPos + ivec2(2, 1)); -# endif - val = minmax3(val, samp.y, samp.z); - } - /* if we are reducing an odd-height texture then fetch the edge texels */ - if (((mipsize.y & 1) != 0) && (texelPos.y == mipsize.y - 3)) { -# ifdef GPU_ARB_texture_gather - samp = gatherLowerMip((vec2(texelPos) + vec2(1.0, 2.0)) / vec2(mipsize)); -# else - samp.x = sampleLowerMip(texelPos + ivec2(0, 2)); - samp.y = sampleLowerMip(texelPos + ivec2(1, 2)); -# endif - val = minmax3(val, samp.x, samp.y); - } #endif #if defined(GPU_INTEL) || defined(GPU_ATI) diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index ecff28dcd38..f2117d8ee67 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -104,6 +104,11 @@ void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) pdfData = min(1024e32, pdf_ggx_reflect(NH, a2)); /* Theoretical limit of 16bit float */ + /* TODO(fclem) This bias should use depth precision and the dot product between + * ray direction and geom normal. */ + float rays_bias = 0.005; + vP = vP + vNg * rays_bias; + vec3 hit_pos = raycast(-1, vP, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true); hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false); @@ -325,10 +330,10 @@ vec3 get_hit_vector(vec3 hit_pos, vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar) { if (is_planar) { - return textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, prbLodPlanarMax)).rgb; + return textureLod(probePlanars, vec3(ref_uvs, planar_index), mip).rgb; } else { - return textureLod(prevColorBuffer, ref_uvs, mip).rgb; + return textureLod(prevColorBuffer, ref_uvs * hizUvScaleBias.xy + hizUvScaleBias.zw, mip).rgb; } } @@ -403,12 +408,6 @@ vec4 get_ssr_samples(vec4 hit_pdf, vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0)))); mip = clamp(mip, 0.0, MAX_MIP); - /* Correct UVs for mipmaping mis-alignment */ - hit_co[0].xy *= mip_ratio_interp(mip.x); - hit_co[0].zw *= mip_ratio_interp(mip.y); - hit_co[1].xy *= mip_ratio_interp(mip.z); - hit_co[1].zw *= mip_ratio_interp(mip.w); - /* Slide 54 */ vec4 bsdf; bsdf.x = bsdf_ggx(N, hit_pos[0], V, roughnessSquared); diff --git a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl index 28947e971d2..165aed2a46f 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl @@ -10,12 +10,6 @@ uniform mat4 prevViewProjectionMatrix; out vec4 FragColor; -vec4 safe_color(vec4 c) -{ - /* Clamp to avoid black square artifacts if a pixel goes NaN. */ - return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */ -} - #ifdef USE_REPROJECTION /** diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index aebd1c3aef3..fbc13d832bd 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -16,10 +16,7 @@ float sample_depth(vec2 uv, int index, float lod) } else { #endif - lod = clamp(floor(lod), 0.0, 8.0); - /* Correct UVs for mipmaping mis-alignment */ - uv *= mipRatio[int(lod) + hizMipOffset]; - return textureLod(maxzBuffer, uv, lod).r; + return textureLod(maxzBuffer, uv * hizUvScale.xy, floor(lod)).r; #ifdef PLANAR_PROBE_RAYTRACE } #endif @@ -37,10 +34,10 @@ vec4 sample_depth_grouped(vec4 uv1, vec4 uv2, int index, float lod) } else { #endif - depths.x = textureLod(maxzBuffer, uv1.xy, lod).r; - depths.y = textureLod(maxzBuffer, uv1.zw, lod).r; - depths.z = textureLod(maxzBuffer, uv2.xy, lod).r; - depths.w = textureLod(maxzBuffer, uv2.zw, lod).r; + depths.x = textureLod(maxzBuffer, uv1.xy * hizUvScale.xy, lod).r; + depths.y = textureLod(maxzBuffer, uv1.zw * hizUvScale.xy, lod).r; + depths.z = textureLod(maxzBuffer, uv2.xy * hizUvScale.xy, lod).r; + depths.w = textureLod(maxzBuffer, uv2.zw * hizUvScale.xy, lod).r; #ifdef PLANAR_PROBE_RAYTRACE } #endif @@ -131,9 +128,6 @@ void prepare_raycast(vec3 ray_origin, #endif ss_ray = ss_start * m.xyyy + 0.5; ss_step *= m.xyyy; - - /* take the center of the texel. */ - // ss_ray.xy += sign(ss_ray.xy) * m * ssrPixelSize * (1.0 + hizMipOffset); } /* See times_and_deltas. */ @@ -175,9 +169,7 @@ vec3 raycast(int index, bool hit = false; float iter; for (iter = 1.0; !hit && (ray_time < max_time) && (iter < MAX_STEP); iter++) { - /* Minimum stride of 2 because we are using half res minmax zbuffer. */ - /* WORKAROUND: Factor is a bit higher than 2 to avoid some banding. To investigate. */ - float stride = max(1.0, iter * trace_quality) * (2.0 + 0.05); + float stride = max(1.01, iter * trace_quality); float lod = log2(stride * 0.5 * trace_quality) * lod_fac; ray_time += stride; diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl index 15c28efe622..907a9cf17f8 100644 --- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl @@ -68,10 +68,7 @@ vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughness vec2 texture_size = vec2(textureSize(colorBuffer, 0).xy); float mip = clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, 9.0); - /* Correct UVs for mipmaping mis-alignment */ - hit_uvs *= mip_ratio_interp(mip); - - vec3 spec = textureLod(colorBuffer, hit_uvs, mip).xyz; + vec3 spec = textureLod(colorBuffer, hit_uvs * hizUvScale.xy, mip).xyz; float mask = screen_border_mask(hit_uvs); return vec4(spec, mask); diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl index d02fd27f35f..0344b977139 100644 --- a/source/blender/draw/intern/shaders/common_math_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_lib.glsl @@ -128,6 +128,12 @@ vec3 normalize_len(vec3 v, out float len) return v / len; } +vec4 safe_color(vec4 c) +{ + /* Clamp to avoid black square artifacts if a pixel goes NaN. */ + return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */ +} + /** \} */ /* ---------------------------------------------------------------------- */ -- cgit v1.2.3 From 6842c549bb3f976fc4891d2e6f7469b3705655f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 5 Mar 2021 20:32:54 +0100 Subject: EEVEE: SSRayTrace: Cleanup/Refactor This is a major rewrite that improves the screen space raytracing a little bit. This also decouple ray preparation from raytracing to be reuse in other part of the code. This changes a few things: - Reflections have lower grazing angle failure - Reflections have less self intersection issues - Contact shadows are now fully opaque (faster) Unrelated but some self intersection / incorrect bad rays are caused by the ray reconstruction technique used by the SSR. This is not fixed by this commit but I added a TODO. --- .../engines/eevee/shaders/effect_ssr_frag.glsl | 71 ++-- .../draw/engines/eevee/shaders/lights_lib.glsl | 33 +- .../draw/engines/eevee/shaders/raytrace_lib.glsl | 380 ++++++++++----------- .../draw/engines/eevee/shaders/ssr_lib.glsl | 16 +- 4 files changed, 237 insertions(+), 263 deletions(-) diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index f2117d8ee67..66183e1bc02 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -63,14 +63,19 @@ void do_planar_ssr( pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */ - /* Since viewspace hit position can land behind the camera in this case, - * we save the reflected view position (visualize it as the hit position - * below the reflection plane). This way it's garanted that the hit will - * be in front of the camera. That let us tag the bad rays with a negative - * sign in the Z component. */ - vec3 hit_pos = raycast(index, vP, R * 1e16, 1e16, rand.y, ssrQuality, a2, false); - - hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), true); + Ray ray; + ray.origin = vP; + ray.direction = R * 1e16; + + RayTraceParameters params; + params.jitter = rand.y; + params.trace_quality = ssrQuality; + params.roughness = a2; + + vec3 hit_pos; + bool hit = raytrace_planar(ray, params, index, hit_pos); + + hitData = encode_hit_data(hit_pos.xy, hit, true); } void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) @@ -104,27 +109,30 @@ void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) pdfData = min(1024e32, pdf_ggx_reflect(NH, a2)); /* Theoretical limit of 16bit float */ - /* TODO(fclem) This bias should use depth precision and the dot product between - * ray direction and geom normal. */ - float rays_bias = 0.005; - vP = vP + vNg * rays_bias; + vP = raytrace_offset(vP, vNg); + + Ray ray; + ray.origin = vP; + ray.direction = R * 1e16; - vec3 hit_pos = raycast(-1, vP, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true); + RayTraceParameters params; + params.thickness = ssrThickness; + params.jitter = rand.y; + params.trace_quality = ssrQuality; + params.roughness = a2; - hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false); + vec3 hit_pos; + bool hit = raytrace(ray, params, true, hit_pos); + + hitData = encode_hit_data(hit_pos.xy, hit, false); } +in vec4 uvcoordsvar; + void main() { -# ifdef FULLRES - ivec2 fullres_texel = ivec2(gl_FragCoord.xy); - ivec2 halfres_texel = fullres_texel; -# else - ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2 + halfresOffset; - ivec2 halfres_texel = ivec2(gl_FragCoord.xy); -# endif - - float depth = texelFetch(depthBuffer, fullres_texel, 0).r; + vec2 uvs = uvcoordsvar.xy; + float depth = textureLod(depthBuffer, uvs, 0.0).r; /* Default: not hits. */ hitData = encode_hit_data(vec2(0.5), false, false); @@ -136,18 +144,16 @@ void main() return; } - vec2 uvs = vec2(fullres_texel) / vec2(textureSize(depthBuffer, 0)); - /* Using view space */ vec3 vP = get_view_space_from_depth(uvs, depth); vec3 P = transform_point(ViewMatrixInverse, vP); vec3 vV = viewCameraVec(vP); vec3 V = cameraVec(P); - vec3 vN = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, vV); + vec3 vN = normal_decode(texture(normalBuffer, uvs, 0).rg, vV); vec3 N = transform_direction(ViewMatrixInverse, vN); /* Retrieve pixel data */ - vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba; + vec4 speccol_roughness = texture(specroughBuffer, uvs, 0).rgba; /* Early out */ if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) { @@ -163,7 +169,7 @@ void main() return; } - vec4 rand = texelfetch_noise_tex(halfres_texel); + vec4 rand = texelfetch_noise_tex(vec2(gl_FragCoord.xy)); /* Gives *perfect* reflection for very small roughness */ if (roughness < 0.04) { @@ -194,11 +200,6 @@ void main() } } - /* Constant bias (due to depth buffer precision). Helps with self intersection. */ - /* Magic numbers for 24bits of precision. - * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */ - vP.z = get_view_z_from_depth(depth - mix(2.4e-7, 4.8e-7, depth)); - do_ssr(vV, vN, vT, vB, vP, a2, rand); } @@ -333,7 +334,7 @@ vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar return textureLod(probePlanars, vec3(ref_uvs, planar_index), mip).rgb; } else { - return textureLod(prevColorBuffer, ref_uvs * hizUvScaleBias.xy + hizUvScaleBias.zw, mip).rgb; + return textureLod(prevColorBuffer, ref_uvs * hizUvScale.xy, mip).rgb; } } @@ -356,6 +357,8 @@ vec4 get_ssr_samples(vec4 hit_pdf, hit_co[1].xy = decode_hit_data(hit_data[1].xy, has_hit.z, is_planar.z); hit_co[1].zw = decode_hit_data(hit_data[1].zw, has_hit.w, is_planar.w); + /* TODO/FIXME(fclem) This is giving precision issues due to refined intersection. This is most + * noticeable on rough surfaces. */ vec4 hit_depth; hit_depth.x = get_sample_depth(hit_co[0].xy, is_planar.x, planar_index); hit_depth.y = get_sample_depth(hit_co[0].zw, is_planar.y, planar_index); diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl index 04ad53eabb7..bd752d33819 100644 --- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl @@ -276,31 +276,30 @@ float light_contact_shadows( /* Only compute if not already in shadow. */ if (sd.sh_contact_dist > 0.0) { /* Contact Shadows. */ - vec3 ray_ori, ray_dir; - float trace_distance; + Ray ray; if (ld.l_type == SUN) { - trace_distance = sd.sh_contact_dist; - ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance; + ray.direction = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * + sd.sh_contact_dist; } else { - ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P; - float len = length(ray_dir); - trace_distance = min(sd.sh_contact_dist, len); - ray_dir *= trace_distance / len; + ray.direction = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P; + ray.direction *= saturate(sd.sh_contact_dist * safe_rcp(length(ray.direction))); } - ray_dir = transform_direction(ViewMatrix, ray_dir); - ray_ori = vec3(vP.xy, tracing_depth) + vNg * sd.sh_contact_offset; + ray.direction = transform_direction(ViewMatrix, ray.direction); + ray.origin = vP + vNg * sd.sh_contact_offset; - vec3 hit_pos = raycast( - -1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false); + RayTraceParameters params; + params.thickness = sd.sh_contact_thickness; + params.jitter = rand_x; + params.trace_quality = 0.1; + params.roughness = 0.001; - if (hit_pos.z > 0.0) { - hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z); - float hit_dist = distance(vP, hit_pos); - float dist_ratio = hit_dist / trace_distance; - return saturate(dist_ratio * 3.0 - 2.0); + vec3 hit_position_unused; + + if (raytrace(ray, params, false, hit_position_unused)) { + return 0.0; } } } diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index fbc13d832bd..0adfea9ca73 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -3,253 +3,215 @@ #pragma BLENDER_REQUIRE(common_math_lib.glsl) #pragma BLENDER_REQUIRE(common_uniforms_lib.glsl) +/** + * Screen-Space Raytracing functions. + */ + uniform sampler2D maxzBuffer; uniform sampler2DArray planarDepth; -#define MAX_STEP 256 +struct Ray { + vec3 origin; + vec3 direction; +}; -float sample_depth(vec2 uv, int index, float lod) +vec3 raytrace_offset(vec3 P, vec3 Ng) { -#ifdef PLANAR_PROBE_RAYTRACE - if (index > -1) { - return textureLod(planarDepth, vec3(uv, index), 0.0).r; - } - else { -#endif - return textureLod(maxzBuffer, uv * hizUvScale.xy, floor(lod)).r; -#ifdef PLANAR_PROBE_RAYTRACE - } -#endif + /* TODO(fclem) better offset */ + const float epsilon_f = 1e-4; + return P + epsilon_f * Ng; } -vec4 sample_depth_grouped(vec4 uv1, vec4 uv2, int index, float lod) +/* Inputs expected to be in viewspace. */ +void raytrace_clip_ray_to_near_plane(inout Ray ray) { - vec4 depths; -#ifdef PLANAR_PROBE_RAYTRACE - if (index > -1) { - depths.x = textureLod(planarDepth, vec3(uv1.xy, index), 0.0).r; - depths.y = textureLod(planarDepth, vec3(uv1.zw, index), 0.0).r; - depths.z = textureLod(planarDepth, vec3(uv2.xy, index), 0.0).r; - depths.w = textureLod(planarDepth, vec3(uv2.zw, index), 0.0).r; + float near_dist = get_view_z_from_depth(0.0); + if ((ray.origin.z + ray.direction.z) > near_dist) { + ray.direction *= abs((near_dist - ray.origin.z) / ray.direction.z); } - else { -#endif - depths.x = textureLod(maxzBuffer, uv1.xy * hizUvScale.xy, lod).r; - depths.y = textureLod(maxzBuffer, uv1.zw * hizUvScale.xy, lod).r; - depths.z = textureLod(maxzBuffer, uv2.xy * hizUvScale.xy, lod).r; - depths.w = textureLod(maxzBuffer, uv2.zw * hizUvScale.xy, lod).r; -#ifdef PLANAR_PROBE_RAYTRACE - } -#endif - return depths; } -float refine_isect(float prev_delta, float curr_delta) -{ - /** - * Simplification of 2D intersection : - * r0 = (0.0, prev_ss_ray.z); - * r1 = (1.0, curr_ss_ray.z); - * d0 = (0.0, prev_hit_depth_sample); - * d1 = (1.0, curr_hit_depth_sample); - * vec2 r = r1 - r0; - * vec2 d = d1 - d0; - * vec2 isect = ((d * cross(r1, r0)) - (r * cross(d1, d0))) / cross(r,d); - * - * We only want isect.x to know how much stride we need. So it simplifies : - * - * isect_x = (cross(r1, r0) - cross(d1, d0)) / cross(r,d); - * isect_x = (prev_ss_ray.z - prev_hit_depth_sample.z) / cross(r,d); - */ - return saturate(prev_delta / (prev_delta - curr_delta)); -} +/* Screenspace ray ([0..1] "uv" range) where direction is normalize to be as small as one + * full-resolution pixel. The ray is also clipped to all frustum sides. + */ +struct ScreenSpaceRay { + vec4 origin; + vec4 direction; + float max_time; +}; -void prepare_raycast(vec3 ray_origin, - vec3 ray_dir, - float thickness, - int index, - out vec4 ss_step, - out vec4 ss_ray, - out float max_time) +void raytrace_screenspace_ray_finalize(inout ScreenSpaceRay ray) { - /* Negate the ray direction if it goes towards the camera. - * This way we don't need to care if the projected point - * is behind the near plane. */ - float z_sign = -sign(ray_dir.z); - vec3 ray_end = ray_origin + z_sign * ray_dir; - - /* Project into screen space. */ - vec4 ss_start, ss_end; - ss_start.xyz = project_point(ProjectionMatrix, ray_origin); - ss_end.xyz = project_point(ProjectionMatrix, ray_end); - - /* We interpolate the ray Z + thickness values to check if depth is within threshold. */ - ray_origin.z -= thickness; - ray_end.z -= thickness; - ss_start.w = project_point(ProjectionMatrix, ray_origin).z; - ss_end.w = project_point(ProjectionMatrix, ray_end).z; - - /* XXX This is a hack. A better method is welcome! */ - /* We take the delta between the offsetted depth and the depth and subtract it from the ray - * depth. This will change the world space thickness appearance a bit but we can have negative - * values without worries. We cannot do this in viewspace because of the perspective division. */ - ss_start.w = 2.0 * ss_start.z - ss_start.w; - ss_end.w = 2.0 * ss_end.z - ss_end.w; - - ss_step = ss_end - ss_start; - max_time = length(ss_step.xyz); - ss_step = z_sign * ss_step / length(ss_step.xyz); - + /* Constant bias (due to depth buffer precision). Helps with self intersection. */ + /* Magic numbers for 24bits of precision. + * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */ + const float bias = -2.4e-7 * 2.0; + ray.origin.zw += bias; + ray.direction.zw += bias; + + ray.direction -= ray.origin; + float ray_len_sqr = len_squared(ray.direction.xyz); /* If the line is degenerate, make it cover at least one pixel * to not have to handle zero-pixel extent as a special case later */ - if (dot(ss_step.xy, ss_step.xy) < 0.00001) { - ss_step.xy = vec2(0.0, 0.0001); + if (ray_len_sqr < 0.00001) { + ray.direction.xy = vec2(0.0, 0.0001); } - - /* Make ss_step cover one pixel. */ - ss_step /= max(abs(ss_step.x), abs(ss_step.y)); - ss_step *= (abs(ss_step.x) > abs(ss_step.y)) ? ssrPixelSize.x : ssrPixelSize.y; - + /* Make ray.direction cover one pixel. */ + bool is_more_vertical = abs(ray.direction.x) < abs(ray.direction.y); + ray.direction /= (is_more_vertical) ? abs(ray.direction.y) : abs(ray.direction.x); + ray.direction *= (is_more_vertical) ? ssrPixelSize.y : ssrPixelSize.x; /* Clip to segment's end. */ - max_time /= length(ss_step.xyz); + ray.max_time = sqrt(ray_len_sqr * safe_rcp(len_squared(ray.direction.xyz))); /* Clipping to frustum sides. */ - max_time = min(max_time, line_unit_box_intersect_dist(ss_start.xyz, ss_step.xyz)); + float clip_dist = line_unit_box_intersect_dist(ray.origin.xyz, ray.direction.xyz); + ray.max_time = min(ray.max_time, clip_dist); /* Avoid no iteration. */ - max_time = max(max_time, 1.0); + ray.max_time = max(ray.max_time, 1.1); + /* Convert to texture coords [0..1] range. */ + ray.origin = ray.origin * 0.5 + 0.5; + ray.direction *= 0.5; +} - /* Convert to texture coords. Z component included - * since this is how it's stored in the depth buffer. - * 4th component how far we are on the ray */ -#ifdef PLANAR_PROBE_RAYTRACE - /* Planar Reflections have X mirrored. */ - vec2 m = (index > -1) ? vec2(-0.5, 0.5) : vec2(0.5); -#else - const vec2 m = vec2(0.5); -#endif - ss_ray = ss_start * m.xyyy + 0.5; - ss_step *= m.xyyy; +ScreenSpaceRay raytrace_screenspace_ray_create(Ray ray) +{ + ScreenSpaceRay ssray; + ssray.origin.xyz = project_point(ProjectionMatrix, ray.origin); + ssray.direction.xyz = project_point(ProjectionMatrix, ray.origin + ray.direction); + + raytrace_screenspace_ray_finalize(ssray); + return ssray; } -/* See times_and_deltas. */ -#define curr_time times_and_deltas.x -#define prev_time times_and_deltas.y -#define curr_delta times_and_deltas.z -#define prev_delta times_and_deltas.w +ScreenSpaceRay raytrace_screenspace_ray_create(Ray ray, float thickness) +{ + ScreenSpaceRay ssray; + ssray.origin.xyz = project_point(ProjectionMatrix, ray.origin); + ssray.direction.xyz = project_point(ProjectionMatrix, ray.origin + ray.direction); + /* Interpolate thickness in screen space. + * Calculate thickness further away to avoid near plane clipping issues. */ + ssray.origin.w = get_depth_from_view_z(ray.origin.z - thickness) * 2.0 - 1.0; + ssray.direction.w = get_depth_from_view_z(ray.origin.z + ray.direction.z - thickness) * 2.0 - + 1.0; + + raytrace_screenspace_ray_finalize(ssray); + return ssray; +} -// #define GROUPED_FETCHES /* is still slower, need to see where is the bottleneck. */ -/* Return the hit position, and negate the z component (making it positive) if not hit occurred. */ +struct RayTraceParameters { + /** ViewSpace thickness the objects */ + float thickness; + /** Jitter along the ray to avoid banding artifact when steps are too large. */ + float jitter; + /** Determine how fast the sample steps are getting bigger. */ + float trace_quality; + /** Determine how we can use lower depth mipmaps to make the tracing faster. */ + float roughness; +}; + +/* Return true on hit. */ /* __ray_dir__ is the ray direction premultiplied by its maximum length */ -vec3 raycast(int index, - vec3 ray_origin, - vec3 ray_dir, - float thickness, - float ray_jitter, - float trace_quality, - float roughness, - const bool discard_backface) +/* TODO fclem remove the backface check and do it the SSR resolve code. */ +bool raytrace(Ray ray, + RayTraceParameters params, + const bool discard_backface, + out vec3 hit_position) { - vec4 ss_step, ss_start; - float max_time; - prepare_raycast(ray_origin, ray_dir, thickness, index, ss_step, ss_start, max_time); - - float max_trace_time = max(0.01, max_time - 0.01); + /* Clip to near plane for perspective view where there is a singularity at the camera origin. */ + if (ProjectionMatrix[3][3] == 0.0) { + raytrace_clip_ray_to_near_plane(ray); + } -#ifdef GROUPED_FETCHES - ray_jitter *= 0.25; -#endif + ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray, params.thickness); - /* x : current_time, y: previous_time, z: current_delta, w: previous_delta */ - vec4 times_and_deltas = vec4(0.0); + float prev_delta = 0.0, prev_time = 0.0; + float depth_sample = get_depth_from_view_z(ray.origin.z); + float delta = depth_sample - ssray.origin.z; - float ray_time = 0.0; - float depth_sample = sample_depth(ss_start.xy, index, 0.0); - curr_delta = depth_sample - ss_start.z; + float lod_fac = saturate(fast_sqrt(params.roughness) * 2.0 - 0.4); - float lod_fac = saturate(fast_sqrt(roughness) * 2.0 - 0.4); + /* Cross at least one pixel. */ + float t = 1.001, time = 1.001; bool hit = false; - float iter; - for (iter = 1.0; !hit && (ray_time < max_time) && (iter < MAX_STEP); iter++) { - float stride = max(1.01, iter * trace_quality); - float lod = log2(stride * 0.5 * trace_quality) * lod_fac; - ray_time += stride; - - /* Save previous values. */ - times_and_deltas.xyzw = times_and_deltas.yxwz; - -#ifdef GROUPED_FETCHES - stride *= 4.0; - vec4 jit_stride = mix(vec4(2.0), vec4(stride), vec4(0.0, 0.25, 0.5, 0.75) + ray_jitter); - - vec4 times = min(vec4(ray_time) + jit_stride, vec4(max_trace_time)); - - vec4 uv1 = ss_start.xyxy + ss_step.xyxy * times.xxyy; - vec4 uv2 = ss_start.xyxy + ss_step.xyxy * times.zzww; - - vec4 depth_samples = sample_depth_grouped(uv1, uv2, index, lod); - - vec4 ray_z = ss_start.zzzz + ss_step.zzzz * times.xyzw; - vec4 ray_w = ss_start.wwww + ss_step.wwww * vec4(prev_time, times.xyz); - - vec4 deltas = depth_samples - ray_z; - /* Same as component wise (curr_delta <= 0.0) && (prev_w <= depth_sample). */ - bvec4 test = equal(step(deltas, vec4(0.0)) * step(ray_w, depth_samples), vec4(1.0)); - hit = any(test); - - if (hit) { - vec2 m = vec2(1.0, 0.0); /* Mask */ - - vec4 ret_times_and_deltas = times.wzzz * m.xxyy + deltas.wwwz * m.yyxx; - ret_times_and_deltas = (test.z) ? times.zyyy * m.xxyy + deltas.zzzy * m.yyxx : - ret_times_and_deltas; - ret_times_and_deltas = (test.y) ? times.yxxx * m.xxyy + deltas.yyyx * m.yyxx : - ret_times_and_deltas; - times_and_deltas = (test.x) ? times.xxxx * m.xyyy + deltas.xxxx * m.yyxy + - times_and_deltas.yyww * m.yxyx : - ret_times_and_deltas; - - depth_sample = depth_samples.w; - depth_sample = (test.z) ? depth_samples.z : depth_sample; - depth_sample = (test.y) ? depth_samples.y : depth_sample; - depth_sample = (test.x) ? depth_samples.x : depth_sample; - } - else { - curr_time = times.w; - curr_delta = deltas.w; - } -#else - float jit_stride = mix(2.0, stride, ray_jitter); - - curr_time = min(ray_time + jit_stride, max_trace_time); - vec4 ss_ray = ss_start + ss_step * curr_time; - - depth_sample = sample_depth(ss_ray.xy, index, lod); - - float prev_w = ss_start.w + ss_step.w * prev_time; - curr_delta = depth_sample - ss_ray.z; - hit = (curr_delta <= 0.0) && (prev_w <= depth_sample); -#endif - } + const float max_steps = 255.0; + for (float iter = 1.0; !hit && (time < ssray.max_time) && (iter < max_steps); iter++) { + float stride = 1.0 + iter * params.trace_quality; + float lod = log2(stride) * lod_fac; - /* Discard backface hits. Only do this if the ray traveled enough to avoid losing intricate - * contact reflections. This is only used for SSReflections. */ - if (discard_backface && prev_delta < 0.0 && curr_time > 4.1) { - hit = false; - } + prev_time = time; + prev_delta = delta; + time = min(t + stride * params.jitter, ssray.max_time); + t += stride; + + vec4 ss_p = ssray.origin + ssray.direction * time; + depth_sample = textureLod(maxzBuffer, ss_p.xy * hizUvScale.xy, floor(lod)).r; + + delta = depth_sample - ss_p.z; + /* Check if the ray is below the surface ... */ + hit = (delta < 0.0); + /* ... and above it with the added thickness. */ + hit = hit && (delta > ss_p.z - ss_p.w); + } + /* Discard backface hits. */ + hit = hit && !(discard_backface && prev_delta < 0.0); /* Reject hit if background. */ hit = hit && (depth_sample != 1.0); + /* Refine hit using intersection between the sampled heightfield and the ray. + * This simplifies nicely to this single line. */ + time = mix(prev_time, time, saturate(prev_delta / (prev_delta - delta))); + + hit_position = ssray.origin.xyz + ssray.direction.xyz * time; + + return hit; +} - curr_time = (hit) ? mix(prev_time, curr_time, refine_isect(prev_delta, curr_delta)) : curr_time; - ray_time = (hit) ? curr_time : ray_time; +bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out vec3 hit_position) +{ + /* Clip to near plane for perspective view where there is a singularity at the camera origin. */ + if (ProjectionMatrix[3][3] == 0.0) { + raytrace_clip_ray_to_near_plane(ray); + } + + ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray); + + /* Planar Reflections have X mirrored. */ + ssray.origin.x = 1.0 - ssray.origin.x; + ssray.direction.x = -ssray.direction.x; - /* Clip to frustum. */ - ray_time = max(0.001, min(ray_time, max_time - 1.5)); + float prev_delta = 0.0, prev_time = 0.0; + float depth_sample = get_depth_from_view_z(ray.origin.z); + float delta = depth_sample - ssray.origin.z; + + /* Cross at least one pixel. */ + float t = 1.001, time = 1.001; + bool hit = false; + const float max_steps = 255.0; + for (float iter = 1.0; !hit && (time < ssray.max_time) && (iter < max_steps); iter++) { + float stride = 1.0 + iter * params.trace_quality; + + prev_time = time; + prev_delta = delta; + + time = min(t + stride * params.jitter, ssray.max_time); + t += stride; + + vec4 ss_ray = ssray.origin + ssray.direction * time; + + depth_sample = texture(planarDepth, vec3(ss_ray.xy, planar_ref_id)).r; + + delta = depth_sample - ss_ray.z; + /* Check if the ray is below the surface. */ + hit = (delta < 0.0); + } + /* Reject hit if background. */ + hit = hit && (depth_sample != 1.0); + /* Refine hit using intersection between the sampled heightfield and the ray. + * This simplifies nicely to this single line. */ + time = mix(prev_time, time, saturate(prev_delta / (prev_delta - delta))); - vec4 ss_ray = ss_start + ss_step * ray_time; + hit_position = ssray.origin.xyz + ssray.direction.xyz * time; - /* Tag Z if ray failed. */ - ss_ray.z *= (hit) ? 1.0 : -1.0; - return ss_ray.xyz; + return hit; } float screen_border_mask(vec2 hit_co) diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl index 907a9cf17f8..5a09120916a 100644 --- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl @@ -39,10 +39,20 @@ vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughness R = transform_direction(ViewMatrix, R); - vec3 hit_pos = raycast( - -1, vP, R * 1e16, ssrThickness, rand.y, ssrQuality, roughnessSquared, false); + Ray ray; + ray.origin = vP; + ray.direction = R * 1e16; - if ((hit_pos.z > 0.0) && (F_eta(ior, dot(H, V)) < 1.0)) { + RayTraceParameters params; + params.thickness = ssrThickness; + params.jitter = rand.y; + params.trace_quality = ssrQuality; + params.roughness = roughnessSquared; + + vec3 hit_pos; + bool hit = raytrace(ray, params, false, hit_pos); + + if (hit && (F_eta(ior, dot(H, V)) < 1.0)) { hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z); float hit_dist = distance(hit_pos, vP); -- cgit v1.2.3 From 5db5966cdb61d5711d5c737fd8d000c69be9cf5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 5 Mar 2021 20:46:30 +0100 Subject: EEVEE: Sampling: Split hemisphere sampling just like GGX This is useful for debugging raycasting. --- .../engines/eevee/shaders/bsdf_sampling_lib.glsl | 32 ++++++++++++++-------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl index 4abc313d7e3..bbc79a2d05b 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl @@ -36,7 +36,7 @@ vec3 sample_ggx(vec3 rand, float a2) { /* Theta is the cone angle. */ float z = sqrt((1.0 - rand.x) / (1.0 + a2 * rand.x - rand.x)); /* cos theta */ - float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */ + float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */ float x = r * rand.y; float y = r * rand.z; @@ -51,6 +51,23 @@ vec3 sample_ggx(vec3 rand, float a2, vec3 N, vec3 T, vec3 B, out float NH) return tangent_to_world(Ht, N, T, B); } +vec3 sample_hemisphere(vec3 rand) +{ + /* Theta is the cone angle. */ + float z = rand.x; /* cos theta */ + float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */ + float x = r * rand.y; + float y = r * rand.z; + + return vec3(x, y, z); +} + +vec3 sample_hemisphere(vec3 rand, vec3 N, vec3 T, vec3 B) +{ + vec3 Ht = sample_hemisphere(rand); + return tangent_to_world(Ht, N, T, B); +} + #ifdef HAMMERSLEY_SIZE vec3 sample_ggx(float nsample, float inv_sample_count, float a2, vec3 N, vec3 T, vec3 B) { @@ -62,14 +79,7 @@ vec3 sample_ggx(float nsample, float inv_sample_count, float a2, vec3 N, vec3 T, vec3 sample_hemisphere(float nsample, float inv_sample_count, vec3 N, vec3 T, vec3 B) { vec3 Xi = hammersley_3d(nsample, inv_sample_count); - - float z = Xi.x; /* cos theta */ - float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */ - float x = r * Xi.y; - float y = r * Xi.z; - - vec3 Ht = vec3(x, y, z); - + vec3 Ht = sample_hemisphere(Xi); return tangent_to_world(Ht, N, T, B); } @@ -77,8 +87,8 @@ vec3 sample_cone(float nsample, float inv_sample_count, float angle, vec3 N, vec { vec3 Xi = hammersley_3d(nsample, inv_sample_count); - float z = cos(angle * Xi.x); /* cos theta */ - float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */ + float z = cos(angle * Xi.x); /* cos theta */ + float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */ float x = r * Xi.y; float y = r * Xi.z; -- cgit v1.2.3 From 0983e66e03001d9f38075d3a9ee8fcaa7966a7d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 8 Mar 2021 17:12:25 +0100 Subject: EEVEE: Occlusion: Use ScreenSpaceRay for iteration The sampling is now optimum with every samples being at least one pixel appart. Also use a squared repartition to improve the sampling near the center. This also removes the thickness heuristic since it seems to remove a lot of details and bias the AO too much. --- .../blender/draw/engines/eevee/eevee_occlusion.c | 2 +- .../eevee/shaders/ambient_occlusion_lib.glsl | 83 +++++++++++----------- .../draw/engines/eevee/shaders/raytrace_lib.glsl | 6 +- 3 files changed, 48 insertions(+), 43 deletions(-) diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index a3b581357e0..a7874440895 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -62,7 +62,7 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) common_data->ao_dist = scene_eval->eevee.gtao_distance; common_data->ao_factor = scene_eval->eevee.gtao_factor; - common_data->ao_quality = 1.0f - scene_eval->eevee.gtao_quality; + common_data->ao_quality = scene_eval->eevee.gtao_quality; if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) { common_data->ao_settings = 1.0f; /* USE_AO */ diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 0b01b186b1b..689f99edad9 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -31,7 +31,6 @@ uniform sampler2D horizonBuffer; #define USE_BENT_NORMAL 2 #define USE_DENOISE 4 -#define MAX_LOD 6.0 #define NO_OCCLUSION_DATA OcclusionData(vec4(M_PI, -M_PI, M_PI, -M_PI), 1.0) struct OcclusionData { @@ -77,25 +76,38 @@ vec2 get_ao_dir(float jitter) float search_horizon(vec3 vI, vec3 vP, float noise, - vec2 uv_start, - vec2 uv_dir, + ScreenSpaceRay ssray, sampler2D depth_tx, const float inverted, float radius, const float sample_count) { - float sample_count_inv = 1.0 / sample_count; /* Init at cos(M_PI). */ float h = (inverted != 0.0) ? 1.0 : -1.0; - /* TODO(fclem) samples steps should be using the same approach as raytrace. (DDA line algo.) */ - for (float i = 0.0; i < sample_count; i++) { - float t = ((i + noise) * sample_count_inv); - vec2 uv = uv_start + uv_dir * t; - float lod = min(MAX_LOD, max(i - noise, 0.0) * aoQuality); + ssray.max_time -= 1.0; + if (ssray.max_time <= 2.0) { + /* Produces self shadowing under this threshold. */ + return fast_acos(h); + } + + float prev_time, time = 0.0; + for (float iter = 0.0; time < ssray.max_time && iter < sample_count; iter++) { + prev_time = time; + /* Gives us good precision at center and ensure we cross at least one pixel per iteration. */ + time = 1.0 + iter + sqr((iter + noise) / sample_count) * ssray.max_time; + float stride = time - prev_time; + float lod = (log2(stride) - noise) / (1.0 + aoQuality); + + vec2 uv = ssray.origin.xy + ssray.direction.xy * time; float depth = textureLod(depth_tx, uv * hizUvScale.xy, floor(lod)).r; + if (depth == 1.0 && inverted == 0.0) { + /* Skip background. This avoids issues with the thickness heuristic. */ + continue; + } + /* Bias depth a bit to avoid self shadowing issues. */ const float bias = 2.0 * 2.4e-7; depth += (inverted != 0.0) ? -bias : bias; @@ -107,25 +119,16 @@ float search_horizon(vec3 vI, float s_h = dot(vI, omega_s / len); /* Blend weight to fade artifacts. */ float dist_ratio = abs(len) / radius; - /* TODO(fclem) parameter. */ - float dist_fac = sqr(saturate(dist_ratio * 2.0 - 1.0)); + /* Sphere falloff. */ + float dist_fac = sqr(saturate(dist_ratio)); + /* Unbiased, gives too much hard cut behind objects */ + // float dist_fac = step(0.999, dist_ratio); - /* Thickness heuristic (Eq. 9). */ if (inverted != 0.0) { h = min(h, s_h); } else { - /* TODO This need to take the stride distance into account. Now it works because stride is - * constant. */ - if (s_h < h) { - /* TODO(fclem) parameter. */ - const float thickness_fac = 0.2; - s_h = mix(h, s_h, thickness_fac); - } - else { - s_h = max(h, s_h); - } - h = mix(s_h, h, dist_fac); + h = mix(max(h, s_h), h, dist_fac); } } return fast_acos(h); @@ -150,22 +153,22 @@ OcclusionData occlusion_search( NO_OCCLUSION_DATA; for (int i = 0; i < 2; i++) { - /* View > NDC > Uv space. */ - vec2 uv_dir = dir * area * 0.5; - /* Offset the start one pixel to avoid self shadowing. */ - /* TODO(fclem) Using DDA line algo should fix this. */ - vec2 px_dir = uv_dir * textureSize(depth_tx, 0); - float max_px_dir = max_v2(abs(px_dir)); - vec2 uv_ofs = (px_dir / max_px_dir) / textureSize(depth_tx, 0); - /* No need to trace more. */ - uv_dir -= uv_ofs; - - if (max_px_dir > 1.0) { - data.horizons[0 + i * 2] = search_horizon( - vI, vP, noise.y, uv + uv_ofs, uv_dir, depth_tx, inverted, radius, dir_sample_count); - data.horizons[1 + i * 2] = -search_horizon( - vI, vP, noise.y, uv - uv_ofs, -uv_dir, depth_tx, inverted, radius, dir_sample_count); - } + Ray ray; + ray.origin = vP; + ray.direction = vec3(dir * radius, 0.0); + + ScreenSpaceRay ssray; + + ssray = raytrace_screenspace_ray_create(ray); + data.horizons[0 + i * 2] = search_horizon( + vI, vP, noise.y, ssray, depth_tx, inverted, radius, dir_sample_count); + + ray.direction = -ray.direction; + + ssray = raytrace_screenspace_ray_create(ray); + data.horizons[1 + i * 2] = -search_horizon( + vI, vP, noise.y, ssray, depth_tx, inverted, radius, dir_sample_count); + /* Rotate 90 degrees. */ dir = vec2(-dir.y, dir.x); } @@ -388,7 +391,7 @@ OcclusionData occlusion_load(vec3 vP, float custom_occlusion) data = unpack_occlusion_data(texelFetch(horizonBuffer, ivec2(gl_FragCoord.xy), 0)); } #else - /* For blended surfaces and */ + /* For blended surfaces. */ data = occlusion_search(vP, maxzBuffer, aoDistance, 0.0, 8.0); #endif diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index 0adfea9ca73..7c375aabb62 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -65,8 +65,6 @@ void raytrace_screenspace_ray_finalize(inout ScreenSpaceRay ray) /* Clipping to frustum sides. */ float clip_dist = line_unit_box_intersect_dist(ray.origin.xyz, ray.direction.xyz); ray.max_time = min(ray.max_time, clip_dist); - /* Avoid no iteration. */ - ray.max_time = max(ray.max_time, 1.1); /* Convert to texture coords [0..1] range. */ ray.origin = ray.origin * 0.5 + 0.5; ray.direction *= 0.5; @@ -122,6 +120,8 @@ bool raytrace(Ray ray, } ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray, params.thickness); + /* Avoid no iteration. */ + ssray.max_time = max(ssray.max_time, 1.1); float prev_delta = 0.0, prev_time = 0.0; float depth_sample = get_depth_from_view_z(ray.origin.z); @@ -173,6 +173,8 @@ bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out } ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray); + /* Avoid no iteration. */ + ssray.max_time = max(ssray.max_time, 1.1); /* Planar Reflections have X mirrored. */ ssray.origin.x = 1.0 - ssray.origin.x; -- cgit v1.2.3 From 1540f1df076ccd4fda224b7f56aa6ca0d2a9b1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 8 Mar 2021 17:16:46 +0100 Subject: EEVEE: RenderPass: Improve AO pass if screen space radius is small This just bypass the occlusion computation if there is no occlusion data. This avoids weird looking occlusion due to the screen space geometric normal reconstruction. --- source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl index 19ae0acc443..16b1a7ffeaa 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl @@ -99,9 +99,12 @@ void main() OcclusionData data = occlusion_load(vP, 1.0); - float visibility = diffuse_occlusion(data, V, N, Ng); - - FragColor = vec4(visibility); + if (min_v4(abs(data.horizons)) != M_PI) { + FragColor = vec4(diffuse_occlusion(data, V, N, Ng)); + } + else { + FragColor = vec4(1.0); + } } } -- cgit v1.2.3 From 30cb4326fe0f5f0a8dbcbb8f4b474226c833d793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 8 Mar 2021 17:19:06 +0100 Subject: EEVEE: Ambient Occlusion: Add sample parameter support for the AO node The actual sample count is rounded up to a multiple of 4 because we sample 4 horizons directions. Changing this setting forces the shader to recompile (because using a GPU_constant). --- .../shaders/material/gpu_shader_material_ambient_occlusion.glsl | 3 ++- .../blender/nodes/shader/nodes/node_shader_ambient_occlusion.c | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl index 0231aeca04b..edf2c93c9a0 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl @@ -3,12 +3,13 @@ void node_ambient_occlusion(vec4 color, float dist, vec3 normal, const float inverted, + const float sample_count, out vec4 result_color, out float result_ao) { vec3 bent_normal; vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); - OcclusionData data = occlusion_search(viewPosition, maxzBuffer, dist, inverted, 8.0); + OcclusionData data = occlusion_search(viewPosition, maxzBuffer, dist, inverted, sample_count); vec3 V = cameraVec(worldPosition); vec3 N = normalize(normal); diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c index 36971d4e799..abe80ebcefb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c +++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c @@ -47,8 +47,15 @@ static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat, GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE); float inverted = node->custom2 ? 1.0f : 0.0f; + float f_samples = divide_ceil_u(node->custom1, 4); - return GPU_stack_link(mat, node, "node_ambient_occlusion", in, out, GPU_constant(&inverted)); + return GPU_stack_link(mat, + node, + "node_ambient_occlusion", + in, + out, + GPU_constant(&inverted), + GPU_constant(&f_samples)); } static void node_shader_init_ambient_occlusion(bNodeTree *UNUSED(ntree), bNode *node) -- cgit v1.2.3 From bf799cb12c6991ef8fcbfcd0bc0777e62e08ad9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 8 Mar 2021 17:21:17 +0100 Subject: Fix T81741 EEVEE: Ambient Occlusion does not converge properly This was due to the AO random sampling using the same "seed" as the AA jitter. Decorelating the noise fixes the issue. --- .../blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 689f99edad9..a0bfd440dd9 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -60,7 +60,11 @@ vec2 get_ao_area(float view_depth, float radius) vec2 get_ao_noise(void) { - return texelfetch_noise_tex(gl_FragCoord.xy).xy; + vec2 noise = texelfetch_noise_tex(gl_FragCoord.xy).xy; + /* Decorrelate noise from AA. */ + /* TODO(fclem) we should use a more general approach for more random number dimentions. */ + noise = fract(noise * 6.1803402007); + return noise; } vec2 get_ao_dir(float jitter) -- cgit v1.2.3 From 9ce950daabbf580fc1b8da2c325ba2903e02b62e Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 8 Mar 2021 11:41:23 -0500 Subject: Cleanup: Move geometry component implementations to separate files Currently the implementations specific to each geometry type are in the same file. This makes it difficult to tell which code is generic for all component types and which is specific to a certain type. The two files, `attribute_access.cc`, and `geometry_set.cc` are also getting quite long. This commit splits up the implementation for every geometry component, and adds an internal header file for the common parts of the attribute access code. This was discussed with Jacques Lucke. --- .../blenkernel/intern/attribute_access_intern.hh | 499 ++++++++++++++ .../intern/geometry_component_instances.cc | 173 +++++ .../blenkernel/intern/geometry_component_mesh.cc | 735 +++++++++++++++++++++ .../intern/geometry_component_pointcloud.cc | 207 ++++++ .../blenkernel/intern/geometry_component_volume.cc | 100 +++ 5 files changed, 1714 insertions(+) create mode 100644 source/blender/blenkernel/intern/attribute_access_intern.hh create mode 100644 source/blender/blenkernel/intern/geometry_component_instances.cc create mode 100644 source/blender/blenkernel/intern/geometry_component_mesh.cc create mode 100644 source/blender/blenkernel/intern/geometry_component_pointcloud.cc create mode 100644 source/blender/blenkernel/intern/geometry_component_volume.cc diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh new file mode 100644 index 00000000000..299da4c97fe --- /dev/null +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -0,0 +1,499 @@ +/* + * 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. + */ + +#include "BLI_map.hh" +#include "BLI_span.hh" +#include "BLI_string_ref.hh" +#include "BLI_vector.hh" + +namespace blender::bke { + +class ConstantReadAttribute final : public ReadAttribute { + private: + void *value_; + + public: + ConstantReadAttribute(AttributeDomain domain, + const int64_t size, + const CPPType &type, + const void *value) + : ReadAttribute(domain, type, size) + { + value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); + type.copy_to_uninitialized(value, value_); + } + + ~ConstantReadAttribute() override + { + this->cpp_type_.destruct(value_); + MEM_freeN(value_); + } + + void get_internal(const int64_t UNUSED(index), void *r_value) const override + { + this->cpp_type_.copy_to_uninitialized(value_, r_value); + } + + void initialize_span() const override + { + const int element_size = cpp_type_.size(); + array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__); + array_is_temporary_ = true; + cpp_type_.fill_uninitialized(value_, array_buffer_, size_); + } +}; + +template class ArrayReadAttribute final : public ReadAttribute { + private: + Span data_; + + public: + ArrayReadAttribute(AttributeDomain domain, Span data) + : ReadAttribute(domain, CPPType::get(), data.size()), data_(data) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + new (r_value) T(data_[index]); + } + + void initialize_span() const override + { + /* The data will not be modified, so this const_cast is fine. */ + array_buffer_ = const_cast(data_.data()); + array_is_temporary_ = false; + } +}; + +template class OwnedArrayReadAttribute final : public ReadAttribute { + private: + Array data_; + + public: + OwnedArrayReadAttribute(AttributeDomain domain, Array data) + : ReadAttribute(domain, CPPType::get(), data.size()), data_(std::move(data)) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + new (r_value) T(data_[index]); + } + + void initialize_span() const override + { + /* The data will not be modified, so this const_cast is fine. */ + array_buffer_ = const_cast(data_.data()); + array_is_temporary_ = false; + } +}; + +template +class DerivedArrayReadAttribute final : public ReadAttribute { + private: + blender::Span data_; + + public: + DerivedArrayReadAttribute(AttributeDomain domain, Span data) + : ReadAttribute(domain, CPPType::get(), data.size()), data_(data) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + const StructT &struct_value = data_[index]; + const ElemT value = GetFunc(struct_value); + new (r_value) ElemT(value); + } +}; + +template class ArrayWriteAttribute final : public WriteAttribute { + private: + MutableSpan data_; + + public: + ArrayWriteAttribute(AttributeDomain domain, MutableSpan data) + : WriteAttribute(domain, CPPType::get(), data.size()), data_(data) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + new (r_value) T(data_[index]); + } + + void set_internal(const int64_t index, const void *value) override + { + data_[index] = *reinterpret_cast(value); + } + + void initialize_span(const bool UNUSED(write_only)) override + { + array_buffer_ = data_.data(); + array_is_temporary_ = false; + } + + void apply_span_if_necessary() override + { + /* Do nothing, because the span contains the attribute itself already. */ + } +}; + +template +class DerivedArrayWriteAttribute final : public WriteAttribute { + private: + blender::MutableSpan data_; + + public: + DerivedArrayWriteAttribute(AttributeDomain domain, blender::MutableSpan data) + : WriteAttribute(domain, CPPType::get(), data.size()), data_(data) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + const StructT &struct_value = data_[index]; + const ElemT value = GetFunc(struct_value); + new (r_value) ElemT(value); + } + + void set_internal(const int64_t index, const void *value) override + { + StructT &struct_value = data_[index]; + const ElemT &typed_value = *reinterpret_cast(value); + SetFunc(struct_value, typed_value); + } +}; + +/** + * Utility to group together multiple functions that are used to access custom data on geometry + * components in a generic way. + */ +struct CustomDataAccessInfo { + using CustomDataGetter = CustomData *(*)(GeometryComponent &component); + using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component); + using UpdateCustomDataPointers = void (*)(GeometryComponent &component); + + CustomDataGetter get_custom_data; + ConstCustomDataGetter get_const_custom_data; + UpdateCustomDataPointers update_custom_data_pointers; +}; + +/** + * A #BuiltinAttributeProvider is responsible for exactly one attribute on a geometry component. + * The attribute is identified by its name and has a fixed domain and type. Builtin attributes do + * not follow the same loose rules as other attributes, because they are mapped to internal + * "legacy" data structures. For example, some builtin attributes cannot be deleted. */ +class BuiltinAttributeProvider { + public: + /* Some utility enums to avoid hard to read booleans in function calls. */ + enum CreatableEnum { + Creatable, + NonCreatable, + }; + enum WritableEnum { + Writable, + Readonly, + }; + enum DeletableEnum { + Deletable, + NonDeletable, + }; + + protected: + const std::string name_; + const AttributeDomain domain_; + const CustomDataType data_type_; + const CreatableEnum createable_; + const WritableEnum writable_; + const DeletableEnum deletable_; + + public: + BuiltinAttributeProvider(std::string name, + const AttributeDomain domain, + const CustomDataType data_type, + const CreatableEnum createable, + const WritableEnum writable, + const DeletableEnum deletable) + : name_(std::move(name)), + domain_(domain), + data_type_(data_type), + createable_(createable), + writable_(writable), + deletable_(deletable) + { + } + + virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0; + virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0; + virtual bool try_delete(GeometryComponent &component) const = 0; + virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0; + virtual bool exists(const GeometryComponent &component) const = 0; + + blender::StringRefNull name() const + { + return name_; + } + + AttributeDomain domain() const + { + return domain_; + } + + CustomDataType data_type() const + { + return data_type_; + } +}; + +/** + * A #DynamicAttributesProvider manages a set of named attributes on a geometry component. Each + * attribute has a name, domain and type. + */ +class DynamicAttributesProvider { + public: + virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component, + const blender::StringRef attribute_name) const = 0; + virtual WriteAttributePtr try_get_for_write(GeometryComponent &component, + const blender::StringRef attribute_name) const = 0; + virtual bool try_delete(GeometryComponent &component, + const blender::StringRef attribute_name) const = 0; + virtual bool try_create(GeometryComponent &UNUSED(component), + const blender::StringRef UNUSED(attribute_name), + const AttributeDomain UNUSED(domain), + const CustomDataType UNUSED(data_type)) const + { + /* Some providers should not create new attributes. */ + return false; + }; + + virtual bool foreach_attribute(const GeometryComponent &component, + const AttributeForeachCallback callback) const = 0; + virtual void supported_domains(blender::Vector &r_domains) const = 0; +}; + +/** + * This is the attribute provider for most user generated attributes. + */ +class CustomDataAttributeProvider final : public DynamicAttributesProvider { + private: + static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | + CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | + CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL; + const AttributeDomain domain_; + const CustomDataAccessInfo custom_data_access_; + + public: + CustomDataAttributeProvider(const AttributeDomain domain, + const CustomDataAccessInfo custom_data_access) + : domain_(domain), custom_data_access_(custom_data_access) + { + } + + ReadAttributePtr try_get_for_read(const GeometryComponent &component, + const blender::StringRef attribute_name) const final; + + WriteAttributePtr try_get_for_write(GeometryComponent &component, + const blender::StringRef attribute_name) const final; + + bool try_delete(GeometryComponent &component, + const blender::StringRef attribute_name) const final; + + bool try_create(GeometryComponent &component, + const blender::StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type) const final; + + bool foreach_attribute(const GeometryComponent &component, + const AttributeForeachCallback callback) const final; + + void supported_domains(blender::Vector &r_domains) const final + { + r_domains.append_non_duplicates(domain_); + } + + private: + template + ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer, + const int domain_size) const + { + return std::make_unique>( + domain_, Span(static_cast(layer.data), domain_size)); + } + + template + WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const + { + return std::make_unique>( + domain_, MutableSpan(static_cast(layer.data), domain_size)); + } + + bool type_is_supported(CustomDataType data_type) const + { + return ((1ULL << data_type) & supported_types_mask) != 0; + } +}; + +/** + * This attribute provider is used for uv maps and vertex colors. + */ +class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { + private: + using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); + using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); + const AttributeDomain domain_; + const CustomDataType attribute_type_; + const CustomDataType stored_type_; + const CustomDataAccessInfo custom_data_access_; + const AsReadAttribute as_read_attribute_; + const AsWriteAttribute as_write_attribute_; + + public: + NamedLegacyCustomDataProvider(const AttributeDomain domain, + const CustomDataType attribute_type, + const CustomDataType stored_type, + const CustomDataAccessInfo custom_data_access, + const AsReadAttribute as_read_attribute, + const AsWriteAttribute as_write_attribute) + : domain_(domain), + attribute_type_(attribute_type), + stored_type_(stored_type), + custom_data_access_(custom_data_access), + as_read_attribute_(as_read_attribute), + as_write_attribute_(as_write_attribute) + { + } + + ReadAttributePtr try_get_for_read(const GeometryComponent &component, + const StringRef attribute_name) const final; + WriteAttributePtr try_get_for_write(GeometryComponent &component, + const StringRef attribute_name) const final; + bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final; + bool foreach_attribute(const GeometryComponent &component, + const AttributeForeachCallback callback) const final; + void supported_domains(Vector &r_domains) const final; +}; + +/** + * This provider is used to provide access to builtin attributes. It supports making internal types + * available as different types. For example, the vertex position attribute is stored as part of + * the #MVert struct, but is exposed as float3 attribute. + */ +class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { + using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); + using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); + using UpdateOnRead = void (*)(const GeometryComponent &component); + using UpdateOnWrite = void (*)(GeometryComponent &component); + const CustomDataType stored_type_; + const CustomDataAccessInfo custom_data_access_; + const AsReadAttribute as_read_attribute_; + const AsWriteAttribute as_write_attribute_; + const UpdateOnRead update_on_read_; + const UpdateOnWrite update_on_write_; + + public: + BuiltinCustomDataLayerProvider(std::string attribute_name, + const AttributeDomain domain, + const CustomDataType attribute_type, + const CustomDataType stored_type, + const CreatableEnum creatable, + const WritableEnum writable, + const DeletableEnum deletable, + const CustomDataAccessInfo custom_data_access, + const AsReadAttribute as_read_attribute, + const AsWriteAttribute as_write_attribute, + const UpdateOnRead update_on_read, + const UpdateOnWrite update_on_write) + : BuiltinAttributeProvider( + std::move(attribute_name), domain, attribute_type, creatable, writable, deletable), + stored_type_(stored_type), + custom_data_access_(custom_data_access), + as_read_attribute_(as_read_attribute), + as_write_attribute_(as_write_attribute), + update_on_read_(update_on_read), + update_on_write_(update_on_write) + { + } + + ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final; + WriteAttributePtr try_get_for_write(GeometryComponent &component) const final; + bool try_delete(GeometryComponent &component) const final; + bool try_create(GeometryComponent &component) const final; + bool exists(const GeometryComponent &component) const final; +}; + +/** + * This is a container for multiple attribute providers that are used by one geometry component + * type (e.g. there is a set of attribute providers for mesh components). + */ +class ComponentAttributeProviders { + private: + /** + * Builtin attribute providers are identified by their name. Attribute names that are in this + * map will only be accessed using builtin attribute providers. Therefore, these providers have + * higher priority when an attribute name is looked up. Usually, that means that builtin + * providers are checked before dynamic ones. + */ + blender::Map builtin_attribute_providers_; + /** + * An ordered list of dynamic attribute providers. The order is important because that is order + * in which they are checked when an attribute is looked up. + */ + blender::Vector dynamic_attribute_providers_; + /** + * All the domains that are supported by at least one of the providers above. + */ + blender::Vector supported_domains_; + + public: + ComponentAttributeProviders( + blender::Span builtin_attribute_providers, + blender::Span dynamic_attribute_providers) + : dynamic_attribute_providers_(dynamic_attribute_providers) + { + blender::Set domains; + for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) { + /* Use #add_new to make sure that no two builtin attributes have the same name. */ + builtin_attribute_providers_.add_new(provider->name(), provider); + supported_domains_.append_non_duplicates(provider->domain()); + } + for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) { + provider->supported_domains(supported_domains_); + } + } + + const blender::Map &builtin_attribute_providers() + const + { + return builtin_attribute_providers_; + } + + blender::Span dynamic_attribute_providers() const + { + return dynamic_attribute_providers_; + } + + blender::Span supported_domains() const + { + return supported_domains_; + } +}; + +} // namespace blender::bke \ No newline at end of file diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc new file mode 100644 index 00000000000..a6ee7a1b918 --- /dev/null +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -0,0 +1,173 @@ +/* + * 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. + */ + +#include "BLI_float4x4.hh" +#include "BLI_map.hh" +#include "BLI_rand.hh" +#include "BLI_set.hh" +#include "BLI_span.hh" +#include "BLI_vector.hh" + +#include "DNA_collection_types.h" + +#include "BKE_geometry_set.hh" + +using blender::float4x4; +using blender::Map; +using blender::MutableSpan; +using blender::Set; +using blender::Span; + +/* -------------------------------------------------------------------- */ +/** \name Geometry Component Implementation + * \{ */ + +InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentType::Instances) +{ +} + +GeometryComponent *InstancesComponent::copy() const +{ + InstancesComponent *new_component = new InstancesComponent(); + new_component->transforms_ = transforms_; + new_component->instanced_data_ = instanced_data_; + return new_component; +} + +void InstancesComponent::clear() +{ + instanced_data_.clear(); + transforms_.clear(); +} + +void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id) +{ + InstancedData data; + data.type = INSTANCE_DATA_TYPE_OBJECT; + data.data.object = object; + this->add_instance(data, transform, id); +} + +void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id) +{ + InstancedData data; + data.type = INSTANCE_DATA_TYPE_COLLECTION; + data.data.collection = collection; + this->add_instance(data, transform, id); +} + +void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id) +{ + instanced_data_.append(data); + transforms_.append(transform); + ids_.append(id); +} + +Span InstancesComponent::instanced_data() const +{ + return instanced_data_; +} + +Span InstancesComponent::transforms() const +{ + return transforms_; +} + +Span InstancesComponent::ids() const +{ + return ids_; +} + +MutableSpan InstancesComponent::transforms() +{ + return transforms_; +} + +int InstancesComponent::instances_amount() const +{ + const int size = instanced_data_.size(); + BLI_assert(transforms_.size() == size); + return size; +} + +bool InstancesComponent::is_empty() const +{ + return transforms_.size() == 0; +} + +static blender::Array generate_unique_instance_ids(Span original_ids) +{ + using namespace blender; + Array unique_ids(original_ids.size()); + + Set used_unique_ids; + used_unique_ids.reserve(original_ids.size()); + Vector instances_with_id_collision; + for (const int instance_index : original_ids.index_range()) { + const int original_id = original_ids[instance_index]; + if (used_unique_ids.add(original_id)) { + /* The original id has not been used by another instance yet. */ + unique_ids[instance_index] = original_id; + } + else { + /* The original id of this instance collided with a previous instance, it needs to be looked + * at again in a second pass. Don't generate a new random id here, because this might collide + * with other existing ids. */ + instances_with_id_collision.append(instance_index); + } + } + + Map generator_by_original_id; + for (const int instance_index : instances_with_id_collision) { + const int original_id = original_ids[instance_index]; + RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() { + RandomNumberGenerator rng; + rng.seed_random(original_id); + return rng; + }); + + const int max_iteration = 100; + for (int iteration = 0;; iteration++) { + /* Try generating random numbers until an unused one has been found. */ + const int random_id = rng.get_int32(); + if (used_unique_ids.add(random_id)) { + /* This random id is not used by another instance. */ + unique_ids[instance_index] = random_id; + break; + } + if (iteration == max_iteration) { + /* It seems to be very unlikely that we ever run into this case (assuming there are less + * than 2^30 instances). However, if that happens, it's better to use an id that is not + * unique than to be stuck in an infinite loop. */ + unique_ids[instance_index] = original_id; + break; + } + } + } + + return unique_ids; +} + +blender::Span InstancesComponent::almost_unique_ids() const +{ + std::lock_guard lock(almost_unique_ids_mutex_); + if (almost_unique_ids_.size() != ids_.size()) { + almost_unique_ids_ = generate_unique_instance_ids(ids_); + } + return almost_unique_ids_; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc new file mode 100644 index 00000000000..03b938942a7 --- /dev/null +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -0,0 +1,735 @@ +/* + * 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. + */ + +#include "BLI_listbase.h" +#include "BLI_threads.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_attribute_access.hh" +#include "BKE_attribute_math.hh" +#include "BKE_deform.h" +#include "BKE_geometry_set.hh" +#include "BKE_lib_id.h" +#include "BKE_mesh.h" + +#include "attribute_access_intern.hh" + +/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */ +extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id); + +using blender::bke::ReadAttributePtr; + +/* -------------------------------------------------------------------- */ +/** \name Geometry Component Implementation + * \{ */ + +MeshComponent::MeshComponent() : GeometryComponent(GeometryComponentType::Mesh) +{ +} + +MeshComponent::~MeshComponent() +{ + this->clear(); +} + +GeometryComponent *MeshComponent::copy() const +{ + MeshComponent *new_component = new MeshComponent(); + if (mesh_ != nullptr) { + new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false); + new_component->ownership_ = GeometryOwnershipType::Owned; + new_component->vertex_group_names_ = blender::Map(vertex_group_names_); + } + return new_component; +} + +void MeshComponent::clear() +{ + BLI_assert(this->is_mutable()); + if (mesh_ != nullptr) { + if (ownership_ == GeometryOwnershipType::Owned) { + BKE_id_free(nullptr, mesh_); + } + mesh_ = nullptr; + } + vertex_group_names_.clear(); +} + +bool MeshComponent::has_mesh() const +{ + return mesh_ != nullptr; +} + +/* Clear the component and replace it with the new mesh. */ +void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership) +{ + BLI_assert(this->is_mutable()); + this->clear(); + mesh_ = mesh; + ownership_ = ownership; +} + +/* This function exists for the same reason as #vertex_group_names_. Non-nodes modifiers need to + * be able to replace the mesh data without losing the vertex group names, which may have come + * from another object. */ +void MeshComponent::replace_mesh_but_keep_vertex_group_names(Mesh *mesh, + GeometryOwnershipType ownership) +{ + BLI_assert(this->is_mutable()); + if (mesh_ != nullptr) { + if (ownership_ == GeometryOwnershipType::Owned) { + BKE_id_free(nullptr, mesh_); + } + mesh_ = nullptr; + } + mesh_ = mesh; + ownership_ = ownership; +} + +/* Return the mesh and clear the component. The caller takes over responsibility for freeing the + * mesh (if the component was responsible before). */ +Mesh *MeshComponent::release() +{ + BLI_assert(this->is_mutable()); + Mesh *mesh = mesh_; + mesh_ = nullptr; + return mesh; +} + +void MeshComponent::copy_vertex_group_names_from_object(const Object &object) +{ + BLI_assert(this->is_mutable()); + vertex_group_names_.clear(); + int index = 0; + LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) { + vertex_group_names_.add(group->name, index); + index++; + } +} + +const blender::Map &MeshComponent::vertex_group_names() const +{ + return vertex_group_names_; +} + +/* This is only exposed for the internal attribute API. */ +blender::Map &MeshComponent::vertex_group_names() +{ + return vertex_group_names_; +} + +/* Get the mesh from this component. This method can be used by multiple threads at the same + * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */ +const Mesh *MeshComponent::get_for_read() const +{ + return mesh_; +} + +/* Get the mesh from this component. This method can only be used when the component is mutable, + * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */ +Mesh *MeshComponent::get_for_write() +{ + BLI_assert(this->is_mutable()); + if (ownership_ == GeometryOwnershipType::ReadOnly) { + mesh_ = BKE_mesh_copy_for_eval(mesh_, false); + ownership_ = GeometryOwnershipType::Owned; + } + return mesh_; +} + +bool MeshComponent::is_empty() const +{ + return mesh_ == nullptr; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Attribute Access + * \{ */ + +int MeshComponent::attribute_domain_size(const AttributeDomain domain) const +{ + BLI_assert(this->attribute_domain_supported(domain)); + if (mesh_ == nullptr) { + return 0; + } + switch (domain) { + case ATTR_DOMAIN_CORNER: + return mesh_->totloop; + case ATTR_DOMAIN_POINT: + return mesh_->totvert; + case ATTR_DOMAIN_EDGE: + return mesh_->totedge; + case ATTR_DOMAIN_POLYGON: + return mesh_->totpoly; + default: + BLI_assert(false); + break; + } + return 0; +} + +namespace blender::bke { + +template +static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, + const TypedReadAttribute &attribute, + MutableSpan r_values) +{ + BLI_assert(r_values.size() == mesh.totvert); + attribute_math::DefaultMixer mixer(r_values); + + for (const int loop_index : IndexRange(mesh.totloop)) { + const T value = attribute[loop_index]; + const MLoop &loop = mesh.mloop[loop_index]; + const int point_index = loop.v; + mixer.mix_in(point_index, value); + } + mixer.finalize(); +} + +static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v>) { + /* We compute all interpolated values at once, because for this interpolation, one has to + * iterate over all loops anyway. */ + Array values(mesh.totvert); + adapt_mesh_domain_corner_to_point_impl(mesh, *attribute, values); + new_attribute = std::make_unique>(ATTR_DOMAIN_POINT, + std::move(values)); + } + }); + return new_attribute; +} + +template +static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh, + const TypedReadAttribute &attribute, + MutableSpan r_values) +{ + BLI_assert(r_values.size() == mesh.totloop); + + for (const int loop_index : IndexRange(mesh.totloop)) { + const int vertex_index = mesh.mloop[loop_index].v; + r_values[loop_index] = attribute[vertex_index]; + } +} + +static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + /* It is not strictly necessary to compute the value for all corners here. Instead one could + * lazily lookup the mesh topology when a specific index accessed. This can be more efficient + * when an algorithm only accesses very few of the corner values. However, for the algorithms + * we currently have, precomputing the array is fine. Also, it is easier to implement. */ + Array values(mesh.totloop); + adapt_mesh_domain_point_to_corner_impl(mesh, *attribute, values); + new_attribute = std::make_unique>(ATTR_DOMAIN_CORNER, + std::move(values)); + }); + return new_attribute; +} + +} // namespace blender::bke + +ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute, + const AttributeDomain new_domain) const +{ + if (!attribute) { + return {}; + } + if (attribute->size() == 0) { + return {}; + } + const AttributeDomain old_domain = attribute->domain(); + if (old_domain == new_domain) { + return attribute; + } + + switch (old_domain) { + case ATTR_DOMAIN_CORNER: { + switch (new_domain) { + case ATTR_DOMAIN_POINT: + return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute)); + default: + break; + } + break; + } + case ATTR_DOMAIN_POINT: { + switch (new_domain) { + case ATTR_DOMAIN_CORNER: + return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute)); + default: + break; + } + } + default: + break; + } + + return {}; +} + +static Mesh *get_mesh_from_component_for_write(GeometryComponent &component) +{ + BLI_assert(component.type() == GeometryComponentType::Mesh); + MeshComponent &mesh_component = static_cast(component); + return mesh_component.get_for_write(); +} + +static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component) +{ + BLI_assert(component.type() == GeometryComponentType::Mesh); + const MeshComponent &mesh_component = static_cast(component); + return mesh_component.get_for_read(); +} + +namespace blender::bke { + +static float3 get_vertex_position(const MVert &vert) +{ + return float3(vert.co); +} + +static void set_vertex_position(MVert &vert, const float3 &position) +{ + copy_v3_v3(vert.co, position); +} + +static ReadAttributePtr make_vertex_position_read_attribute(const void *data, + const int domain_size) +{ + return std::make_unique>( + ATTR_DOMAIN_POINT, Span((const MVert *)data, domain_size)); +} + +static WriteAttributePtr make_vertex_position_write_attribute(void *data, const int domain_size) +{ + return std::make_unique< + DerivedArrayWriteAttribute>( + ATTR_DOMAIN_POINT, MutableSpan((MVert *)data, domain_size)); +} + +static void tag_normals_dirty_when_writing_position(GeometryComponent &component) +{ + Mesh *mesh = get_mesh_from_component_for_write(component); + if (mesh != nullptr) { + mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } +} + +static int get_material_index(const MPoly &mpoly) +{ + return static_cast(mpoly.mat_nr); +} + +static void set_material_index(MPoly &mpoly, const int &index) +{ + mpoly.mat_nr = static_cast(std::clamp(index, 0, SHRT_MAX)); +} + +static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique>( + ATTR_DOMAIN_POLYGON, Span((const MPoly *)data, domain_size)); +} + +static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size) +{ + return std::make_unique< + DerivedArrayWriteAttribute>( + ATTR_DOMAIN_POLYGON, MutableSpan((MPoly *)data, domain_size)); +} + +static float3 get_vertex_normal(const MVert &vert) +{ + float3 result; + normal_short_to_float_v3(result, vert.no); + return result; +} + +static ReadAttributePtr make_vertex_normal_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique>( + ATTR_DOMAIN_POINT, Span((const MVert *)data, domain_size)); +} + +static void update_vertex_normals_when_dirty(const GeometryComponent &component) +{ + const Mesh *mesh = get_mesh_from_component_for_read(component); + if (mesh == nullptr) { + return; + } + + /* Since normals are derived data, const write access to them is okay. However, ensure that + * two threads don't use write normals to a mesh at the same time. Note that this relies on + * the idempotence of the operation; calculating the normals just fills the MVert struct + * rather than allocating new memory. */ + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex; + BLI_mutex_lock(mesh_eval_mutex); + + /* Check again to avoid a second thread needlessly recalculating the same normals. */ + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + BKE_mesh_calc_normals(const_cast(mesh)); + } + + BLI_mutex_unlock(mesh_eval_mutex); + } +} + +static float2 get_loop_uv(const MLoopUV &uv) +{ + return float2(uv.uv); +} + +static void set_loop_uv(MLoopUV &uv, const float2 &co) +{ + copy_v2_v2(uv.uv, co); +} + +static ReadAttributePtr make_uvs_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique>( + ATTR_DOMAIN_CORNER, Span((const MLoopUV *)data, domain_size)); +} + +static WriteAttributePtr make_uvs_write_attribute(void *data, const int domain_size) +{ + return std::make_unique>( + ATTR_DOMAIN_CORNER, MutableSpan((MLoopUV *)data, domain_size)); +} + +static Color4f get_loop_color(const MLoopCol &col) +{ + Color4f value; + rgba_uchar_to_float(value, &col.r); + return value; +} + +static void set_loop_color(MLoopCol &col, const Color4f &value) +{ + rgba_float_to_uchar(&col.r, value); +} + +static ReadAttributePtr make_vertex_color_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique>( + ATTR_DOMAIN_CORNER, Span((const MLoopCol *)data, domain_size)); +} + +static WriteAttributePtr make_vertex_color_write_attribute(void *data, const int domain_size) +{ + return std::make_unique< + DerivedArrayWriteAttribute>( + ATTR_DOMAIN_CORNER, MutableSpan((MLoopCol *)data, domain_size)); +} + +class VertexWeightWriteAttribute final : public WriteAttribute { + private: + MDeformVert *dverts_; + const int dvert_index_; + + public: + VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index) + : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get(), totvert), + dverts_(dverts), + dvert_index_(dvert_index) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + get_internal(dverts_, dvert_index_, index, r_value); + } + + void set_internal(const int64_t index, const void *value) override + { + MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_); + weight->weight = *reinterpret_cast(value); + } + + static void get_internal(const MDeformVert *dverts, + const int dvert_index, + const int64_t index, + void *r_value) + { + if (dverts == nullptr) { + *(float *)r_value = 0.0f; + return; + } + const MDeformVert &dvert = dverts[index]; + for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) { + if (weight.def_nr == dvert_index) { + *(float *)r_value = weight.weight; + return; + } + } + *(float *)r_value = 0.0f; + } +}; + +class VertexWeightReadAttribute final : public ReadAttribute { + private: + const MDeformVert *dverts_; + const int dvert_index_; + + public: + VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index) + : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get(), totvert), + dverts_(dverts), + dvert_index_(dvert_index) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value); + } +}; + +/** + * This provider makes vertex groups available as float attributes. + */ +class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { + public: + ReadAttributePtr try_get_for_read(const GeometryComponent &component, + const StringRef attribute_name) const final + { + BLI_assert(component.type() == GeometryComponentType::Mesh); + const MeshComponent &mesh_component = static_cast(component); + const Mesh *mesh = mesh_component.get_for_read(); + const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( + attribute_name, -1); + if (vertex_group_index < 0) { + return {}; + } + if (mesh == nullptr || mesh->dvert == nullptr) { + static const float default_value = 0.0f; + return std::make_unique( + ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get(), &default_value); + } + return std::make_unique( + mesh->dvert, mesh->totvert, vertex_group_index); + } + + WriteAttributePtr try_get_for_write(GeometryComponent &component, + const StringRef attribute_name) const final + { + BLI_assert(component.type() == GeometryComponentType::Mesh); + MeshComponent &mesh_component = static_cast(component); + Mesh *mesh = mesh_component.get_for_write(); + if (mesh == nullptr) { + return {}; + } + const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( + attribute_name, -1); + if (vertex_group_index < 0) { + return {}; + } + if (mesh->dvert == nullptr) { + BKE_object_defgroup_data_create(&mesh->id); + } + else { + /* Copy the data layer if it is shared with some other mesh. */ + mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer( + &mesh->vdata, CD_MDEFORMVERT, mesh->totvert); + } + return std::make_unique( + mesh->dvert, mesh->totvert, vertex_group_index); + } + + bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final + { + BLI_assert(component.type() == GeometryComponentType::Mesh); + MeshComponent &mesh_component = static_cast(component); + + const int vertex_group_index = mesh_component.vertex_group_names().pop_default_as( + attribute_name, -1); + if (vertex_group_index < 0) { + return false; + } + Mesh *mesh = mesh_component.get_for_write(); + if (mesh == nullptr) { + return true; + } + if (mesh->dvert == nullptr) { + return true; + } + for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) { + MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index); + BKE_defvert_remove_group(&dvert, weight); + } + return true; + } + + bool foreach_attribute(const GeometryComponent &component, + const AttributeForeachCallback callback) const final + { + BLI_assert(component.type() == GeometryComponentType::Mesh); + const MeshComponent &mesh_component = static_cast(component); + for (const auto item : mesh_component.vertex_group_names().items()) { + const StringRefNull name = item.key; + const int vertex_group_index = item.value; + if (vertex_group_index >= 0) { + AttributeMetaData meta_data{ATTR_DOMAIN_POINT, CD_PROP_FLOAT}; + if (!callback(name, meta_data)) { + return false; + } + } + } + return true; + } + + void supported_domains(Vector &r_domains) const final + { + r_domains.append_non_duplicates(ATTR_DOMAIN_POINT); + } +}; + +/** + * In this function all the attribute providers for a mesh component are created. Most data in this + * function is statically allocated, because it does not change over time. + */ +static ComponentAttributeProviders create_attribute_providers_for_mesh() +{ + static auto update_custom_data_pointers = [](GeometryComponent &component) { + Mesh *mesh = get_mesh_from_component_for_write(component); + if (mesh != nullptr) { + BKE_mesh_update_customdata_pointers(mesh, false); + } + }; + +#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \ + [](GeometryComponent &component) -> CustomData * { \ + Mesh *mesh = get_mesh_from_component_for_write(component); \ + return mesh ? &mesh->NAME : nullptr; \ + } +#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \ + [](const GeometryComponent &component) -> const CustomData * { \ + const Mesh *mesh = get_mesh_from_component_for_read(component); \ + return mesh ? &mesh->NAME : nullptr; \ + } + + static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata), + MAKE_CONST_CUSTOM_DATA_GETTER(ldata), + update_custom_data_pointers}; + static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata), + MAKE_CONST_CUSTOM_DATA_GETTER(vdata), + update_custom_data_pointers}; + static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata), + MAKE_CONST_CUSTOM_DATA_GETTER(edata), + update_custom_data_pointers}; + static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), + MAKE_CONST_CUSTOM_DATA_GETTER(pdata), + update_custom_data_pointers}; + +#undef MAKE_CONST_CUSTOM_DATA_GETTER +#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER + + static BuiltinCustomDataLayerProvider position("position", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_MVERT, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + point_access, + make_vertex_position_read_attribute, + make_vertex_position_write_attribute, + nullptr, + tag_normals_dirty_when_writing_position); + + static BuiltinCustomDataLayerProvider material_index("material_index", + ATTR_DOMAIN_POLYGON, + CD_PROP_INT32, + CD_MPOLY, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + polygon_access, + make_material_index_read_attribute, + make_material_index_write_attribute, + nullptr, + nullptr); + + static BuiltinCustomDataLayerProvider vertex_normal("vertex_normal", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_MVERT, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Readonly, + BuiltinAttributeProvider::NonDeletable, + point_access, + make_vertex_normal_read_attribute, + nullptr, + update_vertex_normals_when_dirty, + nullptr); + + static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER, + CD_PROP_FLOAT2, + CD_MLOOPUV, + corner_access, + make_uvs_read_attribute, + make_uvs_write_attribute); + + static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER, + CD_PROP_COLOR, + CD_MLOOPCOL, + corner_access, + make_vertex_color_read_attribute, + make_vertex_color_write_attribute); + + static VertexGroupsAttributeProvider vertex_groups; + static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access); + static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); + static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); + static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access); + + return ComponentAttributeProviders({&position, &material_index, &vertex_normal}, + {&uvs, + &vertex_colors, + &corner_custom_data, + &vertex_groups, + &point_custom_data, + &edge_custom_data, + &polygon_custom_data}); +} + +} // namespace blender::bke + +const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const +{ + static blender::bke::ComponentAttributeProviders providers = + blender::bke::create_attribute_providers_for_mesh(); + return &providers; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc new file mode 100644 index 00000000000..d7f0bf55bc9 --- /dev/null +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -0,0 +1,207 @@ +/* + * 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. + */ + +#include "DNA_pointcloud_types.h" + +#include "BKE_attribute_access.hh" +#include "BKE_geometry_set.hh" +#include "BKE_lib_id.h" +#include "BKE_pointcloud.h" + +#include "attribute_access_intern.hh" + +/* -------------------------------------------------------------------- */ +/** \name Geometry Component Implementation + * \{ */ + +PointCloudComponent::PointCloudComponent() : GeometryComponent(GeometryComponentType::PointCloud) +{ +} + +PointCloudComponent::~PointCloudComponent() +{ + this->clear(); +} + +GeometryComponent *PointCloudComponent::copy() const +{ + PointCloudComponent *new_component = new PointCloudComponent(); + if (pointcloud_ != nullptr) { + new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); + new_component->ownership_ = GeometryOwnershipType::Owned; + } + return new_component; +} + +void PointCloudComponent::clear() +{ + BLI_assert(this->is_mutable()); + if (pointcloud_ != nullptr) { + if (ownership_ == GeometryOwnershipType::Owned) { + BKE_id_free(nullptr, pointcloud_); + } + pointcloud_ = nullptr; + } +} + +bool PointCloudComponent::has_pointcloud() const +{ + return pointcloud_ != nullptr; +} + +/* Clear the component and replace it with the new point cloud. */ +void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership) +{ + BLI_assert(this->is_mutable()); + this->clear(); + pointcloud_ = pointcloud; + ownership_ = ownership; +} + +/* Return the point cloud and clear the component. The caller takes over responsibility for freeing + * the point cloud (if the component was responsible before). */ +PointCloud *PointCloudComponent::release() +{ + BLI_assert(this->is_mutable()); + PointCloud *pointcloud = pointcloud_; + pointcloud_ = nullptr; + return pointcloud; +} + +/* Get the point cloud from this component. This method can be used by multiple threads at the same + * time. Therefore, the returned point cloud should not be modified. No ownership is transferred. + */ +const PointCloud *PointCloudComponent::get_for_read() const +{ + return pointcloud_; +} + +/* Get the point cloud from this component. This method can only be used when the component is + * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is + * transferred. */ +PointCloud *PointCloudComponent::get_for_write() +{ + BLI_assert(this->is_mutable()); + if (ownership_ == GeometryOwnershipType::ReadOnly) { + pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); + ownership_ = GeometryOwnershipType::Owned; + } + return pointcloud_; +} + +bool PointCloudComponent::is_empty() const +{ + return pointcloud_ == nullptr; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Attribute Access + * \{ */ + +int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const +{ + BLI_assert(domain == ATTR_DOMAIN_POINT); + UNUSED_VARS_NDEBUG(domain); + if (pointcloud_ == nullptr) { + return 0; + } + return pointcloud_->totpoint; +} + +namespace blender::bke { + +template +static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique>(Domain, Span((const T *)data, domain_size)); +} + +template +static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size) +{ + return std::make_unique>(Domain, MutableSpan((T *)data, domain_size)); +} + +/** + * In this function all the attribute providers for a point cloud component are created. Most data + * in this function is statically allocated, because it does not change over time. + */ +static ComponentAttributeProviders create_attribute_providers_for_point_cloud() +{ + static auto update_custom_data_pointers = [](GeometryComponent &component) { + PointCloudComponent &pointcloud_component = static_cast(component); + PointCloud *pointcloud = pointcloud_component.get_for_write(); + if (pointcloud != nullptr) { + BKE_pointcloud_update_customdata_pointers(pointcloud); + } + }; + static CustomDataAccessInfo point_access = { + [](GeometryComponent &component) -> CustomData * { + PointCloudComponent &pointcloud_component = static_cast(component); + PointCloud *pointcloud = pointcloud_component.get_for_write(); + return pointcloud ? &pointcloud->pdata : nullptr; + }, + [](const GeometryComponent &component) -> const CustomData * { + const PointCloudComponent &pointcloud_component = static_cast( + component); + const PointCloud *pointcloud = pointcloud_component.get_for_read(); + return pointcloud ? &pointcloud->pdata : nullptr; + }, + update_custom_data_pointers}; + + static BuiltinCustomDataLayerProvider position( + "position", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_PROP_FLOAT3, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + point_access, + make_array_read_attribute, + make_array_write_attribute, + nullptr, + nullptr); + static BuiltinCustomDataLayerProvider radius( + "radius", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT, + CD_PROP_FLOAT, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute, + make_array_write_attribute, + nullptr, + nullptr); + static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); + return ComponentAttributeProviders({&position, &radius}, {&point_custom_data}); +} + +} // namespace blender::bke + +const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers() + const +{ + static blender::bke::ComponentAttributeProviders providers = + blender::bke::create_attribute_providers_for_point_cloud(); + return &providers; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/geometry_component_volume.cc b/source/blender/blenkernel/intern/geometry_component_volume.cc new file mode 100644 index 00000000000..5e35a10fe3d --- /dev/null +++ b/source/blender/blenkernel/intern/geometry_component_volume.cc @@ -0,0 +1,100 @@ +/* + * 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. + */ + +#include "DNA_volume_types.h" + +#include "BKE_geometry_set.hh" +#include "BKE_lib_id.h" +#include "BKE_volume.h" + +/* -------------------------------------------------------------------- */ +/** \name Geometry Component Implementation + * \{ */ + +VolumeComponent::VolumeComponent() : GeometryComponent(GeometryComponentType::Volume) +{ +} + +VolumeComponent::~VolumeComponent() +{ + this->clear(); +} + +GeometryComponent *VolumeComponent::copy() const +{ + VolumeComponent *new_component = new VolumeComponent(); + if (volume_ != nullptr) { + new_component->volume_ = BKE_volume_copy_for_eval(volume_, false); + new_component->ownership_ = GeometryOwnershipType::Owned; + } + return new_component; +} + +void VolumeComponent::clear() +{ + BLI_assert(this->is_mutable()); + if (volume_ != nullptr) { + if (ownership_ == GeometryOwnershipType::Owned) { + BKE_id_free(nullptr, volume_); + } + volume_ = nullptr; + } +} + +bool VolumeComponent::has_volume() const +{ + return volume_ != nullptr; +} + +/* Clear the component and replace it with the new volume. */ +void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership) +{ + BLI_assert(this->is_mutable()); + this->clear(); + volume_ = volume; + ownership_ = ownership; +} + +/* Return the volume and clear the component. The caller takes over responsibility for freeing the + * volume (if the component was responsible before). */ +Volume *VolumeComponent::release() +{ + BLI_assert(this->is_mutable()); + Volume *volume = volume_; + volume_ = nullptr; + return volume; +} + +/* Get the volume from this component. This method can be used by multiple threads at the same + * time. Therefore, the returned volume should not be modified. No ownership is transferred. */ +const Volume *VolumeComponent::get_for_read() const +{ + return volume_; +} + +/* Get the volume from this component. This method can only be used when the component is mutable, + * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */ +Volume *VolumeComponent::get_for_write() +{ + BLI_assert(this->is_mutable()); + if (ownership_ == GeometryOwnershipType::ReadOnly) { + volume_ = BKE_volume_copy_for_eval(volume_, false); + ownership_ = GeometryOwnershipType::Owned; + } + return volume_; +} + +/** \} */ -- cgit v1.2.3 From 8771f015f50ec72c3b0eaac1eb9498d277a4952b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 8 Mar 2021 18:10:26 +0100 Subject: Python version of `make_source_archive.sh` This is a Python version of the existing `make_source_archive.sh` script. IMO it's easier to read, and it'll also be easier to extend with the necessary functionality for D10598. The number of lines of code is larger than `make_source_archive.sh`, but it has considerably less invocations of `awk` ;-) And also the filtering is integrated, instead of forking out to Python to prevent certain files to be included in the tarball. Reviewed By: dfelinto, campbellbarton Differential Revision: https://developer.blender.org/D10629 --- GNUmakefile | 2 +- build_files/utils/make_source_archive.py | 191 +++++++++++++++++++++++++++++++ build_files/utils/make_source_archive.sh | 82 ------------- 3 files changed, 192 insertions(+), 83 deletions(-) create mode 100755 build_files/utils/make_source_archive.py delete mode 100755 build_files/utils/make_source_archive.sh diff --git a/GNUmakefile b/GNUmakefile index 41902809e30..3fe1850ca73 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -506,7 +506,7 @@ check_descriptions: .FORCE # source_archive: .FORCE - ./build_files/utils/make_source_archive.sh + python3 ./build_files/utils/make_source_archive.py INKSCAPE_BIN?="inkscape" icons: .FORCE diff --git a/build_files/utils/make_source_archive.py b/build_files/utils/make_source_archive.py new file mode 100755 index 00000000000..24928742a2d --- /dev/null +++ b/build_files/utils/make_source_archive.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 + +import dataclasses +import os +import re +import subprocess +from pathlib import Path +from typing import Iterable, TextIO + +# This script can run from any location, +# output is created in the $CWD + +SKIP_NAMES = { + ".gitignore", + ".gitmodules", + ".arcconfig", +} + + +def main() -> None: + output_dir = Path(".").absolute() + blender_srcdir = Path(__file__).absolute().parent.parent.parent + print(f"Source dir: {blender_srcdir}") + + version = parse_blender_version(blender_srcdir) + manifest = output_dir / f"blender-{version}-manifest.txt" + tarball = output_dir / f"blender-{version}.tar.xz" + + os.chdir(blender_srcdir) + create_manifest(version, manifest) + create_tarball(version, tarball, manifest) + create_checksum_file(tarball) + cleanup(manifest) + print("Done!") + + +@dataclasses.dataclass +class BlenderVersion: + version: int # 293 for 2.93.1 + patch: int # 1 for 2.93.1 + cycle: str # 'alpha', 'beta', 'release', maybe others. + + @property + def is_release(self) -> bool: + return self.cycle == "release" + + def __str__(self) -> str: + """Convert to version string. + + >>> str(BlenderVersion(293, 1, "alpha")) + '2.93.1-alpha' + >>> str(BlenderVersion(327, 0, "release")) + '3.27.0' + """ + + as_string = f"{self.version/100:.2f}.{self.patch}" + if self.is_release: + return as_string + return f"{as_string}-{self.cycle}" + + +def parse_blender_version(blender_srcdir: Path) -> BlenderVersion: + version_path = blender_srcdir / "source/blender/blenkernel/BKE_blender_version.h" + + version_info = {} + line_re = re.compile(r"^#define (BLENDER_VERSION[A-Z_]*)\s+([0-9a-z]+)$") + + with version_path.open(encoding="utf-8") as version_file: + for line in version_file: + match = line_re.match(line.strip()) + if not match: + continue + version_info[match.group(1)] = match.group(2) + + return BlenderVersion( + int(version_info["BLENDER_VERSION"]), + int(version_info["BLENDER_VERSION_PATCH"]), + version_info["BLENDER_VERSION_CYCLE"], + ) + + +### Manifest creation + + +def create_manifest(version: BlenderVersion, outpath: Path) -> None: + print(f'Building manifest of files: "{outpath}"...', end="", flush=True) + with outpath.open("w", encoding="utf-8") as outfile: + main_files_to_manifest(outfile) + submodules_to_manifest(version, outfile) + print("OK") + + +def main_files_to_manifest(outfile: TextIO) -> None: + for path in git_ls_files(): + print(path, file=outfile) + + +def submodules_to_manifest(version: BlenderVersion, outfile: TextIO) -> None: + skip_addon_contrib = version.is_release + + for line in git_command("submodule"): + submodule = line.split()[1] + + if skip_addon_contrib and submodule == "release/scripts/addons_contrib": + continue + + for path in git_ls_files(Path(submodule)): + print(path, file=outfile) + + +def create_tarball(version: BlenderVersion, tarball: Path, manifest: Path) -> None: + print(f'Creating archive: "{tarball}" ...', end="", flush=True) + command = [ + "tar", + "--transform", + f"s,^,blender-{version}/,g", + "--use-compress-program=xz -9", + "--create", + f"--file={tarball}", + f"--files-from={manifest}", + # Without owner/group args, extracting the files as root will + # use ownership from the tar archive: + "--owner=0", + "--group=0", + ] + subprocess.run(command, check=True, timeout=300) + print("OK") + + +def create_checksum_file(tarball: Path) -> None: + md5_path = tarball.with_name(tarball.name + ".md5sum") + print(f'Creating checksum: "{md5_path}" ...', end="", flush=True) + command = [ + "md5sum", + # The name is enough, as the tarball resides in the same dir as the MD5 + # file, and that's the current working directory. + tarball.name, + ] + md5_cmd = subprocess.run( + command, stdout=subprocess.PIPE, check=True, text=True, timeout=300 + ) + with md5_path.open("w") as outfile: + outfile.write(md5_cmd.stdout) + print("OK") + + +def cleanup(manifest: Path) -> None: + print("Cleaning up ...", end="", flush=True) + if manifest.exists(): + manifest.unlink() + print("OK") + + +## Low-level commands + + +def git_ls_files(directory: Path = Path(".")) -> Iterable[Path]: + """Generator, yields lines of output from 'git ls-files'. + + Only lines that are actually files (so no directories, sockets, etc.) are + returned, and never one from SKIP_NAMES. + """ + for line in git_command("-C", str(directory), "ls-files"): + path = directory / line + if not path.is_file() or path.name in SKIP_NAMES: + continue + yield path + + +def git_command(*cli_args) -> Iterable[str]: + """Generator, yields lines of output from a Git command.""" + command = ("git", *cli_args) + + # import shlex + # print(">", " ".join(shlex.quote(arg) for arg in command)) + + git = subprocess.run( + command, stdout=subprocess.PIPE, check=True, text=True, timeout=30 + ) + for line in git.stdout.split("\n"): + if line: + yield line + + +if __name__ == "__main__": + import doctest + + if doctest.testmod().failed: + raise SystemExit("ERROR: Self-test failed, refusing to run") + + main() diff --git a/build_files/utils/make_source_archive.sh b/build_files/utils/make_source_archive.sh deleted file mode 100755 index 5d9096f3235..00000000000 --- a/build_files/utils/make_source_archive.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/sh - -# This script can run from any location, -# output is created in the $CWD - -BASE_DIR="$PWD" - -blender_srcdir=$(dirname -- $0)/../.. -blender_version=$(grep "BLENDER_VERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') -blender_version_patch=$(grep "BLENDER_VERSION_PATCH\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') -blender_version_cycle=$(grep "BLENDER_VERSION_CYCLE\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') - -VERSION=$(expr $blender_version / 100).$(expr $blender_version % 100).$blender_version_patch -if [ "$blender_version_cycle" = "release" ] ; then - SUBMODULE_EXCLUDE="^\(release/scripts/addons_contrib\)$" -else - VERSION=$VERSION-$blender_version_cycle - SUBMODULE_EXCLUDE="^$" # dummy regex -fi - -MANIFEST="blender-$VERSION-manifest.txt" -TARBALL="blender-$VERSION.tar.xz" - -cd "$blender_srcdir" - -# not so nice, but works -FILTER_FILES_PY=\ -"import os, sys; "\ -"[print(l[:-1]) for l in sys.stdin.readlines() "\ -"if os.path.isfile(l[:-1]) "\ -"if os.path.basename(l[:-1]) not in {"\ -"'.gitignore', "\ -"'.gitmodules', "\ -"'.arcconfig', "\ -"}"\ -"]" - -# Build master list -echo -n "Building manifest of files: \"$BASE_DIR/$MANIFEST\" ..." -git ls-files | python3 -c "$FILTER_FILES_PY" > $BASE_DIR/$MANIFEST - -# Enumerate submodules -for lcv in $(git submodule | awk '{print $2}' | grep -v "$SUBMODULE_EXCLUDE"); do - cd "$BASE_DIR" - cd "$blender_srcdir/$lcv" - git ls-files | python3 -c "$FILTER_FILES_PY" | awk '$0="'"$lcv"/'"$0' >> $BASE_DIR/$MANIFEST - cd "$BASE_DIR" -done -echo "OK" - - -# Create the tarball -# -# Without owner/group args, extracting the files as root will -# use ownership from the tar archive. -cd "$blender_srcdir" -echo -n "Creating archive: \"$BASE_DIR/$TARBALL\" ..." -tar \ - --transform "s,^,blender-$VERSION/,g" \ - --use-compress-program="xz -9" \ - --create \ - --file="$BASE_DIR/$TARBALL" \ - --files-from="$BASE_DIR/$MANIFEST" \ - --owner=0 \ - --group=0 - -echo "OK" - - -# Create checksum file -cd "$BASE_DIR" -echo -n "Creating checksum: \"$BASE_DIR/$TARBALL.md5sum\" ..." -md5sum "$TARBALL" > "$TARBALL.md5sum" -echo "OK" - - -# Cleanup -echo -n "Cleaning up ..." -rm "$BASE_DIR/$MANIFEST" -echo "OK" - -echo "Done!" -- cgit v1.2.3 From 4292bb060d598659889e7448e02142248564fae7 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 8 Mar 2021 15:13:35 +0100 Subject: Outliner: Port scene elements and some related types to new tree-element code design Continuation of work in 2e221de4ceee, 249e4df110e0 and 3a907e742507. Adds new tree-element classes for the scene-ID, scene collections, scene objects, and the view layers base. There is some more temporary stuff in here, which can be removed once we're further along with the porting. Noted that in comments. --- .../blender/editors/space_outliner/CMakeLists.txt | 6 + .../blender/editors/space_outliner/outliner_tree.c | 113 +++------------ .../editors/space_outliner/tree/tree_display.h | 4 + .../editors/space_outliner/tree/tree_element.cc | 45 ++++++ .../editors/space_outliner/tree/tree_element.h | 2 + .../editors/space_outliner/tree/tree_element.hh | 19 ++- .../tree/tree_element_collection_base.cc | 44 ++++++ .../tree/tree_element_collection_base.hh | 36 +++++ .../editors/space_outliner/tree/tree_element_id.cc | 156 +++++++++++++++++++-- .../editors/space_outliner/tree/tree_element_id.hh | 37 ++++- .../tree/tree_element_scene_objects_base.cc | 50 +++++++ .../tree/tree_element_scene_objects_base.hh | 36 +++++ .../tree/tree_element_view_layer_base.cc | 51 +++++++ .../tree/tree_element_view_layer_base.hh | 36 +++++ 14 files changed, 517 insertions(+), 118 deletions(-) create mode 100644 source/blender/editors/space_outliner/tree/tree_element_collection_base.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_collection_base.hh create mode 100644 source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.hh create mode 100644 source/blender/editors/space_outliner/tree/tree_element_view_layer_base.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_view_layer_base.hh diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 7b9bc44f986..82c87a7b199 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -56,10 +56,13 @@ set(SRC tree/tree_display_view_layer.cc tree/tree_element.cc tree/tree_element_anim_data.cc + tree/tree_element_collection_base.cc tree/tree_element_driver_base.cc tree/tree_element_gpencil_layer.cc tree/tree_element_id.cc tree/tree_element_nla.cc + tree/tree_element_scene_objects_base.cc + tree/tree_element_view_layer_base.cc outliner_intern.h tree/tree_display.h @@ -67,10 +70,13 @@ set(SRC tree/tree_element.h tree/tree_element.hh tree/tree_element_anim_data.hh + tree/tree_element_collection_base.hh tree/tree_element_driver_base.hh tree/tree_element_gpencil_layer.hh tree/tree_element_id.hh tree/tree_element_nla.hh + tree/tree_element_scene_objects_base.hh + tree/tree_element_view_layer_base.hh ) set(LIB diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 6ca986660c1..6319b890b3b 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1,4 +1,4 @@ -/* +/* * 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 @@ -92,9 +92,6 @@ #endif /* prototypes */ -static TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, - Collection *collection, - TreeElement *ten); static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner); /* ********************************************************* */ @@ -274,7 +271,7 @@ static void outliner_add_bone(SpaceOutliner *space_outliner, } } -static bool outliner_animdata_test(AnimData *adt) +bool outliner_animdata_test(const AnimData *adt) { if (adt) { return (adt->action || adt->drivers.first || adt->nla_tracks.first); @@ -314,46 +311,6 @@ static void outliner_add_line_styles(SpaceOutliner *space_outliner, } #endif -static void outliner_add_scene_contents(SpaceOutliner *space_outliner, - ListBase *lb, - Scene *sce, - TreeElement *te) -{ - /* View layers */ - TreeElement *ten = outliner_add_element(space_outliner, lb, sce, te, TSE_R_LAYER_BASE, 0); - ten->name = IFACE_("View Layers"); - - ViewLayer *view_layer; - for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - TreeElement *tenlay = outliner_add_element( - space_outliner, &ten->subtree, sce, ten, TSE_R_LAYER, 0); - tenlay->name = view_layer->name; - tenlay->directdata = view_layer; - } - - /* World */ - outliner_add_element(space_outliner, lb, sce->world, te, TSE_SOME_ID, 0); - - /* Collections */ - ten = outliner_add_element(space_outliner, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0); - ten->name = IFACE_("Scene Collection"); - outliner_add_collection_recursive(space_outliner, sce->master_collection, ten); - - /* Objects */ - ten = outliner_add_element(space_outliner, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0); - ten->name = IFACE_("Objects"); - FOREACH_SCENE_OBJECT_BEGIN (sce, ob) { - outliner_add_element(space_outliner, &ten->subtree, ob, ten, TSE_SOME_ID, 0); - } - FOREACH_SCENE_OBJECT_END; - outliner_make_object_parent_hierarchy(&ten->subtree); - - /* Animation Data */ - if (outliner_animdata_test(sce->adt)) { - outliner_add_element(space_outliner, lb, sce, te, TSE_ANIM_DATA, 0); - } -} - /* Can be inlined if necessary. */ static void outliner_add_object_contents(SpaceOutliner *space_outliner, TreeElement *te, @@ -629,32 +586,6 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } } -static void outliner_add_library_override_contents(SpaceOutliner *soops, TreeElement *te, ID *id) -{ - if (!id->override_library) { - return; - } - - PointerRNA idpoin; - RNA_id_pointer_create(id, &idpoin); - - PointerRNA override_ptr; - PropertyRNA *override_prop; - int index = 0; - LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) { - if (!BKE_lib_override_rna_property_find(&idpoin, op, &override_ptr, &override_prop)) { - /* This is fine, override properties list is not always fully up-to-date with current - * RNA/IDProps etc., this gets cleaned up when re-generating the overrides rules, - * no error here. */ - continue; - } - - TreeElement *ten = outliner_add_element( - soops, &te->subtree, id, te, TSE_LIBRARY_OVERRIDE, index++); - ten->name = RNA_property_ui_name(override_prop); - } -} - /* Can be inlined if necessary. */ static void outliner_add_id_contents(SpaceOutliner *space_outliner, TreeElement *te, @@ -668,14 +599,10 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, /* expand specific data always */ switch (GS(id->name)) { - case ID_LI: { - te->name = ((Library *)id)->filepath; - break; - } - case ID_SCE: { - outliner_add_scene_contents(space_outliner, &te->subtree, (Scene *)id, te); + case ID_LI: + case ID_SCE: + BLI_assert(!"ID type expected to be expanded through new tree-element design"); break; - } case ID_OB: { outliner_add_object_contents(space_outliner, te, tselem, (Object *)id); break; @@ -902,17 +829,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, default: break; } - - const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(space_outliner) || - ((space_outliner->filter & SO_FILTER_NO_LIB_OVERRIDE) == 0); - - if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY(id)) { - TreeElement *ten = outliner_add_element( - space_outliner, &te->subtree, id, te, TSE_LIBRARY_OVERRIDE_BASE, 0); - - ten->name = IFACE_("Library Overrides"); - outliner_add_library_override_contents(space_outliner, ten, id); - } } /** @@ -1001,7 +917,11 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, /* Other cases must be caught above. */ BLI_assert(TSE_IS_REAL_ID(tselem)); - te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */ + /* The new type design sets the name already, don't override that here. We need to figure out + * how to deal with the idcode for non-TSE_SOME_ID types still. Some rely on it... */ + if (!te->type) { + te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */ + } te->idcode = GS(id->name); } @@ -1009,11 +929,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, outliner_tree_element_type_expand(te->type, space_outliner); } else if (type == TSE_SOME_ID) { - TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL; - - /* ID data-block. */ - if (tsepar == NULL || tsepar->type != TSE_ID_BASE || space_outliner->filter_id_type) { + /* ID types not (fully) ported to new design yet. */ + if (outliner_tree_element_type_expand_poll(te->type, space_outliner)) { outliner_add_id_contents(space_outliner, te, tselem, id); + outliner_tree_element_type_post_expand(te->type, space_outliner); } } else if (ELEM(type, @@ -1233,9 +1152,9 @@ BLI_INLINE void outliner_add_collection_objects(SpaceOutliner *space_outliner, } } -static TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, - Collection *collection, - TreeElement *ten) +TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, + Collection *collection, + TreeElement *ten) { outliner_add_collection_init(ten, collection); diff --git a/source/blender/editors/space_outliner/tree/tree_display.h b/source/blender/editors/space_outliner/tree/tree_display.h index 4ef71ded133..c0a751f2cd5 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.h +++ b/source/blender/editors/space_outliner/tree/tree_display.h @@ -56,6 +56,10 @@ struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner, short type, short index); void outliner_make_object_parent_hierarchy(ListBase *lb); +bool outliner_animdata_test(const struct AnimData *adt); +TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, + struct Collection *collection, + TreeElement *ten); const char *outliner_idcode_to_plural(short idcode); diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index 79c2831475f..75ecfb5584a 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -21,10 +21,13 @@ #include "DNA_listBase.h" #include "tree_element_anim_data.hh" +#include "tree_element_collection_base.hh" #include "tree_element_driver_base.hh" #include "tree_element_gpencil_layer.hh" #include "tree_element_id.hh" #include "tree_element_nla.hh" +#include "tree_element_scene_objects_base.hh" +#include "tree_element_view_layer_base.hh" #include "tree_element.h" #include "tree_element.hh" @@ -52,6 +55,12 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te return new TreeElementNLAAction(legacy_te); case TSE_GP_LAYER: return new TreeElementGPencilLayer(legacy_te, *static_cast(idv)); + case TSE_R_LAYER_BASE: + return new TreeElementViewLayerBase(legacy_te, *static_cast(idv)); + case TSE_SCENE_COLLECTION_BASE: + return new TreeElementCollectionBase(legacy_te, *static_cast(idv)); + case TSE_SCENE_OBJECTS_BASE: + return new TreeElementSceneObjectsBase(legacy_te, *static_cast(idv)); default: break; } @@ -67,7 +76,33 @@ static void tree_element_free(AbstractTreeElement **tree_element) static void tree_element_expand(AbstractTreeElement &tree_element, SpaceOutliner &space_outliner) { + /* Most types can just expand. IDs optionally expand (hence the poll) and do additional, common + * expanding. Could be done nicer, we could request a small "expander" helper object from the + * element type, that the IDs have a more advanced implementation for. */ + if (!tree_element.expandPoll(space_outliner)) { + return; + } tree_element.expand(space_outliner); + tree_element.postExpand(space_outliner); +} + +/** + * Needed for types that still expand in C, but need to execute the same post-expand logic. Can be + * removed once all ID types expand entirely using the new design. + */ +static void tree_element_post_expand_only(AbstractTreeElement &tree_element, + SpaceOutliner &space_outliner) +{ + tree_element.postExpand(space_outliner); +} +/** + * Needed for types that still expand in C, to poll if they should expand in current context. Can + * be removed once all ID types expand entirely using the new design. + */ +static bool tree_element_expand_poll(AbstractTreeElement &tree_element, + SpaceOutliner &space_outliner) +{ + return tree_element.expandPoll(space_outliner); } } // namespace blender::ed::outliner @@ -91,6 +126,16 @@ bool outliner_tree_element_type_is_expand_valid(TreeElementType *type) *type); return element.isExpandValid(); } +bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner) +{ + return outliner::tree_element_expand_poll( + reinterpret_cast(*type), *space_outliner); +} +void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner) +{ + outliner::tree_element_post_expand_only(reinterpret_cast(*type), + *space_outliner); +} void outliner_tree_element_type_free(TreeElementType **type) { diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h index c3dec1bf68a..8e5b02278cc 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.h +++ b/source/blender/editors/space_outliner/tree/tree_element.h @@ -40,6 +40,8 @@ void outliner_tree_element_type_free(TreeElementType **type); void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner); bool outliner_tree_element_type_is_expand_valid(TreeElementType *type); +bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner); +void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner); #ifdef __cplusplus } diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh index 3e61dd25898..4a7e95556db 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.hh +++ b/source/blender/editors/space_outliner/tree/tree_element.hh @@ -37,17 +37,24 @@ class AbstractTreeElement { TreeElement &legacy_te_; public: - AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te) - { - } virtual ~AbstractTreeElement() = default; + /** + * Check if the type is expandible in current context. + */ + virtual bool expandPoll(const SpaceOutliner &) const + { + return true; + } /** * Let the type add its own children. */ virtual void expand(SpaceOutliner &) const { } + virtual void postExpand(SpaceOutliner &) const + { + } /** * Just while transitioning to the new tree-element design: Some types are only partially ported, @@ -57,6 +64,12 @@ class AbstractTreeElement { { return true; } + + protected: + /* Pseudo-abstract: Only allow creation through derived types. */ + AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te) + { + } }; } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection_base.cc b/source/blender/editors/space_outliner/tree/tree_element_collection_base.cc new file mode 100644 index 00000000000..29e010b100d --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_collection_base.cc @@ -0,0 +1,44 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_listBase.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_collection_base.hh" + +namespace blender::ed::outliner { + +TreeElementCollectionBase::TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene) + : AbstractTreeElement(legacy_te), scene_(scene) +{ + BLI_assert(legacy_te.store_elem->type == TSE_SCENE_COLLECTION_BASE); + legacy_te.name = IFACE_("Scene Collection"); +} + +void TreeElementCollectionBase::expand(SpaceOutliner &space_outliner) const +{ + outliner_add_collection_recursive(&space_outliner, scene_.master_collection, &legacy_te_); +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection_base.hh b/source/blender/editors/space_outliner/tree/tree_element_collection_base.hh new file mode 100644 index 00000000000..e9584d37dfe --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_collection_base.hh @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementCollectionBase final : public AbstractTreeElement { + Scene &scene_; + + public: + TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc index 26787475635..a061c084027 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc @@ -20,30 +20,29 @@ #include "DNA_ID.h" +#include "BLI_listbase_wrapper.hh" #include "BLI_utildefines.h" +#include "BKE_lib_override.h" + +#include "BLT_translation.h" + +#include "RNA_access.h" + #include "../outliner_intern.h" +#include "tree_display.h" #include "tree_element_id.hh" namespace blender::ed::outliner { -TreeElementID::TreeElementID(TreeElement &legacy_te, const ID &id) : AbstractTreeElement(legacy_te) -{ - BLI_assert(legacy_te_.store_elem->type == TSE_SOME_ID); - BLI_assert(TSE_IS_REAL_ID(legacy_te_.store_elem)); - - /* Default, some specific types override this. */ - legacy_te_.name = id.name + 2; - legacy_te_.idcode = GS(id.name); -} - -TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, const ID &id) +TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id) { switch (ID_Type type = GS(id.name); type) { case ID_LI: - return new TreeElementIDLibrary(legacy_te, id); + return new TreeElementIDLibrary(legacy_te, (Library &)id); case ID_SCE: + return new TreeElementIDScene(legacy_te, (Scene &)id); case ID_OB: case ID_ME: case ID_CU: @@ -91,10 +90,137 @@ TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, const ID &id) return nullptr; } -TreeElementIDLibrary::TreeElementIDLibrary(TreeElement &legacy_te, const ID &id) - : TreeElementID(legacy_te, id) +/* -------------------------------------------------------------------- */ +/* ID Tree-Element Base Class (common/default logic) */ + +TreeElementID::TreeElementID(TreeElement &legacy_te, ID &id) + : AbstractTreeElement(legacy_te), id_(id) +{ + BLI_assert(legacy_te_.store_elem->type == TSE_SOME_ID); + BLI_assert(TSE_IS_REAL_ID(legacy_te_.store_elem)); + + /* Default, some specific types override this. */ + legacy_te_.name = id.name + 2; + legacy_te_.idcode = GS(id.name); +} + +void TreeElementID::expand_library_overrides(SpaceOutliner &space_outliner) const +{ + if (!id_.override_library) { + return; + } + + PointerRNA idpoin; + RNA_id_pointer_create(&id_, &idpoin); + + PointerRNA override_rna_ptr; + PropertyRNA *override_rna_prop; + int index = 0; + + for (auto *override_prop : + ListBaseWrapper(id_.override_library->properties)) { + if (!BKE_lib_override_rna_property_find( + &idpoin, override_prop, &override_rna_ptr, &override_rna_prop)) { + /* This is fine, override properties list is not always fully up-to-date with current + * RNA/IDProps etc., this gets cleaned up when re-generating the overrides rules, + * no error here. */ + continue; + } + + TreeElement *ten = outliner_add_element( + &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_LIBRARY_OVERRIDE, index++); + ten->name = RNA_property_ui_name(override_rna_prop); + } +} + +void TreeElementID::postExpand(SpaceOutliner &space_outliner) const +{ + const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(&space_outliner) || + ((space_outliner.filter & SO_FILTER_NO_LIB_OVERRIDE) == 0); + + if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY(&id_)) { + TreeElement *ten = outliner_add_element( + &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_LIBRARY_OVERRIDE_BASE, 0); + + ten->name = IFACE_("Library Overrides"); + expand_library_overrides(space_outliner); + } +} + +bool TreeElementID::expandPoll(const SpaceOutliner &space_outliner) const +{ + const TreeStoreElem *tsepar = legacy_te_.parent ? TREESTORE(legacy_te_.parent) : nullptr; + return (tsepar == NULL || tsepar->type != TSE_ID_BASE || space_outliner.filter_id_type); +} + +void TreeElementID::expand_animation_data(SpaceOutliner &space_outliner, + const AnimData *anim_data) const +{ + if (outliner_animdata_test(anim_data)) { + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_ANIM_DATA, 0); + } +} + +/* -------------------------------------------------------------------- */ +/* Library Tree-Element */ + +TreeElementIDLibrary::TreeElementIDLibrary(TreeElement &legacy_te, Library &library) + : TreeElementID(legacy_te, library.id) +{ + legacy_te.name = library.filepath; +} + +bool TreeElementIDLibrary::isExpandValid() const +{ + return true; +} + +/* -------------------------------------------------------------------- */ +/* Scene Tree-Element */ + +TreeElementIDScene::TreeElementIDScene(TreeElement &legacy_te, Scene &scene) + : TreeElementID(legacy_te, scene.id), scene_(scene) +{ +} + +bool TreeElementIDScene::isExpandValid() const +{ + return true; +} + +void TreeElementIDScene::expand(SpaceOutliner &space_outliner) const +{ + expandViewLayers(space_outliner); + expandWorld(space_outliner); + expandCollections(space_outliner); + expandObjects(space_outliner); + + expand_animation_data(space_outliner, scene_.adt); +} + +void TreeElementIDScene::expandViewLayers(SpaceOutliner &space_outliner) const +{ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER_BASE, 0); +} + +void TreeElementIDScene::expandWorld(SpaceOutliner &space_outliner) const +{ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, scene_.world, &legacy_te_, TSE_SOME_ID, 0); +} + +void TreeElementIDScene::expandCollections(SpaceOutliner &space_outliner) const +{ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_COLLECTION_BASE, 0); +} + +void TreeElementIDScene::expandObjects(SpaceOutliner &space_outliner) const { - legacy_te.name = ((Library &)id).filepath; + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_OBJECTS_BASE, 0); } } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh index 612c1cd4a6f..21bc25564fd 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh @@ -25,10 +25,16 @@ namespace blender::ed::outliner { class TreeElementID : public AbstractTreeElement { + protected: + ID &id_; + public: - TreeElementID(TreeElement &legacy_te, const ID &id); + TreeElementID(TreeElement &legacy_te, ID &id); + + static TreeElementID *createFromID(TreeElement &legacy_te, ID &id); - static TreeElementID *createFromID(TreeElement &legacy_te, const ID &id); + void postExpand(SpaceOutliner &) const override; + bool expandPoll(const SpaceOutliner &) const override; /** * Expanding not implemented for all types yet. Once it is, this can be set to true or @@ -38,11 +44,36 @@ class TreeElementID : public AbstractTreeElement { { return false; } + + protected: + /* ID types with animation data can use this. */ + void expand_animation_data(SpaceOutliner &, const AnimData *) const; + + private: + void expand_library_overrides(SpaceOutliner &) const; }; class TreeElementIDLibrary final : public TreeElementID { public: - TreeElementIDLibrary(TreeElement &legacy_te, const ID &id); + TreeElementIDLibrary(TreeElement &legacy_te, Library &library); + + bool isExpandValid() const override; +}; + +class TreeElementIDScene final : public TreeElementID { + Scene &scene_; + + public: + TreeElementIDScene(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; + bool isExpandValid() const override; + + private: + void expandViewLayers(SpaceOutliner &) const; + void expandWorld(SpaceOutliner &) const; + void expandCollections(SpaceOutliner &) const; + void expandObjects(SpaceOutliner &) const; }; } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.cc b/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.cc new file mode 100644 index 00000000000..4446b8864e6 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.cc @@ -0,0 +1,50 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BKE_collection.h" + +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_scene_objects_base.hh" + +namespace blender::ed::outliner { + +TreeElementSceneObjectsBase::TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene) + : AbstractTreeElement(legacy_te), scene_(scene) +{ + BLI_assert(legacy_te.store_elem->type == TSE_SCENE_OBJECTS_BASE); + legacy_te.name = IFACE_("Objects"); +} + +void TreeElementSceneObjectsBase::expand(SpaceOutliner &space_outliner) const +{ + FOREACH_SCENE_OBJECT_BEGIN (&scene_, ob) { + outliner_add_element(&space_outliner, &legacy_te_.subtree, ob, &legacy_te_, TSE_SOME_ID, 0); + } + FOREACH_SCENE_OBJECT_END; + outliner_make_object_parent_hierarchy(&legacy_te_.subtree); +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.hh b/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.hh new file mode 100644 index 00000000000..a2aa29c4a33 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.hh @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementSceneObjectsBase final : public AbstractTreeElement { + Scene &scene_; + + public: + TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.cc b/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.cc new file mode 100644 index 00000000000..490086203dc --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.cc @@ -0,0 +1,51 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_layer_types.h" + +#include "BLI_listbase_wrapper.hh" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_view_layer_base.hh" + +namespace blender::ed::outliner { + +TreeElementViewLayerBase::TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene) + : AbstractTreeElement(legacy_te), scene_(scene) +{ + BLI_assert(legacy_te.store_elem->type == TSE_R_LAYER_BASE); + legacy_te_.name = IFACE_("View Layers"); +} + +void TreeElementViewLayerBase::expand(SpaceOutliner &space_outliner) const +{ + for (auto *view_layer : ListBaseWrapper(scene_.view_layers)) { + TreeElement *tenlay = outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER, 0); + tenlay->name = view_layer->name; + tenlay->directdata = view_layer; + } +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.hh b/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.hh new file mode 100644 index 00000000000..24e03b265dc --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.hh @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementViewLayerBase final : public AbstractTreeElement { + Scene &scene_; + + public: + TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; +}; + +} // namespace blender::ed::outliner -- cgit v1.2.3 From f0ad78e17c3b48b457ad2cda9224924500e89eb9 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 8 Mar 2021 15:40:25 +0100 Subject: Cleanup: Rename recently added Outliner files to exclude "_base" suffix These files can contain more than just the "base" tree element types. E.g. the class for the view-layer base element can also contain the class for the view-layer elements. Otherwise we'd end up with like >50 files for the individual types, most of them very small. So just give the files a general name and put the related classes in there. --- .../blender/editors/space_outliner/CMakeLists.txt | 16 ++--- .../editors/space_outliner/tree/tree_element.cc | 8 +-- .../space_outliner/tree/tree_element_collection.cc | 44 ++++++++++++++ .../space_outliner/tree/tree_element_collection.hh | 36 ++++++++++++ .../tree/tree_element_collection_base.cc | 44 -------------- .../tree/tree_element_collection_base.hh | 36 ------------ .../space_outliner/tree/tree_element_driver.cc | 68 ++++++++++++++++++++++ .../space_outliner/tree/tree_element_driver.hh | 38 ++++++++++++ .../tree/tree_element_driver_base.cc | 68 ---------------------- .../tree/tree_element_driver_base.hh | 38 ------------ .../tree/tree_element_scene_objects.cc | 50 ++++++++++++++++ .../tree/tree_element_scene_objects.hh | 36 ++++++++++++ .../tree/tree_element_scene_objects_base.cc | 50 ---------------- .../tree/tree_element_scene_objects_base.hh | 36 ------------ .../space_outliner/tree/tree_element_view_layer.cc | 51 ++++++++++++++++ .../space_outliner/tree/tree_element_view_layer.hh | 36 ++++++++++++ .../tree/tree_element_view_layer_base.cc | 51 ---------------- .../tree/tree_element_view_layer_base.hh | 36 ------------ 18 files changed, 371 insertions(+), 371 deletions(-) create mode 100644 source/blender/editors/space_outliner/tree/tree_element_collection.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_collection.hh delete mode 100644 source/blender/editors/space_outliner/tree/tree_element_collection_base.cc delete mode 100644 source/blender/editors/space_outliner/tree/tree_element_collection_base.hh create mode 100644 source/blender/editors/space_outliner/tree/tree_element_driver.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_driver.hh delete mode 100644 source/blender/editors/space_outliner/tree/tree_element_driver_base.cc delete mode 100644 source/blender/editors/space_outliner/tree/tree_element_driver_base.hh create mode 100644 source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh delete mode 100644 source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.cc delete mode 100644 source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.hh create mode 100644 source/blender/editors/space_outliner/tree/tree_element_view_layer.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_view_layer.hh delete mode 100644 source/blender/editors/space_outliner/tree/tree_element_view_layer_base.cc delete mode 100644 source/blender/editors/space_outliner/tree/tree_element_view_layer_base.hh diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 82c87a7b199..0306807d9ad 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -56,13 +56,13 @@ set(SRC tree/tree_display_view_layer.cc tree/tree_element.cc tree/tree_element_anim_data.cc - tree/tree_element_collection_base.cc - tree/tree_element_driver_base.cc + tree/tree_element_collection.cc + tree/tree_element_driver.cc tree/tree_element_gpencil_layer.cc tree/tree_element_id.cc tree/tree_element_nla.cc - tree/tree_element_scene_objects_base.cc - tree/tree_element_view_layer_base.cc + tree/tree_element_scene_objects.cc + tree/tree_element_view_layer.cc outliner_intern.h tree/tree_display.h @@ -70,13 +70,13 @@ set(SRC tree/tree_element.h tree/tree_element.hh tree/tree_element_anim_data.hh - tree/tree_element_collection_base.hh - tree/tree_element_driver_base.hh + tree/tree_element_collection.hh + tree/tree_element_driver.hh tree/tree_element_gpencil_layer.hh tree/tree_element_id.hh tree/tree_element_nla.hh - tree/tree_element_scene_objects_base.hh - tree/tree_element_view_layer_base.hh + tree/tree_element_scene_objects.hh + tree/tree_element_view_layer.hh ) set(LIB diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index 75ecfb5584a..25bd9a53cf8 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -21,13 +21,13 @@ #include "DNA_listBase.h" #include "tree_element_anim_data.hh" -#include "tree_element_collection_base.hh" -#include "tree_element_driver_base.hh" +#include "tree_element_collection.hh" +#include "tree_element_driver.hh" #include "tree_element_gpencil_layer.hh" #include "tree_element_id.hh" #include "tree_element_nla.hh" -#include "tree_element_scene_objects_base.hh" -#include "tree_element_view_layer_base.hh" +#include "tree_element_scene_objects.hh" +#include "tree_element_view_layer.hh" #include "tree_element.h" #include "tree_element.hh" diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.cc b/source/blender/editors/space_outliner/tree/tree_element_collection.cc new file mode 100644 index 00000000000..1add61db7f1 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_collection.cc @@ -0,0 +1,44 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_listBase.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_collection.hh" + +namespace blender::ed::outliner { + +TreeElementCollectionBase::TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene) + : AbstractTreeElement(legacy_te), scene_(scene) +{ + BLI_assert(legacy_te.store_elem->type == TSE_SCENE_COLLECTION_BASE); + legacy_te.name = IFACE_("Scene Collection"); +} + +void TreeElementCollectionBase::expand(SpaceOutliner &space_outliner) const +{ + outliner_add_collection_recursive(&space_outliner, scene_.master_collection, &legacy_te_); +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.hh b/source/blender/editors/space_outliner/tree/tree_element_collection.hh new file mode 100644 index 00000000000..e9584d37dfe --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_collection.hh @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementCollectionBase final : public AbstractTreeElement { + Scene &scene_; + + public: + TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection_base.cc b/source/blender/editors/space_outliner/tree/tree_element_collection_base.cc deleted file mode 100644 index 29e010b100d..00000000000 --- a/source/blender/editors/space_outliner/tree/tree_element_collection_base.cc +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ - -/** \file - * \ingroup spoutliner - */ - -#include "DNA_listBase.h" - -#include "BLT_translation.h" - -#include "../outliner_intern.h" -#include "tree_display.h" - -#include "tree_element_collection_base.hh" - -namespace blender::ed::outliner { - -TreeElementCollectionBase::TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene) - : AbstractTreeElement(legacy_te), scene_(scene) -{ - BLI_assert(legacy_te.store_elem->type == TSE_SCENE_COLLECTION_BASE); - legacy_te.name = IFACE_("Scene Collection"); -} - -void TreeElementCollectionBase::expand(SpaceOutliner &space_outliner) const -{ - outliner_add_collection_recursive(&space_outliner, scene_.master_collection, &legacy_te_); -} - -} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection_base.hh b/source/blender/editors/space_outliner/tree/tree_element_collection_base.hh deleted file mode 100644 index e9584d37dfe..00000000000 --- a/source/blender/editors/space_outliner/tree/tree_element_collection_base.hh +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - */ - -/** \file - * \ingroup spoutliner - */ - -#pragma once - -#include "tree_element.hh" - -namespace blender::ed::outliner { - -class TreeElementCollectionBase final : public AbstractTreeElement { - Scene &scene_; - - public: - TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene); - - void expand(SpaceOutliner &) const override; -}; - -} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver.cc b/source/blender/editors/space_outliner/tree/tree_element_driver.cc new file mode 100644 index 00000000000..42f51908eaa --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_driver.cc @@ -0,0 +1,68 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_listbase_wrapper.hh" + +#include "BKE_fcurve_driver.h" + +#include "DNA_anim_types.h" +#include "DNA_listBase.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_driver.hh" + +namespace blender::ed::outliner { + +TreeElementDriverBase::TreeElementDriverBase(TreeElement &legacy_te, AnimData &anim_data) + : AbstractTreeElement(legacy_te), anim_data_(anim_data) +{ + BLI_assert(legacy_te.store_elem->type == TSE_DRIVER_BASE); + legacy_te.name = IFACE_("Drivers"); +} + +void TreeElementDriverBase::expand(SpaceOutliner &space_outliner) const +{ + ID *lastadded = nullptr; + + for (FCurve *fcu : blender::ListBaseWrapper(anim_data_.drivers)) { + if (fcu->driver && fcu->driver->variables.first) { + ChannelDriver *driver = fcu->driver; + + for (DriverVar *dvar : blender::ListBaseWrapper(driver->variables)) { + /* loop over all targets used here */ + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + if (lastadded != dtar->id) { + /* XXX this lastadded check is rather lame, and also fails quite badly... */ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, dtar->id, &legacy_te_, TSE_LINKED_OB, 0); + lastadded = dtar->id; + } + } + DRIVER_TARGETS_LOOPER_END; + } + } + } +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver.hh b/source/blender/editors/space_outliner/tree/tree_element_driver.hh new file mode 100644 index 00000000000..1925e3570be --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_driver.hh @@ -0,0 +1,38 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +struct TreeElement; + +namespace blender::ed::outliner { + +class TreeElementDriverBase final : public AbstractTreeElement { + AnimData &anim_data_; + + public: + TreeElementDriverBase(TreeElement &legacy_te, AnimData &anim_data); + + void expand(SpaceOutliner &space_outliner) const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc b/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc deleted file mode 100644 index a01a3c42531..00000000000 --- a/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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. - */ - -/** \file - * \ingroup spoutliner - */ - -#include "BLI_listbase_wrapper.hh" - -#include "BKE_fcurve_driver.h" - -#include "DNA_anim_types.h" -#include "DNA_listBase.h" - -#include "BLT_translation.h" - -#include "../outliner_intern.h" -#include "tree_display.h" - -#include "tree_element_driver_base.hh" - -namespace blender::ed::outliner { - -TreeElementDriverBase::TreeElementDriverBase(TreeElement &legacy_te, AnimData &anim_data) - : AbstractTreeElement(legacy_te), anim_data_(anim_data) -{ - BLI_assert(legacy_te.store_elem->type == TSE_DRIVER_BASE); - legacy_te.name = IFACE_("Drivers"); -} - -void TreeElementDriverBase::expand(SpaceOutliner &space_outliner) const -{ - ID *lastadded = nullptr; - - for (FCurve *fcu : blender::ListBaseWrapper(anim_data_.drivers)) { - if (fcu->driver && fcu->driver->variables.first) { - ChannelDriver *driver = fcu->driver; - - for (DriverVar *dvar : blender::ListBaseWrapper(driver->variables)) { - /* loop over all targets used here */ - DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - if (lastadded != dtar->id) { - /* XXX this lastadded check is rather lame, and also fails quite badly... */ - outliner_add_element( - &space_outliner, &legacy_te_.subtree, dtar->id, &legacy_te_, TSE_LINKED_OB, 0); - lastadded = dtar->id; - } - } - DRIVER_TARGETS_LOOPER_END; - } - } - } -} - -} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh b/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh deleted file mode 100644 index 1925e3570be..00000000000 --- a/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - */ - -/** \file - * \ingroup spoutliner - */ - -#pragma once - -#include "tree_element.hh" - -struct TreeElement; - -namespace blender::ed::outliner { - -class TreeElementDriverBase final : public AbstractTreeElement { - AnimData &anim_data_; - - public: - TreeElementDriverBase(TreeElement &legacy_te, AnimData &anim_data); - - void expand(SpaceOutliner &space_outliner) const override; -}; - -} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc new file mode 100644 index 00000000000..a46e8de1bdd --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc @@ -0,0 +1,50 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BKE_collection.h" + +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_scene_objects.hh" + +namespace blender::ed::outliner { + +TreeElementSceneObjectsBase::TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene) + : AbstractTreeElement(legacy_te), scene_(scene) +{ + BLI_assert(legacy_te.store_elem->type == TSE_SCENE_OBJECTS_BASE); + legacy_te.name = IFACE_("Objects"); +} + +void TreeElementSceneObjectsBase::expand(SpaceOutliner &space_outliner) const +{ + FOREACH_SCENE_OBJECT_BEGIN (&scene_, ob) { + outliner_add_element(&space_outliner, &legacy_te_.subtree, ob, &legacy_te_, TSE_SOME_ID, 0); + } + FOREACH_SCENE_OBJECT_END; + outliner_make_object_parent_hierarchy(&legacy_te_.subtree); +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh new file mode 100644 index 00000000000..a2aa29c4a33 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementSceneObjectsBase final : public AbstractTreeElement { + Scene &scene_; + + public: + TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.cc b/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.cc deleted file mode 100644 index 4446b8864e6..00000000000 --- a/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - */ - -/** \file - * \ingroup spoutliner - */ - -#include "BKE_collection.h" - -#include "BLI_utildefines.h" - -#include "BLT_translation.h" - -#include "../outliner_intern.h" -#include "tree_display.h" - -#include "tree_element_scene_objects_base.hh" - -namespace blender::ed::outliner { - -TreeElementSceneObjectsBase::TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene) - : AbstractTreeElement(legacy_te), scene_(scene) -{ - BLI_assert(legacy_te.store_elem->type == TSE_SCENE_OBJECTS_BASE); - legacy_te.name = IFACE_("Objects"); -} - -void TreeElementSceneObjectsBase::expand(SpaceOutliner &space_outliner) const -{ - FOREACH_SCENE_OBJECT_BEGIN (&scene_, ob) { - outliner_add_element(&space_outliner, &legacy_te_.subtree, ob, &legacy_te_, TSE_SOME_ID, 0); - } - FOREACH_SCENE_OBJECT_END; - outliner_make_object_parent_hierarchy(&legacy_te_.subtree); -} - -} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.hh b/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.hh deleted file mode 100644 index a2aa29c4a33..00000000000 --- a/source/blender/editors/space_outliner/tree/tree_element_scene_objects_base.hh +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - */ - -/** \file - * \ingroup spoutliner - */ - -#pragma once - -#include "tree_element.hh" - -namespace blender::ed::outliner { - -class TreeElementSceneObjectsBase final : public AbstractTreeElement { - Scene &scene_; - - public: - TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene); - - void expand(SpaceOutliner &) const override; -}; - -} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc new file mode 100644 index 00000000000..7bb9405147e --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc @@ -0,0 +1,51 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_layer_types.h" + +#include "BLI_listbase_wrapper.hh" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_view_layer.hh" + +namespace blender::ed::outliner { + +TreeElementViewLayerBase::TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene) + : AbstractTreeElement(legacy_te), scene_(scene) +{ + BLI_assert(legacy_te.store_elem->type == TSE_R_LAYER_BASE); + legacy_te_.name = IFACE_("View Layers"); +} + +void TreeElementViewLayerBase::expand(SpaceOutliner &space_outliner) const +{ + for (auto *view_layer : ListBaseWrapper(scene_.view_layers)) { + TreeElement *tenlay = outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER, 0); + tenlay->name = view_layer->name; + tenlay->directdata = view_layer; + } +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh b/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh new file mode 100644 index 00000000000..24e03b265dc --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementViewLayerBase final : public AbstractTreeElement { + Scene &scene_; + + public: + TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.cc b/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.cc deleted file mode 100644 index 490086203dc..00000000000 --- a/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - */ - -/** \file - * \ingroup spoutliner - */ - -#include "DNA_layer_types.h" - -#include "BLI_listbase_wrapper.hh" - -#include "BLT_translation.h" - -#include "../outliner_intern.h" -#include "tree_display.h" - -#include "tree_element_view_layer_base.hh" - -namespace blender::ed::outliner { - -TreeElementViewLayerBase::TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene) - : AbstractTreeElement(legacy_te), scene_(scene) -{ - BLI_assert(legacy_te.store_elem->type == TSE_R_LAYER_BASE); - legacy_te_.name = IFACE_("View Layers"); -} - -void TreeElementViewLayerBase::expand(SpaceOutliner &space_outliner) const -{ - for (auto *view_layer : ListBaseWrapper(scene_.view_layers)) { - TreeElement *tenlay = outliner_add_element( - &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER, 0); - tenlay->name = view_layer->name; - tenlay->directdata = view_layer; - } -} - -} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.hh b/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.hh deleted file mode 100644 index 24e03b265dc..00000000000 --- a/source/blender/editors/space_outliner/tree/tree_element_view_layer_base.hh +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - */ - -/** \file - * \ingroup spoutliner - */ - -#pragma once - -#include "tree_element.hh" - -namespace blender::ed::outliner { - -class TreeElementViewLayerBase final : public AbstractTreeElement { - Scene &scene_; - - public: - TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene); - - void expand(SpaceOutliner &) const override; -}; - -} // namespace blender::ed::outliner -- cgit v1.2.3 From fc0de69471f0e6a69ae6ffd01ca27156e524ce40 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 8 Mar 2021 18:34:53 +0100 Subject: Cleanup: Split up new files for Outliner ID tree-elements Splits up `tree_element_id.cc`/`tree_element_id.hh`. If we move all ID types into this one file, it will become rather big. Smaller files are probably easier to work with. We could still keep small classes like `TreeElementIDLibrary` in the general file, don't mind really, but this creates separate files for that too. --- .../blender/editors/space_outliner/CMakeLists.txt | 4 ++ .../editors/space_outliner/tree/tree_element_id.cc | 63 +----------------- .../editors/space_outliner/tree/tree_element_id.hh | 25 +------- .../space_outliner/tree/tree_element_id_library.cc | 40 ++++++++++++ .../space_outliner/tree/tree_element_id_library.hh | 34 ++++++++++ .../space_outliner/tree/tree_element_id_scene.cc | 74 ++++++++++++++++++++++ .../space_outliner/tree/tree_element_id_scene.hh | 43 +++++++++++++ 7 files changed, 199 insertions(+), 84 deletions(-) create mode 100644 source/blender/editors/space_outliner/tree/tree_element_id_library.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_id_library.hh create mode 100644 source/blender/editors/space_outliner/tree/tree_element_id_scene.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_id_scene.hh diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 0306807d9ad..eb3371e989a 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -60,6 +60,8 @@ set(SRC tree/tree_element_driver.cc tree/tree_element_gpencil_layer.cc tree/tree_element_id.cc + tree/tree_element_id_library.cc + tree/tree_element_id_scene.cc tree/tree_element_nla.cc tree/tree_element_scene_objects.cc tree/tree_element_view_layer.cc @@ -74,6 +76,8 @@ set(SRC tree/tree_element_driver.hh tree/tree_element_gpencil_layer.hh tree/tree_element_id.hh + tree/tree_element_id_library.hh + tree/tree_element_id_scene.hh tree/tree_element_nla.hh tree/tree_element_scene_objects.hh tree/tree_element_view_layer.hh diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc index a061c084027..31dfed35d8a 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc @@ -31,6 +31,8 @@ #include "../outliner_intern.h" #include "tree_display.h" +#include "tree_element_id_library.hh" +#include "tree_element_id_scene.hh" #include "tree_element_id.hh" @@ -162,65 +164,4 @@ void TreeElementID::expand_animation_data(SpaceOutliner &space_outliner, } } -/* -------------------------------------------------------------------- */ -/* Library Tree-Element */ - -TreeElementIDLibrary::TreeElementIDLibrary(TreeElement &legacy_te, Library &library) - : TreeElementID(legacy_te, library.id) -{ - legacy_te.name = library.filepath; -} - -bool TreeElementIDLibrary::isExpandValid() const -{ - return true; -} - -/* -------------------------------------------------------------------- */ -/* Scene Tree-Element */ - -TreeElementIDScene::TreeElementIDScene(TreeElement &legacy_te, Scene &scene) - : TreeElementID(legacy_te, scene.id), scene_(scene) -{ -} - -bool TreeElementIDScene::isExpandValid() const -{ - return true; -} - -void TreeElementIDScene::expand(SpaceOutliner &space_outliner) const -{ - expandViewLayers(space_outliner); - expandWorld(space_outliner); - expandCollections(space_outliner); - expandObjects(space_outliner); - - expand_animation_data(space_outliner, scene_.adt); -} - -void TreeElementIDScene::expandViewLayers(SpaceOutliner &space_outliner) const -{ - outliner_add_element( - &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER_BASE, 0); -} - -void TreeElementIDScene::expandWorld(SpaceOutliner &space_outliner) const -{ - outliner_add_element( - &space_outliner, &legacy_te_.subtree, scene_.world, &legacy_te_, TSE_SOME_ID, 0); -} - -void TreeElementIDScene::expandCollections(SpaceOutliner &space_outliner) const -{ - outliner_add_element( - &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_COLLECTION_BASE, 0); -} - -void TreeElementIDScene::expandObjects(SpaceOutliner &space_outliner) const -{ - outliner_add_element( - &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_OBJECTS_BASE, 0); -} - } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh index 21bc25564fd..2d077464b6d 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh @@ -16,6 +16,8 @@ /** \file * \ingroup spoutliner + * + * Tree element classes for the tree elements directly representing an ID (#TSE_SOME_ID). */ #pragma once @@ -53,27 +55,4 @@ class TreeElementID : public AbstractTreeElement { void expand_library_overrides(SpaceOutliner &) const; }; -class TreeElementIDLibrary final : public TreeElementID { - public: - TreeElementIDLibrary(TreeElement &legacy_te, Library &library); - - bool isExpandValid() const override; -}; - -class TreeElementIDScene final : public TreeElementID { - Scene &scene_; - - public: - TreeElementIDScene(TreeElement &legacy_te, Scene &scene); - - void expand(SpaceOutliner &) const override; - bool isExpandValid() const override; - - private: - void expandViewLayers(SpaceOutliner &) const; - void expandWorld(SpaceOutliner &) const; - void expandCollections(SpaceOutliner &) const; - void expandObjects(SpaceOutliner &) const; -}; - } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc new file mode 100644 index 00000000000..36f536c9845 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc @@ -0,0 +1,40 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_listBase.h" + +#include "../outliner_intern.h" + +#include "tree_element_id_library.hh" + +namespace blender::ed::outliner { + +TreeElementIDLibrary::TreeElementIDLibrary(TreeElement &legacy_te, Library &library) + : TreeElementID(legacy_te, library.id) +{ + legacy_te.name = library.filepath; +} + +bool TreeElementIDLibrary::isExpandValid() const +{ + return true; +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh new file mode 100644 index 00000000000..88660cd8aa9 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element_id.hh" + +namespace blender::ed::outliner { + +class TreeElementIDLibrary final : public TreeElementID { + public: + TreeElementIDLibrary(TreeElement &legacy_te, Library &library); + + bool isExpandValid() const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc new file mode 100644 index 00000000000..ae81b44a1e4 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc @@ -0,0 +1,74 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_listBase.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_id_scene.hh" + +namespace blender::ed::outliner { + +TreeElementIDScene::TreeElementIDScene(TreeElement &legacy_te, Scene &scene) + : TreeElementID(legacy_te, scene.id), scene_(scene) +{ +} + +bool TreeElementIDScene::isExpandValid() const +{ + return true; +} + +void TreeElementIDScene::expand(SpaceOutliner &space_outliner) const +{ + expandViewLayers(space_outliner); + expandWorld(space_outliner); + expandCollections(space_outliner); + expandObjects(space_outliner); + + expand_animation_data(space_outliner, scene_.adt); +} + +void TreeElementIDScene::expandViewLayers(SpaceOutliner &space_outliner) const +{ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER_BASE, 0); +} + +void TreeElementIDScene::expandWorld(SpaceOutliner &space_outliner) const +{ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, scene_.world, &legacy_te_, TSE_SOME_ID, 0); +} + +void TreeElementIDScene::expandCollections(SpaceOutliner &space_outliner) const +{ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_COLLECTION_BASE, 0); +} + +void TreeElementIDScene::expandObjects(SpaceOutliner &space_outliner) const +{ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_OBJECTS_BASE, 0); +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh b/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh new file mode 100644 index 00000000000..3340bacd307 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh @@ -0,0 +1,43 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element_id.hh" + +namespace blender::ed::outliner { + +class TreeElementIDScene final : public TreeElementID { + Scene &scene_; + + public: + TreeElementIDScene(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; + bool isExpandValid() const override; + + private: + void expandViewLayers(SpaceOutliner &) const; + void expandWorld(SpaceOutliner &) const; + void expandCollections(SpaceOutliner &) const; + void expandObjects(SpaceOutliner &) const; +}; + +} // namespace blender::ed::outliner -- cgit v1.2.3 From 84a4f2ae68d40830111ae41b25d76b165e37d611 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 8 Mar 2021 12:45:06 -0500 Subject: Geometry Nodes: Improve performance of point distribute node This commit refactors the point distribute node to skip realizing the instances created by the point instance node or the collection and object info nodes. Realizing instances is not necessary here because it copies all the mesh data and and interpolates all attributes from the instances when this operation does not need to modify the input geometry at all. In the tree leaves test file this patch improves the performance of the node by about 14%. That's not very much, the gain is likely larger for more complicated input instances with more attributes (especially attributes on different domains, where interpolation would be necessary to join all of the instances). Another possible performance improvement would be to parallelize the code in this node where possible. The point distribution code unfortunately gets quite a bit more complicated because it has to handle the complexity of having many inputs instead of just one. Note that this commit changes the randomness of the distribution in some cases, as if the seed input had changed. Differential Revision: https://developer.blender.org/D10596 --- source/blender/blenlib/BLI_math_matrix.h | 1 + source/blender/blenlib/intern/math_matrix.c | 10 + .../geometry/nodes/node_geo_point_distribute.cc | 546 ++++++++++++++------- 3 files changed, 391 insertions(+), 166 deletions(-) diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index eac7f25f11a..6324963f06a 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -331,6 +331,7 @@ void rescale_m4(float mat[4][4], const float scale[3]); void transform_pivot_set_m3(float mat[3][3], const float pivot[2]); void transform_pivot_set_m4(float mat[4][4], const float pivot[3]); +void mat4_to_rot(float rot[3][3], const float wmat[4][4]); void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]); void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]); void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]); diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index b460d75d77f..2ada05d2965 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -2140,6 +2140,16 @@ void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]) } } +void mat4_to_rot(float rot[3][3], const float wmat[4][4]) +{ + normalize_v3_v3(rot[0], wmat[0]); + normalize_v3_v3(rot[1], wmat[1]); + normalize_v3_v3(rot[2], wmat[2]); + if (UNLIKELY(is_negative_m3(rot))) { + negate_m3(rot); + } +} + void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]) { float mat3[3][3]; /* wmat -> 3x3 */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index c40cb2bb0ae..96409837491 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -29,6 +29,7 @@ #include "BKE_attribute_math.hh" #include "BKE_bvhutils.h" #include "BKE_deform.h" +#include "BKE_geometry_set_instances.hh" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_pointcloud.h" @@ -38,6 +39,9 @@ #include "node_geometry_util.hh" +using blender::bke::AttributeKind; +using blender::bke::GeometryInstanceGroup; + static bNodeSocketTemplate geo_node_point_distribute_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, {SOCK_FLOAT, N_("Distance Min"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE}, @@ -89,6 +93,7 @@ static Span get_mesh_looptris(const Mesh &mesh) } static void sample_mesh_surface(const Mesh &mesh, + const float4x4 &transform, const float base_density, const FloatReadAttribute *density_factors, const int seed, @@ -106,9 +111,9 @@ static void sample_mesh_surface(const Mesh &mesh, const int v0_index = mesh.mloop[v0_loop].v; const int v1_index = mesh.mloop[v1_loop].v; const int v2_index = mesh.mloop[v2_loop].v; - const float3 v0_pos = mesh.mvert[v0_index].co; - const float3 v1_pos = mesh.mvert[v1_index].co; - const float3 v2_pos = mesh.mvert[v2_index].co; + const float3 v0_pos = transform * float3(mesh.mvert[v0_index].co); + const float3 v1_pos = transform * float3(mesh.mvert[v1_index].co); + const float3 v2_pos = transform * float3(mesh.mvert[v2_index].co); float looptri_density_factor = 1.0f; if (density_factors != nullptr) { @@ -138,47 +143,64 @@ static void sample_mesh_surface(const Mesh &mesh, } } -BLI_NOINLINE static KDTree_3d *build_kdtree(Span positions) +BLI_NOINLINE static KDTree_3d *build_kdtree(Span> positions_all, + const int initial_points_len) { - KDTree_3d *kdtree = BLI_kdtree_3d_new(positions.size()); - for (const int i : positions.index_range()) { - BLI_kdtree_3d_insert(kdtree, i, positions[i]); + KDTree_3d *kdtree = BLI_kdtree_3d_new(initial_points_len); + + int i_point = 0; + for (const Vector positions : positions_all) { + for (const float3 position : positions) { + BLI_kdtree_3d_insert(kdtree, i_point, position); + i_point++; + } } BLI_kdtree_3d_balance(kdtree); return kdtree; } BLI_NOINLINE static void update_elimination_mask_for_close_points( - Span positions, const float minimum_distance, MutableSpan elimination_mask) + Span> positions_all, + Span instance_start_offsets, + const float minimum_distance, + MutableSpan elimination_mask, + const int initial_points_len) { if (minimum_distance <= 0.0f) { return; } - KDTree_3d *kdtree = build_kdtree(positions); + KDTree_3d *kdtree = build_kdtree(positions_all, initial_points_len); - for (const int i : positions.index_range()) { - if (elimination_mask[i]) { - continue; - } + /* The elimination mask is a flattened array for every point, + * so keep track of the index to it separately. */ + for (const int i_instance : positions_all.index_range()) { + Span positions = positions_all[i_instance]; + const int offset = instance_start_offsets[i_instance]; + + for (const int i : positions.index_range()) { + if (elimination_mask[offset + i]) { + continue; + } - struct CallbackData { - int index; - MutableSpan elimination_mask; - } callback_data = {i, elimination_mask}; - - BLI_kdtree_3d_range_search_cb( - kdtree, - positions[i], - minimum_distance, - [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) { - CallbackData &callback_data = *static_cast(user_data); - if (index != callback_data.index) { - callback_data.elimination_mask[index] = true; - } - return true; - }, - &callback_data); + struct CallbackData { + int index; + MutableSpan elimination_mask; + } callback_data = {offset + i, elimination_mask}; + + BLI_kdtree_3d_range_search_cb( + kdtree, + positions[i], + minimum_distance, + [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) { + CallbackData &callback_data = *static_cast(user_data); + if (index != callback_data.index) { + callback_data.elimination_mask[index] = true; + } + return true; + }, + &callback_data); + } } BLI_kdtree_3d_free(kdtree); } @@ -287,73 +309,106 @@ BLI_NOINLINE static void interpolate_attribute_corner(const Mesh &mesh, } } +template BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh, Span bary_coords, Span looptri_indices, - const StringRef attribute_name, - const ReadAttribute &attribute_in, - GeometryComponent &component) + const AttributeDomain source_domain, + Span source_span, + MutableSpan output_span) { - const CustomDataType data_type = attribute_in.custom_data_type(); - const AttributeDomain domain = attribute_in.domain(); - if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) { - /* Not supported currently. */ - return; - } - - OutputAttributePtr attribute_out = component.attribute_try_get_for_output( - attribute_name, ATTR_DOMAIN_POINT, data_type); - if (!attribute_out) { - return; - } - - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - - Span data_in = attribute_in.get_span(); - MutableSpan data_out = attribute_out->get_span_for_write_only(); - - switch (domain) { - case ATTR_DOMAIN_POINT: { - interpolate_attribute_point(mesh, bary_coords, looptri_indices, data_in, data_out); - break; - } - case ATTR_DOMAIN_CORNER: { - interpolate_attribute_corner(mesh, bary_coords, looptri_indices, data_in, data_out); - break; - } - default: { - BLI_assert(false); - break; - } + switch (source_domain) { + case ATTR_DOMAIN_POINT: { + interpolate_attribute_point(mesh, bary_coords, looptri_indices, source_span, output_span); + break; + } + case ATTR_DOMAIN_CORNER: { + interpolate_attribute_corner( + mesh, bary_coords, looptri_indices, source_span, output_span); + break; } - }); - attribute_out.apply_span_and_save(); + default: { + /* Not supported currently. */ + return; + } + } } -BLI_NOINLINE static void interpolate_existing_attributes(const MeshComponent &mesh_component, - GeometryComponent &component, - Span bary_coords, - Span looptri_indices) +BLI_NOINLINE static void interpolate_existing_attributes( + Span set_groups, + Span instance_start_offsets, + const Map &attributes, + GeometryComponent &component, + Span> bary_coords_array, + Span> looptri_indices_array) { - const Mesh &mesh = *mesh_component.get_for_read(); - - Set attribute_names = mesh_component.attribute_names(); - for (StringRefNull attribute_name : attribute_names) { - if (ELEM(attribute_name, "position", "normal", "id")) { + for (Map::Item entry : attributes.items()) { + StringRef attribute_name = entry.key; + const CustomDataType output_data_type = entry.value.data_type; + /* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */ + OutputAttributePtr attribute_out = component.attribute_try_get_for_output( + attribute_name, ATTR_DOMAIN_POINT, output_data_type); + if (!attribute_out) { continue; } - ReadAttributePtr attribute_in = mesh_component.attribute_try_get_for_read(attribute_name); - interpolate_attribute( - mesh, bary_coords, looptri_indices, attribute_name, *attribute_in, component); + fn::GMutableSpan out_span = attribute_out->get_span_for_write_only(); + + int i_instance = 0; + for (const GeometryInstanceGroup &set_group : set_groups) { + const GeometrySet &set = set_group.geometry_set; + const MeshComponent &source_component = *set.get_component_for_read(); + const Mesh &mesh = *source_component.get_for_read(); + + /* Use a dummy read without specifying a domain or data type in order to + * get the existing attribute's domain. Interpolation is done manually based + * on the bary coords in #interpolate_attribute. */ + ReadAttributePtr dummy_attribute = source_component.attribute_try_get_for_read( + attribute_name); + if (!dummy_attribute) { + i_instance += set_group.transforms.size(); + continue; + } + + const AttributeDomain source_domain = dummy_attribute->domain(); + ReadAttributePtr source_attribute = source_component.attribute_get_for_read( + attribute_name, source_domain, output_data_type, nullptr); + if (!source_attribute) { + i_instance += set_group.transforms.size(); + continue; + } + fn::GSpan source_span = source_attribute->get_span(); + + attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) { + using T = decltype(dummy); + + for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) { + const int offset = instance_start_offsets[i_instance]; + Span bary_coords = bary_coords_array[i_instance]; + Span looptri_indices = looptri_indices_array[i_instance]; + + MutableSpan instance_span = out_span.typed().slice(offset, bary_coords.size()); + interpolate_attribute(mesh, + bary_coords, + looptri_indices, + source_domain, + source_span.typed(), + instance_span); + + i_instance++; + } + }); + } + + attribute_out.apply_span_and_save(); } } -BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh, +BLI_NOINLINE static void compute_special_attributes(Span sets, + Span instance_start_offsets, GeometryComponent &component, - Span bary_coords, - Span looptri_indices) + Span> bary_coords_array, + Span> looptri_indices_array) { OutputAttributePtr id_attribute = component.attribute_try_get_for_output( "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); @@ -362,26 +417,50 @@ BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh, OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output( "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); - MutableSpan ids = id_attribute->get_span_for_write_only(); - MutableSpan normals = normal_attribute->get_span_for_write_only(); - MutableSpan rotations = rotation_attribute->get_span_for_write_only(); - - Span looptris = get_mesh_looptris(mesh); - for (const int i : bary_coords.index_range()) { - const int looptri_index = looptri_indices[i]; - const MLoopTri &looptri = looptris[looptri_index]; - const float3 &bary_coord = bary_coords[i]; - - const int v0_index = mesh.mloop[looptri.tri[0]].v; - const int v1_index = mesh.mloop[looptri.tri[1]].v; - const int v2_index = mesh.mloop[looptri.tri[2]].v; - const float3 v0_pos = mesh.mvert[v0_index].co; - const float3 v1_pos = mesh.mvert[v1_index].co; - const float3 v2_pos = mesh.mvert[v2_index].co; + MutableSpan result_ids = id_attribute->get_span_for_write_only(); + MutableSpan result_normals = normal_attribute->get_span_for_write_only(); + MutableSpan result_rotations = rotation_attribute->get_span_for_write_only(); + + int i_instance = 0; + for (const GeometryInstanceGroup &set_group : sets) { + const GeometrySet &set = set_group.geometry_set; + const MeshComponent &component = *set.get_component_for_read(); + const Mesh &mesh = *component.get_for_read(); + Span looptris = get_mesh_looptris(mesh); + + for (const float4x4 &transform : set_group.transforms) { + const int offset = instance_start_offsets[i_instance]; + + Span bary_coords = bary_coords_array[i_instance]; + Span looptri_indices = looptri_indices_array[i_instance]; + MutableSpan ids = result_ids.slice(offset, bary_coords.size()); + MutableSpan normals = result_normals.slice(offset, bary_coords.size()); + MutableSpan rotations = result_rotations.slice(offset, bary_coords.size()); + + /* Use one matrix multiplication per point instead of three (for each triangle corner). */ + float rotation_matrix[3][3]; + mat4_to_rot(rotation_matrix, transform.values); + + for (const int i : bary_coords.index_range()) { + const int looptri_index = looptri_indices[i]; + const MLoopTri &looptri = looptris[looptri_index]; + const float3 &bary_coord = bary_coords[i]; + + const int v0_index = mesh.mloop[looptri.tri[0]].v; + const int v1_index = mesh.mloop[looptri.tri[1]].v; + const int v2_index = mesh.mloop[looptri.tri[2]].v; + const float3 v0_pos = float3(mesh.mvert[v0_index].co); + const float3 v1_pos = float3(mesh.mvert[v1_index].co); + const float3 v2_pos = float3(mesh.mvert[v2_index].co); + + ids[i] = (int)(bary_coord.hash() + (uint64_t)looptri_index); + normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos); + mul_m3_v3(rotation_matrix, normals[i]); + rotations[i] = normal_to_euler_rotation(normals[i]); + } - ids[i] = (int)(bary_coord.hash() + (uint64_t)looptri_index); - normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos); - rotations[i] = normal_to_euler_rotation(normals[i]); + i_instance++; + } } id_attribute.apply_span_and_save(); @@ -389,109 +468,244 @@ BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh, rotation_attribute.apply_span_and_save(); } -BLI_NOINLINE static void add_remaining_point_attributes(const MeshComponent &mesh_component, - GeometryComponent &component, - Span bary_coords, - Span looptri_indices) +BLI_NOINLINE static void add_remaining_point_attributes( + Span set_groups, + Span instance_start_offsets, + const Map &attributes, + GeometryComponent &component, + Span> bary_coords_array, + Span> looptri_indices_array) { - interpolate_existing_attributes(mesh_component, component, bary_coords, looptri_indices); + interpolate_existing_attributes(set_groups, + instance_start_offsets, + attributes, + component, + bary_coords_array, + looptri_indices_array); compute_special_attributes( - *mesh_component.get_for_read(), component, bary_coords, looptri_indices); + set_groups, instance_start_offsets, component, bary_coords_array, looptri_indices_array); } -static void sample_mesh_surface_with_minimum_distance(const Mesh &mesh, - const float max_density, - const float minimum_distance, - const FloatReadAttribute &density_factors, - const int seed, - Vector &r_positions, - Vector &r_bary_coords, - Vector &r_looptri_indices) +static void distribute_points_random(Span set_groups, + const StringRef density_attribute_name, + const float density, + const int seed, + MutableSpan> positions_all, + MutableSpan> bary_coords_all, + MutableSpan> looptri_indices_all) { - sample_mesh_surface( - mesh, max_density, nullptr, seed, r_positions, r_bary_coords, r_looptri_indices); - Array elimination_mask(r_positions.size(), false); - update_elimination_mask_for_close_points(r_positions, minimum_distance, elimination_mask); - update_elimination_mask_based_on_density_factors( - mesh, density_factors, r_bary_coords, r_looptri_indices, elimination_mask); - eliminate_points_based_on_mask(elimination_mask, r_positions, r_bary_coords, r_looptri_indices); + /* If there is an attribute name, the default value for the densities should be zero so that + * points are only scattered where the attribute exists. Otherwise, just "ignore" the density + * factors. */ + const bool use_one_default = density_attribute_name.is_empty(); + + int i_instance = 0; + for (const GeometryInstanceGroup &set_group : set_groups) { + const GeometrySet &set = set_group.geometry_set; + const MeshComponent &component = *set.get_component_for_read(); + const FloatReadAttribute density_factors = component.attribute_get_for_read( + density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); + const Mesh &mesh = *component.get_for_read(); + for (const float4x4 &transform : set_group.transforms) { + Vector &positions = positions_all[i_instance]; + Vector &bary_coords = bary_coords_all[i_instance]; + Vector &looptri_indices = looptri_indices_all[i_instance]; + sample_mesh_surface(mesh, + transform, + density, + &density_factors, + seed, + positions, + bary_coords, + looptri_indices); + i_instance++; + } + } +} + +static void distribute_points_poisson_disk(Span set_groups, + const StringRef density_attribute_name, + const float density, + const int seed, + const float minimum_distance, + MutableSpan> positions_all, + MutableSpan> bary_coords_all, + MutableSpan> looptri_indices_all) +{ + Array instance_start_offsets(positions_all.size()); + int initial_points_len = 0; + int i_instance = 0; + for (const GeometryInstanceGroup &set_group : set_groups) { + const GeometrySet &set = set_group.geometry_set; + const MeshComponent &component = *set.get_component_for_read(); + const Mesh &mesh = *component.get_for_read(); + for (const float4x4 &transform : set_group.transforms) { + Vector &positions = positions_all[i_instance]; + Vector &bary_coords = bary_coords_all[i_instance]; + Vector &looptri_indices = looptri_indices_all[i_instance]; + sample_mesh_surface( + mesh, transform, density, nullptr, seed, positions, bary_coords, looptri_indices); + + instance_start_offsets[i_instance] = initial_points_len; + initial_points_len += positions.size(); + i_instance++; + } + } + + /* If there is an attribute name, the default value for the densities should be zero so that + * points are only scattered where the attribute exists. Otherwise, just "ignore" the density + * factors. */ + const bool use_one_default = density_attribute_name.is_empty(); + + /* Unlike the other result arrays, the elimination mask in stored as a flat array for every + * point, in order to simplify culling points from the KDTree (which needs to know about all + * points at once). */ + Array elimination_mask(initial_points_len, false); + update_elimination_mask_for_close_points(positions_all, + instance_start_offsets, + minimum_distance, + elimination_mask, + initial_points_len); + + i_instance = 0; + for (const GeometryInstanceGroup &set_group : set_groups) { + const GeometrySet &set = set_group.geometry_set; + const MeshComponent &component = *set.get_component_for_read(); + const Mesh &mesh = *component.get_for_read(); + const FloatReadAttribute density_factors = component.attribute_get_for_read( + density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); + + for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) { + Vector &positions = positions_all[i_instance]; + Vector &bary_coords = bary_coords_all[i_instance]; + Vector &looptri_indices = looptri_indices_all[i_instance]; + + const int offset = instance_start_offsets[i_instance]; + update_elimination_mask_based_on_density_factors( + mesh, + density_factors, + bary_coords, + looptri_indices, + elimination_mask.as_mutable_span().slice(offset, positions.size())); + + eliminate_points_based_on_mask(elimination_mask.as_span().slice(offset, positions.size()), + positions, + bary_coords, + looptri_indices); + + i_instance++; + } + } } static void geo_node_point_distribute_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input("Geometry"); - GeometrySet geometry_set_out; - /* TODO: This node only needs read-only access to input instances. */ - geometry_set = geometry_set_realize_instances(geometry_set); + const GeometryNodePointDistributeMode distribute_method = + static_cast(params.node().custom1); - GeometryNodePointDistributeMode distribute_method = static_cast( - params.node().custom1); + const int seed = params.get_input("Seed"); + const float density = params.extract_input("Density Max"); + const std::string density_attribute_name = params.extract_input( + "Density Attribute"); - if (!geometry_set.has_mesh()) { - params.error_message_add(NodeWarningType::Error, TIP_("Geometry must contain a mesh")); - params.set_output("Geometry", std::move(geometry_set_out)); + if (density <= 0.0f) { + params.set_output("Geometry", std::move(GeometrySet())); return; } - const float density = params.extract_input("Density Max"); - const std::string density_attribute = params.extract_input("Density Attribute"); - - if (density <= 0.0f) { - params.set_output("Geometry", std::move(geometry_set_out)); + Vector set_groups = bke::geometry_set_gather_instances(geometry_set); + if (set_groups.is_empty()) { + params.set_output("Geometry", std::move(GeometrySet())); return; } - const MeshComponent &mesh_component = *geometry_set.get_component_for_read(); - const Mesh *mesh_in = mesh_component.get_for_read(); + /* Remove any set inputs that don't contain a mesh, to avoid checking later on. */ + for (int i = set_groups.size() - 1; i >= 0; i--) { + const GeometrySet &set = set_groups[i].geometry_set; + if (!set.has_mesh()) { + set_groups.remove_and_reorder(i); + } + } - if (mesh_in->mpoly == nullptr) { - params.error_message_add(NodeWarningType::Error, TIP_("Mesh has no faces")); - params.set_output("Geometry", std::move(geometry_set_out)); + if (set_groups.is_empty()) { + params.error_message_add(NodeWarningType::Error, TIP_("Input geometry must contain a mesh")); + params.set_output("Geometry", std::move(GeometrySet())); return; } - const FloatReadAttribute density_factors = mesh_component.attribute_get_for_read( - density_attribute, ATTR_DOMAIN_CORNER, 1.0f); - const int seed = params.get_input("Seed"); + int instances_len = 0; + for (GeometryInstanceGroup &set_group : set_groups) { + instances_len += set_group.transforms.size(); + } + + /* Store data per-instance in order to simplify attribute access after the scattering, + * and to make the point elimination simpler for the poisson disk mode. Note that some + * vectors will be empty if any instances don't contain mesh data. */ + Array> positions_all(instances_len); + Array> bary_coords_all(instances_len); + Array> looptri_indices_all(instances_len); - Vector positions; - Vector bary_coords; - Vector looptri_indices; switch (distribute_method) { - case GEO_NODE_POINT_DISTRIBUTE_RANDOM: - sample_mesh_surface( - *mesh_in, density, &density_factors, seed, positions, bary_coords, looptri_indices); + case GEO_NODE_POINT_DISTRIBUTE_RANDOM: { + distribute_points_random(set_groups, + density_attribute_name, + density, + seed, + positions_all, + bary_coords_all, + looptri_indices_all); break; - case GEO_NODE_POINT_DISTRIBUTE_POISSON: + } + case GEO_NODE_POINT_DISTRIBUTE_POISSON: { const float minimum_distance = params.extract_input("Distance Min"); - sample_mesh_surface_with_minimum_distance(*mesh_in, - density, - minimum_distance, - density_factors, - seed, - positions, - bary_coords, - looptri_indices); + distribute_points_poisson_disk(set_groups, + density_attribute_name, + density, + seed, + minimum_distance, + positions_all, + bary_coords_all, + looptri_indices_all); break; + } } - const int tot_points = positions.size(); - PointCloud *pointcloud = BKE_pointcloud_new_nomain(tot_points); - memcpy(pointcloud->co, positions.data(), sizeof(float3) * tot_points); - for (const int i : positions.index_range()) { - *(float3 *)(pointcloud->co + i) = positions[i]; - pointcloud->radius[i] = 0.05f; + int final_points_len = 0; + Array instance_start_offsets(set_groups.size()); + for (const int i : positions_all.index_range()) { + Vector &positions = positions_all[i]; + instance_start_offsets[i] = final_points_len; + final_points_len += positions.size(); } + PointCloud *pointcloud = BKE_pointcloud_new_nomain(final_points_len); + for (const int instance_index : positions_all.index_range()) { + const int offset = instance_start_offsets[instance_index]; + Span positions = positions_all[instance_index]; + memcpy(pointcloud->co + offset, positions.data(), sizeof(float3) * positions.size()); + } + + uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f); + + GeometrySet geometry_set_out = GeometrySet::create_with_pointcloud(pointcloud); PointCloudComponent &point_component = geometry_set_out.get_component_for_write(); - point_component.replace(pointcloud); - add_remaining_point_attributes(mesh_component, point_component, bary_coords, looptri_indices); + Map attributes; + bke::gather_attribute_info( + attributes, {GeometryComponentType::Mesh}, set_groups, {"position", "normal", "id"}); + add_remaining_point_attributes(set_groups, + instance_start_offsets, + attributes, + point_component, + bary_coords_all, + looptri_indices_all); params.set_output("Geometry", std::move(geometry_set_out)); } + } // namespace blender::nodes void register_node_type_geo_point_distribute() -- cgit v1.2.3 From a45af290f37dfcf7702c5141e642b253a94c7857 Mon Sep 17 00:00:00 2001 From: Mark Stead Date: Mon, 8 Mar 2021 18:19:35 +0100 Subject: Fix T86357: EEVEE: Shadows: Casters have exponential performance degradation with many objects When you have many distinct objects, in an Eevee render then the shadow caster gets exponentially slower as the number of (distinct) objects increase. This is because of the way that frontbuffer->bbox (EEVEE_BoundBox array) and the associated frontbuffer->update bitmap are resized. Currently the resizing is done by reserving space for SH_CASTER_ALLOC_CHUNK (32) objects at a time. When the number of objects is large, then the MEM_reallocN() gets progressively slower because it must memcpy the entire bbox/bitmap data to the new memory chunk. And there will be a lot of *memcpy* operations for a large scene. (Obviously there are a significant number of memory allocations/deallocations too - though this would be linear performance.) I've switched to doubling the frontbuffer->alloc_count (buffer capacity) instead of adding SH_CASTER_ALLOC_CHUNK (32). As I understand this is the only way to eliminate exponential slowdown. Just increasing the size of SH_CASTER_ALLOC_CHUNK would still result in exponential slowdown eventually. In other changes, the "+ 1" in this expression is not necessary. if (id + 1 >= frontbuffer->alloc_count) The buffer is 0-based. So when the buffer is initially allocated then id values from bbox[0] to bbox[31] are valid. Hence when frontbuffer->count == frontbuffer->alloc_count, is when the resizing should be triggered. As it stands the "+ 1" results in resizing the buffer, when there is still capacity for one more object in the buffer. I've changed the initial buffer allocation to use MEM_mallocN() instead of MEM_callocN(). The difference is that malloc() doesn't memset buffer (with zeros) when allocated. I've checked the code where new bbox records are created, and it does not rely on the buffer being initialised with zeros. Anyway, isn't calloc() safer than using malloc()? Well no, it's actually the opposite in this case. Every time the buffer size is increased, it is done using realloc(), and this does not zero-out the uniniitialised portion of the buffer. So the code would break if it was modified to assume that the buffer contains zeros. Hence I believe initialising the buffer using calloc() could be misleading to a new developer. Won't this result in increased memory usage? Yes, if you have millions of objects in your scene, then you are potentially using up-to twice the memory for the shadow caster. (However if you have millions of objects in your scene you're probably finding the Eevee render times a slow.) Note that once the render gets going the frontbuffer bbox/bitmap will be shrunk to a multiple of SH_CASTER_ALLOC_CHUNK (32), therefore releasing the overallocation of memory. As observed in Visual Studio - this appears to be prior to peak memory usage anyway. Note this shrinking is executed in EEVEE_shadows_update() - during the first render sample pass. If necessary you could consider shrinking the buffer immediately after the EEVEE_shadows_caster_register() has done it's work. (Note however it appears you would need to add that function call is multiple places.) Anyway as per the bug report I raised, I observed a 5% increase in peak-memory. And I'm unclear whether this difference in memory is due to me running the debug build. (It could be that there is no difference because of the shrinking.) I couldn't figure out how the shadow caster backbuffer works. I see that EEVEE_shadows_init() has an explicit command to swap the front/back buffers. However this is done only when the buffers are first initialised and there is nothing in there yet. In my testing, the backbuffer->count was always zero, EEVEE_shadows_update() never did anything with the backbuffer. Finally this problem is most evident when using Geometry Nodes or a Particle System to instantiate many objects. Objects created through say the array modifier do not cause any issues because it is considered one object by the shadow caster. Reviewed By: #eevee_viewport, fclem Differential Revision: https://developer.blender.org/D10631 --- source/blender/draw/engines/eevee/eevee_shadows.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index f6fe9a76c70..1f27d2dce34 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -53,7 +53,7 @@ void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata) sldata->shadow_ubo = GPU_uniformbuf_create_ex(shadow_ubo_size, NULL, "evShadow"); for (int i = 0; i < 2; i++) { - sldata->shcasters_buffers[i].bbox = MEM_callocN( + sldata->shcasters_buffers[i].bbox = MEM_mallocN( sizeof(EEVEE_BoundBox) * SH_CASTER_ALLOC_CHUNK, __func__); sldata->shcasters_buffers[i].update = BLI_BITMAP_NEW(SH_CASTER_ALLOC_CHUNK, __func__); sldata->shcasters_buffers[i].alloc_count = SH_CASTER_ALLOC_CHUNK; @@ -133,8 +133,9 @@ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob) int id = frontbuffer->count; /* Make sure shadow_casters is big enough. */ - if (id + 1 >= frontbuffer->alloc_count) { - frontbuffer->alloc_count += SH_CASTER_ALLOC_CHUNK; + if (id >= frontbuffer->alloc_count) { + /* Double capacity to prevent exponential slowdown. */ + frontbuffer->alloc_count *= 2; frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox, sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count); BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count); @@ -173,6 +174,7 @@ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob) } EEVEE_BoundBox *aabb = &frontbuffer->bbox[id]; + /* Note that *aabb has not been initialised yet. */ add_v3_v3v3(aabb->center, min, max); mul_v3_fl(aabb->center, 0.5f); sub_v3_v3v3(aabb->halfdim, aabb->center, max); -- cgit v1.2.3 From 2e19509e60b39837b6f9e38c8cdad64d341846ba Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 8 Mar 2021 13:37:49 -0500 Subject: Geometry Nodes: Rename subdivision nodes This makes the following changes to the name of the two geometry nodes subvision nodes: - `Subdivision Surface` -> `Subdivide Smooth` - `Subdivision Surface Simple` -> `Subdivide` Most of the benefit is that the names are shorter, but it also better mirrors the naming of operations in edit mode, and phrases the names more like actions. This was discussed with the geometry nodes team. --- release/scripts/startup/nodeitems_builtins.py | 4 +- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/BKE_node.h | 4 +- source/blender/blenkernel/intern/node.cc | 4 +- source/blender/blenloader/intern/versioning_290.c | 15 +++ source/blender/nodes/CMakeLists.txt | 4 +- source/blender/nodes/NOD_geometry.h | 4 +- source/blender/nodes/NOD_static_types.h | 4 +- .../nodes/geometry/nodes/node_geo_subdivide.cc | 110 +++++++++++++++++ .../geometry/nodes/node_geo_subdivide_smooth.cc | 133 ++++++++++++++++++++ .../geometry/nodes/node_geo_subdivision_surface.cc | 134 --------------------- .../nodes/node_geo_subdivision_surface_simple.cc | 115 ------------------ 12 files changed, 271 insertions(+), 262 deletions(-) create mode 100644 source/blender/nodes/geometry/nodes/node_geo_subdivide.cc create mode 100644 source/blender/nodes/geometry/nodes/node_geo_subdivide_smooth.cc delete mode 100644 source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc delete mode 100644 source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index e013317b547..83e72e6f84c 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -516,8 +516,8 @@ geometry_node_categories = [ NodeItem("GeometryNodeBoolean"), NodeItem("GeometryNodeTriangulate"), NodeItem("GeometryNodeEdgeSplit"), - NodeItem("GeometryNodeSubdivisionSurface"), - NodeItem("GeometryNodeSubdivisionSurfaceSimple"), + NodeItem("GeometryNodeSubdivideSmooth"), + NodeItem("GeometryNodeSubdivide"), ]), GeometryNodeCategory("GEO_POINT", "Point", items=[ NodeItem("GeometryNodePointDistribute"), diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 66bfe620df7..133f1c5100a 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 10 +#define BLENDER_FILE_SUBVERSION 11 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 655c53455cc..f5f65e71f7f 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1348,7 +1348,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_BOOLEAN 1003 #define GEO_NODE_POINT_DISTRIBUTE 1004 #define GEO_NODE_POINT_INSTANCE 1005 -#define GEO_NODE_SUBDIVISION_SURFACE 1006 +#define GEO_NODE_SUBDIVIDE_SMOOTH 1006 #define GEO_NODE_OBJECT_INFO 1007 #define GEO_NODE_ATTRIBUTE_RANDOMIZE 1008 #define GEO_NODE_ATTRIBUTE_MATH 1009 @@ -1371,7 +1371,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_VOLUME_TO_MESH 1026 #define GEO_NODE_ATTRIBUTE_COMBINE_XYZ 1027 #define GEO_NODE_ATTRIBUTE_SEPARATE_XYZ 1028 -#define GEO_NODE_SUBDIVISION_SURFACE_SIMPLE 1029 +#define GEO_NODE_SUBDIVIDE 1029 /** \} */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index c2ce52b1358..9615fbc31e7 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -4809,8 +4809,8 @@ static void registerGeometryNodes() register_node_type_geo_point_translate(); register_node_type_geo_points_to_volume(); register_node_type_geo_sample_texture(); - register_node_type_geo_subdivision_surface(); - register_node_type_geo_subdivision_surface_simple(); + register_node_type_geo_subdivide_smooth(); + register_node_type_geo_subdivide(); register_node_type_geo_transform(); register_node_type_geo_triangulate(); register_node_type_geo_volume_to_mesh(); diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 1aa1f0302e3..8cf840f665b 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1806,6 +1806,21 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 293, 11)) { + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + if (ntree->type == NTREE_GEOMETRY) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (STREQ(node->idname, "GeometryNodeSubdivisionSurfaceSimple")) { + STRNCPY(node->idname, "GeometryNodeSubdivide"); + } + if (STREQ(node->idname, "GeometryNodeSubdivisionSurface")) { + STRNCPY(node->idname, "GeometryNodeSubdivideSmooth"); + } + } + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 9386f686c73..d89cf2ecefa 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -168,8 +168,8 @@ set(SRC geometry/nodes/node_geo_point_separate.cc geometry/nodes/node_geo_point_translate.cc geometry/nodes/node_geo_points_to_volume.cc - geometry/nodes/node_geo_subdivision_surface.cc - geometry/nodes/node_geo_subdivision_surface_simple.cc + geometry/nodes/node_geo_subdivide_smooth.cc + geometry/nodes/node_geo_subdivide.cc geometry/nodes/node_geo_transform.cc geometry/nodes/node_geo_triangulate.cc geometry/nodes/node_geo_volume_to_mesh.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 3ee8067e81a..b094256190c 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -51,8 +51,8 @@ void register_node_type_geo_point_separate(void); void register_node_type_geo_point_translate(void); void register_node_type_geo_points_to_volume(void); void register_node_type_geo_sample_texture(void); -void register_node_type_geo_subdivision_surface(void); -void register_node_type_geo_subdivision_surface_simple(void); +void register_node_type_geo_subdivide_smooth(void); +void register_node_type_geo_subdivide(void); void register_node_type_geo_transform(void); void register_node_type_geo_triangulate(void); void register_node_type_geo_volume_to_mesh(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 35550bdec48..22204d7204e 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -272,7 +272,7 @@ DefNode(FunctionNode, FN_NODE_INPUT_STRING, def_fn_input_string, "INPUT_STRING", DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "") DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "") DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "") -DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "") +DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_SMOOTH, 0, "SUBDIVIDE_SMOOTH", SubdivideSmooth, "Subdivide Smooth", "") DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Boolean", "") DefNode(GeometryNode, GEO_NODE_POINT_DISTRIBUTE, def_geo_point_distribute, "POINT_DISTRIBUTE", PointDistribute, "Point Distribute", "") DefNode(GeometryNode, GEO_NODE_POINT_INSTANCE, def_geo_point_instance, "POINT_INSTANCE", PointInstance, "Point Instance", "") @@ -298,7 +298,7 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_PROXIMITY, def_geo_attribute_proximity, DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMBINE_XYZ, def_geo_attribute_combine_xyz, "ATTRIBUTE_COMBINE_XYZ", AttributeCombineXYZ, "Attribute Combine XYZ", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "ATTRIBUTE_SEPARATE_XYZ", AttributeSeparateXYZ, "Attribute Separate XYZ", "") -DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE_SIMPLE, 0, "SUBDIVISION_SURFACE_SIMPLE", SubdivisionSurfaceSimple, "Simple Subdivision Surface", "") +DefNode(GeometryNode, GEO_NODE_SUBDIVIDE, 0, "SUBDIVIDE", Subdivide, "Subdivide", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc new file mode 100644 index 00000000000..b5731851229 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#include "MEM_guardedalloc.h" + +#include "BKE_mesh.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_mesh.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_subdivide_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_subdivide_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +namespace blender::nodes { + +static void geo_node_subdivide_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input("Geometry"); + + if (!geometry_set.has_mesh()) { + params.set_output("Geometry", geometry_set); + return; + } + +#ifndef WITH_OPENSUBDIV + params.error_message_add(NodeWarningType::Error, + TIP_("Disabled, Blender was built without OpenSubdiv")); + params.set_output("Geometry", std::move(geometry_set)); + return; +#endif + + /* See CCGSUBSURF_LEVEL_MAX for max limit. */ + const int subdiv_level = clamp_i(params.extract_input("Level"), 0, 11); + + if (subdiv_level == 0) { + params.set_output("Geometry", std::move(geometry_set)); + return; + } + + const Mesh *mesh_in = geometry_set.get_mesh_for_read(); + + /* Initialize mesh settings. */ + SubdivToMeshSettings mesh_settings; + mesh_settings.resolution = (1 << subdiv_level) + 1; + mesh_settings.use_optimal_display = false; + + /* Initialize subdivision settings. */ + SubdivSettings subdiv_settings; + subdiv_settings.is_simple = true; + subdiv_settings.is_adaptive = false; + subdiv_settings.use_creases = false; + subdiv_settings.level = 1; + subdiv_settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf( + 0); + subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(0); + + /* Apply subdivision from mesh. */ + Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, mesh_in); + + /* In case of bad topology, skip to input mesh. */ + if (subdiv == nullptr) { + params.set_output("Geometry", std::move(geometry_set)); + return; + } + + Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in); + BKE_mesh_calc_normals(mesh_out); + + geometry_set.replace_mesh(mesh_out); + + BKE_subdiv_free(subdiv); + + params.set_output("Geometry", std::move(geometry_set)); +} +} // namespace blender::nodes + +void register_node_type_geo_subdivide() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE, "Subdivide", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_subdivide_in, geo_node_subdivide_out); + ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivide_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivide_smooth.cc new file mode 100644 index 00000000000..4d9b8110d65 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivide_smooth.cc @@ -0,0 +1,133 @@ +/* + * 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. + */ + +#include "MEM_guardedalloc.h" + +#include "BKE_mesh.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_mesh.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_subdivide_smooth_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6}, + {SOCK_BOOLEAN, N_("Use Creases")}, + {SOCK_BOOLEAN, N_("Boundary Smooth"), true}, + {SOCK_BOOLEAN, N_("Smooth UVs")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_subdivide_smooth_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void geo_node_subdivide_smooth_layout(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *UNUSED(ptr)) +{ +#ifndef WITH_OPENSUBDIV + uiItemL(layout, IFACE_("Disabled, built without OpenSubdiv"), ICON_ERROR); +#else + UNUSED_VARS(layout); +#endif +} + +namespace blender::nodes { +static void geo_node_subdivide_smooth_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input("Geometry"); + + geometry_set = geometry_set_realize_instances(geometry_set); + + if (!geometry_set.has_mesh()) { + params.set_output("Geometry", geometry_set); + return; + } + +#ifndef WITH_OPENSUBDIV + /* Return input geometry if Blender is built without OpenSubdiv. */ + params.set_output("Geometry", std::move(geometry_set)); + return; +#else + const int subdiv_level = clamp_i(params.extract_input("Level"), 0, 30); + + /* Only process subdivion if level is greater than 0. */ + if (subdiv_level == 0) { + params.set_output("Geometry", std::move(geometry_set)); + return; + } + + const bool use_crease = params.extract_input("Use Creases"); + const bool boundary_smooth = params.extract_input("Boundary Smooth"); + const bool smooth_uvs = params.extract_input("Smooth UVs"); + const Mesh *mesh_in = geometry_set.get_mesh_for_read(); + + /* Initialize mesh settings. */ + SubdivToMeshSettings mesh_settings; + mesh_settings.resolution = (1 << subdiv_level) + 1; + mesh_settings.use_optimal_display = false; + + /* Initialize subdivision settings. */ + SubdivSettings subdiv_settings; + subdiv_settings.is_simple = false; + subdiv_settings.is_adaptive = false; + subdiv_settings.use_creases = use_crease; + subdiv_settings.level = subdiv_level; + + subdiv_settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf( + !boundary_smooth); + subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth( + smooth_uvs); + + /* Apply subdivision to mesh. */ + Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, mesh_in); + + /* In case of bad topology, skip to input mesh. */ + if (subdiv == nullptr) { + params.set_output("Geometry", std::move(geometry_set)); + return; + } + + Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in); + BKE_mesh_calc_normals(mesh_out); + + MeshComponent &mesh_component = geometry_set.get_component_for_write(); + mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_out); + + // BKE_subdiv_stats_print(&subdiv->stats); + BKE_subdiv_free(subdiv); + + params.set_output("Geometry", std::move(geometry_set)); +#endif +} +} // namespace blender::nodes + +void register_node_type_geo_subdivide_smooth() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_SUBDIVIDE_SMOOTH, "Subdivide Smooth", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_subdivide_smooth_in, geo_node_subdivide_smooth_out); + ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_smooth_exec; + ntype.draw_buttons = geo_node_subdivide_smooth_layout; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc deleted file mode 100644 index 47304a0de68..00000000000 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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. - */ - -#include "MEM_guardedalloc.h" - -#include "BKE_mesh.h" -#include "BKE_subdiv.h" -#include "BKE_subdiv_mesh.h" - -#include "UI_interface.h" -#include "UI_resources.h" - -#include "node_geometry_util.hh" - -static bNodeSocketTemplate geo_node_subdivision_surface_in[] = { - {SOCK_GEOMETRY, N_("Geometry")}, - {SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6}, - {SOCK_BOOLEAN, N_("Use Creases")}, - {SOCK_BOOLEAN, N_("Boundary Smooth"), true}, - {SOCK_BOOLEAN, N_("Smooth UVs")}, - {-1, ""}, -}; - -static bNodeSocketTemplate geo_node_subdivision_surface_out[] = { - {SOCK_GEOMETRY, N_("Geometry")}, - {-1, ""}, -}; - -static void geo_node_subdivision_surface_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *UNUSED(ptr)) -{ -#ifndef WITH_OPENSUBDIV - uiItemL(layout, IFACE_("Disabled, built without OpenSubdiv"), ICON_ERROR); -#else - UNUSED_VARS(layout); -#endif -} - -namespace blender::nodes { -static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) -{ - GeometrySet geometry_set = params.extract_input("Geometry"); - - geometry_set = geometry_set_realize_instances(geometry_set); - - if (!geometry_set.has_mesh()) { - params.set_output("Geometry", geometry_set); - return; - } - -#ifndef WITH_OPENSUBDIV - /* Return input geometry if Blender is built without OpenSubdiv. */ - params.set_output("Geometry", std::move(geometry_set)); - return; -#else - const int subdiv_level = clamp_i(params.extract_input("Level"), 0, 30); - - /* Only process subdivion if level is greater than 0. */ - if (subdiv_level == 0) { - params.set_output("Geometry", std::move(geometry_set)); - return; - } - - const bool use_crease = params.extract_input("Use Creases"); - const bool boundary_smooth = params.extract_input("Boundary Smooth"); - const bool smooth_uvs = params.extract_input("Smooth UVs"); - const Mesh *mesh_in = geometry_set.get_mesh_for_read(); - - /* Initialize mesh settings. */ - SubdivToMeshSettings mesh_settings; - mesh_settings.resolution = (1 << subdiv_level) + 1; - mesh_settings.use_optimal_display = false; - - /* Initialize subdivision settings. */ - SubdivSettings subdiv_settings; - subdiv_settings.is_simple = false; - subdiv_settings.is_adaptive = false; - subdiv_settings.use_creases = use_crease; - subdiv_settings.level = subdiv_level; - - subdiv_settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf( - !boundary_smooth); - subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth( - smooth_uvs); - - /* Apply subdivision to mesh. */ - Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, mesh_in); - - /* In case of bad topology, skip to input mesh. */ - if (subdiv == nullptr) { - params.set_output("Geometry", std::move(geometry_set)); - return; - } - - Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in); - BKE_mesh_calc_normals(mesh_out); - - MeshComponent &mesh_component = geometry_set.get_component_for_write(); - mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_out); - - // BKE_subdiv_stats_print(&subdiv->stats); - BKE_subdiv_free(subdiv); - - params.set_output("Geometry", std::move(geometry_set)); -#endif -} -} // namespace blender::nodes - -void register_node_type_geo_subdivision_surface() -{ - static bNodeType ntype; - - geo_node_type_base( - &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0); - node_type_socket_templates( - &ntype, geo_node_subdivision_surface_in, geo_node_subdivision_surface_out); - ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec; - ntype.draw_buttons = geo_node_subdivision_surface_layout; - nodeRegisterType(&ntype); -} diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc deleted file mode 100644 index 38560d277e3..00000000000 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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. - */ - -#include "MEM_guardedalloc.h" - -#include "BKE_mesh.h" -#include "BKE_subdiv.h" -#include "BKE_subdiv_mesh.h" - -#include "UI_interface.h" -#include "UI_resources.h" - -#include "node_geometry_util.hh" - -static bNodeSocketTemplate geo_node_subdivision_surface_simple_in[] = { - {SOCK_GEOMETRY, N_("Geometry")}, - {SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6}, - {-1, ""}, -}; - -static bNodeSocketTemplate geo_node_subdivision_surface_simple_out[] = { - {SOCK_GEOMETRY, N_("Geometry")}, - {-1, ""}, -}; - -namespace blender::nodes { - -static void geo_node_subdivision_surface_simple_exec(GeoNodeExecParams params) -{ - GeometrySet geometry_set = params.extract_input("Geometry"); - - if (!geometry_set.has_mesh()) { - params.set_output("Geometry", geometry_set); - return; - } - -#ifndef WITH_OPENSUBDIV - params.error_message_add(NodeWarningType::Error, - TIP_("Disabled, Blender was built without OpenSubdiv")); - params.set_output("Geometry", std::move(geometry_set)); - return; -#endif - - /* See CCGSUBSURF_LEVEL_MAX for max limit. */ - const int subdiv_level = clamp_i(params.extract_input("Level"), 0, 11); - - if (subdiv_level == 0) { - params.set_output("Geometry", std::move(geometry_set)); - return; - } - - const Mesh *mesh_in = geometry_set.get_mesh_for_read(); - - /* Initialize mesh settings. */ - SubdivToMeshSettings mesh_settings; - mesh_settings.resolution = (1 << subdiv_level) + 1; - mesh_settings.use_optimal_display = false; - - /* Initialize subdivision settings. */ - SubdivSettings subdiv_settings; - subdiv_settings.is_simple = true; - subdiv_settings.is_adaptive = false; - subdiv_settings.use_creases = false; - subdiv_settings.level = 1; - subdiv_settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf( - 0); - subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(0); - - /* Apply subdivision from mesh. */ - Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, mesh_in); - - /* In case of bad topology, skip to input mesh. */ - if (subdiv == nullptr) { - params.set_output("Geometry", std::move(geometry_set)); - return; - } - - Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in); - BKE_mesh_calc_normals(mesh_out); - - geometry_set.replace_mesh(mesh_out); - - BKE_subdiv_free(subdiv); - - params.set_output("Geometry", std::move(geometry_set)); -} -} // namespace blender::nodes - -void register_node_type_geo_subdivision_surface_simple() -{ - static bNodeType ntype; - - geo_node_type_base(&ntype, - GEO_NODE_SUBDIVISION_SURFACE_SIMPLE, - "Simple Subdivision Surface", - NODE_CLASS_GEOMETRY, - 0); - node_type_socket_templates( - &ntype, geo_node_subdivision_surface_simple_in, geo_node_subdivision_surface_simple_out); - ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_simple_exec; - nodeRegisterType(&ntype); -} -- cgit v1.2.3 From 8df968d69f07d961097f646a405aa455e6a743f3 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Tue, 2 Mar 2021 14:57:51 +0100 Subject: "Show Texture in texture tab" button: full support for Sculpt / Paint In {rBb279fef85d1a} the button that displays a texture in a Properties Editor texture tab was added for geometry nodes. Same commit will actually show them for Brush textures as well (but disabled -- because the Texture users dont match). This task is for finanlizing proper support for Brush textures as well. There was originally a separate patch for this (see {D9813}) but most of it was already implemented by above commit. **what this solves** from the default startup file: - go to any sculpt or paint mode and add a texture to your brush - observe the button to edit this texture in the Properties editor is greyed out {F9860470} There are two possible solutions: - [1] call the texture template for the brush `texture_slot` texture (instead of the brush 'texture') from the python UI code, this is then working in harmony how ButsTextureUser works for brushes - [2] tweak the way `ButsTextureUser` works (dont rely on `RNA_BrushTextureSlot` there) This patch implements the first solution. Since `brush.texture_slot` is `br->mtex` RNA wrapped and `brush.texture` is `br->mtex.tex` RNA wrapped, this really comes down to doing the same thing. I checked that creating a new texture and unlinking/deleting will have the same results even though they take slightly different code paths: assignment and NULLing the pointers are working on the same (see above) and RNA update callbacks also do the same [even though in different functions]: - brush.texture will do rna_Brush_main_tex_update - brush.texture_slot.texture will do rna_TextureSlotTexture_update / rna_TextureSlot_update (only difference here is an additional DEG relations update in the case of texture_slot which should not do harm) Differential Revision: https://developer.blender.org/D10626 --- release/scripts/startup/bl_ui/properties_paint_common.py | 5 ++--- release/scripts/startup/bl_ui/space_image.py | 3 ++- release/scripts/startup/bl_ui/space_view3d_toolbar.py | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 9620666858f..6989139d447 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -277,11 +277,10 @@ class TextureMaskPanel(BrushPanel): layout.use_property_decorate = False brush = context.tool_settings.image_paint.brush + mask_tex_slot = brush.mask_texture_slot col = layout.column() - col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8) - - mask_tex_slot = brush.mask_texture_slot + col.template_ID_preview(mask_tex_slot, "texture", new="texture.new", rows=3, cols=8) # map_mode layout.row().prop(mask_tex_slot, "mask_map_mode", text="Mask Mapping") diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 9b5942cbaa9..e7589709130 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -1189,9 +1189,10 @@ class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel): tool_settings = context.tool_settings.image_paint brush = tool_settings.brush + tex_slot = brush.texture_slot col = layout.column() - col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8) + col.template_ID_preview(tex_slot, "texture", new="texture.new", rows=3, cols=8) brush_texture_settings(col, brush, 0) diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 83ab5bf3100..ee8fc1f3531 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -631,10 +631,10 @@ class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel): settings = self.paint_settings(context) brush = settings.brush + tex_slot = brush.texture_slot col = layout.column() - - col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8) + col.template_ID_preview(tex_slot, "texture", new="texture.new", rows=3, cols=8) brush_texture_settings(col, brush, context.sculpt_object) @@ -658,8 +658,9 @@ class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel, TextureMaskPanel): brush = context.tool_settings.image_paint.brush col = layout.column() + mask_tex_slot = brush.mask_texture_slot - col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8) + col.template_ID_preview(mask_tex_slot, "texture", new="texture.new", rows=3, cols=8) brush_mask_texture_settings(col, brush) -- cgit v1.2.3 From d25ab68cf4b28c01281dd689a3926887fa7d32a4 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 8 Mar 2021 16:31:51 -0500 Subject: Cleanup: Complete earlier geometry component refactor This was meant to be part of rB9ce950daabbf, but the change dropped from the set at some point in the process of updating and committing. Sorry for the noise. --- source/blender/blenkernel/CMakeLists.txt | 5 + .../blender/blenkernel/intern/attribute_access.cc | 1789 ++++---------------- source/blender/blenkernel/intern/geometry_set.cc | 431 ----- 3 files changed, 349 insertions(+), 1876 deletions(-) diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index c954d0670f0..310ac6c4903 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -131,6 +131,10 @@ set(SRC intern/fmodifier.c intern/font.c intern/freestyle.c + intern/geometry_component_instances.cc + intern/geometry_component_mesh.cc + intern/geometry_component_pointcloud.cc + intern/geometry_component_volume.cc intern/geometry_set.cc intern/geometry_set_instances.cc intern/gpencil.c @@ -430,6 +434,7 @@ set(SRC nla_private.h particle_private.h tracking_private.h + intern/attribute_access_intern.hh intern/CCGSubSurf.h intern/CCGSubSurf_inline.h intern/CCGSubSurf_intern.h diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index b04af5327ca..01a1333c3ce 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -37,6 +37,8 @@ #include "NOD_node_tree_multi_function.hh" +#include "attribute_access_intern.hh" + static CLG_LogRef LOG = {"bke.attribute_access"}; using blender::float3; @@ -47,9 +49,6 @@ using blender::bke::ReadAttributePtr; using blender::bke::WriteAttributePtr; using blender::fn::GMutableSpan; -/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */ -extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id); - namespace blender::bke { /* -------------------------------------------------------------------- */ @@ -159,101 +158,6 @@ void WriteAttribute::apply_span_if_necessary() } } -class VertexWeightWriteAttribute final : public WriteAttribute { - private: - MDeformVert *dverts_; - const int dvert_index_; - - public: - VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index) - : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get(), totvert), - dverts_(dverts), - dvert_index_(dvert_index) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - get_internal(dverts_, dvert_index_, index, r_value); - } - - void set_internal(const int64_t index, const void *value) override - { - MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_); - weight->weight = *reinterpret_cast(value); - } - - static void get_internal(const MDeformVert *dverts, - const int dvert_index, - const int64_t index, - void *r_value) - { - if (dverts == nullptr) { - *(float *)r_value = 0.0f; - return; - } - const MDeformVert &dvert = dverts[index]; - for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) { - if (weight.def_nr == dvert_index) { - *(float *)r_value = weight.weight; - return; - } - } - *(float *)r_value = 0.0f; - } -}; - -class VertexWeightReadAttribute final : public ReadAttribute { - private: - const MDeformVert *dverts_; - const int dvert_index_; - - public: - VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index) - : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get(), totvert), - dverts_(dverts), - dvert_index_(dvert_index) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value); - } -}; - -template class ArrayWriteAttribute final : public WriteAttribute { - private: - MutableSpan data_; - - public: - ArrayWriteAttribute(AttributeDomain domain, MutableSpan data) - : WriteAttribute(domain, CPPType::get(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - new (r_value) T(data_[index]); - } - - void set_internal(const int64_t index, const void *value) override - { - data_[index] = *reinterpret_cast(value); - } - - void initialize_span(const bool UNUSED(write_only)) override - { - array_buffer_ = data_.data(); - array_is_temporary_ = false; - } - - void apply_span_if_necessary() override - { - /* Do nothing, because the span contains the attribute itself already. */ - } -}; - /* This is used by the #OutputAttributePtr class. */ class TemporaryWriteAttribute final : public WriteAttribute { public: @@ -302,135 +206,6 @@ class TemporaryWriteAttribute final : public WriteAttribute { } }; -template class ArrayReadAttribute final : public ReadAttribute { - private: - Span data_; - - public: - ArrayReadAttribute(AttributeDomain domain, Span data) - : ReadAttribute(domain, CPPType::get(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - new (r_value) T(data_[index]); - } - - void initialize_span() const override - { - /* The data will not be modified, so this const_cast is fine. */ - array_buffer_ = const_cast(data_.data()); - array_is_temporary_ = false; - } -}; - -template class OwnedArrayReadAttribute final : public ReadAttribute { - private: - Array data_; - - public: - OwnedArrayReadAttribute(AttributeDomain domain, Array data) - : ReadAttribute(domain, CPPType::get(), data.size()), data_(std::move(data)) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - new (r_value) T(data_[index]); - } - - void initialize_span() const override - { - /* The data will not be modified, so this const_cast is fine. */ - array_buffer_ = const_cast(data_.data()); - array_is_temporary_ = false; - } -}; - -template -class DerivedArrayWriteAttribute final : public WriteAttribute { - private: - MutableSpan data_; - - public: - DerivedArrayWriteAttribute(AttributeDomain domain, MutableSpan data) - : WriteAttribute(domain, CPPType::get(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - const StructT &struct_value = data_[index]; - const ElemT value = GetFunc(struct_value); - new (r_value) ElemT(value); - } - - void set_internal(const int64_t index, const void *value) override - { - StructT &struct_value = data_[index]; - const ElemT &typed_value = *reinterpret_cast(value); - SetFunc(struct_value, typed_value); - } -}; - -template -class DerivedArrayReadAttribute final : public ReadAttribute { - private: - Span data_; - - public: - DerivedArrayReadAttribute(AttributeDomain domain, Span data) - : ReadAttribute(domain, CPPType::get(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - const StructT &struct_value = data_[index]; - const ElemT value = GetFunc(struct_value); - new (r_value) ElemT(value); - } -}; - -class ConstantReadAttribute final : public ReadAttribute { - private: - void *value_; - - public: - ConstantReadAttribute(AttributeDomain domain, - const int64_t size, - const CPPType &type, - const void *value) - : ReadAttribute(domain, type, size) - { - value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); - type.copy_to_uninitialized(value, value_); - } - - ~ConstantReadAttribute() override - { - this->cpp_type_.destruct(value_); - MEM_freeN(value_); - } - - void get_internal(const int64_t UNUSED(index), void *r_value) const override - { - this->cpp_type_.copy_to_uninitialized(value_, r_value); - } - - void initialize_span() const override - { - const int element_size = cpp_type_.size(); - array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__); - array_is_temporary_ = true; - cpp_type_.fill_uninitialized(value_, array_buffer_, size_); - } -}; - class ConvertedReadAttribute final : public ReadAttribute { private: const CPPType &from_type_; @@ -499,1120 +274,414 @@ CustomDataType cpp_type_to_custom_data_type(const blender::fn::CPPType &type) if (type.is()) { return CD_PROP_BOOL; } - return static_cast(-1); -} - -static int attribute_data_type_complexity(const CustomDataType data_type) -{ - switch (data_type) { - case CD_PROP_BOOL: - return 0; - case CD_PROP_INT32: - return 1; - case CD_PROP_FLOAT: - return 2; - case CD_PROP_FLOAT2: - return 3; - case CD_PROP_FLOAT3: - return 4; - case CD_PROP_COLOR: - return 5; -#if 0 /* These attribute types are not supported yet. */ - case CD_MLOOPCOL: - return 3; - case CD_PROP_STRING: - return 6; -#endif - default: - /* Only accept "generic" custom data types used by the attribute system. */ - BLI_assert(false); - return 0; - } -} - -CustomDataType attribute_data_type_highest_complexity(Span data_types) -{ - int highest_complexity = INT_MIN; - CustomDataType most_complex_type = CD_PROP_COLOR; - - for (const CustomDataType data_type : data_types) { - const int complexity = attribute_data_type_complexity(data_type); - if (complexity > highest_complexity) { - highest_complexity = complexity; - most_complex_type = data_type; - } - } - - return most_complex_type; -} - -/** - * \note Generally the order should mirror the order of the domains - * established in each component's ComponentAttributeProviders. - */ -static int attribute_domain_priority(const AttributeDomain domain) -{ - switch (domain) { -#if 0 - case ATTR_DOMAIN_CURVE: - return 0; -#endif - case ATTR_DOMAIN_POLYGON: - return 1; - case ATTR_DOMAIN_EDGE: - return 2; - case ATTR_DOMAIN_POINT: - return 3; - case ATTR_DOMAIN_CORNER: - return 4; - default: - /* Domain not supported in nodes yet. */ - BLI_assert(false); - return 0; - } -} - -/** - * Domains with a higher "information density" have a higher priority, in order - * to choose a domain that will not lose data through domain conversion. - */ -AttributeDomain attribute_domain_highest_priority(Span domains) -{ - int highest_priority = INT_MIN; - AttributeDomain highest_priority_domain = ATTR_DOMAIN_CORNER; - - for (const AttributeDomain domain : domains) { - const int priority = attribute_domain_priority(domain); - if (priority > highest_priority) { - highest_priority = priority; - highest_priority_domain = domain; - } - } - - return highest_priority_domain; -} - -/** - * A #BuiltinAttributeProvider is responsible for exactly one attribute on a geometry component. - * The attribute is identified by its name and has a fixed domain and type. Builtin attributes do - * not follow the same loose rules as other attributes, because they are mapped to internal - * "legacy" data structures. For example, some builtin attributes cannot be deleted. */ -class BuiltinAttributeProvider { - public: - /* Some utility enums to avoid hard to read booleans in function calls. */ - enum CreatableEnum { - Creatable, - NonCreatable, - }; - enum WritableEnum { - Writable, - Readonly, - }; - enum DeletableEnum { - Deletable, - NonDeletable, - }; - - protected: - const std::string name_; - const AttributeDomain domain_; - const CustomDataType data_type_; - const CreatableEnum createable_; - const WritableEnum writable_; - const DeletableEnum deletable_; - - public: - BuiltinAttributeProvider(std::string name, - const AttributeDomain domain, - const CustomDataType data_type, - const CreatableEnum createable, - const WritableEnum writable, - const DeletableEnum deletable) - : name_(std::move(name)), - domain_(domain), - data_type_(data_type), - createable_(createable), - writable_(writable), - deletable_(deletable) - { - } - - virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0; - virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0; - virtual bool try_delete(GeometryComponent &component) const = 0; - virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0; - virtual bool exists(const GeometryComponent &component) const = 0; - - StringRefNull name() const - { - return name_; - } - - AttributeDomain domain() const - { - return domain_; - } - - CustomDataType data_type() const - { - return data_type_; - } -}; - -/** - * A #DynamicAttributesProvider manages a set of named attributes on a geometry component. Each - * attribute has a name, domain and type. - */ -class DynamicAttributesProvider { - public: - virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const = 0; - virtual WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const = 0; - virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0; - virtual bool try_create(GeometryComponent &UNUSED(component), - const StringRef UNUSED(attribute_name), - const AttributeDomain UNUSED(domain), - const CustomDataType UNUSED(data_type)) const - { - /* Some providers should not create new attributes. */ - return false; - }; - - virtual bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const = 0; - virtual void supported_domains(Vector &r_domains) const = 0; -}; - -/** - * Utility to group together multiple functions that are used to access custom data on geometry - * components in a generic way. - */ -struct CustomDataAccessInfo { - using CustomDataGetter = CustomData *(*)(GeometryComponent &component); - using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component); - using UpdateCustomDataPointers = void (*)(GeometryComponent &component); - - CustomDataGetter get_custom_data; - ConstCustomDataGetter get_const_custom_data; - UpdateCustomDataPointers update_custom_data_pointers; -}; - -/** - * This provider is used to provide access to builtin attributes. It supports making internal types - * available as different types. For example, the vertex position attribute is stored as part of - * the #MVert struct, but is exposed as float3 attribute. - */ -class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { - using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); - using UpdateOnRead = void (*)(const GeometryComponent &component); - using UpdateOnWrite = void (*)(GeometryComponent &component); - const CustomDataType stored_type_; - const CustomDataAccessInfo custom_data_access_; - const AsReadAttribute as_read_attribute_; - const AsWriteAttribute as_write_attribute_; - const UpdateOnRead update_on_read_; - const UpdateOnWrite update_on_write_; - - public: - BuiltinCustomDataLayerProvider(std::string attribute_name, - const AttributeDomain domain, - const CustomDataType attribute_type, - const CustomDataType stored_type, - const CreatableEnum creatable, - const WritableEnum writable, - const DeletableEnum deletable, - const CustomDataAccessInfo custom_data_access, - const AsReadAttribute as_read_attribute, - const AsWriteAttribute as_write_attribute, - const UpdateOnRead update_on_read, - const UpdateOnWrite update_on_write) - : BuiltinAttributeProvider( - std::move(attribute_name), domain, attribute_type, creatable, writable, deletable), - stored_type_(stored_type), - custom_data_access_(custom_data_access), - as_read_attribute_(as_read_attribute), - as_write_attribute_(as_write_attribute), - update_on_read_(update_on_read), - update_on_write_(update_on_write) - { - } - - ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - - if (update_on_read_ != nullptr) { - update_on_read_(component); - } - - const int domain_size = component.attribute_domain_size(domain_); - const void *data = CustomData_get_layer(custom_data, stored_type_); - if (data == nullptr) { - return {}; - } - return as_read_attribute_(data, domain_size); - } - - WriteAttributePtr try_get_for_write(GeometryComponent &component) const final - { - if (writable_ != Writable) { - return {}; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - const int domain_size = component.attribute_domain_size(domain_); - void *data = CustomData_get_layer(custom_data, stored_type_); - if (data == nullptr) { - return {}; - } - void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size); - if (data != new_data) { - custom_data_access_.update_custom_data_pointers(component); - data = new_data; - } - if (update_on_write_ != nullptr) { - update_on_write_(component); - } - return as_write_attribute_(data, domain_size); - } - - bool try_delete(GeometryComponent &component) const final - { - if (deletable_ != Deletable) { - return false; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - - const int domain_size = component.attribute_domain_size(domain_); - const int layer_index = CustomData_get_layer_index(custom_data, stored_type_); - const bool delete_success = CustomData_free_layer( - custom_data, stored_type_, domain_size, layer_index); - if (delete_success) { - custom_data_access_.update_custom_data_pointers(component); - } - return delete_success; - } - - bool try_create(GeometryComponent &component) const final - { - if (createable_ != Creatable) { - return false; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - if (CustomData_get_layer(custom_data, stored_type_) != nullptr) { - /* Exists already. */ - return false; - } - const int domain_size = component.attribute_domain_size(domain_); - const void *data = CustomData_add_layer( - custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size); - const bool success = data != nullptr; - if (success) { - custom_data_access_.update_custom_data_pointers(component); - } - return success; - } - - bool exists(const GeometryComponent &component) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return false; - } - const void *data = CustomData_get_layer(custom_data, stored_type_); - return data != nullptr; - } -}; - -/** - * This is the attribute provider for most user generated attributes. - */ -class CustomDataAttributeProvider final : public DynamicAttributesProvider { - private: - static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | - CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | - CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL; - const AttributeDomain domain_; - const CustomDataAccessInfo custom_data_access_; - - public: - CustomDataAttributeProvider(const AttributeDomain domain, - const CustomDataAccessInfo custom_data_access) - : domain_(domain), custom_data_access_(custom_data_access) - { - } - - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - const int domain_size = component.attribute_domain_size(domain_); - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - if (layer.name != attribute_name) { - continue; - } - const CustomDataType data_type = (CustomDataType)layer.type; - switch (data_type) { - case CD_PROP_FLOAT: - return this->layer_to_read_attribute(layer, domain_size); - case CD_PROP_FLOAT2: - return this->layer_to_read_attribute(layer, domain_size); - case CD_PROP_FLOAT3: - return this->layer_to_read_attribute(layer, domain_size); - case CD_PROP_INT32: - return this->layer_to_read_attribute(layer, domain_size); - case CD_PROP_COLOR: - return this->layer_to_read_attribute(layer, domain_size); - case CD_PROP_BOOL: - return this->layer_to_read_attribute(layer, domain_size); - default: - break; - } - } - return {}; - } - - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - const int domain_size = component.attribute_domain_size(domain_); - for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { - if (layer.name != attribute_name) { - continue; - } - CustomData_duplicate_referenced_layer_named( - custom_data, layer.type, layer.name, domain_size); - const CustomDataType data_type = (CustomDataType)layer.type; - switch (data_type) { - case CD_PROP_FLOAT: - return this->layer_to_write_attribute(layer, domain_size); - case CD_PROP_FLOAT2: - return this->layer_to_write_attribute(layer, domain_size); - case CD_PROP_FLOAT3: - return this->layer_to_write_attribute(layer, domain_size); - case CD_PROP_INT32: - return this->layer_to_write_attribute(layer, domain_size); - case CD_PROP_COLOR: - return this->layer_to_write_attribute(layer, domain_size); - case CD_PROP_BOOL: - return this->layer_to_write_attribute(layer, domain_size); - default: - break; - } - } - return {}; - } - - bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - const int domain_size = component.attribute_domain_size(domain_); - for (const int i : IndexRange(custom_data->totlayer)) { - const CustomDataLayer &layer = custom_data->layers[i]; - if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) { - CustomData_free_layer(custom_data, layer.type, domain_size, i); - return true; - } - } - return false; - } - - bool try_create(GeometryComponent &component, - const StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type) const final - { - if (domain_ != domain) { - return false; - } - if (!this->type_is_supported(data_type)) { - return false; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - if (layer.name == attribute_name) { - return false; - } - } - const int domain_size = component.attribute_domain_size(domain_); - char attribute_name_c[MAX_NAME]; - attribute_name.copy(attribute_name_c); - CustomData_add_layer_named( - custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); - return true; - } - - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return true; - } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - const CustomDataType data_type = (CustomDataType)layer.type; - if (this->type_is_supported(data_type)) { - AttributeMetaData meta_data{domain_, data_type}; - if (!callback(layer.name, meta_data)) { - return false; - } - } - } - return true; - } - - void supported_domains(Vector &r_domains) const final - { - r_domains.append_non_duplicates(domain_); - } - - private: - template - ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer, - const int domain_size) const - { - return std::make_unique>( - domain_, Span(static_cast(layer.data), domain_size)); - } - - template - WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const - { - return std::make_unique>( - domain_, MutableSpan(static_cast(layer.data), domain_size)); - } - - bool type_is_supported(CustomDataType data_type) const - { - return ((1ULL << data_type) & supported_types_mask) != 0; - } -}; - -static Mesh *get_mesh_from_component_for_write(GeometryComponent &component) -{ - BLI_assert(component.type() == GeometryComponentType::Mesh); - MeshComponent &mesh_component = static_cast(component); - return mesh_component.get_for_write(); -} - -static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component) -{ - BLI_assert(component.type() == GeometryComponentType::Mesh); - const MeshComponent &mesh_component = static_cast(component); - return mesh_component.get_for_read(); -} - -/** - * This attribute provider is used for uv maps and vertex colors. - */ -class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { - private: - using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); - const AttributeDomain domain_; - const CustomDataType attribute_type_; - const CustomDataType stored_type_; - const CustomDataAccessInfo custom_data_access_; - const AsReadAttribute as_read_attribute_; - const AsWriteAttribute as_write_attribute_; - - public: - NamedLegacyCustomDataProvider(const AttributeDomain domain, - const CustomDataType attribute_type, - const CustomDataType stored_type, - const CustomDataAccessInfo custom_data_access, - const AsReadAttribute as_read_attribute, - const AsWriteAttribute as_write_attribute) - : domain_(domain), - attribute_type_(attribute_type), - stored_type_(stored_type), - custom_data_access_(custom_data_access), - as_read_attribute_(as_read_attribute), - as_write_attribute_(as_write_attribute) - { - } - - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - if (layer.type == stored_type_) { - if (layer.name == attribute_name) { - const int domain_size = component.attribute_domain_size(domain_); - return as_read_attribute_(layer.data, domain_size); - } - } - } - return {}; - } - - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { - if (layer.type == stored_type_) { - if (layer.name == attribute_name) { - const int domain_size = component.attribute_domain_size(domain_); - void *data_old = layer.data; - void *data_new = CustomData_duplicate_referenced_layer_named( - custom_data, stored_type_, layer.name, domain_size); - if (data_old != data_new) { - custom_data_access_.update_custom_data_pointers(component); - } - return as_write_attribute_(layer.data, domain_size); - } - } - } - return {}; - } - - bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - for (const int i : IndexRange(custom_data->totlayer)) { - const CustomDataLayer &layer = custom_data->layers[i]; - if (layer.type == stored_type_) { - if (layer.name == attribute_name) { - const int domain_size = component.attribute_domain_size(domain_); - CustomData_free_layer(custom_data, stored_type_, domain_size, i); - custom_data_access_.update_custom_data_pointers(component); - return true; - } - } - } - return false; - } - - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return true; - } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - if (layer.type == stored_type_) { - AttributeMetaData meta_data{domain_, attribute_type_}; - if (!callback(layer.name, meta_data)) { - return false; - } - } - } - return true; - } - - void supported_domains(Vector &r_domains) const final - { - r_domains.append_non_duplicates(domain_); - } -}; - -/** - * This provider makes vertex groups available as float attributes. - */ -class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { - public: - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - const MeshComponent &mesh_component = static_cast(component); - const Mesh *mesh = mesh_component.get_for_read(); - const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( - attribute_name, -1); - if (vertex_group_index < 0) { - return {}; - } - if (mesh == nullptr || mesh->dvert == nullptr) { - static const float default_value = 0.0f; - return std::make_unique( - ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get(), &default_value); - } - return std::make_unique( - mesh->dvert, mesh->totvert, vertex_group_index); - } - - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - MeshComponent &mesh_component = static_cast(component); - Mesh *mesh = mesh_component.get_for_write(); - if (mesh == nullptr) { - return {}; - } - const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( - attribute_name, -1); - if (vertex_group_index < 0) { - return {}; - } - if (mesh->dvert == nullptr) { - BKE_object_defgroup_data_create(&mesh->id); - } - else { - /* Copy the data layer if it is shared with some other mesh. */ - mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer( - &mesh->vdata, CD_MDEFORMVERT, mesh->totvert); - } - return std::make_unique( - mesh->dvert, mesh->totvert, vertex_group_index); - } - - bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - MeshComponent &mesh_component = static_cast(component); - - const int vertex_group_index = mesh_component.vertex_group_names().pop_default_as( - attribute_name, -1); - if (vertex_group_index < 0) { - return false; - } - Mesh *mesh = mesh_component.get_for_write(); - if (mesh == nullptr) { - return true; - } - if (mesh->dvert == nullptr) { - return true; - } - for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) { - MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index); - BKE_defvert_remove_group(&dvert, weight); - } - return true; - } - - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - const MeshComponent &mesh_component = static_cast(component); - for (const auto item : mesh_component.vertex_group_names().items()) { - const StringRefNull name = item.key; - const int vertex_group_index = item.value; - if (vertex_group_index >= 0) { - AttributeMetaData meta_data{ATTR_DOMAIN_POINT, CD_PROP_FLOAT}; - if (!callback(name, meta_data)) { - return false; - } - } - } - return true; - } - - void supported_domains(Vector &r_domains) const final - { - r_domains.append_non_duplicates(ATTR_DOMAIN_POINT); - } -}; - -/** - * This is a container for multiple attribute providers that are used by one geometry component - * type (e.g. there is a set of attribute providers for mesh components). - */ -class ComponentAttributeProviders { - private: - /** - * Builtin attribute providers are identified by their name. Attribute names that are in this - * map will only be accessed using builtin attribute providers. Therefore, these providers have - * higher priority when an attribute name is looked up. Usually, that means that builtin - * providers are checked before dynamic ones. - */ - Map builtin_attribute_providers_; - /** - * An ordered list of dynamic attribute providers. The order is important because that is order - * in which they are checked when an attribute is looked up. - */ - Vector dynamic_attribute_providers_; - /** - * All the domains that are supported by at least one of the providers above. - */ - Vector supported_domains_; - - public: - ComponentAttributeProviders(Span builtin_attribute_providers, - Span dynamic_attribute_providers) - : dynamic_attribute_providers_(dynamic_attribute_providers) - { - Set domains; - for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) { - /* Use #add_new to make sure that no two builtin attributes have the same name. */ - builtin_attribute_providers_.add_new(provider->name(), provider); - supported_domains_.append_non_duplicates(provider->domain()); - } - for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) { - provider->supported_domains(supported_domains_); - } - } - - const Map &builtin_attribute_providers() const - { - return builtin_attribute_providers_; - } - - Span dynamic_attribute_providers() const - { - return dynamic_attribute_providers_; - } - - Span supported_domains() const - { - return supported_domains_; - } -}; - -static float3 get_vertex_position(const MVert &vert) -{ - return float3(vert.co); + return static_cast(-1); } -static void set_vertex_position(MVert &vert, const float3 &position) +static int attribute_data_type_complexity(const CustomDataType data_type) { - copy_v3_v3(vert.co, position); + switch (data_type) { + case CD_PROP_BOOL: + return 0; + case CD_PROP_INT32: + return 1; + case CD_PROP_FLOAT: + return 2; + case CD_PROP_FLOAT2: + return 3; + case CD_PROP_FLOAT3: + return 4; + case CD_PROP_COLOR: + return 5; +#if 0 /* These attribute types are not supported yet. */ + case CD_MLOOPCOL: + return 3; + case CD_PROP_STRING: + return 6; +#endif + default: + /* Only accept "generic" custom data types used by the attribute system. */ + BLI_assert(false); + return 0; + } } -static ReadAttributePtr make_vertex_position_read_attribute(const void *data, - const int domain_size) +CustomDataType attribute_data_type_highest_complexity(Span data_types) { - return std::make_unique>( - ATTR_DOMAIN_POINT, Span((const MVert *)data, domain_size)); -} + int highest_complexity = INT_MIN; + CustomDataType most_complex_type = CD_PROP_COLOR; -static WriteAttributePtr make_vertex_position_write_attribute(void *data, const int domain_size) -{ - return std::make_unique< - DerivedArrayWriteAttribute>( - ATTR_DOMAIN_POINT, MutableSpan((MVert *)data, domain_size)); + for (const CustomDataType data_type : data_types) { + const int complexity = attribute_data_type_complexity(data_type); + if (complexity > highest_complexity) { + highest_complexity = complexity; + most_complex_type = data_type; + } + } + + return most_complex_type; } -static void tag_normals_dirty_when_writing_position(GeometryComponent &component) +/** + * \note Generally the order should mirror the order of the domains + * established in each component's ComponentAttributeProviders. + */ +static int attribute_domain_priority(const AttributeDomain domain) { - Mesh *mesh = get_mesh_from_component_for_write(component); - if (mesh != nullptr) { - mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + switch (domain) { +#if 0 + case ATTR_DOMAIN_CURVE: + return 0; +#endif + case ATTR_DOMAIN_POLYGON: + return 1; + case ATTR_DOMAIN_EDGE: + return 2; + case ATTR_DOMAIN_POINT: + return 3; + case ATTR_DOMAIN_CORNER: + return 4; + default: + /* Domain not supported in nodes yet. */ + BLI_assert(false); + return 0; } } -static int get_material_index(const MPoly &mpoly) +/** + * Domains with a higher "information density" have a higher priority, in order + * to choose a domain that will not lose data through domain conversion. + */ +AttributeDomain attribute_domain_highest_priority(Span domains) { - return static_cast(mpoly.mat_nr); -} + int highest_priority = INT_MIN; + AttributeDomain highest_priority_domain = ATTR_DOMAIN_CORNER; -static void set_material_index(MPoly &mpoly, const int &index) -{ - mpoly.mat_nr = static_cast(std::clamp(index, 0, SHRT_MAX)); -} + for (const AttributeDomain domain : domains) { + const int priority = attribute_domain_priority(domain); + if (priority > highest_priority) { + highest_priority = priority; + highest_priority_domain = domain; + } + } -static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique>( - ATTR_DOMAIN_POLYGON, Span((const MPoly *)data, domain_size)); + return highest_priority_domain; } -static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size) +ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read( + const GeometryComponent &component) const { - return std::make_unique< - DerivedArrayWriteAttribute>( - ATTR_DOMAIN_POLYGON, MutableSpan((MPoly *)data, domain_size)); -} + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return {}; + } -static float3 get_vertex_normal(const MVert &vert) -{ - float3 result; - normal_short_to_float_v3(result, vert.no); - return result; + if (update_on_read_ != nullptr) { + update_on_read_(component); + } + + const int domain_size = component.attribute_domain_size(domain_); + const void *data = CustomData_get_layer(custom_data, stored_type_); + if (data == nullptr) { + return {}; + } + return as_read_attribute_(data, domain_size); } -static ReadAttributePtr make_vertex_normal_read_attribute(const void *data, const int domain_size) +WriteAttributePtr BuiltinCustomDataLayerProvider::try_get_for_write( + GeometryComponent &component) const { - return std::make_unique>( - ATTR_DOMAIN_POINT, Span((const MVert *)data, domain_size)); + if (writable_ != Writable) { + return {}; + } + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return {}; + } + const int domain_size = component.attribute_domain_size(domain_); + void *data = CustomData_get_layer(custom_data, stored_type_); + if (data == nullptr) { + return {}; + } + void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size); + if (data != new_data) { + custom_data_access_.update_custom_data_pointers(component); + data = new_data; + } + if (update_on_write_ != nullptr) { + update_on_write_(component); + } + return as_write_attribute_(data, domain_size); } -static void update_vertex_normals_when_dirty(const GeometryComponent &component) +bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const { - const Mesh *mesh = get_mesh_from_component_for_read(component); - if (mesh == nullptr) { - return; + if (deletable_ != Deletable) { + return false; + } + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return {}; } - /* Since normals are derived data, `const` write access to them is okay. However, ensure that - * two threads don't use write normals to a mesh at the same time. Note that this relies on - * the idempotence of the operation; calculating the normals just fills the #MVert struct - * rather than allocating new memory. */ - if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { - ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex; - BLI_mutex_lock(mesh_eval_mutex); - - /* Check again to avoid a second thread needlessly recalculating the same normals. */ - if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { - BKE_mesh_calc_normals(const_cast(mesh)); - } - - BLI_mutex_unlock(mesh_eval_mutex); + const int domain_size = component.attribute_domain_size(domain_); + const int layer_index = CustomData_get_layer_index(custom_data, stored_type_); + const bool delete_success = CustomData_free_layer( + custom_data, stored_type_, domain_size, layer_index); + if (delete_success) { + custom_data_access_.update_custom_data_pointers(component); } + return delete_success; } -static float2 get_loop_uv(const MLoopUV &uv) +bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) const { - return float2(uv.uv); + if (createable_ != Creatable) { + return false; + } + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return false; + } + if (CustomData_get_layer(custom_data, stored_type_) != nullptr) { + /* Exists already. */ + return false; + } + const int domain_size = component.attribute_domain_size(domain_); + const void *data = CustomData_add_layer( + custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size); + const bool success = data != nullptr; + if (success) { + custom_data_access_.update_custom_data_pointers(component); + } + return success; } -static void set_loop_uv(MLoopUV &uv, const float2 &co) +bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) const { - copy_v2_v2(uv.uv, co); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return false; + } + const void *data = CustomData_get_layer(custom_data, stored_type_); + return data != nullptr; } -static ReadAttributePtr make_uvs_read_attribute(const void *data, const int domain_size) +ReadAttributePtr CustomDataAttributeProvider::try_get_for_read( + const GeometryComponent &component, const StringRef attribute_name) const { - return std::make_unique>( - ATTR_DOMAIN_CORNER, Span((const MLoopUV *)data, domain_size)); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return {}; + } + const int domain_size = component.attribute_domain_size(domain_); + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (layer.name != attribute_name) { + continue; + } + const CustomDataType data_type = (CustomDataType)layer.type; + switch (data_type) { + case CD_PROP_FLOAT: + return this->layer_to_read_attribute(layer, domain_size); + case CD_PROP_FLOAT2: + return this->layer_to_read_attribute(layer, domain_size); + case CD_PROP_FLOAT3: + return this->layer_to_read_attribute(layer, domain_size); + case CD_PROP_INT32: + return this->layer_to_read_attribute(layer, domain_size); + case CD_PROP_COLOR: + return this->layer_to_read_attribute(layer, domain_size); + case CD_PROP_BOOL: + return this->layer_to_read_attribute(layer, domain_size); + default: + break; + } + } + return {}; } -static WriteAttributePtr make_uvs_write_attribute(void *data, const int domain_size) +WriteAttributePtr CustomDataAttributeProvider::try_get_for_write( + GeometryComponent &component, const StringRef attribute_name) const { - return std::make_unique>( - ATTR_DOMAIN_CORNER, MutableSpan((MLoopUV *)data, domain_size)); + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return {}; + } + const int domain_size = component.attribute_domain_size(domain_); + for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { + if (layer.name != attribute_name) { + continue; + } + CustomData_duplicate_referenced_layer_named(custom_data, layer.type, layer.name, domain_size); + const CustomDataType data_type = (CustomDataType)layer.type; + switch (data_type) { + case CD_PROP_FLOAT: + return this->layer_to_write_attribute(layer, domain_size); + case CD_PROP_FLOAT2: + return this->layer_to_write_attribute(layer, domain_size); + case CD_PROP_FLOAT3: + return this->layer_to_write_attribute(layer, domain_size); + case CD_PROP_INT32: + return this->layer_to_write_attribute(layer, domain_size); + case CD_PROP_COLOR: + return this->layer_to_write_attribute(layer, domain_size); + case CD_PROP_BOOL: + return this->layer_to_write_attribute(layer, domain_size); + default: + break; + } + } + return {}; } -static Color4f get_loop_color(const MLoopCol &col) +bool CustomDataAttributeProvider::try_delete(GeometryComponent &component, + const StringRef attribute_name) const { - Color4f value; - rgba_uchar_to_float(value, &col.r); - return value; + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return false; + } + const int domain_size = component.attribute_domain_size(domain_); + for (const int i : IndexRange(custom_data->totlayer)) { + const CustomDataLayer &layer = custom_data->layers[i]; + if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) { + CustomData_free_layer(custom_data, layer.type, domain_size, i); + return true; + } + } + return false; } -static void set_loop_color(MLoopCol &col, const Color4f &value) +bool CustomDataAttributeProvider::try_create(GeometryComponent &component, + const StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type) const { - rgba_float_to_uchar(&col.r, value); + if (domain_ != domain) { + return false; + } + if (!this->type_is_supported(data_type)) { + return false; + } + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return false; + } + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (layer.name == attribute_name) { + return false; + } + } + const int domain_size = component.attribute_domain_size(domain_); + char attribute_name_c[MAX_NAME]; + attribute_name.copy(attribute_name_c); + CustomData_add_layer_named( + custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); + return true; } -static ReadAttributePtr make_vertex_color_read_attribute(const void *data, const int domain_size) +bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &component, + const AttributeForeachCallback callback) const { - return std::make_unique>( - ATTR_DOMAIN_CORNER, Span((const MLoopCol *)data, domain_size)); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return true; + } + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + const CustomDataType data_type = (CustomDataType)layer.type; + if (this->type_is_supported(data_type)) { + AttributeMetaData meta_data{domain_, data_type}; + if (!callback(layer.name, meta_data)) { + return false; + } + } + } + return true; } -static WriteAttributePtr make_vertex_color_write_attribute(void *data, const int domain_size) +ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read( + const GeometryComponent &component, const StringRef attribute_name) const { - return std::make_unique< - DerivedArrayWriteAttribute>( - ATTR_DOMAIN_CORNER, MutableSpan((MLoopCol *)data, domain_size)); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return {}; + } + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (layer.type == stored_type_) { + if (layer.name == attribute_name) { + const int domain_size = component.attribute_domain_size(domain_); + return as_read_attribute_(layer.data, domain_size); + } + } + } + return {}; } -template -static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size) +WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write( + GeometryComponent &component, const StringRef attribute_name) const { - return std::make_unique>(Domain, Span((const T *)data, domain_size)); + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return {}; + } + for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { + if (layer.type == stored_type_) { + if (layer.name == attribute_name) { + const int domain_size = component.attribute_domain_size(domain_); + void *data_old = layer.data; + void *data_new = CustomData_duplicate_referenced_layer_named( + custom_data, stored_type_, layer.name, domain_size); + if (data_old != data_new) { + custom_data_access_.update_custom_data_pointers(component); + } + return as_write_attribute_(layer.data, domain_size); + } + } + } + return {}; } -template -static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size) +bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component, + const StringRef attribute_name) const { - return std::make_unique>(Domain, MutableSpan((T *)data, domain_size)); + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return false; + } + for (const int i : IndexRange(custom_data->totlayer)) { + const CustomDataLayer &layer = custom_data->layers[i]; + if (layer.type == stored_type_) { + if (layer.name == attribute_name) { + const int domain_size = component.attribute_domain_size(domain_); + CustomData_free_layer(custom_data, stored_type_, domain_size, i); + custom_data_access_.update_custom_data_pointers(component); + return true; + } + } + } + return false; } -/** - * In this function all the attribute providers for a mesh component are created. Most data in this - * function is statically allocated, because it does not change over time. - */ -static ComponentAttributeProviders create_attribute_providers_for_mesh() +bool NamedLegacyCustomDataProvider::foreach_attribute( + const GeometryComponent &component, const AttributeForeachCallback callback) const { - static auto update_custom_data_pointers = [](GeometryComponent &component) { - Mesh *mesh = get_mesh_from_component_for_write(component); - if (mesh != nullptr) { - BKE_mesh_update_customdata_pointers(mesh, false); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return true; + } + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (layer.type == stored_type_) { + AttributeMetaData meta_data{domain_, attribute_type_}; + if (!callback(layer.name, meta_data)) { + return false; + } } - }; - -#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \ - [](GeometryComponent &component) -> CustomData * { \ - Mesh *mesh = get_mesh_from_component_for_write(component); \ - return mesh ? &mesh->NAME : nullptr; \ - } -#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \ - [](const GeometryComponent &component) -> const CustomData * { \ - const Mesh *mesh = get_mesh_from_component_for_read(component); \ - return mesh ? &mesh->NAME : nullptr; \ - } - - static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata), - MAKE_CONST_CUSTOM_DATA_GETTER(ldata), - update_custom_data_pointers}; - static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata), - MAKE_CONST_CUSTOM_DATA_GETTER(vdata), - update_custom_data_pointers}; - static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata), - MAKE_CONST_CUSTOM_DATA_GETTER(edata), - update_custom_data_pointers}; - static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), - MAKE_CONST_CUSTOM_DATA_GETTER(pdata), - update_custom_data_pointers}; - -#undef MAKE_CONST_CUSTOM_DATA_GETTER -#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER - - static BuiltinCustomDataLayerProvider position("position", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT3, - CD_MVERT, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - point_access, - make_vertex_position_read_attribute, - make_vertex_position_write_attribute, - nullptr, - tag_normals_dirty_when_writing_position); - - static BuiltinCustomDataLayerProvider material_index("material_index", - ATTR_DOMAIN_POLYGON, - CD_PROP_INT32, - CD_MPOLY, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - polygon_access, - make_material_index_read_attribute, - make_material_index_write_attribute, - nullptr, - nullptr); - - static BuiltinCustomDataLayerProvider vertex_normal("vertex_normal", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT3, - CD_MVERT, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Readonly, - BuiltinAttributeProvider::NonDeletable, - point_access, - make_vertex_normal_read_attribute, - nullptr, - update_vertex_normals_when_dirty, - nullptr); - - static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER, - CD_PROP_FLOAT2, - CD_MLOOPUV, - corner_access, - make_uvs_read_attribute, - make_uvs_write_attribute); - - static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER, - CD_PROP_COLOR, - CD_MLOOPCOL, - corner_access, - make_vertex_color_read_attribute, - make_vertex_color_write_attribute); - - static VertexGroupsAttributeProvider vertex_groups; - static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access); - static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); - static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); - static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access); - - return ComponentAttributeProviders({&position, &material_index, &vertex_normal}, - {&uvs, - &vertex_colors, - &corner_custom_data, - &vertex_groups, - &point_custom_data, - &edge_custom_data, - &polygon_custom_data}); + } + return true; } -/** - * In this function all the attribute providers for a point cloud component are created. Most data - * in this function is statically allocated, because it does not change over time. - */ -static ComponentAttributeProviders create_attribute_providers_for_point_cloud() +void NamedLegacyCustomDataProvider::supported_domains(Vector &r_domains) const { - static auto update_custom_data_pointers = [](GeometryComponent &component) { - PointCloudComponent &pointcloud_component = static_cast(component); - PointCloud *pointcloud = pointcloud_component.get_for_write(); - if (pointcloud != nullptr) { - BKE_pointcloud_update_customdata_pointers(pointcloud); - } - }; - static CustomDataAccessInfo point_access = { - [](GeometryComponent &component) -> CustomData * { - PointCloudComponent &pointcloud_component = static_cast(component); - PointCloud *pointcloud = pointcloud_component.get_for_write(); - return pointcloud ? &pointcloud->pdata : nullptr; - }, - [](const GeometryComponent &component) -> const CustomData * { - const PointCloudComponent &pointcloud_component = static_cast( - component); - const PointCloud *pointcloud = pointcloud_component.get_for_read(); - return pointcloud ? &pointcloud->pdata : nullptr; - }, - update_custom_data_pointers}; - - static BuiltinCustomDataLayerProvider position( - "position", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT3, - CD_PROP_FLOAT3, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - point_access, - make_array_read_attribute, - make_array_write_attribute, - nullptr, - nullptr); - static BuiltinCustomDataLayerProvider radius( - "radius", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT, - CD_PROP_FLOAT, - BuiltinAttributeProvider::Creatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::Deletable, - point_access, - make_array_read_attribute, - make_array_write_attribute, - nullptr, - nullptr); - static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); - return ComponentAttributeProviders({&position, &radius}, {&point_custom_data}); + r_domains.append_non_duplicates(domain_); } } // namespace blender::bke @@ -2056,173 +1125,3 @@ void OutputAttributePtr::apply_span_and_save() } /** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Point Cloud Component - * \{ */ - -const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers() - const -{ - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_point_cloud(); - return &providers; -} - -int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const -{ - BLI_assert(domain == ATTR_DOMAIN_POINT); - UNUSED_VARS_NDEBUG(domain); - if (pointcloud_ == nullptr) { - return 0; - } - return pointcloud_->totpoint; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Mesh Component - * \{ */ - -const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const -{ - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_mesh(); - return &providers; -} - -int MeshComponent::attribute_domain_size(const AttributeDomain domain) const -{ - BLI_assert(this->attribute_domain_supported(domain)); - if (mesh_ == nullptr) { - return 0; - } - switch (domain) { - case ATTR_DOMAIN_CORNER: - return mesh_->totloop; - case ATTR_DOMAIN_POINT: - return mesh_->totvert; - case ATTR_DOMAIN_EDGE: - return mesh_->totedge; - case ATTR_DOMAIN_POLYGON: - return mesh_->totpoly; - default: - BLI_assert(false); - break; - } - return 0; -} - -namespace blender::bke { - -template -static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, - const TypedReadAttribute &attribute, - MutableSpan r_values) -{ - BLI_assert(r_values.size() == mesh.totvert); - attribute_math::DefaultMixer mixer(r_values); - - for (const int loop_index : IndexRange(mesh.totloop)) { - const T value = attribute[loop_index]; - const MLoop &loop = mesh.mloop[loop_index]; - const int point_index = loop.v; - mixer.mix_in(point_index, value); - } - mixer.finalize(); -} - -static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, - ReadAttributePtr attribute) -{ - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - if constexpr (!std::is_void_v>) { - /* We compute all interpolated values at once, because for this interpolation, one has to - * iterate over all loops anyway. */ - Array values(mesh.totvert); - adapt_mesh_domain_corner_to_point_impl(mesh, *attribute, values); - new_attribute = std::make_unique>(ATTR_DOMAIN_POINT, - std::move(values)); - } - }); - return new_attribute; -} - -template -static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh, - const TypedReadAttribute &attribute, - MutableSpan r_values) -{ - BLI_assert(r_values.size() == mesh.totloop); - - for (const int loop_index : IndexRange(mesh.totloop)) { - const int vertex_index = mesh.mloop[loop_index].v; - r_values[loop_index] = attribute[vertex_index]; - } -} - -static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, - ReadAttributePtr attribute) -{ - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - /* It is not strictly necessary to compute the value for all corners here. Instead one could - * lazily lookup the mesh topology when a specific index accessed. This can be more efficient - * when an algorithm only accesses very few of the corner values. However, for the algorithms - * we currently have, precomputing the array is fine. Also, it is easier to implement. */ - Array values(mesh.totloop); - adapt_mesh_domain_point_to_corner_impl(mesh, *attribute, values); - new_attribute = std::make_unique>(ATTR_DOMAIN_CORNER, - std::move(values)); - }); - return new_attribute; -} - -} // namespace blender::bke - -ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute, - const AttributeDomain new_domain) const -{ - if (!attribute) { - return {}; - } - if (attribute->size() == 0) { - return {}; - } - const AttributeDomain old_domain = attribute->domain(); - if (old_domain == new_domain) { - return attribute; - } - - switch (old_domain) { - case ATTR_DOMAIN_CORNER: { - switch (new_domain) { - case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute)); - default: - break; - } - break; - } - case ATTR_DOMAIN_POINT: { - switch (new_domain) { - case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute)); - default: - break; - } - } - default: - break; - } - - return {}; -} - -/** \} */ diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 0274dfdbd1c..e7fb184023d 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -310,437 +310,6 @@ Volume *GeometrySet::get_volume_for_write() /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Mesh Component - * \{ */ - -MeshComponent::MeshComponent() : GeometryComponent(GeometryComponentType::Mesh) -{ -} - -MeshComponent::~MeshComponent() -{ - this->clear(); -} - -GeometryComponent *MeshComponent::copy() const -{ - MeshComponent *new_component = new MeshComponent(); - if (mesh_ != nullptr) { - new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false); - new_component->ownership_ = GeometryOwnershipType::Owned; - new_component->vertex_group_names_ = blender::Map(vertex_group_names_); - } - return new_component; -} - -void MeshComponent::clear() -{ - BLI_assert(this->is_mutable()); - if (mesh_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, mesh_); - } - mesh_ = nullptr; - } - vertex_group_names_.clear(); -} - -bool MeshComponent::has_mesh() const -{ - return mesh_ != nullptr; -} - -/* Clear the component and replace it with the new mesh. */ -void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - this->clear(); - mesh_ = mesh; - ownership_ = ownership; -} - -/* This function exists for the same reason as #vertex_group_names_. Non-nodes modifiers need to - * be able to replace the mesh data without losing the vertex group names, which may have come - * from another object. */ -void MeshComponent::replace_mesh_but_keep_vertex_group_names(Mesh *mesh, - GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - if (mesh_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, mesh_); - } - mesh_ = nullptr; - } - mesh_ = mesh; - ownership_ = ownership; -} - -/* Return the mesh and clear the component. The caller takes over responsibility for freeing the - * mesh (if the component was responsible before). */ -Mesh *MeshComponent::release() -{ - BLI_assert(this->is_mutable()); - Mesh *mesh = mesh_; - mesh_ = nullptr; - return mesh; -} - -void MeshComponent::copy_vertex_group_names_from_object(const Object &object) -{ - BLI_assert(this->is_mutable()); - vertex_group_names_.clear(); - int index = 0; - LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) { - vertex_group_names_.add(group->name, index); - index++; - } -} - -const blender::Map &MeshComponent::vertex_group_names() const -{ - return vertex_group_names_; -} - -/* This is only exposed for the internal attribute API. */ -blender::Map &MeshComponent::vertex_group_names() -{ - return vertex_group_names_; -} - -/* Get the mesh from this component. This method can be used by multiple threads at the same - * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */ -const Mesh *MeshComponent::get_for_read() const -{ - return mesh_; -} - -/* Get the mesh from this component. This method can only be used when the component is mutable, - * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */ -Mesh *MeshComponent::get_for_write() -{ - BLI_assert(this->is_mutable()); - if (ownership_ == GeometryOwnershipType::ReadOnly) { - mesh_ = BKE_mesh_copy_for_eval(mesh_, false); - ownership_ = GeometryOwnershipType::Owned; - } - return mesh_; -} - -bool MeshComponent::is_empty() const -{ - return mesh_ == nullptr; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Pointcloud Component - * \{ */ - -PointCloudComponent::PointCloudComponent() : GeometryComponent(GeometryComponentType::PointCloud) -{ -} - -PointCloudComponent::~PointCloudComponent() -{ - this->clear(); -} - -GeometryComponent *PointCloudComponent::copy() const -{ - PointCloudComponent *new_component = new PointCloudComponent(); - if (pointcloud_ != nullptr) { - new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); - new_component->ownership_ = GeometryOwnershipType::Owned; - } - return new_component; -} - -void PointCloudComponent::clear() -{ - BLI_assert(this->is_mutable()); - if (pointcloud_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, pointcloud_); - } - pointcloud_ = nullptr; - } -} - -bool PointCloudComponent::has_pointcloud() const -{ - return pointcloud_ != nullptr; -} - -/* Clear the component and replace it with the new point cloud. */ -void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - this->clear(); - pointcloud_ = pointcloud; - ownership_ = ownership; -} - -/* Return the point cloud and clear the component. The caller takes over responsibility for freeing - * the point cloud (if the component was responsible before). */ -PointCloud *PointCloudComponent::release() -{ - BLI_assert(this->is_mutable()); - PointCloud *pointcloud = pointcloud_; - pointcloud_ = nullptr; - return pointcloud; -} - -/* Get the point cloud from this component. This method can be used by multiple threads at the same - * time. Therefore, the returned point cloud should not be modified. No ownership is transferred. - */ -const PointCloud *PointCloudComponent::get_for_read() const -{ - return pointcloud_; -} - -/* Get the point cloud from this component. This method can only be used when the component is - * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is - * transferred. */ -PointCloud *PointCloudComponent::get_for_write() -{ - BLI_assert(this->is_mutable()); - if (ownership_ == GeometryOwnershipType::ReadOnly) { - pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); - ownership_ = GeometryOwnershipType::Owned; - } - return pointcloud_; -} - -bool PointCloudComponent::is_empty() const -{ - return pointcloud_ == nullptr; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Instances Component - * \{ */ - -InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentType::Instances) -{ -} - -GeometryComponent *InstancesComponent::copy() const -{ - InstancesComponent *new_component = new InstancesComponent(); - new_component->transforms_ = transforms_; - new_component->instanced_data_ = instanced_data_; - return new_component; -} - -void InstancesComponent::clear() -{ - instanced_data_.clear(); - transforms_.clear(); -} - -void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id) -{ - InstancedData data; - data.type = INSTANCE_DATA_TYPE_OBJECT; - data.data.object = object; - this->add_instance(data, transform, id); -} - -void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id) -{ - InstancedData data; - data.type = INSTANCE_DATA_TYPE_COLLECTION; - data.data.collection = collection; - this->add_instance(data, transform, id); -} - -void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id) -{ - instanced_data_.append(data); - transforms_.append(transform); - ids_.append(id); -} - -Span InstancesComponent::instanced_data() const -{ - return instanced_data_; -} - -Span InstancesComponent::transforms() const -{ - return transforms_; -} - -Span InstancesComponent::ids() const -{ - return ids_; -} - -MutableSpan InstancesComponent::transforms() -{ - return transforms_; -} - -int InstancesComponent::instances_amount() const -{ - const int size = instanced_data_.size(); - BLI_assert(transforms_.size() == size); - return size; -} - -bool InstancesComponent::is_empty() const -{ - return transforms_.size() == 0; -} - -static blender::Array generate_unique_instance_ids(Span original_ids) -{ - using namespace blender; - Array unique_ids(original_ids.size()); - - Set used_unique_ids; - used_unique_ids.reserve(original_ids.size()); - Vector instances_with_id_collision; - for (const int instance_index : original_ids.index_range()) { - const int original_id = original_ids[instance_index]; - if (used_unique_ids.add(original_id)) { - /* The original id has not been used by another instance yet. */ - unique_ids[instance_index] = original_id; - } - else { - /* The original id of this instance collided with a previous instance, it needs to be looked - * at again in a second pass. Don't generate a new random id here, because this might collide - * with other existing ids. */ - instances_with_id_collision.append(instance_index); - } - } - - Map generator_by_original_id; - for (const int instance_index : instances_with_id_collision) { - const int original_id = original_ids[instance_index]; - RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() { - RandomNumberGenerator rng; - rng.seed_random(original_id); - return rng; - }); - - const int max_iteration = 100; - for (int iteration = 0;; iteration++) { - /* Try generating random numbers until an unused one has been found. */ - const int random_id = rng.get_int32(); - if (used_unique_ids.add(random_id)) { - /* This random id is not used by another instance. */ - unique_ids[instance_index] = random_id; - break; - } - if (iteration == max_iteration) { - /* It seems to be very unlikely that we ever run into this case (assuming there are less - * than 2^30 instances). However, if that happens, it's better to use an id that is not - * unique than to be stuck in an infinite loop. */ - unique_ids[instance_index] = original_id; - break; - } - } - } - - return unique_ids; -} - -blender::Span InstancesComponent::almost_unique_ids() const -{ - std::lock_guard lock(almost_unique_ids_mutex_); - if (almost_unique_ids_.size() != ids_.size()) { - almost_unique_ids_ = generate_unique_instance_ids(ids_); - } - return almost_unique_ids_; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Volume Component - * \{ */ - -VolumeComponent::VolumeComponent() : GeometryComponent(GeometryComponentType::Volume) -{ -} - -VolumeComponent::~VolumeComponent() -{ - this->clear(); -} - -GeometryComponent *VolumeComponent::copy() const -{ - VolumeComponent *new_component = new VolumeComponent(); - if (volume_ != nullptr) { - new_component->volume_ = BKE_volume_copy_for_eval(volume_, false); - new_component->ownership_ = GeometryOwnershipType::Owned; - } - return new_component; -} - -void VolumeComponent::clear() -{ - BLI_assert(this->is_mutable()); - if (volume_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, volume_); - } - volume_ = nullptr; - } -} - -bool VolumeComponent::has_volume() const -{ - return volume_ != nullptr; -} - -/* Clear the component and replace it with the new volume. */ -void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - this->clear(); - volume_ = volume; - ownership_ = ownership; -} - -/* Return the volume and clear the component. The caller takes over responsibility for freeing the - * volume (if the component was responsible before). */ -Volume *VolumeComponent::release() -{ - BLI_assert(this->is_mutable()); - Volume *volume = volume_; - volume_ = nullptr; - return volume; -} - -/* Get the volume from this component. This method can be used by multiple threads at the same - * time. Therefore, the returned volume should not be modified. No ownership is transferred. */ -const Volume *VolumeComponent::get_for_read() const -{ - return volume_; -} - -/* Get the volume from this component. This method can only be used when the component is mutable, - * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */ -Volume *VolumeComponent::get_for_write() -{ - BLI_assert(this->is_mutable()); - if (ownership_ == GeometryOwnershipType::ReadOnly) { - volume_ = BKE_volume_copy_for_eval(volume_, false); - ownership_ = GeometryOwnershipType::Owned; - } - return volume_; -} - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name C API * \{ */ -- cgit v1.2.3 From 745576b16e32343fedd8040f284b9001d8b72c77 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 8 Mar 2021 22:22:16 -0500 Subject: UI: Clean up sub-panel for new boolean modifier options A few changes to make this consistent with other modifier panels: - Title case for UI labels - Use property split (and therefore decorators) - Declare sublayout variables after getting modifier info --- source/blender/makesrna/intern/rna_modifier.c | 8 +++++--- source/blender/modifiers/intern/MOD_boolean.c | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 8624384e3ec..98a2b683f18 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -2791,7 +2791,7 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) prop = RNA_def_property(srna, "use_hole_tolerant", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", eBooleanModifierFlag_HoleTolerant); - RNA_def_property_ui_text(prop, "Hole tolerant", "Better results when there are holes (slower)"); + RNA_def_property_ui_text(prop, "Hole Tolerant", "Better results when there are holes (slower)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); /* BMesh debugging options, only used when G_DEBUG is set */ @@ -3139,7 +3139,8 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 1, FLT_MAX); RNA_def_property_ui_range(prop, 1, 1000, 1, 3); - RNA_def_property_ui_text(prop, "Aspect X", "Horizontal aspect ratio (only used for camera projectors)"); + RNA_def_property_ui_text( + prop, "Aspect X", "Horizontal aspect ratio (only used for camera projectors)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "aspect_y", PROP_FLOAT, PROP_NONE); @@ -3147,7 +3148,8 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 1, FLT_MAX); RNA_def_property_ui_range(prop, 1, 1000, 1, 3); - RNA_def_property_ui_text(prop, "Aspect Y", "Vertical aspect ratio (only used for camera projectors)"); + RNA_def_property_ui_text( + prop, "Aspect Y", "Vertical aspect ratio (only used for camera projectors)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "scale_x", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 74a0687e64b..6ffbf518dd1 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -864,13 +864,15 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) static void solver_options_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - uiLayout *col = uiLayoutColumn(layout, true); PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); const bool use_exact = RNA_enum_get(ptr, "solver") == eBooleanModifierSolver_Exact; const bool operand_object = RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object; + uiLayoutSetPropSep(layout, true); + + uiLayout *col = uiLayoutColumn(layout, true); if (use_exact) { /* When operand is collection, we always use_self. */ if (operand_object) { @@ -883,7 +885,6 @@ static void solver_options_panel_draw(const bContext *UNUSED(C), Panel *panel) } if (G.debug) { - col = uiLayoutColumn(layout, true); uiItemR(col, ptr, "debug_options", 0, NULL, ICON_NONE); } } -- cgit v1.2.3 From dc3e9048aef7205376295e4887c589bb4bc319d0 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 9 Mar 2021 09:30:59 +0100 Subject: Cleanup: fix warnings --- source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index 96409837491..742383f5b46 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -149,7 +149,7 @@ BLI_NOINLINE static KDTree_3d *build_kdtree(Span> positions_all, KDTree_3d *kdtree = BLI_kdtree_3d_new(initial_points_len); int i_point = 0; - for (const Vector positions : positions_all) { + for (const Vector &positions : positions_all) { for (const float3 position : positions) { BLI_kdtree_3d_insert(kdtree, i_point, position); i_point++; @@ -611,13 +611,13 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) "Density Attribute"); if (density <= 0.0f) { - params.set_output("Geometry", std::move(GeometrySet())); + params.set_output("Geometry", GeometrySet()); return; } Vector set_groups = bke::geometry_set_gather_instances(geometry_set); if (set_groups.is_empty()) { - params.set_output("Geometry", std::move(GeometrySet())); + params.set_output("Geometry", GeometrySet()); return; } @@ -631,7 +631,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) if (set_groups.is_empty()) { params.error_message_add(NodeWarningType::Error, TIP_("Input geometry must contain a mesh")); - params.set_output("Geometry", std::move(GeometrySet())); + params.set_output("Geometry", GeometrySet()); return; } -- cgit v1.2.3 From 07a9d39f57093c886fe64b02006cae26193eb8aa Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 9 Mar 2021 09:45:18 +0100 Subject: Fix: unconnected multi socket input crashes The crash would only happen when the output of the Join Geometry node is used. --- source/blender/modifiers/intern/MOD_nodes.cc | 4 ++++ source/blender/nodes/NOD_geometry_exec.hh | 16 ++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index c0c7897413b..34730292133 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -424,6 +424,10 @@ class GeometryNodesEvaluator { if (socket_ref->bsocket()->type != SOCK_GEOMETRY) { continue; } + if (socket_ref->is_multi_input_socket()) { + /* Not needed currently. */ + continue; + } bNodeTree *btree_cow = node->btree(); bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow); diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 1772f92c4b6..5b123e68fe2 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -120,13 +120,17 @@ class GeoNodeExecParams { template Vector extract_multi_input(StringRef identifier) { Vector values; - values.append(input_values_.extract(identifier)); - int i = 1; - std::string sub_identifier = identifier + "[1]"; - while (input_values_.contains(sub_identifier)) { + int index = 0; + while (true) { + std::string sub_identifier = identifier; + if (index > 0) { + sub_identifier += "[" + std::to_string(index) + "]"; + } + if (!input_values_.contains(sub_identifier)) { + break; + } values.append(input_values_.extract(sub_identifier)); - i++; - sub_identifier = identifier + "[" + std::to_string(i) + "]"; + index++; } return values; } -- cgit v1.2.3 From 2283b6ef6928c2ce0bfe283a9c4744a113412574 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 9 Mar 2021 23:46:14 +1100 Subject: Fix the session UUID being set for temporary blend file data Triggered by temporarily appending library linked data from Python. --- source/blender/blenkernel/intern/lib_id.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index f3a1c01ad26..af921307bfb 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -171,7 +171,9 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id) /* Conceptually, an ID made local is not the same as the linked one anymore. Reflect that by * regenerating its session UUID. */ - BKE_lib_libblock_session_uuid_renew(id); + if ((id->tag & LIB_TAG_TEMP_MAIN) == 0) { + BKE_lib_libblock_session_uuid_renew(id); + } /* We need to tag this IDs and all of its users, conceptually new local ID and original linked * ones are two completely different data-blocks that were virtually remapped, even though in -- cgit v1.2.3 From 7f9b6b1dc920a6da6b028a5e8c14d7c14aab4555 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 16 Dec 2020 13:13:13 +0100 Subject: Sculpt: 'Unifiy' Dyntopo Detail Size operators Prior to rB99a7c917eab7, Shift + D was used to set detail size for both constant and relative detail (using radial control). The commit added an improved operator for doing this for constant detail (showing the triangle grid representation), but left the user without a shortcut to do this for relative detail. Interestingly rB99a7c917eab7 only changed this for the Blender keymap, the Industy Compatible keymap still has the "old" entry. This patch changes both keymaps to have both entries. For user experience, the real change here is to have both available on one 'primary' shortcut (Shift+D), the improved 'dyntopo_detail_size_edit' operator will now act on all possible cases. If it deals with constant detail, it acts as before, if it deals with relative detail etc, it will fallback to the "old" way of doing it via radial control instead. I assume this adresses what was stated in rB99a7c917eab7: "Deciding if both detail sizes can be unified needs a separate discussion" Also, move dyntopo_detail_size_edit to sculpt_detail.c Fixes T83828 Maniphest Tasks: T83828 Differential Revision: https://developer.blender.org/D9871 --- .../keyconfig/keymap_data/blender_default.py | 1 + .../keymap_data/industry_compatible_data.py | 3 +- source/blender/editors/sculpt_paint/sculpt.c | 335 ------------------- .../blender/editors/sculpt_paint/sculpt_detail.c | 353 ++++++++++++++++++++- .../blender/editors/sculpt_paint/sculpt_intern.h | 1 + 5 files changed, 354 insertions(+), 339 deletions(-) diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 577448554b7..8b94de98972 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -4509,6 +4509,7 @@ def km_sculpt(params): # Dynamic topology ("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None), ("sculpt.dyntopo_detail_size_edit", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True, "alt": True}, None), # Remesh ("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None), ("object.voxel_size_edit", {"type": 'R', "value": 'PRESS', "shift": True}, None), diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py index 214b8f98ff6..c69f7ace926 100644 --- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -3395,7 +3395,8 @@ def km_sculpt(params): {"properties": [("data_path", 'scene.tool_settings.sculpt.show_mask')]}), # Dynamic topology ("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None), - ("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("sculpt.dyntopo_detail_size_edit", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True, "alt": True}, None), # Remesh ("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None), ("object.quadriflow_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True, "alt": True}, None), diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 631327ddfe8..0b30303de91 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -76,11 +76,6 @@ #include "IMB_colormanagement.h" -#include "GPU_immediate.h" -#include "GPU_immediate_util.h" -#include "GPU_matrix.h" -#include "GPU_state.h" - #include "WM_api.h" #include "WM_message.h" #include "WM_toolsystem.h" @@ -89,7 +84,6 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_sculpt.h" -#include "ED_space_api.h" #include "ED_view3d.h" #include "paint_intern.h" #include "sculpt_intern.h" @@ -9433,335 +9427,6 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot) 1.0f); } -/* -------------------------------------------------------------------- */ -/** \name Dyntopo Detail Size Edit Operator - * \{ */ - -/* Defines how much the mouse movement will modify the detail size value. */ -#define DETAIL_SIZE_DELTA_SPEED 0.08f -#define DETAIL_SIZE_DELTA_ACCURATE_SPEED 0.004f - -typedef struct DyntopoDetailSizeEditCustomData { - void *draw_handle; - Object *active_object; - - float init_mval[2]; - float accurate_mval[2]; - - float outline_col[4]; - - bool accurate_mode; - bool sample_mode; - - float init_detail_size; - float accurate_detail_size; - float detail_size; - float radius; - - float preview_tri[3][3]; - float gizmo_mat[4][4]; -} DyntopoDetailSizeEditCustomData; - -static void dyntopo_detail_size_parallel_lines_draw(uint pos3d, - DyntopoDetailSizeEditCustomData *cd, - const float start_co[3], - const float end_co[3], - bool flip, - const float angle) -{ - float object_space_constant_detail = 1.0f / - (cd->detail_size * mat4_to_scale(cd->active_object->obmat)); - - /* The constant detail represents the maximum edge length allowed before subdividing it. If the - * triangle grid preview is created with this value it will represent an ideal mesh density where - * all edges have the exact maximum length, which never happens in practice. As the minimum edge - * length for dyntopo is 0.4 * max_edge_length, this adjust the detail size to the average - * between max and min edge length so the preview is more accurate. */ - object_space_constant_detail *= 0.7f; - - const float total_len = len_v3v3(cd->preview_tri[0], cd->preview_tri[1]); - const int tot_lines = (int)(total_len / object_space_constant_detail) + 1; - const float tot_lines_fl = total_len / object_space_constant_detail; - float spacing_disp[3]; - sub_v3_v3v3(spacing_disp, end_co, start_co); - normalize_v3(spacing_disp); - - float line_disp[3]; - rotate_v2_v2fl(line_disp, spacing_disp, DEG2RAD(angle)); - mul_v3_fl(spacing_disp, total_len / tot_lines_fl); - - immBegin(GPU_PRIM_LINES, (uint)tot_lines * 2); - for (int i = 0; i < tot_lines; i++) { - float line_length; - if (flip) { - line_length = total_len * ((float)i / (float)tot_lines_fl); - } - else { - line_length = total_len * (1.0f - ((float)i / (float)tot_lines_fl)); - } - float line_start[3]; - copy_v3_v3(line_start, start_co); - madd_v3_v3v3fl(line_start, line_start, spacing_disp, i); - float line_end[3]; - madd_v3_v3v3fl(line_end, line_start, line_disp, line_length); - immVertex3fv(pos3d, line_start); - immVertex3fv(pos3d, line_end); - } - immEnd(); -} - -static void dyntopo_detail_size_edit_draw(const bContext *UNUSED(C), - ARegion *UNUSED(ar), - void *arg) -{ - DyntopoDetailSizeEditCustomData *cd = arg; - GPU_blend(GPU_BLEND_ALPHA); - GPU_line_smooth(true); - - uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - GPU_matrix_push(); - GPU_matrix_mul(cd->gizmo_mat); - - /* Draw Cursor */ - immUniformColor4fv(cd->outline_col); - GPU_line_width(3.0f); - - imm_draw_circle_wire_3d(pos3d, 0, 0, cd->radius, 80); - - /* Draw Triangle. */ - immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f); - immBegin(GPU_PRIM_LINES, 6); - immVertex3fv(pos3d, cd->preview_tri[0]); - immVertex3fv(pos3d, cd->preview_tri[1]); - - immVertex3fv(pos3d, cd->preview_tri[1]); - immVertex3fv(pos3d, cd->preview_tri[2]); - - immVertex3fv(pos3d, cd->preview_tri[2]); - immVertex3fv(pos3d, cd->preview_tri[0]); - immEnd(); - - /* Draw Grid */ - GPU_line_width(1.0f); - dyntopo_detail_size_parallel_lines_draw( - pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], false, 60.0f); - dyntopo_detail_size_parallel_lines_draw( - pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], true, 120.0f); - dyntopo_detail_size_parallel_lines_draw( - pos3d, cd, cd->preview_tri[0], cd->preview_tri[2], false, -60.0f); - - immUnbindProgram(); - GPU_matrix_pop(); - GPU_blend(GPU_BLEND_NONE); - GPU_line_smooth(false); -} - -static void dyntopo_detail_size_edit_cancel(bContext *C, wmOperator *op) -{ - Object *active_object = CTX_data_active_object(C); - SculptSession *ss = active_object->sculpt; - ARegion *region = CTX_wm_region(C); - DyntopoDetailSizeEditCustomData *cd = op->customdata; - ED_region_draw_cb_exit(region->type, cd->draw_handle); - ss->draw_faded_cursor = false; - MEM_freeN(op->customdata); - ED_workspace_status_text(C, NULL); -} - -static void dyntopo_detail_size_sample_from_surface(Object *ob, - DyntopoDetailSizeEditCustomData *cd) -{ - SculptSession *ss = ob->sculpt; - const int active_vertex = SCULPT_active_vertex_get(ss); - - float len_accum = 0; - int num_neighbors = 0; - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) { - len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex), - SCULPT_vertex_co_get(ss, ni.index)); - num_neighbors++; - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - - if (num_neighbors > 0) { - const float avg_edge_len = len_accum / num_neighbors; - /* Use 0.7 as the average of min and max dyntopo edge length. */ - const float detail_size = 0.7f / (avg_edge_len * mat4_to_scale(cd->active_object->obmat)); - cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f); - } -} - -static void dyntopo_detail_size_update_from_mouse_delta(DyntopoDetailSizeEditCustomData *cd, - const wmEvent *event) -{ - const float mval[2] = {event->mval[0], event->mval[1]}; - - float detail_size_delta; - if (cd->accurate_mode) { - detail_size_delta = mval[0] - cd->accurate_mval[0]; - cd->detail_size = cd->accurate_detail_size + - detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED; - } - else { - detail_size_delta = mval[0] - cd->init_mval[0]; - cd->detail_size = cd->init_detail_size + detail_size_delta * DETAIL_SIZE_DELTA_SPEED; - } - - if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) { - cd->accurate_mode = true; - copy_v2_v2(cd->accurate_mval, mval); - cd->accurate_detail_size = cd->detail_size; - } - if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) { - cd->accurate_mode = false; - cd->accurate_detail_size = 0.0f; - } - - cd->detail_size = clamp_f(cd->detail_size, 1.0f, 500.0f); -} - -static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - Object *active_object = CTX_data_active_object(C); - SculptSession *ss = active_object->sculpt; - ARegion *region = CTX_wm_region(C); - DyntopoDetailSizeEditCustomData *cd = op->customdata; - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - - /* Cancel modal operator */ - if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) || - (event->type == RIGHTMOUSE && event->val == KM_PRESS)) { - dyntopo_detail_size_edit_cancel(C, op); - ED_region_tag_redraw(region); - return OPERATOR_FINISHED; - } - - /* Finish modal operator */ - if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) || - (event->type == EVT_RETKEY && event->val == KM_PRESS) || - (event->type == EVT_PADENTER && event->val == KM_PRESS)) { - ED_region_draw_cb_exit(region->type, cd->draw_handle); - sd->constant_detail = cd->detail_size; - ss->draw_faded_cursor = false; - MEM_freeN(op->customdata); - ED_region_tag_redraw(region); - ED_workspace_status_text(C, NULL); - return OPERATOR_FINISHED; - } - - ED_region_tag_redraw(region); - - if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) { - cd->sample_mode = true; - } - if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) { - cd->sample_mode = false; - } - - /* Sample mode sets the detail size sampling the average edge length under the surface. */ - if (cd->sample_mode) { - dyntopo_detail_size_sample_from_surface(active_object, cd); - return OPERATOR_RUNNING_MODAL; - } - /* Regular mode, changes the detail size by moving the cursor. */ - dyntopo_detail_size_update_from_mouse_delta(cd, event); - - return OPERATOR_RUNNING_MODAL; -} - -static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ARegion *region = CTX_wm_region(C); - Object *active_object = CTX_data_active_object(C); - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - DyntopoDetailSizeEditCustomData *cd = MEM_callocN(sizeof(DyntopoDetailSizeEditCustomData), - "Dyntopo Detail Size Edit OP Custom Data"); - - /* Initial operator Custom Data setup. */ - cd->draw_handle = ED_region_draw_cb_activate( - region->type, dyntopo_detail_size_edit_draw, cd, REGION_DRAW_POST_VIEW); - cd->active_object = active_object; - cd->init_mval[0] = event->mval[0]; - cd->init_mval[1] = event->mval[1]; - cd->detail_size = sd->constant_detail; - cd->init_detail_size = sd->constant_detail; - copy_v4_v4(cd->outline_col, brush->add_col); - op->customdata = cd; - - SculptSession *ss = active_object->sculpt; - cd->radius = ss->cursor_radius; - - /* Generates the matrix to position the gizmo in the surface of the mesh using the same location - * and orientation as the brush cursor. */ - float cursor_trans[4][4], cursor_rot[4][4]; - const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f}; - float quat[4]; - copy_m4_m4(cursor_trans, active_object->obmat); - translate_m4( - cursor_trans, ss->cursor_location[0], ss->cursor_location[1], ss->cursor_location[2]); - - float cursor_normal[3]; - if (!is_zero_v3(ss->cursor_sampled_normal)) { - copy_v3_v3(cursor_normal, ss->cursor_sampled_normal); - } - else { - copy_v3_v3(cursor_normal, ss->cursor_normal); - } - - rotation_between_vecs_to_quat(quat, z_axis, cursor_normal); - quat_to_mat4(cursor_rot, quat); - copy_m4_m4(cd->gizmo_mat, cursor_trans); - mul_m4_m4_post(cd->gizmo_mat, cursor_rot); - - /* Initialize the position of the triangle vertices. */ - const float y_axis[3] = {0.0f, cd->radius, 0.0f}; - for (int i = 0; i < 3; i++) { - zero_v3(cd->preview_tri[i]); - rotate_v2_v2fl(cd->preview_tri[i], y_axis, DEG2RAD(120.0f * i)); - } - - SCULPT_vertex_random_access_ensure(ss); - - WM_event_add_modal_handler(C, op); - ED_region_tag_redraw(region); - - ss->draw_faded_cursor = true; - - const char *status_str = TIP_( - "Move the mouse to change the dyntopo detail size. LMB: confirm size, ESC/RMB: cancel"); - ED_workspace_status_text(C, status_str); - - return OPERATOR_RUNNING_MODAL; -} - -static bool dyntopo_detail_size_edit_poll(bContext *C) -{ - Object *ob = CTX_data_active_object(C); - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - - return SCULPT_mode_poll(C) && ob->sculpt->bm && (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT); -} - -static void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Edit Dyntopo Detail Size"; - ot->description = "Modify the constant detail size of dyntopo interactively"; - ot->idname = "SCULPT_OT_dyntopo_detail_size_edit"; - - /* api callbacks */ - ot->poll = dyntopo_detail_size_edit_poll; - ot->invoke = dyntopo_detail_size_edit_invoke; - ot->modal = dyntopo_detail_size_edit_modal; - ot->cancel = dyntopo_detail_size_edit_cancel; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - void ED_operatortypes_sculpt(void) { WM_operatortype_append(SCULPT_OT_brush_stroke); diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index ddf7ba1e412..1246c624941 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -37,10 +37,17 @@ #include "DEG_depsgraph.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_state.h" + #include "WM_api.h" #include "WM_types.h" #include "ED_screen.h" +#include "ED_sculpt.h" +#include "ED_space_api.h" #include "ED_view3d.h" #include "sculpt_intern.h" @@ -359,8 +366,12 @@ void SCULPT_OT_sample_detail_size(wmOperatorType *ot) /* Dynamic-topology detail size. * - * This should be improved further, perhaps by showing a triangle - * grid rather than brush alpha. */ + * Currently, there are two operators editing the detail size: + * - SCULPT_OT_set_detail_size uses radial control for all methods + * - SCULPT_OT_dyntopo_detail_size_edit shows a triangle grid representation of the detail + * resolution (for constant detail method, falls back to radial control for the remaining methods). + */ + static void set_brush_rc_props(PointerRNA *ptr, const char *prop) { char *path = BLI_sprintfN("tool_settings.sculpt.brush.%s", prop); @@ -368,7 +379,7 @@ static void set_brush_rc_props(PointerRNA *ptr, const char *prop) MEM_freeN(path); } -static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op)) +static void sculpt_detail_size_set_radial_control(bContext *C) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -394,6 +405,11 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op)) WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr); WM_operator_properties_free(&props_ptr); +} + +static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op)) +{ + sculpt_detail_size_set_radial_control(C); return OPERATOR_FINISHED; } @@ -412,3 +428,334 @@ void SCULPT_OT_set_detail_size(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/* -------------------------------------------------------------------- */ +/** \name Dyntopo Detail Size Edit Operator + * \{ */ + +/* Defines how much the mouse movement will modify the detail size value. */ +#define DETAIL_SIZE_DELTA_SPEED 0.08f +#define DETAIL_SIZE_DELTA_ACCURATE_SPEED 0.004f + +typedef struct DyntopoDetailSizeEditCustomData { + void *draw_handle; + Object *active_object; + + float init_mval[2]; + float accurate_mval[2]; + + float outline_col[4]; + + bool accurate_mode; + bool sample_mode; + + float init_detail_size; + float accurate_detail_size; + float detail_size; + float radius; + + float preview_tri[3][3]; + float gizmo_mat[4][4]; +} DyntopoDetailSizeEditCustomData; + +static void dyntopo_detail_size_parallel_lines_draw(uint pos3d, + DyntopoDetailSizeEditCustomData *cd, + const float start_co[3], + const float end_co[3], + bool flip, + const float angle) +{ + float object_space_constant_detail = 1.0f / + (cd->detail_size * mat4_to_scale(cd->active_object->obmat)); + + /* The constant detail represents the maximum edge length allowed before subdividing it. If the + * triangle grid preview is created with this value it will represent an ideal mesh density where + * all edges have the exact maximum length, which never happens in practice. As the minimum edge + * length for dyntopo is 0.4 * max_edge_length, this adjust the detail size to the average + * between max and min edge length so the preview is more accurate. */ + object_space_constant_detail *= 0.7f; + + const float total_len = len_v3v3(cd->preview_tri[0], cd->preview_tri[1]); + const int tot_lines = (int)(total_len / object_space_constant_detail) + 1; + const float tot_lines_fl = total_len / object_space_constant_detail; + float spacing_disp[3]; + sub_v3_v3v3(spacing_disp, end_co, start_co); + normalize_v3(spacing_disp); + + float line_disp[3]; + rotate_v2_v2fl(line_disp, spacing_disp, DEG2RAD(angle)); + mul_v3_fl(spacing_disp, total_len / tot_lines_fl); + + immBegin(GPU_PRIM_LINES, (uint)tot_lines * 2); + for (int i = 0; i < tot_lines; i++) { + float line_length; + if (flip) { + line_length = total_len * ((float)i / (float)tot_lines_fl); + } + else { + line_length = total_len * (1.0f - ((float)i / (float)tot_lines_fl)); + } + float line_start[3]; + copy_v3_v3(line_start, start_co); + madd_v3_v3v3fl(line_start, line_start, spacing_disp, i); + float line_end[3]; + madd_v3_v3v3fl(line_end, line_start, line_disp, line_length); + immVertex3fv(pos3d, line_start); + immVertex3fv(pos3d, line_end); + } + immEnd(); +} + +static void dyntopo_detail_size_edit_draw(const bContext *UNUSED(C), + ARegion *UNUSED(ar), + void *arg) +{ + DyntopoDetailSizeEditCustomData *cd = arg; + GPU_blend(GPU_BLEND_ALPHA); + GPU_line_smooth(true); + + uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + GPU_matrix_push(); + GPU_matrix_mul(cd->gizmo_mat); + + /* Draw Cursor */ + immUniformColor4fv(cd->outline_col); + GPU_line_width(3.0f); + + imm_draw_circle_wire_3d(pos3d, 0, 0, cd->radius, 80); + + /* Draw Triangle. */ + immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f); + immBegin(GPU_PRIM_LINES, 6); + immVertex3fv(pos3d, cd->preview_tri[0]); + immVertex3fv(pos3d, cd->preview_tri[1]); + + immVertex3fv(pos3d, cd->preview_tri[1]); + immVertex3fv(pos3d, cd->preview_tri[2]); + + immVertex3fv(pos3d, cd->preview_tri[2]); + immVertex3fv(pos3d, cd->preview_tri[0]); + immEnd(); + + /* Draw Grid */ + GPU_line_width(1.0f); + dyntopo_detail_size_parallel_lines_draw( + pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], false, 60.0f); + dyntopo_detail_size_parallel_lines_draw( + pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], true, 120.0f); + dyntopo_detail_size_parallel_lines_draw( + pos3d, cd, cd->preview_tri[0], cd->preview_tri[2], false, -60.0f); + + immUnbindProgram(); + GPU_matrix_pop(); + GPU_blend(GPU_BLEND_NONE); + GPU_line_smooth(false); +} + +static void dyntopo_detail_size_edit_cancel(bContext *C, wmOperator *op) +{ + Object *active_object = CTX_data_active_object(C); + SculptSession *ss = active_object->sculpt; + ARegion *region = CTX_wm_region(C); + DyntopoDetailSizeEditCustomData *cd = op->customdata; + ED_region_draw_cb_exit(region->type, cd->draw_handle); + ss->draw_faded_cursor = false; + MEM_freeN(op->customdata); + ED_workspace_status_text(C, NULL); +} + +static void dyntopo_detail_size_sample_from_surface(Object *ob, + DyntopoDetailSizeEditCustomData *cd) +{ + SculptSession *ss = ob->sculpt; + const int active_vertex = SCULPT_active_vertex_get(ss); + + float len_accum = 0; + int num_neighbors = 0; + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) { + len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex), + SCULPT_vertex_co_get(ss, ni.index)); + num_neighbors++; + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + if (num_neighbors > 0) { + const float avg_edge_len = len_accum / num_neighbors; + /* Use 0.7 as the average of min and max dyntopo edge length. */ + const float detail_size = 0.7f / (avg_edge_len * mat4_to_scale(cd->active_object->obmat)); + cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f); + } +} + +static void dyntopo_detail_size_update_from_mouse_delta(DyntopoDetailSizeEditCustomData *cd, + const wmEvent *event) +{ + const float mval[2] = {event->mval[0], event->mval[1]}; + + float detail_size_delta; + if (cd->accurate_mode) { + detail_size_delta = mval[0] - cd->accurate_mval[0]; + cd->detail_size = cd->accurate_detail_size + + detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED; + } + else { + detail_size_delta = mval[0] - cd->init_mval[0]; + cd->detail_size = cd->init_detail_size + detail_size_delta * DETAIL_SIZE_DELTA_SPEED; + } + + if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) { + cd->accurate_mode = true; + copy_v2_v2(cd->accurate_mval, mval); + cd->accurate_detail_size = cd->detail_size; + } + if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) { + cd->accurate_mode = false; + cd->accurate_detail_size = 0.0f; + } + + cd->detail_size = clamp_f(cd->detail_size, 1.0f, 500.0f); +} + +static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + Object *active_object = CTX_data_active_object(C); + SculptSession *ss = active_object->sculpt; + ARegion *region = CTX_wm_region(C); + DyntopoDetailSizeEditCustomData *cd = op->customdata; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + + /* Cancel modal operator */ + if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) || + (event->type == RIGHTMOUSE && event->val == KM_PRESS)) { + dyntopo_detail_size_edit_cancel(C, op); + ED_region_tag_redraw(region); + return OPERATOR_FINISHED; + } + + /* Finish modal operator */ + if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) || + (event->type == EVT_RETKEY && event->val == KM_PRESS) || + (event->type == EVT_PADENTER && event->val == KM_PRESS)) { + ED_region_draw_cb_exit(region->type, cd->draw_handle); + sd->constant_detail = cd->detail_size; + ss->draw_faded_cursor = false; + MEM_freeN(op->customdata); + ED_region_tag_redraw(region); + ED_workspace_status_text(C, NULL); + return OPERATOR_FINISHED; + } + + ED_region_tag_redraw(region); + + if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) { + cd->sample_mode = true; + } + if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) { + cd->sample_mode = false; + } + + /* Sample mode sets the detail size sampling the average edge length under the surface. */ + if (cd->sample_mode) { + dyntopo_detail_size_sample_from_surface(active_object, cd); + return OPERATOR_RUNNING_MODAL; + } + /* Regular mode, changes the detail size by moving the cursor. */ + dyntopo_detail_size_update_from_mouse_delta(cd, event); + + return OPERATOR_RUNNING_MODAL; +} + +static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + + /* Fallback to radial control for modes other than SCULPT_DYNTOPO_DETAIL_CONSTANT [same as in + * SCULPT_OT_set_detail_size]. */ + if (!(sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL))) { + sculpt_detail_size_set_radial_control(C); + + return OPERATOR_FINISHED; + } + + /* Special method for SCULPT_DYNTOPO_DETAIL_CONSTANT. */ + ARegion *region = CTX_wm_region(C); + Object *active_object = CTX_data_active_object(C); + Brush *brush = BKE_paint_brush(&sd->paint); + + DyntopoDetailSizeEditCustomData *cd = MEM_callocN(sizeof(DyntopoDetailSizeEditCustomData), + "Dyntopo Detail Size Edit OP Custom Data"); + + /* Initial operator Custom Data setup. */ + cd->draw_handle = ED_region_draw_cb_activate( + region->type, dyntopo_detail_size_edit_draw, cd, REGION_DRAW_POST_VIEW); + cd->active_object = active_object; + cd->init_mval[0] = event->mval[0]; + cd->init_mval[1] = event->mval[1]; + cd->detail_size = sd->constant_detail; + cd->init_detail_size = sd->constant_detail; + copy_v4_v4(cd->outline_col, brush->add_col); + op->customdata = cd; + + SculptSession *ss = active_object->sculpt; + cd->radius = ss->cursor_radius; + + /* Generates the matrix to position the gizmo in the surface of the mesh using the same location + * and orientation as the brush cursor. */ + float cursor_trans[4][4], cursor_rot[4][4]; + const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f}; + float quat[4]; + copy_m4_m4(cursor_trans, active_object->obmat); + translate_m4( + cursor_trans, ss->cursor_location[0], ss->cursor_location[1], ss->cursor_location[2]); + + float cursor_normal[3]; + if (!is_zero_v3(ss->cursor_sampled_normal)) { + copy_v3_v3(cursor_normal, ss->cursor_sampled_normal); + } + else { + copy_v3_v3(cursor_normal, ss->cursor_normal); + } + + rotation_between_vecs_to_quat(quat, z_axis, cursor_normal); + quat_to_mat4(cursor_rot, quat); + copy_m4_m4(cd->gizmo_mat, cursor_trans); + mul_m4_m4_post(cd->gizmo_mat, cursor_rot); + + /* Initize the position of the triangle vertices. */ + const float y_axis[3] = {0.0f, cd->radius, 0.0f}; + for (int i = 0; i < 3; i++) { + zero_v3(cd->preview_tri[i]); + rotate_v2_v2fl(cd->preview_tri[i], y_axis, DEG2RAD(120.0f * i)); + } + + SCULPT_vertex_random_access_ensure(ss); + + WM_event_add_modal_handler(C, op); + ED_region_tag_redraw(region); + + ss->draw_faded_cursor = true; + + const char *status_str = TIP_( + "Move the mouse to change the dyntopo detail size. LMB: confirm size, ESC/RMB: cancel"); + ED_workspace_status_text(C, status_str); + + return OPERATOR_RUNNING_MODAL; +} + +void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Edit Dyntopo Detail Size"; + ot->description = "Modify the detail size of dyntopo interactively"; + ot->idname = "SCULPT_OT_dyntopo_detail_size_edit"; + + /* api callbacks */ + ot->poll = sculpt_and_dynamic_topology_poll; + ot->invoke = dyntopo_detail_size_edit_invoke; + ot->modal = dyntopo_detail_size_edit_modal; + ot->cancel = dyntopo_detail_size_edit_cancel; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 19c4eda7593..16c2996e392 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -1360,6 +1360,7 @@ void SCULPT_OT_mask_expand(struct wmOperatorType *ot); void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot); void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot); void SCULPT_OT_set_detail_size(struct wmOperatorType *ot); +void SCULPT_OT_dyntopo_detail_size_edit(struct wmOperatorType *ot); /* Dyntopo. */ void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot); -- cgit v1.2.3 From 68ff213cd4a26cde9b7b01570578e1a950768c3f Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 9 Mar 2021 14:17:06 +0100 Subject: Cleanup: Correct area writing function name This function writes areas, not regions. The old name read as if it was regions. --- source/blender/blenkernel/intern/screen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index aa1a9403908..f0220373678 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -1217,7 +1217,7 @@ static void write_panel_list(BlendWriter *writer, ListBase *lb) } } -static void write_area_regions(BlendWriter *writer, ScrArea *area) +static void write_area(BlendWriter *writer, ScrArea *area) { LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { write_region(writer, region, area->spacetype); @@ -1359,7 +1359,7 @@ void BKE_screen_area_map_blend_write(BlendWriter *writer, ScrAreaMap *area_map) BLO_write_struct(writer, ScrGlobalAreaData, area->global); - write_area_regions(writer, area); + write_area(writer, area); area->butspacetype = SPACE_EMPTY; /* Unset again, was changed above. */ } -- cgit v1.2.3 From 6114d909d6b438cd8c0f2f82f8716b2994bc9f7e Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Tue, 9 Mar 2021 14:13:59 +0100 Subject: Fix T86417: Crash deleting Shader AOV from an empty list Missing NULL check in {rB2bae11d5c08a}. Candidate for corrective release I guess. Maniphest Tasks: T86417 Differential Revision: https://developer.blender.org/D10666 --- source/blender/editors/render/render_shading.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index bfad79a1da9..b4cac58db1f 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -1074,6 +1074,11 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); + + if (view_layer->active_aov == NULL) { + return OPERATOR_FINISHED; + } + BKE_view_layer_remove_aov(view_layer, view_layer->active_aov); RenderEngineType *engine_type = RE_engines_find(scene->r.engine); -- cgit v1.2.3 From be6b3923f5732e3da9d1ef432c092d90f9343fdf Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Tue, 9 Mar 2021 19:19:08 +0530 Subject: Compositor: silence clang/clang-tidy override warnings `-Winconsistent-missing-override` and `modernize-use-override`. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D10654 --- .../blender/compositor/operations/COM_MultilayerImageOperation.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h index f5176b0a4db..bfc59cabdbf 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h @@ -28,7 +28,7 @@ class MultilayerBaseOperation : public BaseImageOperation { protected: RenderLayer *m_renderLayer; RenderPass *m_renderPass; - ImBuf *getImBuf(); + ImBuf *getImBuf() override; public: /** @@ -44,7 +44,7 @@ class MultilayerColorOperation : public MultilayerBaseOperation { { this->addOutputSocket(COM_DT_COLOR); } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; std::unique_ptr getMetaData() const override; }; @@ -55,7 +55,7 @@ class MultilayerValueOperation : public MultilayerBaseOperation { { this->addOutputSocket(COM_DT_VALUE); } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MultilayerVectorOperation : public MultilayerBaseOperation { @@ -65,5 +65,5 @@ class MultilayerVectorOperation : public MultilayerBaseOperation { { this->addOutputSocket(COM_DT_VECTOR); } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; -- cgit v1.2.3 From cdb0b3cedc9b242b75affadf0a0a33959320ab77 Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Tue, 9 Mar 2021 19:19:21 +0530 Subject: Compositor: Silence -Wself-assign Use member initializer list for constructor. Use `this->` for member function. Introduced in rBef53859d24a9720882e3ca6c5415faefec6fb82c Reviewed By: jbakker Differential Revision: https://developer.blender.org/D10653 --- source/blender/compositor/intern/COM_ChunkOrderHotspot.cc | 13 +++---------- source/blender/compositor/intern/COM_ChunkOrderHotspot.h | 5 +++-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc index bbc98d086a6..d31ff518ecd 100644 --- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc +++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc @@ -19,18 +19,11 @@ #include "COM_ChunkOrderHotspot.h" #include -ChunkOrderHotspot::ChunkOrderHotspot(int x, int y, float addition) -{ - x = x; - y = y; - addition = addition; -} - double ChunkOrderHotspot::calc_distance(int x, int y) { - int dx = x - x; - int dy = y - y; + int dx = this->x - x; + int dy = this->y - y; double result = sqrt((double)(dx * dx + dy * dy)); - result += (double)addition; + result += (double)this->addition; return result; } diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.h b/source/blender/compositor/intern/COM_ChunkOrderHotspot.h index af0cf897673..d7f40921836 100644 --- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.h +++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.h @@ -27,8 +27,9 @@ struct ChunkOrderHotspot { int y; float addition; - public: - ChunkOrderHotspot(int x, int y, float addition); + ChunkOrderHotspot(int x, int y, float addition) : x(x), y(y), addition(addition) + { + } double calc_distance(int x, int y); -- cgit v1.2.3 From eaada565910b4ff31081ced86c3b7242f2f28b4e Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 9 Mar 2021 15:19:00 +0100 Subject: Cleanup: add resource manager for cryptomatte session. Auto frees cryptomatte session when it the pointer is collected from the stack. Reviewed By: Jacques Lucke Differential Revision: https://developer.blender.org/D10667 --- release/datafiles/locale | 2 +- release/scripts/addons | 2 +- source/blender/blenkernel/BKE_cryptomatte.hh | 11 +++++++++++ source/blender/blenkernel/intern/cryptomatte_test.cc | 7 +++---- source/tools | 2 +- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/release/datafiles/locale b/release/datafiles/locale index aafea2abb18..b06e7fe345e 160000 --- a/release/datafiles/locale +++ b/release/datafiles/locale @@ -1 +1 @@ -Subproject commit aafea2abb18bb42e7d31a6926b2caba90f4e0316 +Subproject commit b06e7fe345e4a313eb701692e5d45033131caee1 diff --git a/release/scripts/addons b/release/scripts/addons index 117faa96af3..ef3104dae30 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit 117faa96af35685d72e5e01f9a386d163d874133 +Subproject commit ef3104dae302dcfb08b21e32d10b548bf304bd29 diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh index f10b4c1f7c4..98fdfc965bc 100644 --- a/source/blender/blenkernel/BKE_cryptomatte.hh +++ b/source/blender/blenkernel/BKE_cryptomatte.hh @@ -29,6 +29,8 @@ #include "BLI_map.hh" #include "BLI_string_ref.hh" +#include "BKE_cryptomatte.h" + struct ID; namespace blender::bke::cryptomatte { @@ -103,4 +105,13 @@ struct CryptomatteStampDataCallbackData { static void extract_layer_manifest(void *_data, const char *propname, char *propvalue, int len); }; +struct CryptomatteSessionDeleter { + void operator()(CryptomatteSession *session) + { + BKE_cryptomatte_free(session); + } +}; + +using CryptomatteSessionPtr = std::unique_ptr; + } // namespace blender::bke::cryptomatte diff --git a/source/blender/blenkernel/intern/cryptomatte_test.cc b/source/blender/blenkernel/intern/cryptomatte_test.cc index d9be252d654..5c57c906ca2 100644 --- a/source/blender/blenkernel/intern/cryptomatte_test.cc +++ b/source/blender/blenkernel/intern/cryptomatte_test.cc @@ -157,8 +157,8 @@ TEST(cryptomatte, session_from_stamp_data) BKE_render_result_stamp_data(render_result, "cryptomatte/uiop/name", "layer2"); BKE_render_result_stamp_data( render_result, "cryptomatte/uiop/manifest", "{\"Object2\":\"87654321\"}"); - CryptomatteSession *session = BKE_cryptomatte_init_from_render_result(render_result); - EXPECT_NE(session, nullptr); + CryptomatteSessionPtr session(BKE_cryptomatte_init_from_render_result(render_result)); + EXPECT_NE(session.get(), nullptr); RE_FreeRenderResult(render_result); /* Create StampData from CryptomatteSession. */ @@ -166,14 +166,13 @@ TEST(cryptomatte, session_from_stamp_data) BLI_strncpy(view_layer.name, "viewlayername", sizeof(view_layer.name)); RenderResult *render_result2 = static_cast( MEM_callocN(sizeof(RenderResult), __func__)); - BKE_cryptomatte_store_metadata(session, render_result2, &view_layer); + BKE_cryptomatte_store_metadata(session.get(), render_result2, &view_layer); /* Validate StampData. */ BKE_stamp_info_callback( nullptr, render_result2->stamp_data, validate_cryptomatte_session_from_stamp_data, false); RE_FreeRenderResult(render_result2); - BKE_cryptomatte_free(session); } } // namespace blender::bke::cryptomatte::tests diff --git a/source/tools b/source/tools index c37d8bd28dd..b66c22e1fb9 160000 --- a/source/tools +++ b/source/tools @@ -1 +1 @@ -Subproject commit c37d8bd28ddddb8f1b0dff5739d75f8004e8034f +Subproject commit b66c22e1fb977bf8dd3797ebedc28fbe28f0305e -- cgit v1.2.3 From 0700441578c9bb4d3f45d59183f26d3293499113 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 9 Mar 2021 09:27:44 -0500 Subject: Geometry Nodes: Expose "shade smooth" as an attribute This patch exposes the "Shade Smooth" value as a boolean attribute. This setting is exposed as a check-box in the mesh data properties, but the value is actually stored for every face, allowing some faces to be shaded smooth with a simple per-face control. One bonus, this allows at least a workaround to the lack of control of whether meshes created by nodes are shaded smooth or not: just use an attribute fill node. Differential Revision: https://developer.blender.org/D10538 --- .../blenkernel/intern/geometry_component_mesh.cc | 38 +++++++++++++++++++++- .../blenkernel/intern/geometry_set_instances.cc | 6 ++-- .../nodes/geometry/nodes/node_geo_join_geometry.cc | 2 +- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 03b938942a7..31809b1ffec 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -405,6 +405,29 @@ static void update_vertex_normals_when_dirty(const GeometryComponent &component) } } +static bool get_shade_smooth(const MPoly &mpoly) +{ + return mpoly.flag & ME_SMOOTH; +} + +static void set_shade_smooth(MPoly &mpoly, const bool &value) +{ + SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH); +} + +static ReadAttributePtr make_shade_smooth_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique>( + ATTR_DOMAIN_POLYGON, Span((const MPoly *)data, domain_size)); +} + +static WriteAttributePtr make_shade_smooth_write_attribute(void *data, const int domain_size) +{ + return std::make_unique< + DerivedArrayWriteAttribute>( + ATTR_DOMAIN_POLYGON, MutableSpan((MPoly *)data, domain_size)); +} + static float2 get_loop_uv(const MLoopUV &uv) { return float2(uv.uv); @@ -680,6 +703,19 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() nullptr, nullptr); + static BuiltinCustomDataLayerProvider shade_smooth("shade_smooth", + ATTR_DOMAIN_POLYGON, + CD_PROP_BOOL, + CD_MPOLY, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + polygon_access, + make_shade_smooth_read_attribute, + make_shade_smooth_write_attribute, + nullptr, + nullptr); + static BuiltinCustomDataLayerProvider vertex_normal("vertex_normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, @@ -713,7 +749,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access); - return ComponentAttributeProviders({&position, &material_index, &vertex_normal}, + return ComponentAttributeProviders({&position, &material_index, &vertex_normal, &shade_smooth}, {&uvs, &vertex_colors, &corner_custom_data, diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 6c4c3231667..f3006385da3 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -378,8 +378,10 @@ static void join_instance_groups_mesh(Span set_groups, /* Don't copy attributes that are stored directly in the mesh data structs. */ Map attributes; - gather_attribute_info( - attributes, component_types, set_groups, {"position", "material_index", "vertex_normal"}); + gather_attribute_info(attributes, + component_types, + set_groups, + {"position", "material_index", "vertex_normal", "shade_smooth"}); join_attributes( set_groups, component_types, attributes, static_cast(dst_component)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 9dce52c072d..45aaf81d63f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -224,7 +224,7 @@ static void join_components(Span src_components, Geometry /* Don't copy attributes that are stored directly in the mesh data structs. */ join_attributes(to_base_components(src_components), dst_component, - {"position", "material_index", "vertex_normal"}); + {"position", "material_index", "vertex_normal", "shade_smooth"}); } static void join_components(Span src_components, GeometrySet &result) -- cgit v1.2.3 From 077beb738c931037eae40ce54a43aa8dc87e01a3 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 9 Mar 2021 16:34:43 +0100 Subject: Cleanup: use nullptr in cpp. --- source/blender/editors/space_outliner/tree/tree_element_id.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc index 31dfed35d8a..823a7644f38 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc @@ -152,7 +152,7 @@ void TreeElementID::postExpand(SpaceOutliner &space_outliner) const bool TreeElementID::expandPoll(const SpaceOutliner &space_outliner) const { const TreeStoreElem *tsepar = legacy_te_.parent ? TREESTORE(legacy_te_.parent) : nullptr; - return (tsepar == NULL || tsepar->type != TSE_ID_BASE || space_outliner.filter_id_type); + return (tsepar == nullptr || tsepar->type != TSE_ID_BASE || space_outliner.filter_id_type); } void TreeElementID::expand_animation_data(SpaceOutliner &space_outliner, -- cgit v1.2.3 From c6a831cfbc9b24fa8b1ed4852178c139e6ed79a6 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 9 Mar 2021 16:50:47 +0100 Subject: Cleanup: use raw strings. --- .../blender/blenkernel/intern/cryptomatte_test.cc | 26 ++++++++++------------ 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/source/blender/blenkernel/intern/cryptomatte_test.cc b/source/blender/blenkernel/intern/cryptomatte_test.cc index 5c57c906ca2..faf1ad91cdc 100644 --- a/source/blender/blenkernel/intern/cryptomatte_test.cc +++ b/source/blender/blenkernel/intern/cryptomatte_test.cc @@ -75,17 +75,15 @@ static void test_cryptomatte_manifest(std::string expected, std::string manifest TEST(cryptomatte, layer_from_manifest) { test_cryptomatte_manifest("{}", "{}"); - test_cryptomatte_manifest("{\"Object\":\"12345678\"}", "{\"Object\": \"12345678\"}"); - test_cryptomatte_manifest("{\"Object\":\"12345678\",\"Object2\":\"87654321\"}", - "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}"); + test_cryptomatte_manifest(R"({"Object":"12345678"})", R"({"Object": "12345678"})"); + test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321")})", + R"({"Object":"12345678","Object2":"87654321"})"); + test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321"})", + R"( { "Object" : "12345678" , "Object2" : "87654321" } )"); + test_cryptomatte_manifest(R"({"Object\"01\"":"12345678"})", R"({"Object\"01\"": "12345678"})"); test_cryptomatte_manifest( - "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}", - " { \"Object\" : \"12345678\" , \"Object2\" : \"87654321\" } "); - test_cryptomatte_manifest("{\"Object\\\"01\\\"\":\"12345678\"}", - "{\"Object\\\"01\\\"\": \"12345678\"}"); - test_cryptomatte_manifest( - "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\",\"Object2\":\"87654321\"}", - "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\", \"Object2\":\"87654321\"}"); + R"({"Object\"01\"":"12345678","Object":"12345678","Object2":"87654321"})", + R"({"Object\"01\"":"12345678","Object":"12345678", "Object2":"87654321"})"); } TEST(cryptomatte, extract_layer_hash_from_metadata_key) @@ -125,7 +123,7 @@ static void validate_cryptomatte_session_from_stamp_data(void *UNUSED(data), EXPECT_STREQ("uint32_to_float32", propvalue); } else if (prop_name == "cryptomatte/87f095e/manifest") { - EXPECT_STREQ("{\"Object\":\"12345678\"}", propvalue); + EXPECT_STREQ(R"({"Object":"12345678"})", propvalue); } else if (prop_name == "cryptomatte/c42daa7/name") { @@ -138,7 +136,7 @@ static void validate_cryptomatte_session_from_stamp_data(void *UNUSED(data), EXPECT_STREQ("uint32_to_float32", propvalue); } else if (prop_name == "cryptomatte/c42daa7/manifest") { - EXPECT_STREQ("{\"Object2\":\"87654321\"}", propvalue); + EXPECT_STREQ(R"({"Object2":"87654321"})", propvalue); } else { @@ -153,10 +151,10 @@ TEST(cryptomatte, session_from_stamp_data) MEM_callocN(sizeof(RenderResult), __func__)); BKE_render_result_stamp_data(render_result, "cryptomatte/qwerty/name", "layer1"); BKE_render_result_stamp_data( - render_result, "cryptomatte/qwerty/manifest", "{\"Object\":\"12345678\"}"); + render_result, "cryptomatte/qwerty/manifest", R"({"Object":"12345678"})"); BKE_render_result_stamp_data(render_result, "cryptomatte/uiop/name", "layer2"); BKE_render_result_stamp_data( - render_result, "cryptomatte/uiop/manifest", "{\"Object2\":\"87654321\"}"); + render_result, "cryptomatte/uiop/manifest", R"({"Object2":"87654321"})"); CryptomatteSessionPtr session(BKE_cryptomatte_init_from_render_result(render_result)); EXPECT_NE(session.get(), nullptr); RE_FreeRenderResult(render_result); -- cgit v1.2.3 From 04e816bd11a1424f51703fc0921dda843f0ff41e Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 9 Mar 2021 16:59:58 +0100 Subject: Fix T86432: missing check if attribute is available This failed when the component did exist, but did not contain any data. --- source/blender/nodes/geometry/nodes/node_geo_point_translate.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc index cb3cd012c77..015f4cd38e7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc @@ -46,6 +46,9 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co { OutputAttributePtr position_attribute = component.attribute_try_get_for_output( "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); + if (!position_attribute) { + return; + } ReadAttributePtr attribute = params.get_input_attribute( "Translation", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr); if (!attribute) { -- cgit v1.2.3 From cd1e6df534105990d726d610dca763099ccfdc1a Mon Sep 17 00:00:00 2001 From: Corbin Dunn Date: Tue, 9 Mar 2021 21:38:41 +0530 Subject: macOS/Ghost: Replace NSAutoreleasePool with @autoreleasepool - Automatic and guaranteed cleanup. - Improves readability and reduces chances of errors by removing `[pool drain]` statements. Reviewed By: #platform_macos, sebbas, ankitm Differential Revision: https://developer.blender.org/D10616 --- intern/ghost/intern/GHOST_SystemCocoa.mm | 477 +++++++++++++++---------------- 1 file changed, 231 insertions(+), 246 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 4a23b30e078..e7bbf3bb462 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -563,97 +563,96 @@ GHOST_TSuccess GHOST_SystemCocoa::init() SetFrontProcess(&psn); }*/ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [NSApplication sharedApplication]; // initializes NSApp - - if ([NSApp mainMenu] == nil) { - NSMenu *mainMenubar = [[NSMenu alloc] init]; - NSMenuItem *menuItem; - NSMenu *windowMenu; - NSMenu *appMenu; - - // Create the application menu - appMenu = [[NSMenu alloc] initWithTitle:@"Blender"]; - - [appMenu addItemWithTitle:@"About Blender" - action:@selector(orderFrontStandardAboutPanel:) - keyEquivalent:@""]; - [appMenu addItem:[NSMenuItem separatorItem]]; - - menuItem = [appMenu addItemWithTitle:@"Hide Blender" - action:@selector(hide:) - keyEquivalent:@"h"]; - [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand]; - - menuItem = [appMenu addItemWithTitle:@"Hide Others" - action:@selector(hideOtherApplications:) - keyEquivalent:@"h"]; - [menuItem - setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)]; - - [appMenu addItemWithTitle:@"Show All" - action:@selector(unhideAllApplications:) - keyEquivalent:@""]; - - menuItem = [appMenu addItemWithTitle:@"Quit Blender" - action:@selector(terminate:) - keyEquivalent:@"q"]; - [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand]; - - menuItem = [[NSMenuItem alloc] init]; - [menuItem setSubmenu:appMenu]; - - [mainMenubar addItem:menuItem]; - [menuItem release]; - [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; // Needed for 10.5 - [appMenu release]; - - // Create the window menu - windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; - - menuItem = [windowMenu addItemWithTitle:@"Minimize" - action:@selector(performMiniaturize:) - keyEquivalent:@"m"]; - [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand]; - - [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""]; - - menuItem = [windowMenu addItemWithTitle:@"Enter Full Screen" - action:@selector(toggleFullScreen:) - keyEquivalent:@"f"]; - [menuItem - setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand]; - - menuItem = [windowMenu addItemWithTitle:@"Close" - action:@selector(performClose:) - keyEquivalent:@"w"]; - [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand]; - - menuItem = [[NSMenuItem alloc] init]; - [menuItem setSubmenu:windowMenu]; - - [mainMenubar addItem:menuItem]; - [menuItem release]; - - [NSApp setMainMenu:mainMenubar]; - [NSApp setWindowsMenu:windowMenu]; - [windowMenu release]; - } - - if ([NSApp delegate] == nil) { - CocoaAppDelegate *appDelegate = [[CocoaAppDelegate alloc] init]; - [appDelegate setSystemCocoa:this]; - [NSApp setDelegate:appDelegate]; - } + @autoreleasepool { + [NSApplication sharedApplication]; // initializes NSApp + + if ([NSApp mainMenu] == nil) { + NSMenu *mainMenubar = [[NSMenu alloc] init]; + NSMenuItem *menuItem; + NSMenu *windowMenu; + NSMenu *appMenu; + + // Create the application menu + appMenu = [[NSMenu alloc] initWithTitle:@"Blender"]; + + [appMenu addItemWithTitle:@"About Blender" + action:@selector(orderFrontStandardAboutPanel:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + + menuItem = [appMenu addItemWithTitle:@"Hide Blender" + action:@selector(hide:) + keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand]; + + menuItem = [appMenu addItemWithTitle:@"Hide Others" + action:@selector(hideOtherApplications:) + keyEquivalent:@"h"]; + [menuItem + setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)]; + + [appMenu addItemWithTitle:@"Show All" + action:@selector(unhideAllApplications:) + keyEquivalent:@""]; + + menuItem = [appMenu addItemWithTitle:@"Quit Blender" + action:@selector(terminate:) + keyEquivalent:@"q"]; + [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand]; + + menuItem = [[NSMenuItem alloc] init]; + [menuItem setSubmenu:appMenu]; + + [mainMenubar addItem:menuItem]; + [menuItem release]; + [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; // Needed for 10.5 + [appMenu release]; + + // Create the window menu + windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + + menuItem = [windowMenu addItemWithTitle:@"Minimize" + action:@selector(performMiniaturize:) + keyEquivalent:@"m"]; + [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand]; + + [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""]; + + menuItem = [windowMenu addItemWithTitle:@"Enter Full Screen" + action:@selector(toggleFullScreen:) + keyEquivalent:@"f"]; + [menuItem + setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand]; + + menuItem = [windowMenu addItemWithTitle:@"Close" + action:@selector(performClose:) + keyEquivalent:@"w"]; + [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand]; + + menuItem = [[NSMenuItem alloc] init]; + [menuItem setSubmenu:windowMenu]; + + [mainMenubar addItem:menuItem]; + [menuItem release]; + + [NSApp setMainMenu:mainMenubar]; + [NSApp setWindowsMenu:windowMenu]; + [windowMenu release]; + } - // AppKit provides automatic window tabbing. Blender is a single-tabbed application without a - // macOS tab bar, and should explicitly opt-out of this. This is also controlled by the macOS - // user default #NSWindowTabbingEnabled. - NSWindow.allowsAutomaticWindowTabbing = NO; + if ([NSApp delegate] == nil) { + CocoaAppDelegate *appDelegate = [[CocoaAppDelegate alloc] init]; + [appDelegate setSystemCocoa:this]; + [NSApp setDelegate:appDelegate]; + } - [NSApp finishLaunching]; + // AppKit provides automatic window tabbing. Blender is a single-tabbed application + // without a macOS tab bar, and should explicitly opt-out of this. This is also + // controlled by the macOS user default #NSWindowTabbingEnabled. + NSWindow.allowsAutomaticWindowTabbing = NO; - [pool drain]; + [NSApp finishLaunching]; + } } return success; } @@ -676,30 +675,27 @@ GHOST_TUns8 GHOST_SystemCocoa::getNumDisplays() const { // Note that OS X supports monitor hot plug // We do not support multiple monitors at the moment - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - GHOST_TUns8 count = [[NSScreen screens] count]; - - [pool drain]; + @autoreleasepool { + GHOST_TUns8 count = [[NSScreen screens] count]; + } return count; } void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - // Get visible frame, that is frame excluding dock and top menu bar - NSRect frame = [[NSScreen mainScreen] visibleFrame]; - - // Returns max window contents (excluding title bar...) - NSRect contentRect = [NSWindow - contentRectForFrameRect:frame - styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable)]; - - width = contentRect.size.width; - height = contentRect.size.height; - - [pool drain]; + @autoreleasepool { + // Get visible frame, that is frame excluding dock and top menu bar + NSRect frame = [[NSScreen mainScreen] visibleFrame]; + + // Returns max window contents (excluding title bar...) + NSRect contentRect = [NSWindow + contentRectForFrameRect:frame + styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable)]; + + width = contentRect.size.width; + height = contentRect.size.height; + } } void GHOST_SystemCocoa::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const @@ -720,53 +716,52 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title, const bool is_dialog, const GHOST_IWindow *parentWindow) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; GHOST_IWindow *window = NULL; - - // Get the available rect for including window contents - NSRect frame = [[NSScreen mainScreen] visibleFrame]; - NSRect contentRect = [NSWindow - contentRectForFrameRect:frame - styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable)]; - - GHOST_TInt32 bottom = (contentRect.size.height - 1) - height - top; - - // Ensures window top left is inside this available rect - left = left > contentRect.origin.x ? left : contentRect.origin.x; - // Add contentRect.origin.y to respect docksize - bottom = bottom > contentRect.origin.y ? bottom + contentRect.origin.y : contentRect.origin.y; - - window = new GHOST_WindowCocoa(this, - title, - left, - bottom, - width, - height, - state, - type, - glSettings.flags & GHOST_glStereoVisual, - glSettings.flags & GHOST_glDebugContext, - is_dialog, - (GHOST_WindowCocoa *)parentWindow); - - if (window->getValid()) { - // Store the pointer to the window - GHOST_ASSERT(m_windowManager, "m_windowManager not initialized"); - m_windowManager->addWindow(window); - m_windowManager->setActiveWindow(window); - /* Need to tell window manager the new window is the active one - * (Cocoa does not send the event activate upon window creation). */ - pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window)); - pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); - } - else { - GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n"); - delete window; - window = NULL; + @autoreleasepool { + + // Get the available rect for including window contents + NSRect frame = [[NSScreen mainScreen] visibleFrame]; + NSRect contentRect = [NSWindow + contentRectForFrameRect:frame + styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable)]; + + GHOST_TInt32 bottom = (contentRect.size.height - 1) - height - top; + + // Ensures window top left is inside this available rect + left = left > contentRect.origin.x ? left : contentRect.origin.x; + // Add contentRect.origin.y to respect docksize + bottom = bottom > contentRect.origin.y ? bottom + contentRect.origin.y : contentRect.origin.y; + + window = new GHOST_WindowCocoa(this, + title, + left, + bottom, + width, + height, + state, + type, + glSettings.flags & GHOST_glStereoVisual, + glSettings.flags & GHOST_glDebugContext, + is_dialog, + (GHOST_WindowCocoa *)parentWindow); + + if (window->getValid()) { + // Store the pointer to the window + GHOST_ASSERT(m_windowManager, "m_windowManager not initialized"); + m_windowManager->addWindow(window); + m_windowManager->setActiveWindow(window); + /* Need to tell window manager the new window is the active one + * (Cocoa does not send the event activate upon window creation). */ + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window)); + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); + } + else { + GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n"); + delete window; + window = NULL; + } } - - [pool drain]; return window; } @@ -841,29 +836,28 @@ GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(GHOST_TInt32 x, GHOST_T if (!window) return GHOST_kFailure; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSScreen *windowScreen = window->getScreen(); - NSRect screenRect = [windowScreen frame]; + @autoreleasepool { + NSScreen *windowScreen = window->getScreen(); + NSRect screenRect = [windowScreen frame]; - // Set position relative to current screen - xf -= screenRect.origin.x; - yf -= screenRect.origin.y; + // Set position relative to current screen + xf -= screenRect.origin.x; + yf -= screenRect.origin.y; - // Quartz Display Services uses the old coordinates (top left origin) - yf = screenRect.size.height - yf; + // Quartz Display Services uses the old coordinates (top left origin) + yf = screenRect.size.height - yf; - CGDisplayMoveCursorToPoint((CGDirectDisplayID)[[[windowScreen deviceDescription] - objectForKey:@"NSScreenNumber"] unsignedIntValue], - CGPointMake(xf, yf)); + CGDisplayMoveCursorToPoint((CGDirectDisplayID)[[[windowScreen deviceDescription] + objectForKey:@"NSScreenNumber"] unsignedIntValue], + CGPointMake(xf, yf)); - // See https://stackoverflow.com/a/17559012. By default, hardware events - // will be suppressed for 500ms after a synthetic mouse event. For unknown - // reasons CGEventSourceSetLocalEventsSuppressionInterval does not work, - // however calling CGAssociateMouseAndMouseCursorPosition also removes the - // delay, even if this is undocumented. - CGAssociateMouseAndMouseCursorPosition(true); - - [pool drain]; + // See https://stackoverflow.com/a/17559012. By default, hardware events + // will be suppressed for 500ms after a synthetic mouse event. For unknown + // reasons CGEventSourceSetLocalEventsSuppressionInterval does not work, + // however calling CGAssociateMouseAndMouseCursorPosition also removes the + // delay, even if this is undocumented. + CGAssociateMouseAndMouseCursorPosition(true); + } return GHOST_kSuccess; } @@ -928,42 +922,40 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent) } #endif do { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - event = [NSApp nextEventMatchingMask:NSEventMaskAny - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES]; - if (event == nil) { - [pool drain]; - break; - } + @autoreleasepool { + event = [NSApp nextEventMatchingMask:NSEventMaskAny + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event == nil) { + break; + } - anyProcessed = true; + anyProcessed = true; - // Send event to NSApp to ensure Mac wide events are handled, - // this will send events to CocoaWindow which will call back - // to handleKeyEvent, handleMouseEvent and handleTabletEvent + // Send event to NSApp to ensure Mac wide events are handled, + // this will send events to CocoaWindow which will call back + // to handleKeyEvent, handleMouseEvent and handleTabletEvent - // There is on special exception for ctrl+(shift)+tab. We do not - // get keyDown events delivered to the view because they are - // special hotkeys to switch between views, so override directly + // There is on special exception for ctrl+(shift)+tab. We do not + // get keyDown events delivered to the view because they are + // special hotkeys to switch between views, so override directly - if ([event type] == NSEventTypeKeyDown && [event keyCode] == kVK_Tab && - ([event modifierFlags] & NSEventModifierFlagControl)) { - handleKeyEvent(event); - } - else { - // For some reason NSApp is swallowing the key up events when modifier - // key is pressed, even if there seems to be no apparent reason to do - // so, as a workaround we always handle these up events. - if ([event type] == NSEventTypeKeyUp && - ([event modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagOption))) + if ([event type] == NSEventTypeKeyDown && [event keyCode] == kVK_Tab && + ([event modifierFlags] & NSEventModifierFlagControl)) { handleKeyEvent(event); - - [NSApp sendEvent:event]; + } + else { + // For some reason NSApp is swallowing the key up events when modifier + // key is pressed, even if there seems to be no apparent reason to do + // so, as a workaround we always handle these up events. + if ([event type] == NSEventTypeKeyUp && + ([event modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagOption))) + handleKeyEvent(event); + + [NSApp sendEvent:event]; + } } - - [pool drain]; } while (event != nil); #if 0 } while (waitForEvent && !anyProcessed); // Needed only for timer implementation @@ -1953,52 +1945,47 @@ GHOST_TUns8 *GHOST_SystemCocoa::getClipboard(bool selection) const GHOST_TUns8 *temp_buff; size_t pastedTextSize; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + @autoreleasepool { - NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; + NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; - if (pasteBoard == nil) { - [pool drain]; - return NULL; - } - - NSArray *supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil]; + if (pasteBoard == nil) { + return NULL; + } - NSString *bestType = [[NSPasteboard generalPasteboard] availableTypeFromArray:supportedTypes]; + NSArray *supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil]; - if (bestType == nil) { - [pool drain]; - return NULL; - } + NSString *bestType = [[NSPasteboard generalPasteboard] availableTypeFromArray:supportedTypes]; - NSString *textPasted = [pasteBoard stringForType:NSStringPboardType]; + if (bestType == nil) { + return NULL; + } - if (textPasted == nil) { - [pool drain]; - return NULL; - } + NSString *textPasted = [pasteBoard stringForType:NSStringPboardType]; - pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + if (textPasted == nil) { + return NULL; + } - temp_buff = (GHOST_TUns8 *)malloc(pastedTextSize + 1); + pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - if (temp_buff == NULL) { - [pool drain]; - return NULL; - } + temp_buff = (GHOST_TUns8 *)malloc(pastedTextSize + 1); - strncpy( - (char *)temp_buff, [textPasted cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize); + if (temp_buff == NULL) { + return NULL; + } - temp_buff[pastedTextSize] = '\0'; + strncpy( + (char *)temp_buff, [textPasted cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize); - [pool drain]; + temp_buff[pastedTextSize] = '\0'; - if (temp_buff) { - return temp_buff; - } - else { - return NULL; + if (temp_buff) { + return temp_buff; + } + else { + return NULL; + } } } @@ -2009,22 +1996,20 @@ void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const if (selection) return; // for copying the selection, used on X11 - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; + @autoreleasepool { - if (pasteBoard == nil) { - [pool drain]; - return; - } + NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; - NSArray *supportedTypes = [NSArray arrayWithObject:NSStringPboardType]; + if (pasteBoard == nil) { + return; + } - [pasteBoard declareTypes:supportedTypes owner:nil]; + NSArray *supportedTypes = [NSArray arrayWithObject:NSStringPboardType]; - textToCopy = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding]; + [pasteBoard declareTypes:supportedTypes owner:nil]; - [pasteBoard setString:textToCopy forType:NSStringPboardType]; + textToCopy = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding]; - [pool drain]; + [pasteBoard setString:textToCopy forType:NSStringPboardType]; + } } -- cgit v1.2.3 From 9d046019e2eb6b24f7b4ec2c6e5ff102f9532594 Mon Sep 17 00:00:00 2001 From: Corbin Dunn Date: Tue, 9 Mar 2021 21:38:44 +0530 Subject: macOS/Ghost: Remove unnecessary nil checks. Reviewed By: #platform_macos, sebbas, ankitm Differential Revision: https://developer.blender.org/D10616 --- intern/ghost/intern/GHOST_SystemCocoa.mm | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index e7bbf3bb462..baa2bcd47b6 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -386,13 +386,11 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) - (id)init { self = [super init]; - if (self) { - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - [center addObserver:self - selector:@selector(windowWillClose:) - name:NSWindowWillCloseNotification - object:nil]; - } + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserver:self + selector:@selector(windowWillClose:) + name:NSWindowWillCloseNotification + object:nil]; return self; } @@ -1669,10 +1667,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) NSEventPhase momentumPhase = NSEventPhaseNone; NSEventPhase phase = NSEventPhaseNone; - if ([event respondsToSelector:@selector(momentumPhase)]) - momentumPhase = [event momentumPhase]; - if ([event respondsToSelector:@selector(phase)]) - phase = [event phase]; + momentumPhase = [event momentumPhase]; + phase = [event phase]; /* when pressing a key while momentum scrolling continues after * lifting fingers off the trackpad, the action can unexpectedly -- cgit v1.2.3 From 4069016de893866c996d0979ab35e9f3c6aeb957 Mon Sep 17 00:00:00 2001 From: Corbin Dunn Date: Tue, 9 Mar 2021 21:38:47 +0530 Subject: macOS/Ghost: Simplify pasteboard and screen count code Reviewed By: #platform_macos, sebbas, ankitm Differential Revision: https://developer.blender.org/D10616 --- intern/ghost/intern/GHOST_SystemCocoa.mm | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index baa2bcd47b6..9c28449a4e5 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -674,9 +674,8 @@ GHOST_TUns8 GHOST_SystemCocoa::getNumDisplays() const // Note that OS X supports monitor hot plug // We do not support multiple monitors at the moment @autoreleasepool { - GHOST_TUns8 count = [[NSScreen screens] count]; + return NSScreen.screens.count; } - return count; } void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const @@ -1945,18 +1944,6 @@ GHOST_TUns8 *GHOST_SystemCocoa::getClipboard(bool selection) const NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; - if (pasteBoard == nil) { - return NULL; - } - - NSArray *supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil]; - - NSString *bestType = [[NSPasteboard generalPasteboard] availableTypeFromArray:supportedTypes]; - - if (bestType == nil) { - return NULL; - } - NSString *textPasted = [pasteBoard stringForType:NSStringPboardType]; if (textPasted == nil) { @@ -1987,25 +1974,14 @@ GHOST_TUns8 *GHOST_SystemCocoa::getClipboard(bool selection) const void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const { - NSString *textToCopy; - if (selection) return; // for copying the selection, used on X11 @autoreleasepool { - NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; - - if (pasteBoard == nil) { - return; - } - - NSArray *supportedTypes = [NSArray arrayWithObject:NSStringPboardType]; - - [pasteBoard declareTypes:supportedTypes owner:nil]; - - textToCopy = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding]; - + NSPasteboard *pasteBoard = NSPasteboard.generalPasteboard; + [pasteBoard declareTypes:@[ NSStringPboardType ] owner:nil]; + NSString *textToCopy = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding]; [pasteBoard setString:textToCopy forType:NSStringPboardType]; } } -- cgit v1.2.3 From 8351e2d4b94c601bcf1984a2c92ccfaa2a2601fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 9 Mar 2021 17:42:09 +0100 Subject: Cleanup: add missing full stop to docstring of function No functional changes. --- source/blender/makesrna/intern/rna_pose_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c index d93972aa0ad..29516830058 100644 --- a/source/blender/makesrna/intern/rna_pose_api.c +++ b/source/blender/makesrna/intern/rna_pose_api.c @@ -136,7 +136,7 @@ void RNA_api_pose(StructRNA *srna) RNA_def_function_ui_description( func, "Apply the given action to this pose by evaluating it at a specific time. Only updates the " - "pose of selected bones, or all bones if none are selected"); + "pose of selected bones, or all bones if none are selected."); parm = RNA_def_pointer(func, "action", "Action", "Action", "The Action containing the pose"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); -- cgit v1.2.3 From b1ef55abdbb9f47712049748ccf65d009c059160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 9 Mar 2021 17:24:49 +0100 Subject: Cleanup: Document `ensure()`-like behaviour of `KeyMaps.new()` Document the fact that `bpy.types.KeyMaps.new()` will not create a new keymap but instead return an existing one, if one with the given name/space/region already exists. No functional changes. --- source/blender/makesrna/intern/rna_wm_api.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index cb20b480ee5..e7ca41bb5be 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -1216,6 +1216,11 @@ void RNA_api_keymaps(StructRNA *srna) func = RNA_def_function(srna, "new", "rna_keymap_new"); /* add_keymap */ RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_ui_description( + func, + "Ensure the keymap exists. This will return the one with the given name/space type/region " + "type, or create a new one if it does not exist yet."); + parm = RNA_def_string(func, "name", NULL, 0, "Name", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_enum(func, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", ""); -- cgit v1.2.3 From e5c1e13ef09bbb81f6da15d99fe1c49b4fe527ec Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Wed, 3 Mar 2021 20:01:54 +0100 Subject: Sculpt: Init Face Sets by Face Sets boundaries This adds an extra option to the Face Sets Init operator to initialize individual Face Sets based on the current Face Sets boundaries. In particular, this is useful for splitting the patterns created by Expand into individual Face Sets for further editing. Reviewed By: JacquesLucke Differential Revision: https://developer.blender.org/D10608 --- release/scripts/startup/bl_ui/space_view3d.py | 3 +++ .../blender/editors/sculpt_paint/sculpt_face_set.c | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 26e0c128f7c..4b687945974 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -3197,6 +3197,9 @@ class VIEW3D_MT_face_sets_init(Menu): op = layout.operator("sculpt.face_sets_init", text='By Loose Parts') op.mode = 'LOOSE_PARTS' + op = layout.operator("sculpt.face_sets_init", text='By Face Set Boundaries') + op.mode = 'FACE_SET_BOUNDARIES' + op = layout.operator("sculpt.face_sets_init", text='By Materials') op.mode = 'MATERIALS' diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index df03d2adeaf..332e551c577 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -447,6 +447,7 @@ typedef enum eSculptFaceSetsInitMode { SCULPT_FACE_SETS_FROM_SHARP_EDGES = 5, SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT = 6, SCULPT_FACE_SETS_FROM_FACE_MAPS = 7, + SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES = 8, } eSculptFaceSetsInitMode; static EnumPropertyItem prop_sculpt_face_sets_init_types[] = { @@ -506,6 +507,14 @@ static EnumPropertyItem prop_sculpt_face_sets_init_types[] = { "Face Sets from Face Maps", "Create a Face Set per Face Map", }, + { + SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES, + "FACE_SET_BOUNDARIES", + 0, + "Face Sets from Face Set Boundaries", + "Create a Face Set per isolated Face Set", + }, + {0, NULL, 0, NULL, NULL}, }; @@ -557,6 +566,14 @@ static bool sculpt_face_sets_init_sharp_edges_test(BMesh *UNUSED(bm), return BM_elem_flag_test(from_e, BM_ELEM_SMOOTH); } +static bool sculpt_face_sets_init_face_set_boundary_test( + BMesh *bm, BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float UNUSED(threshold)) +{ + const int cd_face_sets_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS); + return BM_ELEM_CD_GET_INT(from_f, cd_face_sets_offset) == + BM_ELEM_CD_GET_INT(to_f, cd_face_sets_offset); +} + static void sculpt_face_sets_init_flood_fill(Object *ob, face_sets_flood_fill_test test, const float threshold) @@ -725,6 +742,10 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op) case SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT: sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_bevel_weight_test, threshold); break; + case SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES: + sculpt_face_sets_init_flood_fill( + ob, sculpt_face_sets_init_face_set_boundary_test, threshold); + break; case SCULPT_FACE_SETS_FROM_FACE_MAPS: sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_FACE_MAPS); break; -- cgit v1.2.3 From 3f7b585a083573ef5e94784ba5d3d4f4c7b97255 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Wed, 3 Mar 2021 22:17:24 +0100 Subject: Fix crash in boundary brush after refactor A missing continue in this loop. Reviewed By: JacquesLucke Differential Revision: https://developer.blender.org/D10610 --- source/blender/editors/sculpt_paint/sculpt_boundary.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c index f1fb402ae41..f79621ccffd 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.c +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c @@ -589,6 +589,7 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b for (int i = 0; i < totvert; i++) { if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) { + continue; } sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex], SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex), -- cgit v1.2.3 From 996586860b0e2c86e515df1e38316afda32df4a0 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 9 Mar 2021 13:31:51 -0500 Subject: Cleanup: Do not pass stack allocated string to MEM_callocN --- source/blender/editors/animation/fmodifier_ui.c | 18 +++++------------- .../gpencil_modifiers/intern/MOD_gpencil_ui_common.c | 17 ++++------------- source/blender/modifiers/intern/MOD_ui_common.c | 16 ++++------------ source/blender/shader_fx/intern/FX_ui_common.c | 17 ++++------------- 4 files changed, 17 insertions(+), 51 deletions(-) diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index 1809daa3fcb..653bd72b364 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -173,15 +173,11 @@ static PanelType *fmodifier_panel_register(ARegionType *region_type, PanelTypePollFn poll, const char *id_prefix) { - /* Get the name for the modifier's panel. */ - char panel_idname[BKE_ST_MAXNAME]; - const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type); - BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_PT_%s", id_prefix, fmi->name); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); /* Intentionally leave the label field blank. The header is filled with buttons. */ - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type); + BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_PT_%s", id_prefix, fmi->name); BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); @@ -215,13 +211,9 @@ static PanelType *fmodifier_subpanel_register(ARegionType *region_type, PanelTypePollFn poll, PanelType *parent) { - /* Create the subpanel's ID name. */ - char panel_idname[BKE_ST_MAXNAME]; - BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME); BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c index 05e7a23bc82..10383a9417d 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c @@ -371,14 +371,9 @@ PanelType *gpencil_modifier_panel_register(ARegionType *region_type, GpencilModifierType type, PanelDrawFn draw) { + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - /* Get the name for the modifier's panel. */ - char panel_idname[BKE_ST_MAXNAME]; - BKE_gpencil_modifierType_panel_id(type, panel_idname); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); - - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BKE_gpencil_modifierType_panel_id(type, panel_type->idname); BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); @@ -412,13 +407,9 @@ PanelType *gpencil_modifier_subpanel_register(ARegionType *region_type, PanelDrawFn draw, PanelType *parent) { - /* Create the subpanel's ID name. */ - char panel_idname[BKE_ST_MAXNAME]; - BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c index 821c74496f2..6b2facc16a2 100644 --- a/source/blender/modifiers/intern/MOD_ui_common.c +++ b/source/blender/modifiers/intern/MOD_ui_common.c @@ -409,13 +409,9 @@ static void modifier_panel_header(const bContext *C, Panel *panel) */ PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw) { - /* Get the name for the modifier's panel. */ - char panel_idname[BKE_ST_MAXNAME]; - BKE_modifier_type_panel_id(type, panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); - - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BKE_modifier_type_panel_id(type, panel_type->idname); BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); @@ -450,13 +446,9 @@ PanelType *modifier_subpanel_register(ARegionType *region_type, PanelDrawFn draw, PanelType *parent) { - /* Create the subpanel's ID name. */ - char panel_idname[BKE_ST_MAXNAME]; - BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c index 9a86e1e96f5..8a259c6aaff 100644 --- a/source/blender/shader_fx/intern/FX_ui_common.c +++ b/source/blender/shader_fx/intern/FX_ui_common.c @@ -241,14 +241,9 @@ static bool shaderfx_ui_poll(const bContext *C, PanelType *UNUSED(pt)) */ PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw) { + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - /* Get the name for the effect's panel. */ - char panel_idname[BKE_ST_MAXNAME]; - BKE_shaderfxType_panel_id(type, panel_idname); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); - - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BKE_shaderfxType_panel_id(type, panel_type->idname); BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "shaderfx", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); @@ -282,13 +277,9 @@ PanelType *shaderfx_subpanel_register(ARegionType *region_type, PanelDrawFn draw, PanelType *parent) { - /* Create the subpanel's ID name. */ - char panel_idname[BKE_ST_MAXNAME]; - BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "shaderfx", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); -- cgit v1.2.3 From 80f7f1070f177ae543f2fa35dd5d458e87ff30c1 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 9 Mar 2021 13:39:05 -0500 Subject: Geometry Nodes: Add Attribute interpolation for polygon domains This commit adds interpolation to and from attribute on the polygon domain. Interpolation is done automatically when a node uses attributes on two different domains. The following are the new interpolations and corresponding simple test cases: - **Point to Polygon**: Painting the shade smooth attribute in weight paint mode - **Polygon to Point**: Moving points along a normal based on the material index - **Polygon to Corner**: Scaling a UV map with the material index before sampling a texture {F9881516} This is also necessary for an improved implementation of the `normal` attribute. Differential Revision: https://developer.blender.org/D10393 --- .../blenkernel/intern/geometry_component_mesh.cc | 167 +++++++++++++++++++++ 1 file changed, 167 insertions(+) diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 31809b1ffec..53defc89b7e 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -256,6 +256,157 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, return new_attribute; } +/** + * \note Theoretically this interpolation does not need to compute all values at once. + * However, doing that makes the implementation simpler, and this can be optimized in the future if + * only some values are required. + */ +template +static void adapt_mesh_domain_corner_to_polygon_impl(const Mesh &mesh, + Span old_values, + MutableSpan r_values) +{ + BLI_assert(r_values.size() == mesh.totpoly); + attribute_math::DefaultMixer mixer(r_values); + + for (const int poly_index : IndexRange(mesh.totpoly)) { + const MPoly &poly = mesh.mpoly[poly_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const T value = old_values[loop_index]; + mixer.mix_in(poly_index, value); + } + } + + mixer.finalize(); +} + +static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v>) { + Array values(mesh.totpoly); + adapt_mesh_domain_corner_to_polygon_impl(mesh, attribute->get_span(), values); + new_attribute = std::make_unique>(ATTR_DOMAIN_POINT, + std::move(values)); + } + }); + return new_attribute; +} + +template +void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh, + Span old_values, + MutableSpan r_values) +{ + BLI_assert(r_values.size() == mesh.totvert); + attribute_math::DefaultMixer mixer(r_values); + + for (const int poly_index : IndexRange(mesh.totpoly)) { + const MPoly &poly = mesh.mpoly[poly_index]; + const T value = old_values[poly_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const MLoop &loop = mesh.mloop[loop_index]; + const int point_index = loop.v; + mixer.mix_in(point_index, value); + } + } + + mixer.finalize(); +} + +static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v>) { + Array values(mesh.totvert); + adapt_mesh_domain_polygon_to_point_impl(mesh, attribute->get_span(), values); + new_attribute = std::make_unique>(ATTR_DOMAIN_POINT, + std::move(values)); + } + }); + return new_attribute; +} + +template +void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh, + const Span old_values, + MutableSpan r_values) +{ + BLI_assert(r_values.size() == mesh.totloop); + + for (const int poly_index : IndexRange(mesh.totpoly)) { + const MPoly &poly = mesh.mpoly[poly_index]; + MutableSpan poly_corner_values = r_values.slice(poly.loopstart, poly.totloop); + poly_corner_values.fill(old_values[poly_index]); + } +} + +static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v>) { + Array values(mesh.totloop); + adapt_mesh_domain_polygon_to_corner_impl(mesh, attribute->get_span(), values); + new_attribute = std::make_unique>(ATTR_DOMAIN_POINT, + std::move(values)); + } + }); + return new_attribute; +} + +/** + * \note Theoretically this interpolation does not need to compute all values at once. + * However, doing that makes the implementation simpler, and this can be optimized in the future if + * only some values are required. + */ +template +static void adapt_mesh_domain_point_to_polygon_impl(const Mesh &mesh, + const Span old_values, + MutableSpan r_values) +{ + BLI_assert(r_values.size() == mesh.totpoly); + attribute_math::DefaultMixer mixer(r_values); + + for (const int poly_index : IndexRange(mesh.totpoly)) { + const MPoly &poly = mesh.mpoly[poly_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + MLoop &loop = mesh.mloop[loop_index]; + const int point_index = loop.v; + mixer.mix_in(poly_index, old_values[point_index]); + } + } + mixer.finalize(); +} + +static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v>) { + Array values(mesh.totpoly); + adapt_mesh_domain_point_to_polygon_impl(mesh, attribute->get_span(), values); + new_attribute = std::make_unique>(ATTR_DOMAIN_POINT, + std::move(values)); + } + }); + return new_attribute; +} + } // namespace blender::bke ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute, @@ -277,6 +428,8 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr switch (new_domain) { case ATTR_DOMAIN_POINT: return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute)); + case ATTR_DOMAIN_POLYGON: + return blender::bke::adapt_mesh_domain_corner_to_polygon(*mesh_, std::move(attribute)); default: break; } @@ -286,9 +439,23 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr switch (new_domain) { case ATTR_DOMAIN_CORNER: return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute)); + case ATTR_DOMAIN_POLYGON: + return blender::bke::adapt_mesh_domain_point_to_polygon(*mesh_, std::move(attribute)); + default: + break; + } + break; + } + case ATTR_DOMAIN_POLYGON: { + switch (new_domain) { + case ATTR_DOMAIN_POINT: + return blender::bke::adapt_mesh_domain_polygon_to_point(*mesh_, std::move(attribute)); + case ATTR_DOMAIN_CORNER: + return blender::bke::adapt_mesh_domain_polygon_to_corner(*mesh_, std::move(attribute)); default: break; } + break; } default: break; -- cgit v1.2.3 From cfd7b4d1cd48ecffbf61d45dfa4f24ccda3d6a71 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Tue, 9 Mar 2021 16:02:40 -0300 Subject: BLI: New 'BLI_array_iter_spiral_square' No functional changes. This function replaces some of the logic in `DRW_select_buffer_find_nearest_to_point` that traverses a buffer in a spiral way to search for a closer pixel (not the closest). Differential Revision: https://developer.blender.org/D10548 --- source/blender/blenlib/BLI_array_utils.h | 8 ++ source/blender/blenlib/intern/array_utils.c | 97 ++++++++++++++++++++++++- source/blender/draw/intern/draw_select_buffer.c | 92 +++++++++-------------- 3 files changed, 135 insertions(+), 62 deletions(-) diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h index bd37d22023b..8f4630dd732 100644 --- a/source/blender/blenlib/BLI_array_utils.h +++ b/source/blender/blenlib/BLI_array_utils.h @@ -89,6 +89,14 @@ bool _bli_array_iter_span(const void *arr, bool _bli_array_is_zeroed(const void *arr, unsigned int arr_len, size_t arr_stride); #define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr))) +bool _bli_array_iter_spiral_square(const void *arr_v, + const int arr_shape[2], + const size_t elem_size, + const int center[2], + const bool (*test_fn)(const void *arr_item, void *user_data), + void *user_data); +#define BLI_array_iter_spiral_square(arr, arr_shape, center, test_fn, user_data) \ + _bli_array_iter_spiral_square(arr, arr_shape, sizeof(*(arr)), center, test_fn, user_data) #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c index 2da2bbbc2a5..5d35cf09c30 100644 --- a/source/blender/blenlib/intern/array_utils.c +++ b/source/blender/blenlib/intern/array_utils.c @@ -27,13 +27,13 @@ #include "MEM_guardedalloc.h" -#include "BLI_array_utils.h" - #include "BLI_alloca.h" +#include "BLI_math_base.h" +#include "BLI_strict_flags.h" #include "BLI_sys_types.h" #include "BLI_utildefines.h" -#include "BLI_strict_flags.h" +#include "BLI_array_utils.h" /** *In-place array reverse. @@ -318,3 +318,94 @@ bool _bli_array_is_zeroed(const void *arr_v, unsigned int arr_len, size_t arr_st } return true; } + +/** + * Smart function to sample a rect spiraling outside. + * Nice for selection ID. + * + * \param arr_shape: dimensions [w, h]. + * \param center: coordinates [x, y] indicating where to start transversing. + */ +bool _bli_array_iter_spiral_square(const void *arr_v, + const int arr_shape[2], + size_t elem_size, + const int center[2], + const bool (*test_fn)(const void *arr_item, void *user_data), + void *user_data) +{ + BLI_assert(center[0] >= 0 && center[1] >= 0 && center[0] < arr_shape[0] && + center[1] < arr_shape[1]); + + const char *arr = arr_v; + const int stride[2] = {arr_shape[1] * (int)elem_size, (int)elem_size}; + + /* Test center first. */ + int ofs[2] = {center[0] * stride[0], center[1] * stride[1]}; + if (test_fn(arr + ofs[0] + ofs[1], user_data)) { + return true; + } + + /* #steps_in and #steps_out are the "diameters" of the inscribed and ciscunscript squares in the + * rectangle. Each step smaller than #steps_in does not need to check bounds. */ + int steps_in, steps_out; + { + int x_minus = center[0]; + int x_plus = arr_shape[0] - center[0] - 1; + int y_minus = center[1]; + int y_plus = arr_shape[1] - center[1] - 1; + + steps_in = 2 * min_iiii(x_minus, x_plus, y_minus, y_plus); + steps_out = 2 * max_iiii(x_minus, x_plus, y_minus, y_plus); + } + + /* For check_bounds. */ + int limits[2] = {(arr_shape[0] - 1) * stride[0], stride[0] - stride[1]}; + + int steps = 0; + while (steps < steps_out) { + steps += 2; + + /* Move one step to the diagonal of the negative quadrant. */ + ofs[0] -= stride[0]; + ofs[1] -= stride[1]; + + bool check_bounds = steps > steps_in; + + /* sign: 0 neg; 1 pos; */ + for (int sign = 2; sign--;) { + /* axis: 0 x; 1 y; */ + for (int axis = 2; axis--;) { + int ofs_step = stride[axis]; + if (!sign) { + ofs_step *= -1; + } + + int ofs_iter = ofs[axis] + ofs_step; + int ofs_dest = ofs[axis] + steps * ofs_step; + int ofs_other = ofs[!axis]; + + ofs[axis] = ofs_dest; + if (check_bounds) { + if (ofs_other < 0 || ofs_other > limits[!axis]) { + /* Out of bounds. */ + continue; + } + + CLAMP(ofs_iter, 0, limits[axis]); + CLAMP(ofs_dest, 0, limits[axis]); + } + + while (true) { + if (test_fn(arr + ofs_other + ofs_iter, user_data)) { + return true; + } + if (ofs_iter == ofs_dest) { + break; + } + ofs_iter += ofs_step; + } + } + } + } + return false; +} diff --git a/source/blender/draw/intern/draw_select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c index b5151293c1b..d7438b7e0f0 100644 --- a/source/blender/draw/intern/draw_select_buffer.c +++ b/source/blender/draw/intern/draw_select_buffer.c @@ -24,6 +24,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_array_utils.h" #include "BLI_bitmap.h" #include "BLI_bitmap_draw_2d.h" #include "BLI_rect.h" @@ -336,6 +337,26 @@ uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph, return ret; } +struct SelectReadData { + const void *val_ptr; + uint id_min; + uint id_max; + uint r_index; +}; + +static bool select_buffer_test_fn(const void *__restrict value, void *__restrict userdata) +{ + struct SelectReadData *data = userdata; + uint hit_id = *(uint *)value; + if (hit_id && hit_id >= data->id_min && hit_id < data->id_max) { + /* Start at 1 to confirm. */ + data->val_ptr = value; + data->r_index = (hit_id - data->id_min) + 1; + return true; + } + return false; +} + /** * Find the selection id closest to \a center. * \param dist: Use to initialize the distance, @@ -349,13 +370,8 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, const uint id_max, uint *dist) { - /* Smart function to sample a rect spiraling outside, nice for selection ID. */ - /* Create region around center (typically the mouse cursor). - * This must be square and have an odd width, - * the spiraling algorithm does not work with arbitrary rectangles. */ - - uint index = 0; + * This must be square and have an odd width. */ rcti rect; BLI_rcti_init_pt_radius(&rect, center, *dist); @@ -364,7 +380,6 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, int width = BLI_rcti_size_x(&rect); int height = width; - BLI_assert(width == height); /* Read from selection framebuffer. */ @@ -372,64 +387,23 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, const uint *buf = DRW_select_buffer_read(depsgraph, region, v3d, &rect, &buf_len); if (buf == NULL) { - return index; + return 0; } - BLI_assert(width * height == buf_len); - - /* Spiral, starting from center of buffer. */ - int spiral_offset = height * (int)(width / 2) + (height / 2); - int spiral_direction = 0; - - for (int nr = 1; nr <= height; nr++) { - for (int a = 0; a < 2; a++) { - for (int b = 0; b < nr; b++) { - /* Find hit within the specified range. */ - uint hit_id = buf[spiral_offset]; - - if (hit_id && hit_id >= id_min && hit_id < id_max) { - /* Get x/y from spiral offset. */ - int hit_x = spiral_offset % width; - int hit_y = spiral_offset / width; - - int center_x = width / 2; - int center_y = height / 2; + const int shape[2] = {height, width}; + const int center_yx[2] = {(height - 1) / 2, (width - 1) / 2}; + struct SelectReadData data = {NULL, id_min, id_max, 0}; + BLI_array_iter_spiral_square(buf, shape, center_yx, select_buffer_test_fn, &data); - /* Manhattan distance in keeping with other screen-based selection. */ - *dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y)); - - /* Indices start at 1 here. */ - index = (hit_id - id_min) + 1; - goto exit; - } - - /* Next spiral step. */ - if (spiral_direction == 0) { - spiral_offset += 1; /* right */ - } - else if (spiral_direction == 1) { - spiral_offset -= width; /* down */ - } - else if (spiral_direction == 2) { - spiral_offset -= 1; /* left */ - } - else { - spiral_offset += width; /* up */ - } - - /* Stop if we are outside the buffer. */ - if (spiral_offset < 0 || spiral_offset >= buf_len) { - goto exit; - } - } - - spiral_direction = (spiral_direction + 1) % 4; - } + if (data.val_ptr) { + size_t offset = ((size_t)data.val_ptr - (size_t)buf) / sizeof(*buf); + int hit_x = offset % width; + int hit_y = offset / width; + *dist = (uint)(abs(hit_y - center_yx[0]) + abs(hit_x - center_yx[1])); } -exit: MEM_freeN((void *)buf); - return index; + return data.r_index; } /** \} */ -- cgit v1.2.3 From dcd7dacc4fd8d72f3388268959b1324f7aae95e4 Mon Sep 17 00:00:00 2001 From: Wayde Moss Date: Tue, 9 Mar 2021 15:09:09 -0500 Subject: Graph Editor: FCurve Show Extrapolation Toggle Adds toggle to graph editor (View->Show Extrapolation). When disabled, then fcurves only draw over the keyframe range. For baked fcurves and ghost fcurves, the range is all sampled points. It is intended for frequent use so anybody could assign hotkey or add to quick favorites that's why GE-View is the best place for it. Show Extrapolation is the default. Reviewed By: sybren, Stan1, looch Differential Revision: http://developer.blender.org/D10442 --- release/scripts/startup/bl_ui/space_graph.py | 2 + source/blender/editors/space_graph/graph_draw.c | 139 +++++++++++++++++------- source/blender/makesdna/DNA_space_types.h | 1 + source/blender/makesrna/intern/rna_space.c | 5 + 4 files changed, 110 insertions(+), 37 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 6ece6a4c841..31e81d1454e 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -135,6 +135,8 @@ class GRAPH_MT_view(Menu): layout.separator() + layout.prop(st, "show_extrapolation") + layout.prop(st, "show_handles") layout.prop(st, "use_only_selected_curves_handles") diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 4752f62b58c..c5358cdfa5b 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -35,6 +35,7 @@ #include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" +#include "BKE_action.h" #include "BKE_anim_data.h" #include "BKE_context.h" #include "BKE_curve.h" @@ -579,8 +580,13 @@ static void draw_fcurve_samples(SpaceGraph *sipo, ARegion *region, FCurve *fcu) /* Helper func - just draw the F-Curve by sampling the visible region * (for drawing curves with modifiers). */ -static void draw_fcurve_curve( - bAnimContext *ac, ID *id, FCurve *fcu_, View2D *v2d, uint pos, const bool use_nla_remap) +static void draw_fcurve_curve(bAnimContext *ac, + ID *id, + FCurve *fcu_, + View2D *v2d, + uint pos, + const bool use_nla_remap, + const bool draw_extrapolation) { SpaceGraph *sipo = (SpaceGraph *)ac->sl; short mapping_flag = ANIM_get_normalization_flags(ac); @@ -641,40 +647,90 @@ static void draw_fcurve_curve( /* the start/end times are simply the horizontal extents of the 'cur' rect */ float stime = v2d->cur.xmin; - float etime = v2d->cur.xmax + - samplefreq; /* + samplefreq here so that last item gets included... */ + float etime = v2d->cur.xmax; - /* at each sampling interval, add a new vertex - * - apply the unit correction factor to the calculated values so that - * the displayed values appear correctly in the viewport - */ + AnimData *adt = use_nla_remap ? BKE_animdata_from_id(id) : NULL; + + /* If not drawing extrapolation, then change fcurve drawing bounds to its keyframe bounds clamped + * by graph editor bounds. */ + if (!draw_extrapolation) { + float fcu_start = 0; + float fcu_end = 0; + BKE_fcurve_calc_range(fcu_, &fcu_start, &fcu_end, false, false); - int n = roundf((etime - stime) / samplefreq); + fcu_start = BKE_nla_tweakedit_remap(adt, fcu_start, NLATIME_CONVERT_MAP); + fcu_end = BKE_nla_tweakedit_remap(adt, fcu_end, NLATIME_CONVERT_MAP); - if (n > 0) { - immBegin(GPU_PRIM_LINE_STRIP, (n + 1)); + /* Account for reversed NLA strip effect. */ + if (fcu_end < fcu_start) { + SWAP(float, fcu_start, fcu_end); + } - AnimData *adt = use_nla_remap ? BKE_animdata_from_id(id) : NULL; - /* NLA remapping is linear so we don't have to remap per iteration. */ - const float eval_start = BKE_nla_tweakedit_remap(adt, stime, NLATIME_CONVERT_UNMAP); - const float eval_freq = BKE_nla_tweakedit_remap( - adt, stime + samplefreq, NLATIME_CONVERT_UNMAP) - - eval_start; + /* Clamp to graph editor rendering bounds. */ + stime = max_ff(stime, fcu_start); + etime = min_ff(etime, fcu_end); + } + + const int total_samples = roundf((etime - stime) / samplefreq); + if (total_samples <= 0) { + return; + } - for (int i = 0; i <= n; i++) { - float ctime = stime + i * samplefreq; - const float eval_time = eval_start + i * eval_freq; - immVertex2f(pos, ctime, (evaluate_fcurve(&fcurve_for_draw, eval_time) + offset) * unitFac); + /* NLA remapping is linear so we don't have to remap per iteration. */ + const float eval_start = BKE_nla_tweakedit_remap(adt, stime, NLATIME_CONVERT_UNMAP); + const float eval_freq = BKE_nla_tweakedit_remap(adt, stime + samplefreq, NLATIME_CONVERT_UNMAP) - + eval_start; + const float eval_end = BKE_nla_tweakedit_remap(adt, etime, NLATIME_CONVERT_UNMAP); + + immBegin(GPU_PRIM_LINE_STRIP, (total_samples + 1)); + + /* At each sampling interval, add a new vertex. + * + * Apply the unit correction factor to the calculated values so that the displayed values appear + * correctly in the viewport. + */ + for (int i = 0; i < total_samples; i++) { + const float ctime = stime + i * samplefreq; + float eval_time = eval_start + i * eval_freq; + + /* Prevent drawing past bounds, due to floating point problems. + * User-wise, prevent visual flickering. + * + * This is to cover the case where: + * eval_start + total_samples * eval_freq > eval_end + * due to floating point problems. + */ + if (eval_time > eval_end) { + eval_time = eval_end; } - immEnd(); + immVertex2f(pos, ctime, (evaluate_fcurve(&fcurve_for_draw, eval_time) + offset) * unitFac); } + + /* Ensure we include end boundary point. + * User-wise, prevent visual flickering. + * + * This is to cover the case where: + * eval_start + total_samples * eval_freq < eval_end + * due to floating point problems. + */ + immVertex2f(pos, etime, (evaluate_fcurve(&fcurve_for_draw, eval_end) + offset) * unitFac); + + immEnd(); } /* helper func - draw a samples-based F-Curve */ -static void draw_fcurve_curve_samples( - bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, const uint shdr_pos) +static void draw_fcurve_curve_samples(bAnimContext *ac, + ID *id, + FCurve *fcu, + View2D *v2d, + const uint shdr_pos, + const bool draw_extrapolation) { + if (!draw_extrapolation && fcu->totvert == 1) { + return; + } + FPoint *prevfpt = fcu->fpt; FPoint *fpt = prevfpt + 1; float fac, v[2]; @@ -683,11 +739,13 @@ static void draw_fcurve_curve_samples( short mapping_flag = ANIM_get_normalization_flags(ac); int count = fcu->totvert; - if (prevfpt->vec[0] > v2d->cur.xmin) { + const bool extrap_left = draw_extrapolation && prevfpt->vec[0] > v2d->cur.xmin; + if (extrap_left) { count++; } - if ((prevfpt + b - 1)->vec[0] < v2d->cur.xmax) { + const bool extrap_right = draw_extrapolation && (prevfpt + b - 1)->vec[0] < v2d->cur.xmax; + if (extrap_right) { count++; } @@ -700,7 +758,7 @@ static void draw_fcurve_curve_samples( immBegin(GPU_PRIM_LINE_STRIP, count); /* extrapolate to left? - left-side of view comes before first keyframe? */ - if (prevfpt->vec[0] > v2d->cur.xmin) { + if (extrap_left) { v[0] = v2d->cur.xmin; /* y-value depends on the interpolation */ @@ -734,7 +792,7 @@ static void draw_fcurve_curve_samples( } /* extrapolate to right? (see code for left-extrapolation above too) */ - if (prevfpt->vec[0] < v2d->cur.xmax) { + if (extrap_right) { v[0] = v2d->cur.xmax; /* y-value depends on the interpolation */ @@ -779,8 +837,13 @@ static bool fcurve_can_use_simple_bezt_drawing(FCurve *fcu) } /* helper func - draw one repeat of an F-Curve (using Bezier curve approximations) */ -static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, uint pos) +static void draw_fcurve_curve_bezts( + bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, uint pos, const bool draw_extrapolation) { + if (!draw_extrapolation && fcu->totvert == 1) { + return; + } + BezTriple *prevbezt = fcu->bezt; BezTriple *bezt = prevbezt + 1; float v1[2], v2[2], v3[2], v4[2]; @@ -803,7 +866,7 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2 immBeginAtMost(GPU_PRIM_LINE_STRIP, (b * 32 + 3)); /* extrapolate to left? */ - if (prevbezt->vec[1][0] > v2d->cur.xmin) { + if (draw_extrapolation && prevbezt->vec[1][0] > v2d->cur.xmin) { /* left-side of view comes before first keyframe, so need to extend as not cyclic */ v1[0] = v2d->cur.xmin; @@ -923,7 +986,7 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2 } /* extrapolate to right? (see code for left-extrapolation above too) */ - if (prevbezt->vec[1][0] < v2d->cur.xmax) { + if (draw_extrapolation && prevbezt->vec[1][0] < v2d->cur.xmax) { v1[0] = v2d->cur.xmax; /* y-value depends on the interpolation */ @@ -1026,6 +1089,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn immUniformColor3fvAlpha(fcu->color, fcurve_display_alpha(fcu)); } + const bool draw_extrapolation = (sipo->flag & SIPO_NO_DRAW_EXTRAPOLATION) == 0; /* draw F-Curve */ if ((fcu->modifiers.first) || (fcu->flag & FCURVE_INT_VALUES)) { /* draw a curve affected by modifiers or only allowed to have integer values @@ -1039,25 +1103,25 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn * curve itself. Afterward, we go back and redo the keyframe remapping so the controls are * drawn properly. */ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, true, false); - draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, true); + draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, true, draw_extrapolation); ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, false, false); } else { - draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, false); + draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, false, draw_extrapolation); } } else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) { /* just draw curve based on defined data (i.e. no modifiers) */ if (fcu->bezt) { if (fcurve_can_use_simple_bezt_drawing(fcu)) { - draw_fcurve_curve_bezts(ac, ale->id, fcu, ®ion->v2d, shdr_pos); + draw_fcurve_curve_bezts(ac, ale->id, fcu, ®ion->v2d, shdr_pos, draw_extrapolation); } else { - draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, false); + draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, false, draw_extrapolation); } } else if (fcu->fpt) { - draw_fcurve_curve_samples(ac, ale->id, fcu, ®ion->v2d, shdr_pos); + draw_fcurve_curve_samples(ac, ale->id, fcu, ®ion->v2d, shdr_pos, draw_extrapolation); } } @@ -1278,6 +1342,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region immUniform1f("dash_width", 20.0f); immUniform1f("dash_factor", 0.5f); + const bool draw_extrapolation = (sipo->flag & SIPO_NO_DRAW_EXTRAPOLATION) == 0; /* the ghost curves are simply sampled F-Curves stored in sipo->runtime.ghost_curves */ for (fcu = sipo->runtime.ghost_curves.first; fcu; fcu = fcu->next) { /* set whatever color the curve has set @@ -1287,7 +1352,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region immUniformColor3fvAlpha(fcu->color, 0.5f); /* simply draw the stored samples */ - draw_fcurve_curve_samples(ac, NULL, fcu, ®ion->v2d, shdr_pos); + draw_fcurve_curve_samples(ac, NULL, fcu, ®ion->v2d, shdr_pos, draw_extrapolation); } immUnbindProgram(); diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 81fd7c45baa..98f652b04f8 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -492,6 +492,7 @@ typedef enum eGraphEdit_Flag { SIPO_NORMALIZE_FREEZE = (1 << 15), /* show markers region */ SIPO_SHOW_MARKERS = (1 << 16), + SIPO_NO_DRAW_EXTRAPOLATION = (1 << 17), } eGraphEdit_Flag; /* SpaceGraph.mode (Graph Editor Mode) */ diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index d0f366d6a18..affb17c7d8c 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -5681,6 +5681,11 @@ static void rna_def_space_graph(BlenderRNA *brna) "If any exists, show markers in a separate row at the bottom of the editor"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); + prop = RNA_def_property(srna, "show_extrapolation", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NO_DRAW_EXTRAPOLATION); + RNA_def_property_ui_text(prop, "Show Extrapolation", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); + /* editing */ prop = RNA_def_property(srna, "use_auto_merge_keyframes", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NOTRANSKEYCULL); -- cgit v1.2.3 From 7d827d0e9e1a396580be988313bfd9ee4273a517 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Tue, 9 Mar 2021 20:41:06 +0100 Subject: Fix T86422: Expand crashing with EEVEE enabled Using EEVEE (as well as some other actions like saving the file or tweaking mesh parameters) can cause a PBVH rebuild. The different sculpt tools can store PBVH nodes or other related data in their caches, so this data becomes invalid if the PBVH rebuilds during evaluation. This ensures that the PBVH does not rebuild while the cache of Expand is being used, like it already happens for brushes and filters. Reviewed By: JacquesLucke Maniphest Tasks: T86422 Differential Revision: https://developer.blender.org/D10675 --- source/blender/blenkernel/intern/paint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 08c5beedbf3..2e81b61ad8c 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1760,7 +1760,7 @@ void BKE_sculpt_update_object_before_eval(Object *ob) SculptSession *ss = ob->sculpt; if (ss && ss->building_vp_handle == false) { - if (!ss->cache && !ss->filter_cache) { + if (!ss->cache && !ss->filter_cache && !ss->expand_cache) { /* We free pbvh on changes, except in the middle of drawing a stroke * since it can't deal with changing PVBH node organization, we hope * topology does not change in the meantime .. weak. */ -- cgit v1.2.3 From 90520026e9cedfd080c649ae0d954a0d68e1c51a Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 9 Mar 2021 21:20:33 +0100 Subject: Fix: only follow first input of multi-input-socket when muted Otherwise muting a Join Geometry node has no effect, when there are multiple Join Geometry nodes in a row. --- source/blender/nodes/NOD_derived_node_tree.hh | 3 ++- source/blender/nodes/intern/derived_node_tree.cc | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index f1dbb2caf29..3529336baf6 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -132,7 +132,8 @@ class DInputSocket : public DSocket { DOutputSocket get_corresponding_group_node_output() const; Vector get_corresponding_group_input_sockets() const; - void foreach_origin_socket(FunctionRef callback) const; + void foreach_origin_socket(FunctionRef callback, + const bool follow_only_first_incoming_link = false) const; }; /* A (nullable) reference to an output socket and the context it is in. */ diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index c5f267470fd..36c64b00f47 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -168,10 +168,15 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const /* Call the given callback for every "real" origin socket. "Real" means that reroutes, muted nodes * and node groups are handled by this function. Origin sockets are ones where a node gets its * inputs from. */ -void DInputSocket::foreach_origin_socket(FunctionRef callback) const +void DInputSocket::foreach_origin_socket(FunctionRef callback, + const bool follow_only_first_incoming_link) const { BLI_assert(*this); - for (const OutputSocketRef *linked_socket : socket_ref_->as_input().linked_sockets()) { + Span linked_sockets_to_check = socket_ref_->as_input().linked_sockets(); + if (follow_only_first_incoming_link) { + linked_sockets_to_check = linked_sockets_to_check.take_front(1); + } + for (const OutputSocketRef *linked_socket : linked_sockets_to_check) { const NodeRef &linked_node = linked_socket->node(); DOutputSocket linked_dsocket{context_, linked_socket}; @@ -180,7 +185,7 @@ void DInputSocket::foreach_origin_socket(FunctionRef callback) co for (const InternalLinkRef *internal_link : linked_node.internal_links()) { if (&internal_link->to() == linked_socket) { DInputSocket input_of_muted_node{context_, &internal_link->from()}; - input_of_muted_node.foreach_origin_socket(callback); + input_of_muted_node.foreach_origin_socket(callback, true); } } } -- cgit v1.2.3 From 53b82efed66baddff3b7ef6c93a919ef10f4ef42 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Tue, 9 Mar 2021 19:09:53 +0100 Subject: Fix (unreported) geometry node attribute search not working in the Properties Editor Since rBb279fef85d1a, the nodes properties for geometry nodes using a texture are displayed in the Properties Editor. rB85421c4fab02 added an attribute search button, but this was missing still (gave just the regular text button) if this was displayed in the Properties Editor. ref b279fef85d1a / T86416 / D10671 / D10673 Maniphest Tasks: T86416 Differential Revision: https://developer.blender.org/D10674 --- source/blender/editors/space_node/node_templates.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index f0e3f5442cc..b0c0f660717 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -826,11 +826,22 @@ static void ui_node_draw_input( case SOCK_INT: case SOCK_BOOLEAN: case SOCK_RGBA: - case SOCK_STRING: uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE); uiItemDecoratorR( split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX); break; + case SOCK_STRING: { + const bNodeTree *node_tree = (const bNodeTree *)nodeptr.owner_id; + if (node_tree->type == NTREE_GEOMETRY) { + node_geometry_add_attribute_search_button(node_tree, node, &inputptr, row); + } + else { + uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE); + } + uiItemDecoratorR( + split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX); + break; + } default: add_dummy_decorator = true; } -- cgit v1.2.3