New Corner Pin node: uses explicit corner values for a plane warp transformation.
authorLukas Tönne <lukas.toenne@gmail.com>
Tue, 11 Mar 2014 13:07:49 +0000 (14:07 +0100)
committerLukas Tönne <lukas.toenne@gmail.com>
Tue, 11 Mar 2014 13:12:08 +0000 (14:12 +0100)
This was suggested by Christopher Barrett (terrachild). Corner pin is a common feature in compositing.

The corners for the plane warping can be defined by using vector node inputs to allow using perspective plane transformations without having to go via the MovieClip editor tracking data.
Uses the same math as the PlaneTrack node, but without the link to MovieClip and Object.

{F78199}

The code for PlaneTrack operations has been restructured a bit to share it with the CornerPin node.

* PlaneDistortCommonOperation.h/.cpp: Shared generic code for warping images based on 4 plane corners and a perspective matrix generated from these. Contains operation base classes for both the WarpImage and Mask operations.

* PlaneTrackOperation.h/.cpp: Current plane track node operations, based on the common code above. These add pointers to MovieClip and Object which define the track data from wich to read the corners.

* PlaneCornerPinOperation.h/.cpp: New corner pin variant, using explicit input sockets for the plane corners.

One downside of the current compositor design is that there is no concept of invariables (constants) that don't vary over the image space. This has already been an issue for Blur nodes (size input is usually constant except when "variable size" is enabled) and a few others. For the corner pin node it is necessary that the corner input sockets are also invariant. They have to be evaluated for each tile now, otherwise the data is not available. This in turn makes it necessary to make the operation "complex" and request full input buffers, which adds unnecessary overhead.

20 files changed:
release/scripts/startup/nodeitems_builtins.py
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/intern/node.c
source/blender/compositor/CMakeLists.txt
source/blender/compositor/intern/COM_Converter.cpp
source/blender/compositor/nodes/COM_CornerPinNode.cpp [new file with mode: 0644]
source/blender/compositor/nodes/COM_CornerPinNode.h [moved from source/blender/compositor/operations/COM_PlaneTrackMaskOperation.h with 56% similarity]
source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp
source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp [new file with mode: 0644]
source/blender/compositor/operations/COM_PlaneCornerPinOperation.h [new file with mode: 0644]
source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp [moved from source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp with 54% similarity]
source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h [moved from source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.h with 62% similarity]
source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp [deleted file]
source/blender/compositor/operations/COM_PlaneTrackOperation.cpp [moved from source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp with 65% similarity]
source/blender/compositor/operations/COM_PlaneTrackOperation.h [moved from source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h with 57% similarity]
source/blender/editors/space_node/drawnode.c
source/blender/nodes/CMakeLists.txt
source/blender/nodes/NOD_composite.h
source/blender/nodes/NOD_static_types.h
source/blender/nodes/composite/nodes/node_composite_cornerpin.c [new file with mode: 0644]

