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