index 6ade49112151dad4e2116143c509cb4c232a1249..be989f0aee7901c08ea3846aa62b154bc26035f2 100644 (file)
@@ -349,6 +349,7 @@ compositor_node_categories = [
         NodeItem("CompositorNodeTransform"),
         NodeItem("CompositorNodeStabilize"),
         NodeItem("CompositorNodePlaneTrackDeform"),
+        NodeItem("CompositorNodeCornerPin"),
         ]),
     CompositorNodeCategory("CMP_GROUP", "Group", items=node_group_items),
     CompositorNodeCategory("CMP_LAYOUT", "Layout", items=[
index 59ea921e11e8b34df8fe6b30462453a51de23e99..af912b998c40a4c3dbfaa192591ddfc0def97b35 100644 (file)
@@ -897,6 +897,7 @@ void            ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
 
 #define CMP_NODE_MAP_RANGE     319
 #define CMP_NODE_PLANETRACKDEFORM      320
+#define CMP_NODE_CORNERPIN          321
 
 /* channel toggles */
 #define CMP_CHAN_RGB           1
index d6225560e325fc511fc5aaa924b39da946fc84dd..249fb5264feda3c4cbb5d44a45bcaad5c4a0e246 100644 (file)
@@ -3460,6 +3460,7 @@ static void registerCompositNodes(void)
        register_node_type_cmp_mask();
        register_node_type_cmp_trackpos();
        register_node_type_cmp_planetrackdeform();
+       register_node_type_cmp_cornerpin();
 }
 
 static void registerShaderNodes(void) 
index 11add975db55bd932072048bfaff7205aecbf129..cbb1017facd8bcf9af8e2e333c05b0adb0f8191d 100644 (file)
@@ -185,6 +185,8 @@ set(SRC
        nodes/COM_GlareNode.cpp
        nodes/COM_GlareNode.h
 
+       nodes/COM_CornerPinNode.cpp
+       nodes/COM_CornerPinNode.h
        nodes/COM_PlaneTrackDeformNode.cpp
        nodes/COM_PlaneTrackDeformNode.h
 
@@ -488,12 +490,12 @@ set(SRC
        operations/COM_ProjectorLensDistortionOperation.h
        operations/COM_ScreenLensDistortionOperation.cpp
        operations/COM_ScreenLensDistortionOperation.h
-       operations/COM_PlaneTrackCommonOperation.cpp
-       operations/COM_PlaneTrackCommonOperation.h
-       operations/COM_PlaneTrackMaskOperation.cpp
-       operations/COM_PlaneTrackMaskOperation.h
-       operations/COM_PlaneTrackWarpImageOperation.cpp
-       operations/COM_PlaneTrackWarpImageOperation.h
+       operations/COM_PlaneDistortCommonOperation.cpp
+       operations/COM_PlaneDistortCommonOperation.h
+       operations/COM_PlaneTrackOperation.cpp
+       operations/COM_PlaneTrackOperation.h
+       operations/COM_PlaneCornerPinOperation.cpp
+       operations/COM_PlaneCornerPinOperation.h
 
        #Filter operations
        operations/COM_ConvolutionFilterOperation.h
index 384cfbe47fa2a4fdb457d93476fade09bb979f56..7103b49f32f8ca0eadcc79ce61cb256f3d12240b 100644 (file)
@@ -49,6 +49,7 @@
 #include "COM_ConvertAlphaNode.h"
 #include "COM_ConvertOperation.h"
 #include "COM_Converter.h"
+#include "COM_CornerPinNode.h"
 #include "COM_CropNode.h"
 #include "COM_DefocusNode.h"
 #include "COM_DespeckleNode.h"
@@ -401,6 +402,9 @@ Node *Converter::convert(bNode *b_node, bool fast)
                case CMP_NODE_PLANETRACKDEFORM:
                        node = new PlaneTrackDeformNode(b_node);
                        break;
+               case CMP_NODE_CORNERPIN:
+                       node = new CornerPinNode(b_node);
+                       break;
                default:
                        node = new MuteNode(b_node);
                        break;
diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cpp b/source/blender/compositor/nodes/COM_CornerPinNode.cpp
new file mode 100644 (file)
index 0000000..3115be8
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor:
+ *             Lukas Toenne
+ */
+
+#include "COM_CornerPinNode.h"
+#include "COM_ExecutionSystem.h"
+
+#include "COM_PlaneCornerPinOperation.h"
+
+CornerPinNode::CornerPinNode(bNode *editorNode) : Node(editorNode)
+{
+}
+
+void CornerPinNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context)
+{
+       InputSocket *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 };
+
+       OutputSocket *output_warped_image = this->getOutputSocket(0);
+       OutputSocket *output_plane = this->getOutputSocket(1);
+
+       PlaneCornerPinWarpImageOperation *warp_image_operation = new PlaneCornerPinWarpImageOperation();
+       
+       input_image->relinkConnections(warp_image_operation->getInputSocket(0), 0, graph);
+       for (int i = 0; i < 4; ++i) {
+               int node_index = node_corner_index[i];
+               getInputSocket(node_index)->relinkConnections(warp_image_operation->getInputSocket(i+1),
+                                                             node_index, graph);
+       }
+       output_warped_image->relinkConnections(warp_image_operation->getOutputSocket());
+       
+       graph->addOperation(warp_image_operation);
+       
+       PlaneCornerPinMaskOperation *plane_mask_operation = new PlaneCornerPinMaskOperation();
+       
+       /* connect mask op inputs to the same sockets as the warp image op */
+       for (int i = 0; i < 4; ++i)
+               addLink(graph,
+                       warp_image_operation->getInputSocket(i+1)->getConnection()->getFromSocket(),
+                       plane_mask_operation->getInputSocket(i));
+       output_plane->relinkConnections(plane_mask_operation->getOutputSocket());
+       
+       graph->addOperation(plane_mask_operation);
+}
similarity index 56%
rename from source/blender/compositor/operations/COM_PlaneTrackMaskOperation.h
rename to source/blender/compositor/nodes/COM_CornerPinNode.h
index 7f76395407963426a17fd29874a1954d69870d49..b8b8a16384c37c3f19950efcaa6a1eae243edde7 100644 (file)
@@ -1,6 +1,5 @@
-
 /*
- * Copyright 2013, Blender Foundation.
+ * Copyright 2014, Blender Foundation.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * Contributor:
- *             Sergey Sharybin
+ *             Lukas Toenne
  */
 
-#ifndef _COM_PlaneTrackMaskOperation_h
-#define _COM_PlaneTrackMaskOperation_h
-
-#include <string.h>
-
-#include "COM_PlaneTrackCommonOperation.h"
-
-#include "DNA_movieclip_types.h"
-#include "DNA_tracking_types.h"
+#ifndef _COM_CornerPinNode_h
+#define _COM_CornerPinNode_h
 
-#include "BLI_listbase.h"
-#include "BLI_string.h"
+#include "COM_Node.h"
 
-class PlaneTrackMaskOperation : public PlaneTrackCommonOperation {
-protected:
-       int m_osa;
-       float m_jitter[32][2];
+extern "C" {
+#include "DNA_node_types.h"
+}
 
+/**
+ * @brief CornerPinNode
+ * @ingroup Node
+ */
+class CornerPinNode : public Node {
 public:
-       PlaneTrackMaskOperation();
-
-       void initExecution();
-
-       void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+       CornerPinNode(bNode *editorNode);
+       void convertToOperations(ExecutionSystem *graph, CompositorContext *context);
 };
 
-#endif
+#endif /* _COM_CornerPinNode_h */
index f52c696b772c8adf4eefb7f87a2e8b0e922591fb..944e04e4f4fa534b4201bd3d8445cd7616bd2f94 100644 (file)
@@ -24,8 +24,7 @@
 #include "COM_PlaneTrackDeformNode.h"
 #include "COM_ExecutionSystem.h"
 
-#include "COM_PlaneTrackMaskOperation.h"
-#include "COM_PlaneTrackWarpImageOperation.h"
+#include "COM_PlaneTrackOperation.h"
 
 extern "C" {
 #  include "BKE_node.h"
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
new file mode 100644 (file)
index 0000000..fe27200
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2014, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor:
+ *             Lukas Toenne
+ */
+
+#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"
+
+extern "C" {
+#  include "BLI_jitter.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() :
+    PlaneDistortMaskOperation(),
+    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);
+               
+               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() :
+    PlaneDistortWarpImageOperation(),
+    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);
+               calculatePerspectiveMatrix();
+               
+               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;
+//     return PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(input, readOperation, output);
+}
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h
new file mode 100644 (file)
index 0000000..ed70d9c
--- /dev/null
@@ -0,0 +1,68 @@
+
+/*
+ * Copyright 2014, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor:
+ *             Lukas Toenne
+ */
+
+#ifndef _COM_CornerPinWarpImageOperation_h
+#define _COM_CornerPinWarpImageOperation_h
+
+#include <string.h>
+
+#include "COM_PlaneDistortCommonOperation.h"
+
+#include "DNA_movieclip_types.h"
+#include "DNA_tracking_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+
+class PlaneCornerPinMaskOperation : public PlaneDistortMaskOperation {
+private:
+       bool m_corners_ready;
+       
+public:
+       PlaneCornerPinMaskOperation();
+       
+       void initExecution();
+       void deinitExecution();
+       
+       void *initializeTileData(rcti *rect);
+       
+       void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
+};
+
+
+class PlaneCornerPinWarpImageOperation : public PlaneDistortWarpImageOperation {
+private:
+       bool m_corners_ready;
+       
+public:
+       PlaneCornerPinWarpImageOperation();
+       
+       void initExecution();
+       void deinitExecution();
+       
+       void *initializeTileData(rcti *rect);
+       
+       bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
+};
+
+#endif
similarity index 54%
rename from source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp
rename to source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
index 6579276fa9f809c86e475daab04d51f83872ddfc..362d7f6d2d7dfb2f3c2103f531bada83cf6a3362 100644 (file)
  *
  * Contributor:
  *             Sergey Sharybin
+ *             Lukas Toenne
  */
 
-#include "COM_PlaneTrackWarpImageOperation.h"
-#include "COM_ReadBufferOperation.h"
+#include "COM_PlaneDistortCommonOperation.h"
 
 #include "MEM_guardedalloc.h"
 
+extern "C" {
 #include "BLI_listbase.h"
 #include "BLI_math.h"
 #include "BLI_math_color.h"
+#include "BLI_jitter.h"
 
-extern "C" {
-#  include "BLI_jitter.h"
-
-#  include "BKE_movieclip.h"
-#  include "BKE_node.h"
-#  include "BKE_tracking.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};
@@ -49,7 +50,8 @@ BLI_INLINE void warpCoord(float x, float y, float matrix[3][3], float uv[2], flo
        deriv[1][1] = (matrix[1][1] - matrix[1][2] * uv[1]) / vec[2];
 }
 
-PlaneTrackWarpImageOperation::PlaneTrackWarpImageOperation() : PlaneTrackCommonOperation()
+PlaneDistortWarpImageOperation::PlaneDistortWarpImageOperation() :
+    NodeOperation()
 {
        this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE);
        this->addOutputSocket(COM_DT_COLOR);
@@ -57,12 +59,24 @@ PlaneTrackWarpImageOperation::PlaneTrackWarpImageOperation() : PlaneTrackCommonO
        this->setComplex(true);
 }
 
-void PlaneTrackWarpImageOperation::initExecution()
+void PlaneDistortWarpImageOperation::calculateCorners(const float corners[4][2], bool normalized)
 {
-       PlaneTrackCommonOperation::initExecution();
-
-       this->m_pixelReader = this->getInputSocketReader(0);
+       if (normalized) {
+               for (int i = 0; i < 4; i++) {
+                       this->m_frameSpaceCorners[i][0] = corners[i][0] * this->getWidth();
+                       this->m_frameSpaceCorners[i][1] = corners[i][1] * this->getHeight();
+               }
+       }
+       else {
+               for (int i = 0; i < 4; i++) {
+                       this->m_frameSpaceCorners[i][0] = corners[i][0];
+                       this->m_frameSpaceCorners[i][1] = corners[i][1];
+               }
+       }
+}
 
+void PlaneDistortWarpImageOperation::calculatePerspectiveMatrix()
+{
        const int width = this->m_pixelReader->getWidth();
        const int height = this->m_pixelReader->getHeight();
        float frame_corners[4][2] = {{0.0f, 0.0f},
@@ -74,12 +88,17 @@ void PlaneTrackWarpImageOperation::initExecution()
                                                  this->m_perspectiveMatrix);
 }
 
-void PlaneTrackWarpImageOperation::deinitExecution()
+void PlaneDistortWarpImageOperation::initExecution()
+{
+       this->m_pixelReader = this->getInputSocketReader(0);
+}
+
+void PlaneDistortWarpImageOperation::deinitExecution()
 {
        this->m_pixelReader = NULL;
 }
 
-void PlaneTrackWarpImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
 {
        float xy[2] = {x, y};
        float uv[2];
@@ -90,12 +109,12 @@ void PlaneTrackWarpImageOperation::executePixelSampled(float output[4], float x,
        m_pixelReader->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1], COM_PS_BILINEAR);
 }
 
-void PlaneTrackWarpImageOperation::pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2])
+void PlaneDistortWarpImageOperation::pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2])
 {
        warpCoord(xy[0], xy[1], m_perspectiveMatrix, r_uv, r_deriv);
 }
 
-bool PlaneTrackWarpImageOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
 {
        float UVs[4][2];
        float deriv[2][2];
@@ -121,3 +140,55 @@ bool PlaneTrackWarpImageOperation::determineDependingAreaOfInterest(rcti *input,
 
        return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
 }
+
+
+/* ******** PlaneDistort Mask ******** */
+
+PlaneDistortMaskOperation::PlaneDistortMaskOperation() :
+    NodeOperation()
+{
+       addOutputSocket(COM_DT_VALUE);
+
+       /* Currently hardcoded to 8 samples. */
+       m_osa = 8;
+}
+
+void PlaneDistortMaskOperation::calculateCorners(const float corners[4][2], bool normalized)
+{
+       if (normalized) {
+               for (int i = 0; i < 4; i++) {
+                       this->m_frameSpaceCorners[i][0] = corners[i][0] * this->getWidth();
+                       this->m_frameSpaceCorners[i][1] = corners[i][1] * this->getHeight();
+               }
+       }
+       else {
+               for (int i = 0; i < 4; i++) {
+                       this->m_frameSpaceCorners[i][0] = corners[i][0];
+                       this->m_frameSpaceCorners[i][1] = corners[i][1];
+               }
+       }
+}
+
+void PlaneDistortMaskOperation::initExecution()
+{
+       BLI_jitter_init(m_jitter[0], m_osa);
+}
+
+void PlaneDistortMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+{
+       float point[2];
+
+       int inside_counter = 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, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[1], this->m_frameSpaceCorners[2]) ||
+                   isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[2], this->m_frameSpaceCorners[3]))
+               {
+                       inside_counter++;
+               }
+       }
+
+       output[0] = (float) inside_counter / this->m_osa;
+}
similarity index 62%
rename from source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.h
rename to source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h
index ceb002c8039c53af2ce2c0f81fbe5e5dadcfcddf..ee2874c6b46bc0dfb1844075d1c2af6829346cad 100644 (file)
  *             Sergey Sharybin
  */
 
-#ifndef _COM_PlaneTrackWarpImageOperation_h
-#define _COM_PlaneTrackWarpImageOperation_h
+#ifndef _COM_PlaneTrackCommonOperation_h
+#define _COM_PlaneTrackCommonOperation_h
 
 #include <string.h>
 
-#include "COM_PlaneTrackCommonOperation.h"
+#include "COM_NodeOperation.h"
 
 #include "DNA_movieclip_types.h"
 #include "DNA_tracking_types.h"
 #include "BLI_listbase.h"
 #include "BLI_string.h"
 
-class PlaneTrackWarpImageOperation : public PlaneTrackCommonOperation {
+
+class PlaneDistortWarpImageOperation : public NodeOperation {
 protected:
        SocketReader *m_pixelReader;
+       float m_frameSpaceCorners[4][2];  /* Corners coordinates in pixel space. */
        float m_perspectiveMatrix[3][3];
 
 public:
-       PlaneTrackWarpImageOperation();
+       PlaneDistortWarpImageOperation();
+
+       void calculateCorners(const float corners[4][2], bool normalized);
+       void calculatePerspectiveMatrix();
 
        void initExecution();
        void deinitExecution();
@@ -50,4 +55,21 @@ public:
        bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
 };
 
+
+class PlaneDistortMaskOperation : public NodeOperation {
+protected:
+       int m_osa;
+       float m_jitter[32][2];
+       float m_frameSpaceCorners[4][2];  /* Corners coordinates in pixel space. */
+
+public:
+       PlaneDistortMaskOperation();
+       
+       void calculateCorners(const float corners[4][2], bool normalized);
+       
+       void initExecution();
+       
+       void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+};
+
 #endif
diff --git a/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp
deleted file mode 100644 (file)
index e43f6ab..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013, Blender Foundation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributor:
- *             Sergey Sharybin
- */
-
-#include "COM_PlaneTrackMaskOperation.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "BLI_math_color.h"
-
-extern "C" {
-#  include "BLI_jitter.h"
-
-#  include "BKE_movieclip.h"
-#  include "BKE_node.h"
-#  include "BKE_tracking.h"
-}
-
-PlaneTrackMaskOperation::PlaneTrackMaskOperation() : PlaneTrackCommonOperation()
-{
-       this->addOutputSocket(COM_DT_VALUE);
-
-       /* Currently hardcoded to 8 samples. */
-       this->m_osa = 8;
-}
-
-void PlaneTrackMaskOperation::initExecution()
-{
-       PlaneTrackCommonOperation::initExecution();
-
-       BLI_jitter_init(this->m_jitter[0], this->m_osa);
-}
-
-void PlaneTrackMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
-{
-       float point[2];
-
-       int inside_counter = 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, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[1], this->m_frameSpaceCorners[2]) ||
-                   isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[2], this->m_frameSpaceCorners[3]))
-               {
-                       inside_counter++;
-               }
-       }
-
-       output[0] = (float) inside_counter / this->m_osa;
-}
similarity index 65%
rename from source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp
rename to source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
index 5deb7b99bce04faf16d54b2b4e4b0e5049fb4c66..fec39cbfde02dbe0d16fe6d518f8086811993e43 100644 (file)
@@ -19,7 +19,8 @@
  *             Sergey Sharybin
  */
 
-#include "COM_PlaneTrackMaskOperation.h"
+#include "COM_PlaneTrackOperation.h"
+#include "COM_ReadBufferOperation.h"
 
 #include "MEM_guardedalloc.h"
 
 #include "BLI_math_color.h"
 
 extern "C" {
+#  include "BLI_jitter.h"
+
 #  include "BKE_movieclip.h"
 #  include "BKE_node.h"
 #  include "BKE_tracking.h"
 }
 
-PlaneTrackCommonOperation::PlaneTrackCommonOperation() : NodeOperation()
+/* ******** PlaneTrackCommon ******** */
+
+PlaneTrackCommon::PlaneTrackCommon()
 {
        this->m_movieClip = NULL;
        this->m_framenumber = 0;
@@ -41,55 +46,72 @@ PlaneTrackCommonOperation::PlaneTrackCommonOperation() : NodeOperation()
        this->m_planeTrackName[0] = '\0';
 }
 
-void PlaneTrackCommonOperation::initExecution()
+void PlaneTrackCommon::readCornersFromTrack(float corners[4][2])
 {
        MovieTracking *tracking;
        MovieTrackingObject *object;
 
-       memset(this->m_corners, 0, sizeof(this->m_corners));
-       memset(this->m_frameSpaceCorners, 0, sizeof(this->m_frameSpaceCorners));
-
        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) {
                        MovieTrackingPlaneMarker *plane_marker;
                        int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber);
-
+                       
                        plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr);
-                       memcpy(this->m_corners, plane_marker->corners, sizeof(this->m_corners));
+                       copy_v2_v2(corners[0], plane_marker->corners[0]);
+                       copy_v2_v2(corners[1], plane_marker->corners[1]);
+                       copy_v2_v2(corners[2], plane_marker->corners[2]);
+                       copy_v2_v2(corners[3], plane_marker->corners[3]);
                }
        }
-
-       for (int i = 0; i < 4; i++) {
-               this->m_frameSpaceCorners[i][0] = this->m_corners[i][0] * this->getWidth();
-               this->m_frameSpaceCorners[i][1] = this->m_corners[i][1] * this->getHeight();
-       }
 }
 
-void PlaneTrackCommonOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void PlaneTrackCommon::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
 {
-       NodeOperation::determineResolution(resolution, preferredResolution);
-
        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];
+       readCornersFromTrack(corners);
+       calculateCorners(corners, true);
+}
+
+/* ******** PlaneTrackWarpImageOperation ******** */
+
+void PlaneTrackWarpImageOperation::initExecution()
+{
+       PlaneDistortWarpImageOperation::initExecution();
+       
+       float corners[4][2];
+       readCornersFromTrack(corners);
+       calculateCorners(corners, true);
+       calculatePerspectiveMatrix();
+}
similarity index 57%
rename from source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h
rename to source/blender/compositor/operations/COM_PlaneTrackOperation.h
index 705bdf4bd816bbae4e8987228d3b2cbf1f8a5384..fdca760650ac86d0ea1836ae37c34bc356c98fe6 100644 (file)
  *             Sergey Sharybin
  */
 
-#ifndef _COM_PlaneTrackCommonOperation_h
-#define _COM_PlaneTrackCommonOperation_h
+#ifndef _COM_PlaneTrackWarpImageOperation_h
+#define _COM_PlaneTrackWarpImageOperation_h
 
 #include <string.h>
 
-#include "COM_NodeOperation.h"
+#include "COM_PlaneDistortCommonOperation.h"
 
 #include "DNA_movieclip_types.h"
 #include "DNA_tracking_types.h"
 #include "BLI_listbase.h"
 #include "BLI_string.h"
 
-class PlaneTrackCommonOperation : public NodeOperation {
+class PlaneTrackCommon {
 protected:
        MovieClip *m_movieClip;
        int m_framenumber;
        char m_trackingObjectName[64];
        char m_planeTrackName[64];
 
-       float m_corners[4][2];            /* Corners coordinates in normalized space. */
-       float m_frameSpaceCorners[4][2];  /* Corners coordinates in pixel space. */
-
-       /**
-        * Determine the output resolution. The resolution is retrieved from the Renderer
+       /* note: this class is not an operation itself (to prevent virtual inheritance issues)
+        * implementation classes must make wrappers to use these methods, see below.
         */
+       void readCornersFromTrack(float corners[4][2]);
        void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
 
 public:
-       PlaneTrackCommonOperation();
+       PlaneTrackCommon();
 
        void setMovieClip(MovieClip *clip) {this->m_movieClip = clip;}
        void setTrackingObject(char *object) { BLI_strncpy(this->m_trackingObjectName, object, sizeof(this->m_trackingObjectName)); }
        void setPlaneTrackName(char *plane_track) { BLI_strncpy(this->m_planeTrackName, plane_track, sizeof(this->m_planeTrackName)); }
        void setFramenumber(int framenumber) {this->m_framenumber = framenumber;}
+};
+
 
+class PlaneTrackMaskOperation : public PlaneDistortMaskOperation, public PlaneTrackCommon {
+public:
+       PlaneTrackMaskOperation() :
+           PlaneDistortMaskOperation(),
+           PlaneTrackCommon()
+       {}
+
+       void initExecution();
+
+       void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+       {
+               PlaneTrackCommon::determineResolution(resolution, preferredResolution);
+       }
+};
+
+
+class PlaneTrackWarpImageOperation : public PlaneDistortWarpImageOperation, public PlaneTrackCommon {
+public:
+       PlaneTrackWarpImageOperation() :
+           PlaneDistortWarpImageOperation(),
+           PlaneTrackCommon()
+       {}
+       
        void initExecution();
+       
+       void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+       {
+               PlaneTrackCommon::determineResolution(resolution, preferredResolution);
+       }
 };
 
 #endif
index 0cdb17cb2d490ba8669f76ada7a1d8fa607422ba..d534eefb0a19e6f4bd648541426b1eb954758b5b 100644 (file)
@@ -2280,6 +2280,10 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
        }
 }
 
+static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout), bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
+{
+}
+
 /* only once called */
 static void node_composit_set_butfunc(bNodeType *ntype)
 {
@@ -2501,6 +2505,9 @@ static void node_composit_set_butfunc(bNodeType *ntype)
                case CMP_NODE_PLANETRACKDEFORM:
                        ntype->draw_buttons = node_composit_buts_planetrackdeform;
                        break;
+               case CMP_NODE_CORNERPIN:
+                       ntype->draw_buttons = node_composit_buts_cornerpin;
+                       break;
        }
 }
 
index 16671e84da0d3ad09bf8839113da9adfe53d64d8..fef6762d6959da6060fc089dd563cce3bb740ec8 100644 (file)
@@ -56,6 +56,7 @@ set(SRC
        composite/nodes/node_composite_colorbalance.c
        composite/nodes/node_composite_common.c
        composite/nodes/node_composite_composite.c
+       composite/nodes/node_composite_cornerpin.c
        composite/nodes/node_composite_crop.c
        composite/nodes/node_composite_curves.c
        composite/nodes/node_composite_despeckle.c
index 782651541255881c0be13f20ff3271aaa9630aee..ad5f35b8faad976dbe2af002401310e67c8881b8 100644 (file)
@@ -136,6 +136,7 @@ void register_node_type_cmp_switch(void);
 void register_node_type_cmp_pixelate(void);
 void register_node_type_cmp_trackpos(void);
 void register_node_type_cmp_planetrackdeform(void);
+void register_node_type_cmp_cornerpin(void);
 
 void node_cmp_rlayers_force_hidden_passes(struct bNode *node);
 
index f7f7118822f8f456699064a212aa7e780693a838..b406ac490086d31eb548b8d04ee7fb352938c1b6 100644 (file)
@@ -204,6 +204,7 @@ DefNode( CompositorNode, CMP_NODE_KEYING,         def_cmp_keying,         "KEYIN
 DefNode( CompositorNode, CMP_NODE_TRACKPOS,       def_cmp_trackpos,       "TRACKPOS",       TrackPos,         "Track Position",    ""              )
 DefNode( CompositorNode, CMP_NODE_PIXELATE,       0,                      "PIXELATE",       Pixelate,         "Pixelate",          ""              )
 DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform",""              )
+DefNode( CompositorNode, CMP_NODE_CORNERPIN,      0,                      "CORNERPIN",      CornerPin,        "Corner Pin",        ""              )
 
 DefNode( TextureNode,    TEX_NODE_OUTPUT,         def_tex_output,         "OUTPUT",         Output,           "Output",            ""              )
 DefNode( TextureNode,    TEX_NODE_CHECKER,        0,                      "CHECKER",        Checker,          "Checker",           ""              )
diff --git a/source/blender/nodes/composite/nodes/node_composite_cornerpin.c b/source/blender/nodes/composite/nodes/node_composite_cornerpin.c
new file mode 100644 (file)
index 0000000..851bf92
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation,
+ *                 Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_planetrackdeform.c
+ *  \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+static bNodeSocketTemplate inputs[] = {
+       {   SOCK_RGBA,      1, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+       {   SOCK_VECTOR,    1, N_("Upper Left"), 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+       {   SOCK_VECTOR,    1, N_("Upper Right"), 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+       {   SOCK_VECTOR,    1, N_("Lower Left"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+       {   SOCK_VECTOR,    1, N_("Lower Right"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+       {   -1, 0, ""   }
+};
+
+static bNodeSocketTemplate outputs[] = {
+       {       SOCK_RGBA,   0,  N_("Image")},
+       {       SOCK_FLOAT,  0,  N_("Plane")},
+       {       -1, 0, ""       }
+};
+
+void register_node_type_cmp_cornerpin(void)
+{
+       static bNodeType ntype;
+
+       cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT, 0);
+       node_type_socket_templates(&ntype, inputs, outputs);
+
+       nodeRegisterType(&ntype);
+}