Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_armature.h8
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_context.h1
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.hh11
-rw-r--r--source/blender/blenkernel/BKE_mesh_boolean_convert.h1
-rw-r--r--source/blender/blenkernel/BKE_node.h20
-rw-r--r--source/blender/blenkernel/CMakeLists.txt6
-rw-r--r--source/blender/blenkernel/intern/armature_pose.cc133
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc1546
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh499
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c7
-rw-r--r--source/blender/blenkernel/intern/context.c9
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc34
-rw-r--r--source/blender/blenkernel/intern/cryptomatte_test.cc46
-rw-r--r--source/blender/blenkernel/intern/displist.c12
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc173
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc938
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc207
-rw-r--r--source/blender/blenkernel/intern/geometry_component_volume.cc100
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc431
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc5
-rw-r--r--source/blender/blenkernel/intern/lib_id.c5
-rw-r--r--source/blender/blenkernel/intern/lib_override.c12
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc10
-rw-r--r--source/blender/blenkernel/intern/node.cc29
-rw-r--r--source/blender/blenkernel/intern/node_ui_storage.cc6
-rw-r--r--source/blender/blenkernel/intern/outliner_treehash.c4
-rw-r--r--source/blender/blenkernel/intern/paint.c2
-rw-r--r--source/blender/blenkernel/intern/particle.c4
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c10
-rw-r--r--source/blender/blenkernel/intern/screen.c8
-rw-r--r--source/blender/blenkernel/intern/simulation.cc1
-rw-r--r--source/blender/blenlib/BLI_array_utils.h8
-rw-r--r--source/blender/blenlib/BLI_linear_allocator.hh50
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h1
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh45
-rw-r--r--source/blender/blenlib/BLI_mesh_boolean.hh2
-rw-r--r--source/blender/blenlib/BLI_resource_collector.hh7
-rw-r--r--source/blender/blenlib/BLI_string_utils.h2
-rw-r--r--source/blender/blenlib/intern/array_utils.c97
-rw-r--r--source/blender/blenlib/intern/math_matrix.c10
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc208
-rw-r--r--source/blender/blenlib/intern/string_utils.c33
-rw-r--r--source/blender/blenlib/tests/BLI_linear_allocator_test.cc23
-rw-r--r--source/blender/blenlib/tests/BLI_mesh_boolean_test.cc79
-rw-r--r--source/blender/blenloader/BLO_readfile.h6
-rw-r--r--source/blender/blenloader/intern/readfile.c50
-rw-r--r--source/blender/blenloader/intern/readfile.h12
-rw-r--r--source/blender/blenloader/intern/versioning_250.c4
-rw-r--r--source/blender/blenloader/intern/versioning_280.c2
-rw-r--r--source/blender/blenloader/intern/versioning_290.c16
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.cc9
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.h2
-rw-r--r--source/blender/compositor/CMakeLists.txt444
-rw-r--r--source/blender/compositor/COM_compositor.h6
-rw-r--r--source/blender/compositor/intern/COM_CPUDevice.cc (renamed from source/blender/compositor/intern/COM_CPUDevice.cpp)4
-rw-r--r--source/blender/compositor/intern/COM_ChunkOrder.cc (renamed from source/blender/compositor/intern/COM_ChunkOrder.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_ChunkOrderHotspot.cc (renamed from source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp)13
-rw-r--r--source/blender/compositor/intern/COM_ChunkOrderHotspot.h5
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.cc (renamed from source/blender/compositor/intern/COM_CompositorContext.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_Converter.cc (renamed from source/blender/compositor/intern/COM_Converter.cpp)31
-rw-r--r--source/blender/compositor/intern/COM_Converter.h79
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc (renamed from source/blender/compositor/intern/COM_Debug.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_Device.cc (renamed from source/blender/compositor/intern/COM_Device.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_Device.h2
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cc (renamed from source/blender/compositor/intern/COM_ExecutionGroup.cpp)229
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.h55
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cc (renamed from source/blender/compositor/intern/COM_ExecutionSystem.cpp)48
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.h27
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cc (renamed from source/blender/compositor/intern/COM_MemoryBuffer.cpp)11
-rw-r--r--source/blender/compositor/intern/COM_MemoryProxy.cc (renamed from source/blender/compositor/intern/COM_MemoryProxy.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_MetaData.cc (renamed from source/blender/compositor/intern/COM_MetaData.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_Node.cc (renamed from source/blender/compositor/intern/COM_Node.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_NodeConverter.cc (renamed from source/blender/compositor/intern/COM_NodeConverter.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_NodeGraph.cc (renamed from source/blender/compositor/intern/COM_NodeGraph.cpp)6
-rw-r--r--source/blender/compositor/intern/COM_NodeGraph.h26
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.cc (renamed from source/blender/compositor/intern/COM_NodeOperation.cpp)8
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h8
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cc (renamed from source/blender/compositor/intern/COM_NodeOperationBuilder.cpp)65
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.h8
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.cc (renamed from source/blender/compositor/intern/COM_OpenCLDevice.cpp)10
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.h8
-rw-r--r--source/blender/compositor/intern/COM_SingleThreadedOperation.cc (renamed from source/blender/compositor/intern/COM_SingleThreadedOperation.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_SocketReader.cc (renamed from source/blender/compositor/intern/COM_SocketReader.cpp)0
-rw-r--r--source/blender/compositor/intern/COM_WorkPackage.cc (renamed from source/blender/compositor/intern/COM_WorkPackage.cpp)6
-rw-r--r--source/blender/compositor/intern/COM_WorkPackage.h30
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cc (renamed from source/blender/compositor/intern/COM_WorkScheduler.cpp)4
-rw-r--r--source/blender/compositor/intern/COM_compositor.cc (renamed from source/blender/compositor/intern/COM_compositor.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_AlphaOverNode.cc (renamed from source/blender/compositor/nodes/COM_AlphaOverNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BilateralBlurNode.cc (renamed from source/blender/compositor/nodes/COM_BilateralBlurNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BlurNode.cc (renamed from source/blender/compositor/nodes/COM_BlurNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BokehBlurNode.cc (renamed from source/blender/compositor/nodes/COM_BokehBlurNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BokehImageNode.cc (renamed from source/blender/compositor/nodes/COM_BokehImageNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BoxMaskNode.cc (renamed from source/blender/compositor/nodes/COM_BoxMaskNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_BrightnessNode.cc (renamed from source/blender/compositor/nodes/COM_BrightnessNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ChannelMatteNode.cc (renamed from source/blender/compositor/nodes/COM_ChannelMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ChromaMatteNode.cc (renamed from source/blender/compositor/nodes/COM_ChromaMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorBalanceNode.cc (renamed from source/blender/compositor/nodes/COM_ColorBalanceNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorCorrectionNode.cc (renamed from source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorCurveNode.cc (renamed from source/blender/compositor/nodes/COM_ColorCurveNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorExposureNode.cc (renamed from source/blender/compositor/nodes/COM_ColorExposureNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorMatteNode.cc (renamed from source/blender/compositor/nodes/COM_ColorMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorNode.cc (renamed from source/blender/compositor/nodes/COM_ColorNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorRampNode.cc (renamed from source/blender/compositor/nodes/COM_ColorRampNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorSpillNode.cc (renamed from source/blender/compositor/nodes/COM_ColorSpillNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ColorToBWNode.cc (renamed from source/blender/compositor/nodes/COM_ColorToBWNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.cc (renamed from source/blender/compositor/nodes/COM_CombineColorNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_CompositorNode.cc (renamed from source/blender/compositor/nodes/COM_CompositorNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ConvertAlphaNode.cc (renamed from source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_CornerPinNode.cc (renamed from source/blender/compositor/nodes/COM_CornerPinNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_CropNode.cc (renamed from source/blender/compositor/nodes/COM_CropNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cc (renamed from source/blender/compositor/nodes/COM_CryptomatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DefocusNode.cc (renamed from source/blender/compositor/nodes/COM_DefocusNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DenoiseNode.cc (renamed from source/blender/compositor/nodes/COM_DenoiseNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DespeckleNode.cc (renamed from source/blender/compositor/nodes/COM_DespeckleNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DifferenceMatteNode.cc (renamed from source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DilateErodeNode.cc (renamed from source/blender/compositor/nodes/COM_DilateErodeNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DirectionalBlurNode.cc (renamed from source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DisplaceNode.cc (renamed from source/blender/compositor/nodes/COM_DisplaceNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DistanceMatteNode.cc (renamed from source/blender/compositor/nodes/COM_DistanceMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc (renamed from source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_EllipseMaskNode.cc (renamed from source/blender/compositor/nodes/COM_EllipseMaskNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_FilterNode.cc (renamed from source/blender/compositor/nodes/COM_FilterNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_FlipNode.cc (renamed from source/blender/compositor/nodes/COM_FlipNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_GammaNode.cc (renamed from source/blender/compositor/nodes/COM_GammaNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_GlareNode.cc (renamed from source/blender/compositor/nodes/COM_GlareNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc (renamed from source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueNode.cc (renamed from source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_IDMaskNode.cc (renamed from source/blender/compositor/nodes/COM_IDMaskNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cc (renamed from source/blender/compositor/nodes/COM_ImageNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_InpaintNode.cc (renamed from source/blender/compositor/nodes/COM_InpaintNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_InvertNode.cc (renamed from source/blender/compositor/nodes/COM_InvertNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_KeyingNode.cc (renamed from source/blender/compositor/nodes/COM_KeyingNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_KeyingScreenNode.cc (renamed from source/blender/compositor/nodes/COM_KeyingScreenNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_LensDistortionNode.cc (renamed from source/blender/compositor/nodes/COM_LensDistortionNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_LuminanceMatteNode.cc (renamed from source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MapRangeNode.cc (renamed from source/blender/compositor/nodes/COM_MapRangeNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MapUVNode.cc (renamed from source/blender/compositor/nodes/COM_MapUVNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MapValueNode.cc (renamed from source/blender/compositor/nodes/COM_MapValueNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MaskNode.cc (renamed from source/blender/compositor/nodes/COM_MaskNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MathNode.cc (renamed from source/blender/compositor/nodes/COM_MathNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MixNode.cc (renamed from source/blender/compositor/nodes/COM_MixNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MovieClipNode.cc (renamed from source/blender/compositor/nodes/COM_MovieClipNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_MovieDistortionNode.cc (renamed from source/blender/compositor/nodes/COM_MovieDistortionNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_NormalNode.cc (renamed from source/blender/compositor/nodes/COM_NormalNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_NormalizeNode.cc (renamed from source/blender/compositor/nodes/COM_NormalizeNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.cc (renamed from source/blender/compositor/nodes/COM_OutputFileNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_PixelateNode.cc (renamed from source/blender/compositor/nodes/COM_PixelateNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc (renamed from source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.cc (renamed from source/blender/compositor/nodes/COM_RenderLayersNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_RotateNode.cc (renamed from source/blender/compositor/nodes/COM_RotateNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ScaleNode.cc (renamed from source/blender/compositor/nodes/COM_ScaleNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.cc (renamed from source/blender/compositor/nodes/COM_SeparateColorNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SetAlphaNode.cc (renamed from source/blender/compositor/nodes/COM_SetAlphaNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SocketProxyNode.cc (renamed from source/blender/compositor/nodes/COM_SocketProxyNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SplitViewerNode.cc (renamed from source/blender/compositor/nodes/COM_SplitViewerNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_Stabilize2dNode.cc (renamed from source/blender/compositor/nodes/COM_Stabilize2dNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SunBeamsNode.cc (renamed from source/blender/compositor/nodes/COM_SunBeamsNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SwitchNode.cc (renamed from source/blender/compositor/nodes/COM_SwitchNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_SwitchViewNode.cc (renamed from source/blender/compositor/nodes/COM_SwitchViewNode.cpp)2
-rw-r--r--source/blender/compositor/nodes/COM_TextureNode.cc (renamed from source/blender/compositor/nodes/COM_TextureNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_TimeNode.cc (renamed from source/blender/compositor/nodes/COM_TimeNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_TonemapNode.cc (renamed from source/blender/compositor/nodes/COM_TonemapNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_TrackPositionNode.cc (renamed from source/blender/compositor/nodes/COM_TrackPositionNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_TransformNode.cc (renamed from source/blender/compositor/nodes/COM_TransformNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_TranslateNode.cc (renamed from source/blender/compositor/nodes/COM_TranslateNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ValueNode.cc (renamed from source/blender/compositor/nodes/COM_ValueNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_VectorBlurNode.cc (renamed from source/blender/compositor/nodes/COM_VectorBlurNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_VectorCurveNode.cc (renamed from source/blender/compositor/nodes/COM_VectorCurveNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ViewLevelsNode.cc (renamed from source/blender/compositor/nodes/COM_ViewLevelsNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ViewerNode.cc (renamed from source/blender/compositor/nodes/COM_ViewerNode.cpp)0
-rw-r--r--source/blender/compositor/nodes/COM_ZCombineNode.cc (renamed from source/blender/compositor/nodes/COM_ZCombineNode.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc (renamed from source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc (renamed from source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc (renamed from source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.cc (renamed from source/blender/compositor/operations/COM_AntiAliasOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_BilateralBlurOperation.cc (renamed from source/blender/compositor/operations/COM_BilateralBlurOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cc (renamed from source/blender/compositor/operations/COM_BlurBaseOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.cc (renamed from source/blender/compositor/operations/COM_BokehBlurOperation.cpp)22
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_BokehImageOperation.cc (renamed from source/blender/compositor/operations/COM_BokehImageOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_BoxMaskOperation.cc (renamed from source/blender/compositor/operations/COM_BoxMaskOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_BrightnessOperation.cc (renamed from source/blender/compositor/operations/COM_BrightnessOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_CalculateMeanOperation.cc (renamed from source/blender/compositor/operations/COM_CalculateMeanOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc (renamed from source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ChangeHSVOperation.cc (renamed from source/blender/compositor/operations/COM_ChangeHSVOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ChannelMatteOperation.cc (renamed from source/blender/compositor/operations/COM_ChannelMatteOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_ChannelMatteOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_ChromaMatteOperation.cc (renamed from source/blender/compositor/operations/COM_ChromaMatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc (renamed from source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc (renamed from source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_ColorCorrectionOperation.cc (renamed from source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_ColorCurveOperation.cc (renamed from source/blender/compositor/operations/COM_ColorCurveOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ColorExposureOperation.cc (renamed from source/blender/compositor/operations/COM_ColorExposureOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ColorMatteOperation.cc (renamed from source/blender/compositor/operations/COM_ColorMatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ColorRampOperation.cc (renamed from source/blender/compositor/operations/COM_ColorRampOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ColorSpillOperation.cc (renamed from source/blender/compositor/operations/COM_ColorSpillOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cc (renamed from source/blender/compositor/operations/COM_CompositorOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc (renamed from source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc (renamed from source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp)6
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.cc (renamed from source/blender/compositor/operations/COM_ConvertOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc (renamed from source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp)8
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc (renamed from source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp)8
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.cc (renamed from source/blender/compositor/operations/COM_CropOperation.cpp)8
-rw-r--r--source/blender/compositor/operations/COM_CryptomatteOperation.cc (renamed from source/blender/compositor/operations/COM_CryptomatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_CurveBaseOperation.cc (renamed from source/blender/compositor/operations/COM_CurveBaseOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DenoiseOperation.cc (renamed from source/blender/compositor/operations/COM_DenoiseOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DespeckleOperation.cc (renamed from source/blender/compositor/operations/COM_DespeckleOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DifferenceMatteOperation.cc (renamed from source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cc (renamed from source/blender/compositor/operations/COM_DilateErodeOperation.cpp)96
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.cc (renamed from source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_DisplaceOperation.cc (renamed from source/blender/compositor/operations/COM_DisplaceOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc (renamed from source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc (renamed from source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc (renamed from source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DotproductOperation.cc (renamed from source/blender/compositor/operations/COM_DotproductOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc (renamed from source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_EllipseMaskOperation.cc (renamed from source/blender/compositor/operations/COM_EllipseMaskOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc (renamed from source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_FlipOperation.cc (renamed from source/blender/compositor/operations/COM_FlipOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GammaCorrectOperation.cc (renamed from source/blender/compositor/operations/COM_GammaCorrectOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GammaOperation.cc (renamed from source/blender/compositor/operations/COM_GammaOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc (renamed from source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc (renamed from source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc (renamed from source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_GaussianXBlurOperation.cc (renamed from source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_GaussianXBlurOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_GaussianYBlurOperation.cc (renamed from source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_GaussianYBlurOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_GlareBaseOperation.cc (renamed from source/blender/compositor/operations/COM_GlareBaseOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GlareFogGlowOperation.cc (renamed from source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GlareGhostOperation.cc (renamed from source/blender/compositor/operations/COM_GlareGhostOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc (renamed from source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GlareStreaksOperation.cc (renamed from source/blender/compositor/operations/COM_GlareStreaksOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_GlareThresholdOperation.cc (renamed from source/blender/compositor/operations/COM_GlareThresholdOperation.cpp)6
-rw-r--r--source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc (renamed from source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_IDMaskOperation.cc (renamed from source/blender/compositor/operations/COM_IDMaskOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cc (renamed from source/blender/compositor/operations/COM_ImageOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.cc (renamed from source/blender/compositor/operations/COM_InpaintOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_InvertOperation.cc (renamed from source/blender/compositor/operations/COM_InvertOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_KeyingBlurOperation.cc (renamed from source/blender/compositor/operations/COM_KeyingBlurOperation.cpp)6
-rw-r--r--source/blender/compositor/operations/COM_KeyingClipOperation.cc (renamed from source/blender/compositor/operations/COM_KeyingClipOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_KeyingDespillOperation.cc (renamed from source/blender/compositor/operations/COM_KeyingDespillOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_KeyingOperation.cc (renamed from source/blender/compositor/operations/COM_KeyingOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.cc (renamed from source/blender/compositor/operations/COM_KeyingScreenOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_LuminanceMatteOperation.cc (renamed from source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_MapRangeOperation.cc (renamed from source/blender/compositor/operations/COM_MapRangeOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cc (renamed from source/blender/compositor/operations/COM_MapUVOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MapValueOperation.cc (renamed from source/blender/compositor/operations/COM_MapValueOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.cc (renamed from source/blender/compositor/operations/COM_MaskOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.cc (renamed from source/blender/compositor/operations/COM_MathBaseOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.cc (renamed from source/blender/compositor/operations/COM_MixOperation.cpp)6
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc (renamed from source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MovieClipOperation.cc (renamed from source/blender/compositor/operations/COM_MovieClipOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cc (renamed from source/blender/compositor/operations/COM_MovieDistortionOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.cc (renamed from source/blender/compositor/operations/COM_MultilayerImageOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_NormalizeOperation.cc (renamed from source/blender/compositor/operations/COM_NormalizeOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc (renamed from source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cc (renamed from source/blender/compositor/operations/COM_OutputFileOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_PixelateOperation.cc (renamed from source/blender/compositor/operations/COM_PixelateOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc (renamed from source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc (renamed from source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cc (renamed from source/blender/compositor/operations/COM_PlaneTrackOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_PreviewOperation.cc (renamed from source/blender/compositor/operations/COM_PreviewOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc (renamed from source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_QualityStepHelper.cc (renamed from source/blender/compositor/operations/COM_QualityStepHelper.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ReadBufferOperation.cc (renamed from source/blender/compositor/operations/COM_ReadBufferOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cc (renamed from source/blender/compositor/operations/COM_RenderLayersProg.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_RotateOperation.cc (renamed from source/blender/compositor/operations/COM_RotateOperation.cpp)8
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.cc (renamed from source/blender/compositor/operations/COM_ScaleOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc (renamed from source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc (renamed from source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc (renamed from source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.cc (renamed from source/blender/compositor/operations/COM_SetColorOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetSamplerOperation.cc (renamed from source/blender/compositor/operations/COM_SetSamplerOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.cc (renamed from source/blender/compositor/operations/COM_SetValueOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SetVectorOperation.cc (renamed from source/blender/compositor/operations/COM_SetVectorOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SocketProxyOperation.cc (renamed from source/blender/compositor/operations/COM_SocketProxyOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.cc (renamed from source/blender/compositor/operations/COM_SplitOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.cc (renamed from source/blender/compositor/operations/COM_SunBeamsOperation.cpp)2
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cc (renamed from source/blender/compositor/operations/COM_TextureOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.cc (renamed from source/blender/compositor/operations/COM_TonemapOperation.cpp)6
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.cc (renamed from source/blender/compositor/operations/COM_TrackPositionOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.cc (renamed from source/blender/compositor/operations/COM_TranslateOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc (renamed from source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp)22
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cc (renamed from source/blender/compositor/operations/COM_VectorBlurOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_VectorCurveOperation.cc (renamed from source/blender/compositor/operations/COM_VectorCurveOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cc (renamed from source/blender/compositor/operations/COM_ViewerOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_WrapOperation.cc (renamed from source/blender/compositor/operations/COM_WrapOperation.cpp)0
-rw-r--r--source/blender/compositor/operations/COM_WriteBufferOperation.cc (renamed from source/blender/compositor/operations/COM_WriteBufferOperation.cpp)4
-rw-r--r--source/blender/compositor/operations/COM_ZCombineOperation.cc (renamed from source/blender/compositor/operations/COM_ZCombineOperation.cpp)4
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c176
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c20
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h35
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c24
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c16
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows.c8
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl92
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl32
-rw-r--r--source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl12
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl25
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl58
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl76
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/lights_lib.glsl33
-rw-r--r--source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl392
-rw-r--r--source/blender/draw/engines/eevee/shaders/ssr_lib.glsl21
-rw-r--r--source/blender/draw/intern/draw_select_buffer.c92
-rw-r--r--source/blender/draw/intern/shaders/common_math_lib.glsl6
-rw-r--r--source/blender/editors/CMakeLists.txt1
-rw-r--r--source/blender/editors/animation/anim_markers.c22
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c18
-rw-r--r--source/blender/editors/armature/armature_select.c17
-rw-r--r--source/blender/editors/armature/pose_slide.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c6
-rw-r--r--source/blender/editors/include/ED_fileselect.h7
-rw-r--r--source/blender/editors/include/ED_space_api.h1
-rw-r--r--source/blender/editors/interface/interface_handlers.c4
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.c1
-rw-r--r--source/blender/editors/interface/interface_widgets.c24
-rw-r--r--source/blender/editors/interface/resources.c3
-rw-r--r--source/blender/editors/io/io_cache.c4
-rw-r--r--source/blender/editors/mesh/editmesh_add.c7
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c13
-rw-r--r--source/blender/editors/render/render_preview.c2
-rw-r--r--source/blender/editors/render/render_shading.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c335
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c353
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c21
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h1
-rw-r--r--source/blender/editors/space_api/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_api/spacetypes.c3
-rw-r--r--source/blender/editors/space_file/file_intern.h16
-rw-r--r--source/blender/editors/space_file/file_ops.c105
-rw-r--r--source/blender/editors/space_file/filelist.c74
-rw-r--r--source/blender/editors/space_file/filelist.h3
-rw-r--r--source/blender/editors/space_file/filesel.c60
-rw-r--r--source/blender/editors/space_file/space_file.c53
-rw-r--r--source/blender/editors/space_graph/graph_draw.c139
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c6
-rw-r--r--source/blender/editors/space_node/drawnode.c7
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc14
-rw-r--r--source/blender/editors/space_node/node_templates.c13
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt18
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c10
-rw-r--r--source/blender/editors/space_outliner/outliner_context.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c35
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c11
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c16
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c9
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c183
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c8
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.h4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_libraries.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_orphaned.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_scenes.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc14
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.cc59
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.h3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.hh28
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_anim_data.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_collection.cc44
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_collection.hh36
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_driver.cc (renamed from source/blender/editors/space_outliner/tree/tree_element_driver_base.cc)2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_driver.hh (renamed from source/blender/editors/space_outliner/tree/tree_element_driver_base.hh)0
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc40
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh34
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.cc167
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.hh58
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.cc40
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.hh34
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_scene.cc74
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_scene.hh43
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc50
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh36
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_view_layer.cc51
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_view_layer.hh36
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c28
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt39
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc221
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_intern.hh19
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_ops.cc21
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c22
-rw-r--r--source/blender/editors/util/ed_util_ops.cc4
-rw-r--r--source/blender/functions/CMakeLists.txt3
-rw-r--r--source/blender/functions/FN_attributes_ref.hh341
-rw-r--r--source/blender/functions/FN_cpp_type.hh6
-rw-r--r--source/blender/functions/FN_multi_function_builder.hh57
-rw-r--r--source/blender/functions/intern/attributes_ref.cc78
-rw-r--r--source/blender/functions/intern/multi_function_network.cc4
-rw-r--r--source/blender/functions/intern/multi_function_network_evaluation.cc36
-rw-r--r--source/blender/functions/tests/FN_attributes_ref_test.cc97
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c17
-rw-r--r--source/blender/gpu/intern/gpu_matrix.cc8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl3
-rw-r--r--source/blender/makesdna/DNA_ID.h6
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h1
-rw-r--r--source/blender/makesdna/DNA_node_types.h3
-rw-r--r--source/blender/makesdna/DNA_outliner_types.h10
-rw-r--r--source/blender/makesdna/DNA_space_types.h25
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/RNA_define.h2
-rw-r--r--source/blender/makesrna/intern/makesrna.c6
-rw-r--r--source/blender/makesrna/intern/rna_access.c20
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c96
-rw-r--r--source/blender/makesrna/intern/rna_define.c12
-rw-r--r--source/blender/makesrna/intern/rna_internal.h1
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c15
-rw-r--r--source/blender/makesrna/intern/rna_pose_api.c52
-rw-r--r--source/blender/makesrna/intern/rna_rna.c4
-rw-r--r--source/blender/makesrna/intern/rna_screen.c4
-rw-r--r--source/blender/makesrna/intern/rna_space.c23
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c21
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c28
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c5
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c45
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc269
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.c16
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c16
-rw-r--r--source/blender/nodes/CMakeLists.txt8
-rw-r--r--source/blender/nodes/NOD_derived_node_tree.hh555
-rw-r--r--source/blender/nodes/NOD_geometry.h4
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh22
-rw-r--r--source/blender/nodes/NOD_node_tree_dependencies.hh76
-rw-r--r--source/blender/nodes/NOD_node_tree_multi_function.hh107
-rw-r--r--source/blender/nodes/NOD_static_types.h4
-rw-r--r--source/blender/nodes/function/nodes/node_fn_group_instance_id.cc7
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_float.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc546
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_translate.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivide.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc)19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivide_smooth.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc)23
-rw-r--r--source/blender/nodes/intern/derived_node_tree.cc639
-rw-r--r--source/blender/nodes/intern/node_exec.c14
-rw-r--r--source/blender/nodes/intern/node_exec.h2
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc15
-rw-r--r--source/blender/nodes/intern/node_tree_dependencies.cc57
-rw-r--r--source/blender/nodes/intern/node_tree_multi_function.cc263
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc10
-rw-r--r--source/blender/nodes/shader/node_shader_util.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.c80
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc217
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c14
-rw-r--r--source/blender/python/intern/CMakeLists.txt2
-rw-r--r--source/blender/python/intern/bpy.c3
-rw-r--r--source/blender/python/intern/bpy_library_load.c16
-rw-r--r--source/blender/python/intern/bpy_rna.c20
-rw-r--r--source/blender/python/intern/bpy_rna_data.c219
-rw-r--r--source/blender/python/intern/bpy_rna_data.h29
-rw-r--r--source/blender/python/intern/bpy_rna_types_capi.c7
-rw-r--r--source/blender/render/intern/multires_bake.c16
-rw-r--r--source/blender/render/intern/texture_procedural.c40
-rw-r--r--source/blender/shader_fx/intern/FX_ui_common.c17
-rw-r--r--source/blender/windowmanager/WM_types.h2
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c4
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c4
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c3
-rw-r--r--source/blender/windowmanager/intern/wm_platform_support.c10
-rw-r--r--source/blender/windowmanager/intern/wm_window.c12
-rw-r--r--source/blender/windowmanager/wm_window.h4
485 files changed, 8459 insertions, 6434 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index db44a771095..f5face2120e 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -27,6 +27,8 @@
extern "C" {
#endif
+struct AnimationEvalContext;
+struct bAction;
struct BMEditMesh;
struct Bone;
struct Depsgraph;
@@ -193,6 +195,12 @@ void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
bool do_extra);
void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan);
+/* Evaluate the action and apply it to the pose. If any pose bones are selected, only FCurves that
+ * relate to those bones are evaluated. */
+void BKE_pose_apply_action(struct Object *ob,
+ struct bAction *action,
+ struct AnimationEvalContext *anim_eval_context);
+
/* get_objectspace_bone_matrix has to be removed still */
void get_objectspace_bone_matrix(struct Bone *bone,
float M_accumulatedMatrix[4][4],
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 66bfe620df7..133f1c5100a 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 10
+#define BLENDER_FILE_SUBVERSION 11
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 94392dd78da..3d30188e517 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -197,6 +197,7 @@ struct SpaceInfo *CTX_wm_space_info(const bContext *C);
struct SpaceUserPref *CTX_wm_space_userpref(const bContext *C);
struct SpaceClip *CTX_wm_space_clip(const bContext *C);
struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C);
+struct SpaceSpreadsheet *CTX_wm_space_spreadsheet(const bContext *C);
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm);
void CTX_wm_window_set(bContext *C, struct wmWindow *win);
diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh
index f10b4c1f7c4..98fdfc965bc 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.hh
+++ b/source/blender/blenkernel/BKE_cryptomatte.hh
@@ -29,6 +29,8 @@
#include "BLI_map.hh"
#include "BLI_string_ref.hh"
+#include "BKE_cryptomatte.h"
+
struct ID;
namespace blender::bke::cryptomatte {
@@ -103,4 +105,13 @@ struct CryptomatteStampDataCallbackData {
static void extract_layer_manifest(void *_data, const char *propname, char *propvalue, int len);
};
+struct CryptomatteSessionDeleter {
+ void operator()(CryptomatteSession *session)
+ {
+ BKE_cryptomatte_free(session);
+ }
+};
+
+using CryptomatteSessionPtr = std::unique_ptr<CryptomatteSession, CryptomatteSessionDeleter>;
+
} // namespace blender::bke::cryptomatte
diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.h b/source/blender/blenkernel/BKE_mesh_boolean_convert.h
index be5cbb305fa..a87f2609e46 100644
--- a/source/blender/blenkernel/BKE_mesh_boolean_convert.h
+++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.h
@@ -31,6 +31,7 @@ Mesh *BKE_mesh_boolean(const Mesh **meshes,
const float (*obmats[])[4][4],
const int meshes_len,
const bool use_self,
+ const bool hole_tolerant,
const int boolean_mode);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index d675df6d868..f5f65e71f7f 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -301,11 +301,11 @@ typedef struct bNodeType {
void (*free_self)(struct bNodeType *ntype);
/* **** execution callbacks **** */
- NodeInitExecFunction initexecfunc;
- NodeFreeExecFunction freeexecfunc;
- NodeExecFunction execfunc;
+ NodeInitExecFunction init_exec_fn;
+ NodeFreeExecFunction free_exec_fn;
+ NodeExecFunction exec_fn;
/* gpu */
- NodeGPUExecFunction gpufunc;
+ NodeGPUExecFunction gpu_fn;
/* Expands the bNode into nodes in a multi-function network, which will be evaluated later on. */
NodeExpandInMFNetworkFunction expand_in_mf_network;
@@ -829,10 +829,10 @@ void node_type_group_update(struct bNodeType *ntype,
struct bNode *node));
void node_type_exec(struct bNodeType *ntype,
- NodeInitExecFunction initexecfunc,
- NodeFreeExecFunction freeexecfunc,
- NodeExecFunction execfunc);
-void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc);
+ NodeInitExecFunction init_exec_fn,
+ NodeFreeExecFunction free_exec_fn,
+ NodeExecFunction exec_fn);
+void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn);
void node_type_internal_links(struct bNodeType *ntype,
void (*update_internal_links)(struct bNodeTree *, struct bNode *));
@@ -1348,7 +1348,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_BOOLEAN 1003
#define GEO_NODE_POINT_DISTRIBUTE 1004
#define GEO_NODE_POINT_INSTANCE 1005
-#define GEO_NODE_SUBDIVISION_SURFACE 1006
+#define GEO_NODE_SUBDIVIDE_SMOOTH 1006
#define GEO_NODE_OBJECT_INFO 1007
#define GEO_NODE_ATTRIBUTE_RANDOMIZE 1008
#define GEO_NODE_ATTRIBUTE_MATH 1009
@@ -1371,7 +1371,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_VOLUME_TO_MESH 1026
#define GEO_NODE_ATTRIBUTE_COMBINE_XYZ 1027
#define GEO_NODE_ATTRIBUTE_SEPARATE_XYZ 1028
-#define GEO_NODE_SUBDIVISION_SURFACE_SIMPLE 1029
+#define GEO_NODE_SUBDIVIDE 1029
/** \} */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 4f0218e2f8f..2aca43c6df7 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -77,6 +77,7 @@ set(SRC
intern/appdir.c
intern/armature.c
intern/armature_deform.c
+ intern/armature_pose.cc
intern/armature_update.c
intern/asset.cc
intern/attribute.c
@@ -130,6 +131,10 @@ set(SRC
intern/fmodifier.c
intern/font.c
intern/freestyle.c
+ intern/geometry_component_instances.cc
+ intern/geometry_component_mesh.cc
+ intern/geometry_component_pointcloud.cc
+ intern/geometry_component_volume.cc
intern/geometry_set.cc
intern/geometry_set_instances.cc
intern/gpencil.c
@@ -429,6 +434,7 @@ set(SRC
nla_private.h
particle_private.h
tracking_private.h
+ intern/attribute_access_intern.hh
intern/CCGSubSurf.h
intern/CCGSubSurf_inline.h
intern/CCGSubSurf_intern.h
diff --git a/source/blender/blenkernel/intern/armature_pose.cc b/source/blender/blenkernel/intern/armature_pose.cc
new file mode 100644
index 00000000000..bb371b16c42
--- /dev/null
+++ b/source/blender/blenkernel/intern/armature_pose.cc
@@ -0,0 +1,133 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Defines and code for core node types
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_animsys.h"
+#include "BKE_armature.h"
+
+#include "BLI_set.hh"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+
+#include "RNA_access.h"
+
+namespace {
+using BoneNameSet = blender::Set<std::string>;
+
+// Forward declarations.
+BoneNameSet pose_apply_find_selected_bones(const bPose *pose);
+void pose_apply_disable_fcurves_for_unselected_bones(bAction *action,
+ const BoneNameSet &selected_bone_names);
+void pose_apply_restore_fcurves(bAction *action);
+} // namespace
+
+void BKE_pose_apply_action(struct Object *ob,
+ struct bAction *action,
+ struct AnimationEvalContext *anim_eval_context)
+{
+ bPose *pose = ob->pose;
+ if (pose == nullptr) {
+ return;
+ }
+
+ const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(pose);
+ const bool limit_to_selected_bones = !selected_bone_names.is_empty();
+
+ if (limit_to_selected_bones) {
+ /* Mute all FCurves that are not associated with selected bones. This separates the concept of
+ * bone selection from the FCurve evaluation code. */
+ pose_apply_disable_fcurves_for_unselected_bones(action, selected_bone_names);
+ }
+
+ /* Apply the Action. */
+ PointerRNA pose_owner_ptr;
+ RNA_id_pointer_create(&ob->id, &pose_owner_ptr);
+ animsys_evaluate_action(&pose_owner_ptr, action, anim_eval_context, false);
+
+ if (limit_to_selected_bones) {
+ pose_apply_restore_fcurves(action);
+ }
+}
+
+namespace {
+BoneNameSet pose_apply_find_selected_bones(const bPose *pose)
+{
+ BoneNameSet selected_bone_names;
+ bool all_bones_selected = true;
+ bool no_bones_selected = true;
+
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
+ const bool is_selected = (pchan->bone->flag & BONE_SELECTED) != 0 &&
+ (pchan->bone->flag & BONE_HIDDEN_P) == 0;
+ all_bones_selected &= is_selected;
+ no_bones_selected &= !is_selected;
+
+ if (is_selected) {
+ /* Bone names are unique, so no need to check for duplicates. */
+ selected_bone_names.add_new(pchan->name);
+ }
+ }
+
+ /* If no bones are selected, act as if all are. */
+ if (all_bones_selected || no_bones_selected) {
+ return BoneNameSet(); /* An empty set means "ignore bone selection". */
+ }
+ return selected_bone_names;
+}
+
+void pose_apply_restore_fcurves(bAction *action)
+{
+ /* TODO(Sybren): Restore the FCurve flags, instead of just erasing the 'disabled' flag. */
+ LISTBASE_FOREACH (FCurve *, fcu, &action->curves) {
+ fcu->flag &= ~FCURVE_DISABLED;
+ }
+}
+
+void pose_apply_disable_fcurves_for_unselected_bones(bAction *action,
+ const BoneNameSet &selected_bone_names)
+{
+ LISTBASE_FOREACH (FCurve *, fcu, &action->curves) {
+ if (!fcu->rna_path || !strstr(fcu->rna_path, "pose.bones[")) {
+ continue;
+ }
+
+ /* Get bone name, and check if this bone is selected. */
+ char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
+ if (!bone_name) {
+ continue;
+ }
+ const bool is_selected = selected_bone_names.contains(bone_name);
+ MEM_freeN(bone_name);
+ if (is_selected) {
+ continue;
+ }
+
+ fcu->flag |= FCURVE_DISABLED;
+ }
+}
+
+} // namespace
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index aeb7fba47e8..01a1333c3ce 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -31,11 +31,14 @@
#include "BLI_color.hh"
#include "BLI_float2.hh"
#include "BLI_span.hh"
+#include "BLI_threads.h"
#include "CLG_log.h"
#include "NOD_node_tree_multi_function.hh"
+#include "attribute_access_intern.hh"
+
static CLG_LogRef LOG = {"bke.attribute_access"};
using blender::float3;
@@ -46,9 +49,6 @@ using blender::bke::ReadAttributePtr;
using blender::bke::WriteAttributePtr;
using blender::fn::GMutableSpan;
-/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
-extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
-
namespace blender::bke {
/* -------------------------------------------------------------------- */
@@ -158,101 +158,6 @@ void WriteAttribute::apply_span_if_necessary()
}
}
-class VertexWeightWriteAttribute final : public WriteAttribute {
- private:
- MDeformVert *dverts_;
- const int dvert_index_;
-
- public:
- VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index)
- : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
- dverts_(dverts),
- dvert_index_(dvert_index)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- get_internal(dverts_, dvert_index_, index, r_value);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
- weight->weight = *reinterpret_cast<const float *>(value);
- }
-
- static void get_internal(const MDeformVert *dverts,
- const int dvert_index,
- const int64_t index,
- void *r_value)
- {
- if (dverts == nullptr) {
- *(float *)r_value = 0.0f;
- return;
- }
- const MDeformVert &dvert = dverts[index];
- for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
- if (weight.def_nr == dvert_index) {
- *(float *)r_value = weight.weight;
- return;
- }
- }
- *(float *)r_value = 0.0f;
- }
-};
-
-class VertexWeightReadAttribute final : public ReadAttribute {
- private:
- const MDeformVert *dverts_;
- const int dvert_index_;
-
- public:
- VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index)
- : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
- dverts_(dverts),
- dvert_index_(dvert_index)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value);
- }
-};
-
-template<typename T> class ArrayWriteAttribute final : public WriteAttribute {
- private:
- MutableSpan<T> data_;
-
- public:
- ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data)
- : WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- data_[index] = *reinterpret_cast<const T *>(value);
- }
-
- void initialize_span(const bool UNUSED(write_only)) override
- {
- array_buffer_ = data_.data();
- array_is_temporary_ = false;
- }
-
- void apply_span_if_necessary() override
- {
- /* Do nothing, because the span contains the attribute itself already. */
- }
-};
-
/* This is used by the #OutputAttributePtr class. */
class TemporaryWriteAttribute final : public WriteAttribute {
public:
@@ -301,135 +206,6 @@ class TemporaryWriteAttribute final : public WriteAttribute {
}
};
-template<typename T> class ArrayReadAttribute final : public ReadAttribute {
- private:
- Span<T> data_;
-
- public:
- ArrayReadAttribute(AttributeDomain domain, Span<T> data)
- : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void initialize_span() const override
- {
- /* The data will not be modified, so this const_cast is fine. */
- array_buffer_ = const_cast<T *>(data_.data());
- array_is_temporary_ = false;
- }
-};
-
-template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute {
- private:
- Array<T> data_;
-
- public:
- OwnedArrayReadAttribute(AttributeDomain domain, Array<T> data)
- : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(std::move(data))
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void initialize_span() const override
- {
- /* The data will not be modified, so this const_cast is fine. */
- array_buffer_ = const_cast<T *>(data_.data());
- array_is_temporary_ = false;
- }
-};
-
-template<typename StructT,
- typename ElemT,
- ElemT (*GetFunc)(const StructT &),
- void (*SetFunc)(StructT &, const ElemT &)>
-class DerivedArrayWriteAttribute final : public WriteAttribute {
- private:
- MutableSpan<StructT> data_;
-
- public:
- DerivedArrayWriteAttribute(AttributeDomain domain, MutableSpan<StructT> data)
- : WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- const StructT &struct_value = data_[index];
- const ElemT value = GetFunc(struct_value);
- new (r_value) ElemT(value);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- StructT &struct_value = data_[index];
- const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value);
- SetFunc(struct_value, typed_value);
- }
-};
-
-template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
-class DerivedArrayReadAttribute final : public ReadAttribute {
- private:
- Span<StructT> data_;
-
- public:
- DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data)
- : ReadAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- const StructT &struct_value = data_[index];
- const ElemT value = GetFunc(struct_value);
- new (r_value) ElemT(value);
- }
-};
-
-class ConstantReadAttribute final : public ReadAttribute {
- private:
- void *value_;
-
- public:
- ConstantReadAttribute(AttributeDomain domain,
- const int64_t size,
- const CPPType &type,
- const void *value)
- : ReadAttribute(domain, type, size)
- {
- value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
- type.copy_to_uninitialized(value, value_);
- }
-
- ~ConstantReadAttribute() override
- {
- this->cpp_type_.destruct(value_);
- MEM_freeN(value_);
- }
-
- void get_internal(const int64_t UNUSED(index), void *r_value) const override
- {
- this->cpp_type_.copy_to_uninitialized(value_, r_value);
- }
-
- void initialize_span() const override
- {
- const int element_size = cpp_type_.size();
- array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
- array_is_temporary_ = true;
- cpp_type_.fill_uninitialized(value_, array_buffer_, size_);
- }
-};
-
class ConvertedReadAttribute final : public ReadAttribute {
private:
const CPPType &from_type_;
@@ -437,9 +213,6 @@ class ConvertedReadAttribute final : public ReadAttribute {
ReadAttributePtr base_attribute_;
const nodes::DataTypeConversions &conversions_;
- static constexpr int MaxValueSize = 64;
- static constexpr int MaxValueAlignment = 64;
-
public:
ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type)
: ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()),
@@ -448,17 +221,13 @@ class ConvertedReadAttribute final : public ReadAttribute {
base_attribute_(std::move(base_attribute)),
conversions_(nodes::get_implicit_type_conversions())
{
- if (from_type_.size() > MaxValueSize || from_type_.alignment() > MaxValueAlignment) {
- throw std::runtime_error(
- "type is larger than expected, the buffer size has to be increased");
- }
}
void get_internal(const int64_t index, void *r_value) const override
{
- AlignedBuffer<MaxValueSize, MaxValueAlignment> buffer;
- base_attribute_->get(index, buffer.ptr());
- conversions_.convert(from_type_, to_type_, buffer.ptr(), r_value);
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ base_attribute_->get(index, buffer);
+ conversions_.convert(from_type_, to_type_, buffer, r_value);
}
};
@@ -598,964 +367,321 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
return highest_priority_domain;
}
-/**
- * A #BuiltinAttributeProvider is responsible for exactly one attribute on a geometry component.
- * The attribute is identified by its name and has a fixed domain and type. Builtin attributes do
- * not follow the same loose rules as other attributes, because they are mapped to internal
- * "legacy" data structures. For example, some builtin attributes cannot be deleted. */
-class BuiltinAttributeProvider {
- public:
- /* Some utility enums to avoid hard to read booleans in function calls. */
- enum CreatableEnum {
- Creatable,
- NonCreatable,
- };
- enum WritableEnum {
- Writable,
- Readonly,
- };
- enum DeletableEnum {
- Deletable,
- NonDeletable,
- };
-
- protected:
- const std::string name_;
- const AttributeDomain domain_;
- const CustomDataType data_type_;
- const CreatableEnum createable_;
- const WritableEnum writable_;
- const DeletableEnum deletable_;
-
- public:
- BuiltinAttributeProvider(std::string name,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const CreatableEnum createable,
- const WritableEnum writable,
- const DeletableEnum deletable)
- : name_(std::move(name)),
- domain_(domain),
- data_type_(data_type),
- createable_(createable),
- writable_(writable),
- deletable_(deletable)
- {
- }
-
- virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0;
- virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0;
- virtual bool try_delete(GeometryComponent &component) const = 0;
- virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0;
- virtual bool exists(const GeometryComponent &component) const = 0;
-
- StringRefNull name() const
- {
- return name_;
- }
-
- AttributeDomain domain() const
- {
- return domain_;
+ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read(
+ const GeometryComponent &component) const
+{
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
+ return {};
}
- CustomDataType data_type() const
- {
- return data_type_;
+ if (update_on_read_ != nullptr) {
+ update_on_read_(component);
}
-};
-
-/**
- * A #DynamicAttributesProvider manages a set of named attributes on a geometry component. Each
- * attribute has a name, domain and type.
- */
-class DynamicAttributesProvider {
- public:
- virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const = 0;
- virtual WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const = 0;
- virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0;
- virtual bool try_create(GeometryComponent &UNUSED(component),
- const StringRef UNUSED(attribute_name),
- const AttributeDomain UNUSED(domain),
- const CustomDataType UNUSED(data_type)) const
- {
- /* Some providers should not create new attributes. */
- return false;
- };
-
- virtual bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const = 0;
- virtual void supported_domains(Vector<AttributeDomain> &r_domains) const = 0;
-};
-
-/**
- * Utility to group together multiple functions that are used to access custom data on geometry
- * components in a generic way.
- */
-struct CustomDataAccessInfo {
- using CustomDataGetter = CustomData *(*)(GeometryComponent &component);
- using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component);
- using UpdateCustomDataPointers = void (*)(GeometryComponent &component);
-
- CustomDataGetter get_custom_data;
- ConstCustomDataGetter get_const_custom_data;
- UpdateCustomDataPointers update_custom_data_pointers;
-};
-/**
- * This provider is used to provide access to builtin attributes. It supports making internal types
- * available as different types. For example, the vertex position attribute is stored as part of
- * the #MVert struct, but is exposed as float3 attribute.
- */
-class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
- using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
- using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
- using UpdateOnWrite = void (*)(GeometryComponent &component);
- const CustomDataType stored_type_;
- const CustomDataAccessInfo custom_data_access_;
- const AsReadAttribute as_read_attribute_;
- const AsWriteAttribute as_write_attribute_;
- const UpdateOnWrite update_on_write_;
-
- public:
- BuiltinCustomDataLayerProvider(std::string attribute_name,
- const AttributeDomain domain,
- const CustomDataType attribute_type,
- const CustomDataType stored_type,
- const CreatableEnum creatable,
- const WritableEnum writable,
- const DeletableEnum deletable,
- const CustomDataAccessInfo custom_data_access,
- const AsReadAttribute as_read_attribute,
- const AsWriteAttribute as_write_attribute,
- const UpdateOnWrite update_on_write)
- : BuiltinAttributeProvider(
- std::move(attribute_name), domain, attribute_type, creatable, writable, deletable),
- stored_type_(stored_type),
- custom_data_access_(custom_data_access),
- as_read_attribute_(as_read_attribute),
- as_write_attribute_(as_write_attribute),
- update_on_write_(update_on_write)
- {
+ const int domain_size = component.attribute_domain_size(domain_);
+ const void *data = CustomData_get_layer(custom_data, stored_type_);
+ if (data == nullptr) {
+ return {};
}
+ return as_read_attribute_(data, domain_size);
+}
- ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- const int domain_size = component.attribute_domain_size(domain_);
- const void *data = CustomData_get_layer(custom_data, stored_type_);
- if (data == nullptr) {
- return {};
- }
- return as_read_attribute_(data, domain_size);
+WriteAttributePtr BuiltinCustomDataLayerProvider::try_get_for_write(
+ GeometryComponent &component) const
+{
+ if (writable_ != Writable) {
+ return {};
}
-
- WriteAttributePtr try_get_for_write(GeometryComponent &component) const final
- {
- if (writable_ != Writable) {
- return {};
- }
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- const int domain_size = component.attribute_domain_size(domain_);
- void *data = CustomData_get_layer(custom_data, stored_type_);
- if (data == nullptr) {
- return {};
- }
- void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size);
- if (data != new_data) {
- custom_data_access_.update_custom_data_pointers(component);
- data = new_data;
- }
- if (update_on_write_ != nullptr) {
- update_on_write_(component);
- }
- return as_write_attribute_(data, domain_size);
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
+ return {};
}
-
- bool try_delete(GeometryComponent &component) const final
- {
- if (deletable_ != Deletable) {
- return false;
- }
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
-
- const int domain_size = component.attribute_domain_size(domain_);
- const int layer_index = CustomData_get_layer_index(custom_data, stored_type_);
- const bool delete_success = CustomData_free_layer(
- custom_data, stored_type_, domain_size, layer_index);
- if (delete_success) {
- custom_data_access_.update_custom_data_pointers(component);
- }
- return delete_success;
+ const int domain_size = component.attribute_domain_size(domain_);
+ void *data = CustomData_get_layer(custom_data, stored_type_);
+ if (data == nullptr) {
+ return {};
}
-
- bool try_create(GeometryComponent &component) const final
- {
- if (createable_ != Creatable) {
- return false;
- }
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return false;
- }
- if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
- /* Exists already. */
- return false;
- }
- const int domain_size = component.attribute_domain_size(domain_);
- const void *data = CustomData_add_layer(
- custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size);
- const bool success = data != nullptr;
- if (success) {
- custom_data_access_.update_custom_data_pointers(component);
- }
- return success;
+ void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size);
+ if (data != new_data) {
+ custom_data_access_.update_custom_data_pointers(component);
+ data = new_data;
}
-
- bool exists(const GeometryComponent &component) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
- return false;
- }
- const void *data = CustomData_get_layer(custom_data, stored_type_);
- return data != nullptr;
+ if (update_on_write_ != nullptr) {
+ update_on_write_(component);
}
-};
-
-/**
- * This is the attribute provider for most user generated attributes.
- */
-class CustomDataAttributeProvider final : public DynamicAttributesProvider {
- private:
- static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 |
- CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 |
- CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL;
- const AttributeDomain domain_;
- const CustomDataAccessInfo custom_data_access_;
+ return as_write_attribute_(data, domain_size);
+}
- public:
- CustomDataAttributeProvider(const AttributeDomain domain,
- const CustomDataAccessInfo custom_data_access)
- : domain_(domain), custom_data_access_(custom_data_access)
- {
+bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const
+{
+ if (deletable_ != Deletable) {
+ return false;
}
-
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- const int domain_size = component.attribute_domain_size(domain_);
- for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- if (layer.name != attribute_name) {
- continue;
- }
- const CustomDataType data_type = (CustomDataType)layer.type;
- switch (data_type) {
- case CD_PROP_FLOAT:
- return this->layer_to_read_attribute<float>(layer, domain_size);
- case CD_PROP_FLOAT2:
- return this->layer_to_read_attribute<float2>(layer, domain_size);
- case CD_PROP_FLOAT3:
- return this->layer_to_read_attribute<float3>(layer, domain_size);
- case CD_PROP_INT32:
- return this->layer_to_read_attribute<int>(layer, domain_size);
- case CD_PROP_COLOR:
- return this->layer_to_read_attribute<Color4f>(layer, domain_size);
- case CD_PROP_BOOL:
- return this->layer_to_read_attribute<bool>(layer, domain_size);
- default:
- break;
- }
- }
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
return {};
}
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- const int domain_size = component.attribute_domain_size(domain_);
- for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
- if (layer.name != attribute_name) {
- continue;
- }
- CustomData_duplicate_referenced_layer_named(
- custom_data, layer.type, layer.name, domain_size);
- const CustomDataType data_type = (CustomDataType)layer.type;
- switch (data_type) {
- case CD_PROP_FLOAT:
- return this->layer_to_write_attribute<float>(layer, domain_size);
- case CD_PROP_FLOAT2:
- return this->layer_to_write_attribute<float2>(layer, domain_size);
- case CD_PROP_FLOAT3:
- return this->layer_to_write_attribute<float3>(layer, domain_size);
- case CD_PROP_INT32:
- return this->layer_to_write_attribute<int>(layer, domain_size);
- case CD_PROP_COLOR:
- return this->layer_to_write_attribute<Color4f>(layer, domain_size);
- case CD_PROP_BOOL:
- return this->layer_to_write_attribute<bool>(layer, domain_size);
- default:
- break;
- }
- }
- return {};
+ const int domain_size = component.attribute_domain_size(domain_);
+ const int layer_index = CustomData_get_layer_index(custom_data, stored_type_);
+ const bool delete_success = CustomData_free_layer(
+ custom_data, stored_type_, domain_size, layer_index);
+ if (delete_success) {
+ custom_data_access_.update_custom_data_pointers(component);
}
+ return delete_success;
+}
- bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
- {
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return false;
- }
- const int domain_size = component.attribute_domain_size(domain_);
- for (const int i : IndexRange(custom_data->totlayer)) {
- const CustomDataLayer &layer = custom_data->layers[i];
- if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) {
- CustomData_free_layer(custom_data, layer.type, domain_size, i);
- return true;
- }
- }
+bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) const
+{
+ if (createable_ != Creatable) {
return false;
}
-
- bool try_create(GeometryComponent &component,
- const StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type) const final
- {
- if (domain_ != domain) {
- return false;
- }
- if (!this->type_is_supported(data_type)) {
- return false;
- }
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return false;
- }
- for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- if (layer.name == attribute_name) {
- return false;
- }
- }
- const int domain_size = component.attribute_domain_size(domain_);
- char attribute_name_c[MAX_NAME];
- attribute_name.copy(attribute_name_c);
- CustomData_add_layer_named(
- custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
- return true;
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
+ return false;
}
-
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
- return true;
- }
- for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- const CustomDataType data_type = (CustomDataType)layer.type;
- if (this->type_is_supported(data_type)) {
- AttributeMetaData meta_data{domain_, data_type};
- if (!callback(layer.name, meta_data)) {
- return false;
- }
- }
- }
- return true;
+ if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
+ /* Exists already. */
+ return false;
}
-
- void supported_domains(Vector<AttributeDomain> &r_domains) const final
- {
- r_domains.append_non_duplicates(domain_);
+ const int domain_size = component.attribute_domain_size(domain_);
+ const void *data = CustomData_add_layer(
+ custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size);
+ const bool success = data != nullptr;
+ if (success) {
+ custom_data_access_.update_custom_data_pointers(component);
}
+ return success;
+}
- private:
- template<typename T>
- ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer,
- const int domain_size) const
- {
- return std::make_unique<ArrayReadAttribute<T>>(
- domain_, Span(static_cast<const T *>(layer.data), domain_size));
+bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) const
+{
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
+ return false;
}
+ const void *data = CustomData_get_layer(custom_data, stored_type_);
+ return data != nullptr;
+}
- template<typename T>
- WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const
- {
- return std::make_unique<ArrayWriteAttribute<T>>(
- domain_, MutableSpan(static_cast<T *>(layer.data), domain_size));
+ReadAttributePtr CustomDataAttributeProvider::try_get_for_read(
+ const GeometryComponent &component, const StringRef attribute_name) const
+{
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
+ return {};
}
-
- bool type_is_supported(CustomDataType data_type) const
- {
- return ((1ULL << data_type) & supported_types_mask) != 0;
+ const int domain_size = component.attribute_domain_size(domain_);
+ for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
+ if (layer.name != attribute_name) {
+ continue;
+ }
+ const CustomDataType data_type = (CustomDataType)layer.type;
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ return this->layer_to_read_attribute<float>(layer, domain_size);
+ case CD_PROP_FLOAT2:
+ return this->layer_to_read_attribute<float2>(layer, domain_size);
+ case CD_PROP_FLOAT3:
+ return this->layer_to_read_attribute<float3>(layer, domain_size);
+ case CD_PROP_INT32:
+ return this->layer_to_read_attribute<int>(layer, domain_size);
+ case CD_PROP_COLOR:
+ return this->layer_to_read_attribute<Color4f>(layer, domain_size);
+ case CD_PROP_BOOL:
+ return this->layer_to_read_attribute<bool>(layer, domain_size);
+ default:
+ break;
+ }
}
-};
-
-static Mesh *get_mesh_from_component_for_write(GeometryComponent &component)
-{
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
- return mesh_component.get_for_write();
+ return {};
}
-static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component)
+WriteAttributePtr CustomDataAttributeProvider::try_get_for_write(
+ GeometryComponent &component, const StringRef attribute_name) const
{
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return mesh_component.get_for_read();
-}
-
-/**
- * This attribute provider is used for uv maps and vertex colors.
- */
-class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
- private:
- using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
- using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
- const AttributeDomain domain_;
- const CustomDataType attribute_type_;
- const CustomDataType stored_type_;
- const CustomDataAccessInfo custom_data_access_;
- const AsReadAttribute as_read_attribute_;
- const AsWriteAttribute as_write_attribute_;
-
- public:
- NamedLegacyCustomDataProvider(const AttributeDomain domain,
- const CustomDataType attribute_type,
- const CustomDataType stored_type,
- const CustomDataAccessInfo custom_data_access,
- const AsReadAttribute as_read_attribute,
- const AsWriteAttribute as_write_attribute)
- : domain_(domain),
- attribute_type_(attribute_type),
- stored_type_(stored_type),
- custom_data_access_(custom_data_access),
- as_read_attribute_(as_read_attribute),
- as_write_attribute_(as_write_attribute)
- {
- }
-
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- if (layer.type == stored_type_) {
- if (layer.name == attribute_name) {
- const int domain_size = component.attribute_domain_size(domain_);
- return as_read_attribute_(layer.data, domain_size);
- }
- }
- }
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
return {};
}
-
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return {};
- }
- for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
- if (layer.type == stored_type_) {
- if (layer.name == attribute_name) {
- const int domain_size = component.attribute_domain_size(domain_);
- void *data_old = layer.data;
- void *data_new = CustomData_duplicate_referenced_layer_named(
- custom_data, stored_type_, layer.name, domain_size);
- if (data_old != data_new) {
- custom_data_access_.update_custom_data_pointers(component);
- }
- return as_write_attribute_(layer.data, domain_size);
- }
- }
+ const int domain_size = component.attribute_domain_size(domain_);
+ for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
+ if (layer.name != attribute_name) {
+ continue;
+ }
+ CustomData_duplicate_referenced_layer_named(custom_data, layer.type, layer.name, domain_size);
+ const CustomDataType data_type = (CustomDataType)layer.type;
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ return this->layer_to_write_attribute<float>(layer, domain_size);
+ case CD_PROP_FLOAT2:
+ return this->layer_to_write_attribute<float2>(layer, domain_size);
+ case CD_PROP_FLOAT3:
+ return this->layer_to_write_attribute<float3>(layer, domain_size);
+ case CD_PROP_INT32:
+ return this->layer_to_write_attribute<int>(layer, domain_size);
+ case CD_PROP_COLOR:
+ return this->layer_to_write_attribute<Color4f>(layer, domain_size);
+ case CD_PROP_BOOL:
+ return this->layer_to_write_attribute<bool>(layer, domain_size);
+ default:
+ break;
}
- return {};
}
+ return {};
+}
- bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
- {
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
- if (custom_data == nullptr) {
- return false;
- }
- for (const int i : IndexRange(custom_data->totlayer)) {
- const CustomDataLayer &layer = custom_data->layers[i];
- if (layer.type == stored_type_) {
- if (layer.name == attribute_name) {
- const int domain_size = component.attribute_domain_size(domain_);
- CustomData_free_layer(custom_data, stored_type_, domain_size, i);
- custom_data_access_.update_custom_data_pointers(component);
- return true;
- }
- }
- }
+bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
+ const StringRef attribute_name) const
+{
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
return false;
}
-
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final
- {
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
- if (custom_data == nullptr) {
+ const int domain_size = component.attribute_domain_size(domain_);
+ for (const int i : IndexRange(custom_data->totlayer)) {
+ const CustomDataLayer &layer = custom_data->layers[i];
+ if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) {
+ CustomData_free_layer(custom_data, layer.type, domain_size, i);
return true;
}
- for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- if (layer.type == stored_type_) {
- AttributeMetaData meta_data{domain_, attribute_type_};
- if (!callback(layer.name, meta_data)) {
- return false;
- }
- }
- }
- return true;
}
+ return false;
+}
- void supported_domains(Vector<AttributeDomain> &r_domains) const final
- {
- r_domains.append_non_duplicates(domain_);
+bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
+ const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type) const
+{
+ if (domain_ != domain) {
+ return false;
}
-};
-
-/**
- * This provider makes vertex groups available as float attributes.
- */
-class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
- public:
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as(
- attribute_name, -1);
- if (vertex_group_index < 0) {
- return {};
- }
- if (mesh == nullptr || mesh->dvert == nullptr) {
- static const float default_value = 0.0f;
- return std::make_unique<ConstantReadAttribute>(
- ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get<float>(), &default_value);
- }
- return std::make_unique<VertexWeightReadAttribute>(
- mesh->dvert, mesh->totvert, vertex_group_index);
+ if (!this->type_is_supported(data_type)) {
+ return false;
}
-
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final
- {
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
- Mesh *mesh = mesh_component.get_for_write();
- if (mesh == nullptr) {
- return {};
- }
- const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as(
- attribute_name, -1);
- if (vertex_group_index < 0) {
- return {};
- }
- if (mesh->dvert == nullptr) {
- BKE_object_defgroup_data_create(&mesh->id);
- }
- else {
- /* Copy the data layer if it is shared with some other mesh. */
- mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer(
- &mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
- }
- return std::make_unique<blender::bke::VertexWeightWriteAttribute>(
- mesh->dvert, mesh->totvert, vertex_group_index);
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
+ return false;
}
-
- bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
- {
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
-
- const int vertex_group_index = mesh_component.vertex_group_names().pop_default_as(
- attribute_name, -1);
- if (vertex_group_index < 0) {
+ for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
+ if (layer.name == attribute_name) {
return false;
}
- Mesh *mesh = mesh_component.get_for_write();
- if (mesh == nullptr) {
- return true;
- }
- if (mesh->dvert == nullptr) {
- return true;
- }
- for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) {
- MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index);
- BKE_defvert_remove_group(&dvert, weight);
- }
- return true;
}
+ const int domain_size = component.attribute_domain_size(domain_);
+ char attribute_name_c[MAX_NAME];
+ attribute_name.copy(attribute_name_c);
+ CustomData_add_layer_named(
+ custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
+ return true;
+}
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final
- {
- BLI_assert(component.type() == GeometryComponentType::Mesh);
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- for (const auto item : mesh_component.vertex_group_names().items()) {
- const StringRefNull name = item.key;
- const int vertex_group_index = item.value;
- if (vertex_group_index >= 0) {
- AttributeMetaData meta_data{ATTR_DOMAIN_POINT, CD_PROP_FLOAT};
- if (!callback(name, meta_data)) {
- return false;
- }
- }
- }
+bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &component,
+ const AttributeForeachCallback callback) const
+{
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
return true;
}
-
- void supported_domains(Vector<AttributeDomain> &r_domains) const final
- {
- r_domains.append_non_duplicates(ATTR_DOMAIN_POINT);
- }
-};
-
-/**
- * This is a container for multiple attribute providers that are used by one geometry component
- * type (e.g. there is a set of attribute providers for mesh components).
- */
-class ComponentAttributeProviders {
- private:
- /**
- * Builtin attribute providers are identified by their name. Attribute names that are in this
- * map will only be accessed using builtin attribute providers. Therefore, these providers have
- * higher priority when an attribute name is looked up. Usually, that means that builtin
- * providers are checked before dynamic ones.
- */
- Map<std::string, const BuiltinAttributeProvider *> builtin_attribute_providers_;
- /**
- * An ordered list of dynamic attribute providers. The order is important because that is order
- * in which they are checked when an attribute is looked up.
- */
- Vector<const DynamicAttributesProvider *> dynamic_attribute_providers_;
- /**
- * All the domains that are supported by at least one of the providers above.
- */
- Vector<AttributeDomain> supported_domains_;
-
- public:
- ComponentAttributeProviders(Span<const BuiltinAttributeProvider *> builtin_attribute_providers,
- Span<const DynamicAttributesProvider *> dynamic_attribute_providers)
- : dynamic_attribute_providers_(dynamic_attribute_providers)
- {
- Set<AttributeDomain> domains;
- for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) {
- /* Use #add_new to make sure that no two builtin attributes have the same name. */
- builtin_attribute_providers_.add_new(provider->name(), provider);
- supported_domains_.append_non_duplicates(provider->domain());
- }
- for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) {
- provider->supported_domains(supported_domains_);
+ for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
+ const CustomDataType data_type = (CustomDataType)layer.type;
+ if (this->type_is_supported(data_type)) {
+ AttributeMetaData meta_data{domain_, data_type};
+ if (!callback(layer.name, meta_data)) {
+ return false;
+ }
}
}
-
- const Map<std::string, const BuiltinAttributeProvider *> &builtin_attribute_providers() const
- {
- return builtin_attribute_providers_;
- }
-
- Span<const DynamicAttributesProvider *> dynamic_attribute_providers() const
- {
- return dynamic_attribute_providers_;
- }
-
- Span<AttributeDomain> supported_domains() const
- {
- return supported_domains_;
- }
-};
-
-static float3 get_vertex_position(const MVert &vert)
-{
- return float3(vert.co);
-}
-
-static void set_vertex_position(MVert &vert, const float3 &position)
-{
- copy_v3_v3(vert.co, position);
-}
-
-static ReadAttributePtr make_vertex_position_read_attribute(const void *data,
- const int domain_size)
-{
- return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_position>>(
- ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size));
+ return true;
}
-static WriteAttributePtr make_vertex_position_write_attribute(void *data, const int domain_size)
+ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read(
+ const GeometryComponent &component, const StringRef attribute_name) const
{
- return std::make_unique<
- DerivedArrayWriteAttribute<MVert, float3, get_vertex_position, set_vertex_position>>(
- ATTR_DOMAIN_POINT, MutableSpan<MVert>((MVert *)data, domain_size));
-}
-
-static void tag_normals_dirty_when_writing_position(GeometryComponent &component)
-{
- Mesh *mesh = get_mesh_from_component_for_write(component);
- if (mesh != nullptr) {
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
+ return {};
}
+ for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
+ if (layer.type == stored_type_) {
+ if (layer.name == attribute_name) {
+ const int domain_size = component.attribute_domain_size(domain_);
+ return as_read_attribute_(layer.data, domain_size);
+ }
+ }
+ }
+ return {};
}
-static int get_material_index(const MPoly &mpoly)
-{
- return static_cast<int>(mpoly.mat_nr);
-}
-
-static void set_material_index(MPoly &mpoly, const int &index)
-{
- mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX));
-}
-
-static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size)
-{
- return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>(
- ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size));
-}
-
-static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size)
-{
- return std::make_unique<
- DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>(
- ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size));
-}
-
-static float2 get_loop_uv(const MLoopUV &uv)
-{
- return float2(uv.uv);
-}
-
-static void set_loop_uv(MLoopUV &uv, const float2 &co)
-{
- copy_v2_v2(uv.uv, co);
-}
-
-static ReadAttributePtr make_uvs_read_attribute(const void *data, const int domain_size)
-{
- return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, get_loop_uv>>(
- ATTR_DOMAIN_CORNER, Span((const MLoopUV *)data, domain_size));
-}
-
-static WriteAttributePtr make_uvs_write_attribute(void *data, const int domain_size)
-{
- return std::make_unique<DerivedArrayWriteAttribute<MLoopUV, float2, get_loop_uv, set_loop_uv>>(
- ATTR_DOMAIN_CORNER, MutableSpan((MLoopUV *)data, domain_size));
-}
-
-static Color4f get_loop_color(const MLoopCol &col)
-{
- Color4f value;
- rgba_uchar_to_float(value, &col.r);
- return value;
-}
-
-static void set_loop_color(MLoopCol &col, const Color4f &value)
-{
- rgba_float_to_uchar(&col.r, value);
-}
-
-static ReadAttributePtr make_vertex_color_read_attribute(const void *data, const int domain_size)
-{
- return std::make_unique<DerivedArrayReadAttribute<MLoopCol, Color4f, get_loop_color>>(
- ATTR_DOMAIN_CORNER, Span((const MLoopCol *)data, domain_size));
-}
-
-static WriteAttributePtr make_vertex_color_write_attribute(void *data, const int domain_size)
-{
- return std::make_unique<
- DerivedArrayWriteAttribute<MLoopCol, Color4f, get_loop_color, set_loop_color>>(
- ATTR_DOMAIN_CORNER, MutableSpan((MLoopCol *)data, domain_size));
-}
-
-template<typename T, AttributeDomain Domain>
-static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size)
+WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write(
+ GeometryComponent &component, const StringRef attribute_name) const
{
- return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size));
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
+ return {};
+ }
+ for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
+ if (layer.type == stored_type_) {
+ if (layer.name == attribute_name) {
+ const int domain_size = component.attribute_domain_size(domain_);
+ void *data_old = layer.data;
+ void *data_new = CustomData_duplicate_referenced_layer_named(
+ custom_data, stored_type_, layer.name, domain_size);
+ if (data_old != data_new) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
+ return as_write_attribute_(layer.data, domain_size);
+ }
+ }
+ }
+ return {};
}
-template<typename T, AttributeDomain Domain>
-static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size)
+bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
+ const StringRef attribute_name) const
{
- return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size));
+ CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ if (custom_data == nullptr) {
+ return false;
+ }
+ for (const int i : IndexRange(custom_data->totlayer)) {
+ const CustomDataLayer &layer = custom_data->layers[i];
+ if (layer.type == stored_type_) {
+ if (layer.name == attribute_name) {
+ const int domain_size = component.attribute_domain_size(domain_);
+ CustomData_free_layer(custom_data, stored_type_, domain_size, i);
+ custom_data_access_.update_custom_data_pointers(component);
+ return true;
+ }
+ }
+ }
+ return false;
}
-/**
- * In this function all the attribute providers for a mesh component are created. Most data in this
- * function is statically allocated, because it does not change over time.
- */
-static ComponentAttributeProviders create_attribute_providers_for_mesh()
+bool NamedLegacyCustomDataProvider::foreach_attribute(
+ const GeometryComponent &component, const AttributeForeachCallback callback) const
{
- static auto update_custom_data_pointers = [](GeometryComponent &component) {
- Mesh *mesh = get_mesh_from_component_for_write(component);
- if (mesh != nullptr) {
- BKE_mesh_update_customdata_pointers(mesh, false);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ if (custom_data == nullptr) {
+ return true;
+ }
+ for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
+ if (layer.type == stored_type_) {
+ AttributeMetaData meta_data{domain_, attribute_type_};
+ if (!callback(layer.name, meta_data)) {
+ return false;
+ }
}
- };
-
-#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \
- [](GeometryComponent &component) -> CustomData * { \
- Mesh *mesh = get_mesh_from_component_for_write(component); \
- return mesh ? &mesh->NAME : nullptr; \
- }
-#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \
- [](const GeometryComponent &component) -> const CustomData * { \
- const Mesh *mesh = get_mesh_from_component_for_read(component); \
- return mesh ? &mesh->NAME : nullptr; \
- }
-
- static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata),
- MAKE_CONST_CUSTOM_DATA_GETTER(ldata),
- update_custom_data_pointers};
- static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata),
- MAKE_CONST_CUSTOM_DATA_GETTER(vdata),
- update_custom_data_pointers};
- static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata),
- MAKE_CONST_CUSTOM_DATA_GETTER(edata),
- update_custom_data_pointers};
- static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata),
- MAKE_CONST_CUSTOM_DATA_GETTER(pdata),
- update_custom_data_pointers};
-
-#undef MAKE_CONST_CUSTOM_DATA_GETTER
-#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER
-
- static BuiltinCustomDataLayerProvider position("position",
- ATTR_DOMAIN_POINT,
- CD_PROP_FLOAT3,
- CD_MVERT,
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::NonDeletable,
- point_access,
- make_vertex_position_read_attribute,
- make_vertex_position_write_attribute,
- tag_normals_dirty_when_writing_position);
-
- static BuiltinCustomDataLayerProvider material_index("material_index",
- ATTR_DOMAIN_POLYGON,
- CD_PROP_INT32,
- CD_MPOLY,
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::NonDeletable,
- polygon_access,
- make_material_index_read_attribute,
- make_material_index_write_attribute,
- nullptr);
-
- static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER,
- CD_PROP_FLOAT2,
- CD_MLOOPUV,
- corner_access,
- make_uvs_read_attribute,
- make_uvs_write_attribute);
-
- static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER,
- CD_PROP_COLOR,
- CD_MLOOPCOL,
- corner_access,
- make_vertex_color_read_attribute,
- make_vertex_color_write_attribute);
-
- static VertexGroupsAttributeProvider vertex_groups;
- static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
- static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
- static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access);
- static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access);
-
- return ComponentAttributeProviders({&position, &material_index},
- {&uvs,
- &vertex_colors,
- &corner_custom_data,
- &vertex_groups,
- &point_custom_data,
- &edge_custom_data,
- &polygon_custom_data});
+ }
+ return true;
}
-/**
- * In this function all the attribute providers for a point cloud component are created. Most data
- * in this function is statically allocated, because it does not change over time.
- */
-static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
+void NamedLegacyCustomDataProvider::supported_domains(Vector<AttributeDomain> &r_domains) const
{
- static auto update_custom_data_pointers = [](GeometryComponent &component) {
- PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
- PointCloud *pointcloud = pointcloud_component.get_for_write();
- if (pointcloud != nullptr) {
- BKE_pointcloud_update_customdata_pointers(pointcloud);
- }
- };
- static CustomDataAccessInfo point_access = {
- [](GeometryComponent &component) -> CustomData * {
- PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
- PointCloud *pointcloud = pointcloud_component.get_for_write();
- return pointcloud ? &pointcloud->pdata : nullptr;
- },
- [](const GeometryComponent &component) -> const CustomData * {
- const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>(
- component);
- const PointCloud *pointcloud = pointcloud_component.get_for_read();
- return pointcloud ? &pointcloud->pdata : nullptr;
- },
- update_custom_data_pointers};
-
- static BuiltinCustomDataLayerProvider position(
- "position",
- ATTR_DOMAIN_POINT,
- CD_PROP_FLOAT3,
- CD_PROP_FLOAT3,
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::NonDeletable,
- point_access,
- make_array_read_attribute<float3, ATTR_DOMAIN_POINT>,
- make_array_write_attribute<float3, ATTR_DOMAIN_POINT>,
- nullptr);
- static BuiltinCustomDataLayerProvider radius(
- "radius",
- ATTR_DOMAIN_POINT,
- CD_PROP_FLOAT,
- CD_PROP_FLOAT,
- BuiltinAttributeProvider::Creatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::Deletable,
- point_access,
- make_array_read_attribute<float, ATTR_DOMAIN_POINT>,
- make_array_write_attribute<float, ATTR_DOMAIN_POINT>,
- nullptr);
- static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
- return ComponentAttributeProviders({&position, &radius}, {&point_custom_data});
+ r_domains.append_non_duplicates(domain_);
}
} // namespace blender::bke
@@ -1999,173 +1125,3 @@ void OutputAttributePtr::apply_span_and_save()
}
/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Point Cloud Component
- * \{ */
-
-const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers()
- const
-{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_point_cloud();
- return &providers;
-}
-
-int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const
-{
- BLI_assert(domain == ATTR_DOMAIN_POINT);
- UNUSED_VARS_NDEBUG(domain);
- if (pointcloud_ == nullptr) {
- return 0;
- }
- return pointcloud_->totpoint;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Mesh Component
- * \{ */
-
-const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const
-{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_mesh();
- return &providers;
-}
-
-int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
-{
- BLI_assert(this->attribute_domain_supported(domain));
- if (mesh_ == nullptr) {
- return 0;
- }
- switch (domain) {
- case ATTR_DOMAIN_CORNER:
- return mesh_->totloop;
- case ATTR_DOMAIN_POINT:
- return mesh_->totvert;
- case ATTR_DOMAIN_EDGE:
- return mesh_->totedge;
- case ATTR_DOMAIN_POLYGON:
- return mesh_->totpoly;
- default:
- BLI_assert(false);
- break;
- }
- return 0;
-}
-
-namespace blender::bke {
-
-template<typename T>
-static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
- const TypedReadAttribute<T> &attribute,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totvert);
- attribute_math::DefaultMixer<T> mixer(r_values);
-
- for (const int loop_index : IndexRange(mesh.totloop)) {
- const T value = attribute[loop_index];
- const MLoop &loop = mesh.mloop[loop_index];
- const int point_index = loop.v;
- mixer.mix_in(point_index, value);
- }
- mixer.finalize();
-}
-
-static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh,
- ReadAttributePtr attribute)
-{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- /* We compute all interpolated values at once, because for this interpolation, one has to
- * iterate over all loops anyway. */
- Array<T> values(mesh.totvert);
- adapt_mesh_domain_corner_to_point_impl<T>(mesh, *attribute, values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
- }
- });
- return new_attribute;
-}
-
-template<typename T>
-static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh,
- const TypedReadAttribute<T> &attribute,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totloop);
-
- for (const int loop_index : IndexRange(mesh.totloop)) {
- const int vertex_index = mesh.mloop[loop_index].v;
- r_values[loop_index] = attribute[vertex_index];
- }
-}
-
-static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
- ReadAttributePtr attribute)
-{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- /* It is not strictly necessary to compute the value for all corners here. Instead one could
- * lazily lookup the mesh topology when a specific index accessed. This can be more efficient
- * when an algorithm only accesses very few of the corner values. However, for the algorithms
- * we currently have, precomputing the array is fine. Also, it is easier to implement. */
- Array<T> values(mesh.totloop);
- adapt_mesh_domain_point_to_corner_impl<T>(mesh, *attribute, values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_CORNER,
- std::move(values));
- });
- return new_attribute;
-}
-
-} // namespace blender::bke
-
-ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
- const AttributeDomain new_domain) const
-{
- if (!attribute) {
- return {};
- }
- if (attribute->size() == 0) {
- return {};
- }
- const AttributeDomain old_domain = attribute->domain();
- if (old_domain == new_domain) {
- return attribute;
- }
-
- switch (old_domain) {
- case ATTR_DOMAIN_CORNER: {
- switch (new_domain) {
- case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
- default:
- break;
- }
- break;
- }
- case ATTR_DOMAIN_POINT: {
- switch (new_domain) {
- case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
- default:
- break;
- }
- }
- default:
- break;
- }
-
- return {};
-}
-
-/** \} */
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
new file mode 100644
index 00000000000..299da4c97fe
--- /dev/null
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -0,0 +1,499 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_map.hh"
+#include "BLI_span.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+namespace blender::bke {
+
+class ConstantReadAttribute final : public ReadAttribute {
+ private:
+ void *value_;
+
+ public:
+ ConstantReadAttribute(AttributeDomain domain,
+ const int64_t size,
+ const CPPType &type,
+ const void *value)
+ : ReadAttribute(domain, type, size)
+ {
+ value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ type.copy_to_uninitialized(value, value_);
+ }
+
+ ~ConstantReadAttribute() override
+ {
+ this->cpp_type_.destruct(value_);
+ MEM_freeN(value_);
+ }
+
+ void get_internal(const int64_t UNUSED(index), void *r_value) const override
+ {
+ this->cpp_type_.copy_to_uninitialized(value_, r_value);
+ }
+
+ void initialize_span() const override
+ {
+ const int element_size = cpp_type_.size();
+ array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
+ array_is_temporary_ = true;
+ cpp_type_.fill_uninitialized(value_, array_buffer_, size_);
+ }
+};
+
+template<typename T> class ArrayReadAttribute final : public ReadAttribute {
+ private:
+ Span<T> data_;
+
+ public:
+ ArrayReadAttribute(AttributeDomain domain, Span<T> data)
+ : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(data_[index]);
+ }
+
+ void initialize_span() const override
+ {
+ /* The data will not be modified, so this const_cast is fine. */
+ array_buffer_ = const_cast<T *>(data_.data());
+ array_is_temporary_ = false;
+ }
+};
+
+template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute {
+ private:
+ Array<T> data_;
+
+ public:
+ OwnedArrayReadAttribute(AttributeDomain domain, Array<T> data)
+ : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(std::move(data))
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(data_[index]);
+ }
+
+ void initialize_span() const override
+ {
+ /* The data will not be modified, so this const_cast is fine. */
+ array_buffer_ = const_cast<T *>(data_.data());
+ array_is_temporary_ = false;
+ }
+};
+
+template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
+class DerivedArrayReadAttribute final : public ReadAttribute {
+ private:
+ blender::Span<StructT> data_;
+
+ public:
+ DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data)
+ : ReadAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ const StructT &struct_value = data_[index];
+ const ElemT value = GetFunc(struct_value);
+ new (r_value) ElemT(value);
+ }
+};
+
+template<typename T> class ArrayWriteAttribute final : public WriteAttribute {
+ private:
+ MutableSpan<T> data_;
+
+ public:
+ ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data)
+ : WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(data_[index]);
+ }
+
+ void set_internal(const int64_t index, const void *value) override
+ {
+ data_[index] = *reinterpret_cast<const T *>(value);
+ }
+
+ void initialize_span(const bool UNUSED(write_only)) override
+ {
+ array_buffer_ = data_.data();
+ array_is_temporary_ = false;
+ }
+
+ void apply_span_if_necessary() override
+ {
+ /* Do nothing, because the span contains the attribute itself already. */
+ }
+};
+
+template<typename StructT,
+ typename ElemT,
+ ElemT (*GetFunc)(const StructT &),
+ void (*SetFunc)(StructT &, const ElemT &)>
+class DerivedArrayWriteAttribute final : public WriteAttribute {
+ private:
+ blender::MutableSpan<StructT> data_;
+
+ public:
+ DerivedArrayWriteAttribute(AttributeDomain domain, blender::MutableSpan<StructT> data)
+ : WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ const StructT &struct_value = data_[index];
+ const ElemT value = GetFunc(struct_value);
+ new (r_value) ElemT(value);
+ }
+
+ void set_internal(const int64_t index, const void *value) override
+ {
+ StructT &struct_value = data_[index];
+ const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value);
+ SetFunc(struct_value, typed_value);
+ }
+};
+
+/**
+ * Utility to group together multiple functions that are used to access custom data on geometry
+ * components in a generic way.
+ */
+struct CustomDataAccessInfo {
+ using CustomDataGetter = CustomData *(*)(GeometryComponent &component);
+ using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component);
+ using UpdateCustomDataPointers = void (*)(GeometryComponent &component);
+
+ CustomDataGetter get_custom_data;
+ ConstCustomDataGetter get_const_custom_data;
+ UpdateCustomDataPointers update_custom_data_pointers;
+};
+
+/**
+ * A #BuiltinAttributeProvider is responsible for exactly one attribute on a geometry component.
+ * The attribute is identified by its name and has a fixed domain and type. Builtin attributes do
+ * not follow the same loose rules as other attributes, because they are mapped to internal
+ * "legacy" data structures. For example, some builtin attributes cannot be deleted. */
+class BuiltinAttributeProvider {
+ public:
+ /* Some utility enums to avoid hard to read booleans in function calls. */
+ enum CreatableEnum {
+ Creatable,
+ NonCreatable,
+ };
+ enum WritableEnum {
+ Writable,
+ Readonly,
+ };
+ enum DeletableEnum {
+ Deletable,
+ NonDeletable,
+ };
+
+ protected:
+ const std::string name_;
+ const AttributeDomain domain_;
+ const CustomDataType data_type_;
+ const CreatableEnum createable_;
+ const WritableEnum writable_;
+ const DeletableEnum deletable_;
+
+ public:
+ BuiltinAttributeProvider(std::string name,
+ const AttributeDomain domain,
+ const CustomDataType data_type,
+ const CreatableEnum createable,
+ const WritableEnum writable,
+ const DeletableEnum deletable)
+ : name_(std::move(name)),
+ domain_(domain),
+ data_type_(data_type),
+ createable_(createable),
+ writable_(writable),
+ deletable_(deletable)
+ {
+ }
+
+ virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0;
+ virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0;
+ virtual bool try_delete(GeometryComponent &component) const = 0;
+ virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0;
+ virtual bool exists(const GeometryComponent &component) const = 0;
+
+ blender::StringRefNull name() const
+ {
+ return name_;
+ }
+
+ AttributeDomain domain() const
+ {
+ return domain_;
+ }
+
+ CustomDataType data_type() const
+ {
+ return data_type_;
+ }
+};
+
+/**
+ * A #DynamicAttributesProvider manages a set of named attributes on a geometry component. Each
+ * attribute has a name, domain and type.
+ */
+class DynamicAttributesProvider {
+ public:
+ virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component,
+ const blender::StringRef attribute_name) const = 0;
+ virtual WriteAttributePtr try_get_for_write(GeometryComponent &component,
+ const blender::StringRef attribute_name) const = 0;
+ virtual bool try_delete(GeometryComponent &component,
+ const blender::StringRef attribute_name) const = 0;
+ virtual bool try_create(GeometryComponent &UNUSED(component),
+ const blender::StringRef UNUSED(attribute_name),
+ const AttributeDomain UNUSED(domain),
+ const CustomDataType UNUSED(data_type)) const
+ {
+ /* Some providers should not create new attributes. */
+ return false;
+ };
+
+ virtual bool foreach_attribute(const GeometryComponent &component,
+ const AttributeForeachCallback callback) const = 0;
+ virtual void supported_domains(blender::Vector<AttributeDomain> &r_domains) const = 0;
+};
+
+/**
+ * This is the attribute provider for most user generated attributes.
+ */
+class CustomDataAttributeProvider final : public DynamicAttributesProvider {
+ private:
+ static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 |
+ CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 |
+ CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL;
+ const AttributeDomain domain_;
+ const CustomDataAccessInfo custom_data_access_;
+
+ public:
+ CustomDataAttributeProvider(const AttributeDomain domain,
+ const CustomDataAccessInfo custom_data_access)
+ : domain_(domain), custom_data_access_(custom_data_access)
+ {
+ }
+
+ ReadAttributePtr try_get_for_read(const GeometryComponent &component,
+ const blender::StringRef attribute_name) const final;
+
+ WriteAttributePtr try_get_for_write(GeometryComponent &component,
+ const blender::StringRef attribute_name) const final;
+
+ bool try_delete(GeometryComponent &component,
+ const blender::StringRef attribute_name) const final;
+
+ bool try_create(GeometryComponent &component,
+ const blender::StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type) const final;
+
+ bool foreach_attribute(const GeometryComponent &component,
+ const AttributeForeachCallback callback) const final;
+
+ void supported_domains(blender::Vector<AttributeDomain> &r_domains) const final
+ {
+ r_domains.append_non_duplicates(domain_);
+ }
+
+ private:
+ template<typename T>
+ ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer,
+ const int domain_size) const
+ {
+ return std::make_unique<ArrayReadAttribute<T>>(
+ domain_, Span(static_cast<const T *>(layer.data), domain_size));
+ }
+
+ template<typename T>
+ WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const
+ {
+ return std::make_unique<ArrayWriteAttribute<T>>(
+ domain_, MutableSpan(static_cast<T *>(layer.data), domain_size));
+ }
+
+ bool type_is_supported(CustomDataType data_type) const
+ {
+ return ((1ULL << data_type) & supported_types_mask) != 0;
+ }
+};
+
+/**
+ * This attribute provider is used for uv maps and vertex colors.
+ */
+class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
+ private:
+ using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
+ using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
+ const AttributeDomain domain_;
+ const CustomDataType attribute_type_;
+ const CustomDataType stored_type_;
+ const CustomDataAccessInfo custom_data_access_;
+ const AsReadAttribute as_read_attribute_;
+ const AsWriteAttribute as_write_attribute_;
+
+ public:
+ NamedLegacyCustomDataProvider(const AttributeDomain domain,
+ const CustomDataType attribute_type,
+ const CustomDataType stored_type,
+ const CustomDataAccessInfo custom_data_access,
+ const AsReadAttribute as_read_attribute,
+ const AsWriteAttribute as_write_attribute)
+ : domain_(domain),
+ attribute_type_(attribute_type),
+ stored_type_(stored_type),
+ custom_data_access_(custom_data_access),
+ as_read_attribute_(as_read_attribute),
+ as_write_attribute_(as_write_attribute)
+ {
+ }
+
+ ReadAttributePtr try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final;
+ WriteAttributePtr try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final;
+ bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
+ bool foreach_attribute(const GeometryComponent &component,
+ const AttributeForeachCallback callback) const final;
+ void supported_domains(Vector<AttributeDomain> &r_domains) const final;
+};
+
+/**
+ * This provider is used to provide access to builtin attributes. It supports making internal types
+ * available as different types. For example, the vertex position attribute is stored as part of
+ * the #MVert struct, but is exposed as float3 attribute.
+ */
+class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
+ using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
+ using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
+ using UpdateOnRead = void (*)(const GeometryComponent &component);
+ using UpdateOnWrite = void (*)(GeometryComponent &component);
+ const CustomDataType stored_type_;
+ const CustomDataAccessInfo custom_data_access_;
+ const AsReadAttribute as_read_attribute_;
+ const AsWriteAttribute as_write_attribute_;
+ const UpdateOnRead update_on_read_;
+ const UpdateOnWrite update_on_write_;
+
+ public:
+ BuiltinCustomDataLayerProvider(std::string attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType attribute_type,
+ const CustomDataType stored_type,
+ const CreatableEnum creatable,
+ const WritableEnum writable,
+ const DeletableEnum deletable,
+ const CustomDataAccessInfo custom_data_access,
+ const AsReadAttribute as_read_attribute,
+ const AsWriteAttribute as_write_attribute,
+ const UpdateOnRead update_on_read,
+ const UpdateOnWrite update_on_write)
+ : BuiltinAttributeProvider(
+ std::move(attribute_name), domain, attribute_type, creatable, writable, deletable),
+ stored_type_(stored_type),
+ custom_data_access_(custom_data_access),
+ as_read_attribute_(as_read_attribute),
+ as_write_attribute_(as_write_attribute),
+ update_on_read_(update_on_read),
+ update_on_write_(update_on_write)
+ {
+ }
+
+ ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final;
+ WriteAttributePtr try_get_for_write(GeometryComponent &component) const final;
+ bool try_delete(GeometryComponent &component) const final;
+ bool try_create(GeometryComponent &component) const final;
+ bool exists(const GeometryComponent &component) const final;
+};
+
+/**
+ * This is a container for multiple attribute providers that are used by one geometry component
+ * type (e.g. there is a set of attribute providers for mesh components).
+ */
+class ComponentAttributeProviders {
+ private:
+ /**
+ * Builtin attribute providers are identified by their name. Attribute names that are in this
+ * map will only be accessed using builtin attribute providers. Therefore, these providers have
+ * higher priority when an attribute name is looked up. Usually, that means that builtin
+ * providers are checked before dynamic ones.
+ */
+ blender::Map<std::string, const BuiltinAttributeProvider *> builtin_attribute_providers_;
+ /**
+ * An ordered list of dynamic attribute providers. The order is important because that is order
+ * in which they are checked when an attribute is looked up.
+ */
+ blender::Vector<const DynamicAttributesProvider *> dynamic_attribute_providers_;
+ /**
+ * All the domains that are supported by at least one of the providers above.
+ */
+ blender::Vector<AttributeDomain> supported_domains_;
+
+ public:
+ ComponentAttributeProviders(
+ blender::Span<const BuiltinAttributeProvider *> builtin_attribute_providers,
+ blender::Span<const DynamicAttributesProvider *> dynamic_attribute_providers)
+ : dynamic_attribute_providers_(dynamic_attribute_providers)
+ {
+ blender::Set<AttributeDomain> domains;
+ for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) {
+ /* Use #add_new to make sure that no two builtin attributes have the same name. */
+ builtin_attribute_providers_.add_new(provider->name(), provider);
+ supported_domains_.append_non_duplicates(provider->domain());
+ }
+ for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) {
+ provider->supported_domains(supported_domains_);
+ }
+ }
+
+ const blender::Map<std::string, const BuiltinAttributeProvider *> &builtin_attribute_providers()
+ const
+ {
+ return builtin_attribute_providers_;
+ }
+
+ blender::Span<const DynamicAttributesProvider *> dynamic_attribute_providers() const
+ {
+ return dynamic_attribute_providers_;
+ }
+
+ blender::Span<AttributeDomain> supported_domains() const
+ {
+ return supported_domains_;
+ }
+};
+
+} // namespace blender::bke \ No newline at end of file
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index 9f5e038fb82..ec8962d5f6d 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -94,8 +94,9 @@ bool BKE_copybuffer_read(Main *bmain_dst,
}
/* Here appending/linking starts. */
const int flag = 0;
+ const int id_tag_extra = 0;
struct LibraryLink_Params liblink_params;
- BLO_library_link_params_init(&liblink_params, bmain_dst, flag);
+ BLO_library_link_params_init(&liblink_params, bmain_dst, flag, id_tag_extra);
Main *mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
BLO_library_link_copypaste(mainl, bh, id_types_mask);
BLO_library_link_end(mainl, &bh, &liblink_params);
@@ -130,6 +131,7 @@ int BKE_copybuffer_paste(bContext *C,
Main *mainl = NULL;
Library *lib;
BlendHandle *bh;
+ const int id_tag_extra = 0;
bh = BLO_blendhandle_from_file(libname, reports);
@@ -148,7 +150,8 @@ int BKE_copybuffer_paste(bContext *C,
/* here appending/linking starts */
struct LibraryLink_Params liblink_params;
- BLO_library_link_params_init_with_context(&liblink_params, bmain, flag, scene, view_layer, v3d);
+ BLO_library_link_params_init_with_context(
+ &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d);
mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
const int num_pasted = BLO_library_link_copypaste(mainl, bh, id_types_mask);
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 6bc385ecd31..cbf7a4483c0 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -914,6 +914,15 @@ struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C)
return NULL;
}
+struct SpaceSpreadsheet *CTX_wm_space_spreadsheet(const bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_SPREADSHEET) {
+ return area->spacedata.first;
+ }
+ return NULL;
+}
+
void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
{
C->wm.manager = wm;
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index 9d9cace3a35..55426f738ff 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -184,37 +184,39 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage)
{
- std::stringstream ss;
- ss.precision(9);
-
+ DynStr *matte_id = BLI_dynstr_new();
bool first = true;
LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) {
if (!first) {
- ss << ',';
+ BLI_dynstr_append(matte_id, ",");
}
- blender::StringRef entry_name(entry->name, BLI_strnlen(entry->name, sizeof(entry->name)));
- if (!entry_name.is_empty()) {
- ss << entry_name;
+ if (BLI_strnlen(entry->name, sizeof(entry->name)) != 0) {
+ BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name));
}
else {
- ss << '<' << std::scientific << entry->encoded_hash << '>';
+ BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash);
}
first = false;
}
-
- /* Convert result to C string. */
- const std::string result_string = ss.str();
- const char *c_str = result_string.c_str();
- size_t result_len = result_string.size() + 1;
- char *result = static_cast<char *>(MEM_mallocN(sizeof(char) * result_len, __func__));
- memcpy(result, c_str, result_len);
+ char *result = BLI_dynstr_get_cstring(matte_id);
+ BLI_dynstr_free(matte_id);
return result;
}
void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const char *matte_id)
{
BLI_freelistN(&node_storage->entries);
- std::optional<CryptomatteSession> session = std::nullopt;
+
+ if (matte_id == nullptr) {
+ MEM_SAFE_FREE(node_storage->matte_id);
+ return;
+ }
+ /* Update the matte_id so the files can be opened in versions that don't
+ * use `CryptomatteEntry`. */
+ if (matte_id != node_storage->matte_id && STREQ(node_storage->matte_id, matte_id)) {
+ MEM_SAFE_FREE(node_storage->matte_id);
+ node_storage->matte_id = static_cast<char *>(MEM_dupallocN(matte_id));
+ }
std::istringstream ss(matte_id);
while (ss.good()) {
diff --git a/source/blender/blenkernel/intern/cryptomatte_test.cc b/source/blender/blenkernel/intern/cryptomatte_test.cc
index 5481b97913c..faf1ad91cdc 100644
--- a/source/blender/blenkernel/intern/cryptomatte_test.cc
+++ b/source/blender/blenkernel/intern/cryptomatte_test.cc
@@ -21,8 +21,6 @@
#include "BKE_cryptomatte.hh"
#include "BKE_image.h"
-#include "DNA_node_types.h"
-
#include "RE_pipeline.h"
#include "MEM_guardedalloc.h"
@@ -77,17 +75,15 @@ static void test_cryptomatte_manifest(std::string expected, std::string manifest
TEST(cryptomatte, layer_from_manifest)
{
test_cryptomatte_manifest("{}", "{}");
- test_cryptomatte_manifest("{\"Object\":\"12345678\"}", "{\"Object\": \"12345678\"}");
- test_cryptomatte_manifest("{\"Object\":\"12345678\",\"Object2\":\"87654321\"}",
- "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}");
- test_cryptomatte_manifest(
- "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}",
- " { \"Object\" : \"12345678\" , \"Object2\" : \"87654321\" } ");
- test_cryptomatte_manifest("{\"Object\\\"01\\\"\":\"12345678\"}",
- "{\"Object\\\"01\\\"\": \"12345678\"}");
+ test_cryptomatte_manifest(R"({"Object":"12345678"})", R"({"Object": "12345678"})");
+ test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321")})",
+ R"({"Object":"12345678","Object2":"87654321"})");
+ test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321"})",
+ R"( { "Object" : "12345678" , "Object2" : "87654321" } )");
+ test_cryptomatte_manifest(R"({"Object\"01\"":"12345678"})", R"({"Object\"01\"": "12345678"})");
test_cryptomatte_manifest(
- "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\",\"Object2\":\"87654321\"}",
- "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\", \"Object2\":\"87654321\"}");
+ R"({"Object\"01\"":"12345678","Object":"12345678","Object2":"87654321"})",
+ R"({"Object\"01\"":"12345678","Object":"12345678", "Object2":"87654321"})");
}
TEST(cryptomatte, extract_layer_hash_from_metadata_key)
@@ -127,7 +123,7 @@ static void validate_cryptomatte_session_from_stamp_data(void *UNUSED(data),
EXPECT_STREQ("uint32_to_float32", propvalue);
}
else if (prop_name == "cryptomatte/87f095e/manifest") {
- EXPECT_STREQ("{\"Object\":\"12345678\"}", propvalue);
+ EXPECT_STREQ(R"({"Object":"12345678"})", propvalue);
}
else if (prop_name == "cryptomatte/c42daa7/name") {
@@ -140,7 +136,7 @@ static void validate_cryptomatte_session_from_stamp_data(void *UNUSED(data),
EXPECT_STREQ("uint32_to_float32", propvalue);
}
else if (prop_name == "cryptomatte/c42daa7/manifest") {
- EXPECT_STREQ("{\"Object2\":\"87654321\"}", propvalue);
+ EXPECT_STREQ(R"({"Object2":"87654321"})", propvalue);
}
else {
@@ -155,12 +151,12 @@ TEST(cryptomatte, session_from_stamp_data)
MEM_callocN(sizeof(RenderResult), __func__));
BKE_render_result_stamp_data(render_result, "cryptomatte/qwerty/name", "layer1");
BKE_render_result_stamp_data(
- render_result, "cryptomatte/qwerty/manifest", "{\"Object\":\"12345678\"}");
+ render_result, "cryptomatte/qwerty/manifest", R"({"Object":"12345678"})");
BKE_render_result_stamp_data(render_result, "cryptomatte/uiop/name", "layer2");
BKE_render_result_stamp_data(
- render_result, "cryptomatte/uiop/manifest", "{\"Object2\":\"87654321\"}");
- CryptomatteSession *session = BKE_cryptomatte_init_from_render_result(render_result);
- EXPECT_NE(session, nullptr);
+ render_result, "cryptomatte/uiop/manifest", R"({"Object2":"87654321"})");
+ CryptomatteSessionPtr session(BKE_cryptomatte_init_from_render_result(render_result));
+ EXPECT_NE(session.get(), nullptr);
RE_FreeRenderResult(render_result);
/* Create StampData from CryptomatteSession. */
@@ -168,25 +164,13 @@ TEST(cryptomatte, session_from_stamp_data)
BLI_strncpy(view_layer.name, "viewlayername", sizeof(view_layer.name));
RenderResult *render_result2 = static_cast<RenderResult *>(
MEM_callocN(sizeof(RenderResult), __func__));
- BKE_cryptomatte_store_metadata(session, render_result2, &view_layer);
+ BKE_cryptomatte_store_metadata(session.get(), render_result2, &view_layer);
/* Validate StampData. */
BKE_stamp_info_callback(
nullptr, render_result2->stamp_data, validate_cryptomatte_session_from_stamp_data, false);
RE_FreeRenderResult(render_result2);
- BKE_cryptomatte_free(session);
-}
-
-TEST(cryptomatte, T86026)
-{
- NodeCryptomatte storage = {{0.0f}};
- CryptomatteEntry entry = {nullptr};
- BLI_addtail(&storage.entries, &entry);
- entry.encoded_hash = 4.76190593e-07;
- char *matte_id = BKE_cryptomatte_entries_to_matte_id(&storage);
- EXPECT_STREQ("<4.761905927e-07>", matte_id);
- MEM_freeN(matte_id);
}
} // namespace blender::bke::cryptomatte::tests
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index c860e57520d..708b1971bd5 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -875,9 +875,9 @@ static float (*displist_vert_coords_alloc(ListBase *dispbase, int *r_vert_len))[
allverts = MEM_mallocN(sizeof(float[3]) * (*r_vert_len), "displist_vert_coords_alloc allverts");
fp = (float *)allverts;
LISTBASE_FOREACH (DispList *, dl, dispbase) {
- int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
- memcpy(fp, dl->verts, sizeof(float) * offs);
- fp += offs;
+ int ofs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
+ memcpy(fp, dl->verts, sizeof(float) * ofs);
+ fp += ofs;
}
return allverts;
@@ -889,9 +889,9 @@ static void displist_vert_coords_apply(ListBase *dispbase, float (*allverts)[3])
fp = (float *)allverts;
LISTBASE_FOREACH (DispList *, dl, dispbase) {
- int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
- memcpy(dl->verts, fp, sizeof(float) * offs);
- fp += offs;
+ int ofs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
+ memcpy(dl->verts, fp, sizeof(float) * ofs);
+ fp += ofs;
}
}
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
new file mode 100644
index 00000000000..a6ee7a1b918
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -0,0 +1,173 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_float4x4.hh"
+#include "BLI_map.hh"
+#include "BLI_rand.hh"
+#include "BLI_set.hh"
+#include "BLI_span.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_collection_types.h"
+
+#include "BKE_geometry_set.hh"
+
+using blender::float4x4;
+using blender::Map;
+using blender::MutableSpan;
+using blender::Set;
+using blender::Span;
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component Implementation
+ * \{ */
+
+InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentType::Instances)
+{
+}
+
+GeometryComponent *InstancesComponent::copy() const
+{
+ InstancesComponent *new_component = new InstancesComponent();
+ new_component->transforms_ = transforms_;
+ new_component->instanced_data_ = instanced_data_;
+ return new_component;
+}
+
+void InstancesComponent::clear()
+{
+ instanced_data_.clear();
+ transforms_.clear();
+}
+
+void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id)
+{
+ InstancedData data;
+ data.type = INSTANCE_DATA_TYPE_OBJECT;
+ data.data.object = object;
+ this->add_instance(data, transform, id);
+}
+
+void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id)
+{
+ InstancedData data;
+ data.type = INSTANCE_DATA_TYPE_COLLECTION;
+ data.data.collection = collection;
+ this->add_instance(data, transform, id);
+}
+
+void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id)
+{
+ instanced_data_.append(data);
+ transforms_.append(transform);
+ ids_.append(id);
+}
+
+Span<InstancedData> InstancesComponent::instanced_data() const
+{
+ return instanced_data_;
+}
+
+Span<float4x4> InstancesComponent::transforms() const
+{
+ return transforms_;
+}
+
+Span<int> InstancesComponent::ids() const
+{
+ return ids_;
+}
+
+MutableSpan<float4x4> InstancesComponent::transforms()
+{
+ return transforms_;
+}
+
+int InstancesComponent::instances_amount() const
+{
+ const int size = instanced_data_.size();
+ BLI_assert(transforms_.size() == size);
+ return size;
+}
+
+bool InstancesComponent::is_empty() const
+{
+ return transforms_.size() == 0;
+}
+
+static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
+{
+ using namespace blender;
+ Array<int> unique_ids(original_ids.size());
+
+ Set<int> used_unique_ids;
+ used_unique_ids.reserve(original_ids.size());
+ Vector<int> instances_with_id_collision;
+ for (const int instance_index : original_ids.index_range()) {
+ const int original_id = original_ids[instance_index];
+ if (used_unique_ids.add(original_id)) {
+ /* The original id has not been used by another instance yet. */
+ unique_ids[instance_index] = original_id;
+ }
+ else {
+ /* The original id of this instance collided with a previous instance, it needs to be looked
+ * at again in a second pass. Don't generate a new random id here, because this might collide
+ * with other existing ids. */
+ instances_with_id_collision.append(instance_index);
+ }
+ }
+
+ Map<int, RandomNumberGenerator> generator_by_original_id;
+ for (const int instance_index : instances_with_id_collision) {
+ const int original_id = original_ids[instance_index];
+ RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
+ RandomNumberGenerator rng;
+ rng.seed_random(original_id);
+ return rng;
+ });
+
+ const int max_iteration = 100;
+ for (int iteration = 0;; iteration++) {
+ /* Try generating random numbers until an unused one has been found. */
+ const int random_id = rng.get_int32();
+ if (used_unique_ids.add(random_id)) {
+ /* This random id is not used by another instance. */
+ unique_ids[instance_index] = random_id;
+ break;
+ }
+ if (iteration == max_iteration) {
+ /* It seems to be very unlikely that we ever run into this case (assuming there are less
+ * than 2^30 instances). However, if that happens, it's better to use an id that is not
+ * unique than to be stuck in an infinite loop. */
+ unique_ids[instance_index] = original_id;
+ break;
+ }
+ }
+ }
+
+ return unique_ids;
+}
+
+blender::Span<int> InstancesComponent::almost_unique_ids() const
+{
+ std::lock_guard lock(almost_unique_ids_mutex_);
+ if (almost_unique_ids_.size() != ids_.size()) {
+ almost_unique_ids_ = generate_unique_instance_ids(ids_);
+ }
+ return almost_unique_ids_;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
new file mode 100644
index 00000000000..53defc89b7e
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -0,0 +1,938 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_threads.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_attribute_access.hh"
+#include "BKE_attribute_math.hh"
+#include "BKE_deform.h"
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+
+#include "attribute_access_intern.hh"
+
+/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
+extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
+
+using blender::bke::ReadAttributePtr;
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component Implementation
+ * \{ */
+
+MeshComponent::MeshComponent() : GeometryComponent(GeometryComponentType::Mesh)
+{
+}
+
+MeshComponent::~MeshComponent()
+{
+ this->clear();
+}
+
+GeometryComponent *MeshComponent::copy() const
+{
+ MeshComponent *new_component = new MeshComponent();
+ if (mesh_ != nullptr) {
+ new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ new_component->vertex_group_names_ = blender::Map(vertex_group_names_);
+ }
+ return new_component;
+}
+
+void MeshComponent::clear()
+{
+ BLI_assert(this->is_mutable());
+ if (mesh_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, mesh_);
+ }
+ mesh_ = nullptr;
+ }
+ vertex_group_names_.clear();
+}
+
+bool MeshComponent::has_mesh() const
+{
+ return mesh_ != nullptr;
+}
+
+/* Clear the component and replace it with the new mesh. */
+void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ this->clear();
+ mesh_ = mesh;
+ ownership_ = ownership;
+}
+
+/* This function exists for the same reason as #vertex_group_names_. Non-nodes modifiers need to
+ * be able to replace the mesh data without losing the vertex group names, which may have come
+ * from another object. */
+void MeshComponent::replace_mesh_but_keep_vertex_group_names(Mesh *mesh,
+ GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ if (mesh_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, mesh_);
+ }
+ mesh_ = nullptr;
+ }
+ mesh_ = mesh;
+ ownership_ = ownership;
+}
+
+/* Return the mesh and clear the component. The caller takes over responsibility for freeing the
+ * mesh (if the component was responsible before). */
+Mesh *MeshComponent::release()
+{
+ BLI_assert(this->is_mutable());
+ Mesh *mesh = mesh_;
+ mesh_ = nullptr;
+ return mesh;
+}
+
+void MeshComponent::copy_vertex_group_names_from_object(const Object &object)
+{
+ BLI_assert(this->is_mutable());
+ vertex_group_names_.clear();
+ int index = 0;
+ LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) {
+ vertex_group_names_.add(group->name, index);
+ index++;
+ }
+}
+
+const blender::Map<std::string, int> &MeshComponent::vertex_group_names() const
+{
+ return vertex_group_names_;
+}
+
+/* This is only exposed for the internal attribute API. */
+blender::Map<std::string, int> &MeshComponent::vertex_group_names()
+{
+ return vertex_group_names_;
+}
+
+/* Get the mesh from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */
+const Mesh *MeshComponent::get_for_read() const
+{
+ return mesh_;
+}
+
+/* Get the mesh from this component. This method can only be used when the component is mutable,
+ * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */
+Mesh *MeshComponent::get_for_write()
+{
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
+ ownership_ = GeometryOwnershipType::Owned;
+ }
+ return mesh_;
+}
+
+bool MeshComponent::is_empty() const
+{
+ return mesh_ == nullptr;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Attribute Access
+ * \{ */
+
+int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
+{
+ BLI_assert(this->attribute_domain_supported(domain));
+ if (mesh_ == nullptr) {
+ return 0;
+ }
+ switch (domain) {
+ case ATTR_DOMAIN_CORNER:
+ return mesh_->totloop;
+ case ATTR_DOMAIN_POINT:
+ return mesh_->totvert;
+ case ATTR_DOMAIN_EDGE:
+ return mesh_->totedge;
+ case ATTR_DOMAIN_POLYGON:
+ return mesh_->totpoly;
+ default:
+ BLI_assert(false);
+ break;
+ }
+ return 0;
+}
+
+namespace blender::bke {
+
+template<typename T>
+static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
+ const TypedReadAttribute<T> &attribute,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totvert);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int loop_index : IndexRange(mesh.totloop)) {
+ const T value = attribute[loop_index];
+ const MLoop &loop = mesh.mloop[loop_index];
+ const int point_index = loop.v;
+ mixer.mix_in(point_index, value);
+ }
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ /* We compute all interpolated values at once, because for this interpolation, one has to
+ * iterate over all loops anyway. */
+ Array<T> values(mesh.totvert);
+ adapt_mesh_domain_corner_to_point_impl<T>(mesh, *attribute, values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+template<typename T>
+static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh,
+ const TypedReadAttribute<T> &attribute,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totloop);
+
+ for (const int loop_index : IndexRange(mesh.totloop)) {
+ const int vertex_index = mesh.mloop[loop_index].v;
+ r_values[loop_index] = attribute[vertex_index];
+ }
+}
+
+static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ /* It is not strictly necessary to compute the value for all corners here. Instead one could
+ * lazily lookup the mesh topology when a specific index accessed. This can be more efficient
+ * when an algorithm only accesses very few of the corner values. However, for the algorithms
+ * we currently have, precomputing the array is fine. Also, it is easier to implement. */
+ Array<T> values(mesh.totloop);
+ adapt_mesh_domain_point_to_corner_impl<T>(mesh, *attribute, values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_CORNER,
+ std::move(values));
+ });
+ return new_attribute;
+}
+
+/**
+ * \note Theoretically this interpolation does not need to compute all values at once.
+ * However, doing that makes the implementation simpler, and this can be optimized in the future if
+ * only some values are required.
+ */
+template<typename T>
+static void adapt_mesh_domain_corner_to_polygon_impl(const Mesh &mesh,
+ Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totpoly);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const T value = old_values[loop_index];
+ mixer.mix_in(poly_index, value);
+ }
+ }
+
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totpoly);
+ adapt_mesh_domain_corner_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+template<typename T>
+void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh,
+ Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totvert);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ const T value = old_values[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ const int point_index = loop.v;
+ mixer.mix_in(point_index, value);
+ }
+ }
+
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totvert);
+ adapt_mesh_domain_polygon_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+template<typename T>
+void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh,
+ const Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totloop);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop);
+ poly_corner_values.fill(old_values[poly_index]);
+ }
+}
+
+static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totloop);
+ adapt_mesh_domain_polygon_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+/**
+ * \note Theoretically this interpolation does not need to compute all values at once.
+ * However, doing that makes the implementation simpler, and this can be optimized in the future if
+ * only some values are required.
+ */
+template<typename T>
+static void adapt_mesh_domain_point_to_polygon_impl(const Mesh &mesh,
+ const Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totpoly);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ MLoop &loop = mesh.mloop[loop_index];
+ const int point_index = loop.v;
+ mixer.mix_in(poly_index, old_values[point_index]);
+ }
+ }
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totpoly);
+ adapt_mesh_domain_point_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+} // namespace blender::bke
+
+ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
+ const AttributeDomain new_domain) const
+{
+ if (!attribute) {
+ return {};
+ }
+ if (attribute->size() == 0) {
+ return {};
+ }
+ const AttributeDomain old_domain = attribute->domain();
+ if (old_domain == new_domain) {
+ return attribute;
+ }
+
+ switch (old_domain) {
+ case ATTR_DOMAIN_CORNER: {
+ switch (new_domain) {
+ case ATTR_DOMAIN_POINT:
+ return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
+ case ATTR_DOMAIN_POLYGON:
+ return blender::bke::adapt_mesh_domain_corner_to_polygon(*mesh_, std::move(attribute));
+ default:
+ break;
+ }
+ break;
+ }
+ case ATTR_DOMAIN_POINT: {
+ switch (new_domain) {
+ case ATTR_DOMAIN_CORNER:
+ return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
+ case ATTR_DOMAIN_POLYGON:
+ return blender::bke::adapt_mesh_domain_point_to_polygon(*mesh_, std::move(attribute));
+ default:
+ break;
+ }
+ break;
+ }
+ case ATTR_DOMAIN_POLYGON: {
+ switch (new_domain) {
+ case ATTR_DOMAIN_POINT:
+ return blender::bke::adapt_mesh_domain_polygon_to_point(*mesh_, std::move(attribute));
+ case ATTR_DOMAIN_CORNER:
+ return blender::bke::adapt_mesh_domain_polygon_to_corner(*mesh_, std::move(attribute));
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return {};
+}
+
+static Mesh *get_mesh_from_component_for_write(GeometryComponent &component)
+{
+ BLI_assert(component.type() == GeometryComponentType::Mesh);
+ MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
+ return mesh_component.get_for_write();
+}
+
+static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component)
+{
+ BLI_assert(component.type() == GeometryComponentType::Mesh);
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return mesh_component.get_for_read();
+}
+
+namespace blender::bke {
+
+static float3 get_vertex_position(const MVert &vert)
+{
+ return float3(vert.co);
+}
+
+static void set_vertex_position(MVert &vert, const float3 &position)
+{
+ copy_v3_v3(vert.co, position);
+}
+
+static ReadAttributePtr make_vertex_position_read_attribute(const void *data,
+ const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_position>>(
+ ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size));
+}
+
+static WriteAttributePtr make_vertex_position_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<
+ DerivedArrayWriteAttribute<MVert, float3, get_vertex_position, set_vertex_position>>(
+ ATTR_DOMAIN_POINT, MutableSpan<MVert>((MVert *)data, domain_size));
+}
+
+static void tag_normals_dirty_when_writing_position(GeometryComponent &component)
+{
+ Mesh *mesh = get_mesh_from_component_for_write(component);
+ if (mesh != nullptr) {
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+}
+
+static int get_material_index(const MPoly &mpoly)
+{
+ return static_cast<int>(mpoly.mat_nr);
+}
+
+static void set_material_index(MPoly &mpoly, const int &index)
+{
+ mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX));
+}
+
+static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>(
+ ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size));
+}
+
+static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<
+ DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>(
+ ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size));
+}
+
+static float3 get_vertex_normal(const MVert &vert)
+{
+ float3 result;
+ normal_short_to_float_v3(result, vert.no);
+ return result;
+}
+
+static ReadAttributePtr make_vertex_normal_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_normal>>(
+ ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size));
+}
+
+static void update_vertex_normals_when_dirty(const GeometryComponent &component)
+{
+ const Mesh *mesh = get_mesh_from_component_for_read(component);
+ if (mesh == nullptr) {
+ return;
+ }
+
+ /* Since normals are derived data, const write access to them is okay. However, ensure that
+ * two threads don't use write normals to a mesh at the same time. Note that this relies on
+ * the idempotence of the operation; calculating the normals just fills the MVert struct
+ * rather than allocating new memory. */
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
+ BLI_mutex_lock(mesh_eval_mutex);
+
+ /* Check again to avoid a second thread needlessly recalculating the same normals. */
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ BKE_mesh_calc_normals(const_cast<Mesh *>(mesh));
+ }
+
+ BLI_mutex_unlock(mesh_eval_mutex);
+ }
+}
+
+static bool get_shade_smooth(const MPoly &mpoly)
+{
+ return mpoly.flag & ME_SMOOTH;
+}
+
+static void set_shade_smooth(MPoly &mpoly, const bool &value)
+{
+ SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH);
+}
+
+static ReadAttributePtr make_shade_smooth_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MPoly, bool, get_shade_smooth>>(
+ ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size));
+}
+
+static WriteAttributePtr make_shade_smooth_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<
+ DerivedArrayWriteAttribute<MPoly, bool, get_shade_smooth, set_shade_smooth>>(
+ ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size));
+}
+
+static float2 get_loop_uv(const MLoopUV &uv)
+{
+ return float2(uv.uv);
+}
+
+static void set_loop_uv(MLoopUV &uv, const float2 &co)
+{
+ copy_v2_v2(uv.uv, co);
+}
+
+static ReadAttributePtr make_uvs_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, get_loop_uv>>(
+ ATTR_DOMAIN_CORNER, Span((const MLoopUV *)data, domain_size));
+}
+
+static WriteAttributePtr make_uvs_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayWriteAttribute<MLoopUV, float2, get_loop_uv, set_loop_uv>>(
+ ATTR_DOMAIN_CORNER, MutableSpan((MLoopUV *)data, domain_size));
+}
+
+static Color4f get_loop_color(const MLoopCol &col)
+{
+ Color4f value;
+ rgba_uchar_to_float(value, &col.r);
+ return value;
+}
+
+static void set_loop_color(MLoopCol &col, const Color4f &value)
+{
+ rgba_float_to_uchar(&col.r, value);
+}
+
+static ReadAttributePtr make_vertex_color_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<DerivedArrayReadAttribute<MLoopCol, Color4f, get_loop_color>>(
+ ATTR_DOMAIN_CORNER, Span((const MLoopCol *)data, domain_size));
+}
+
+static WriteAttributePtr make_vertex_color_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<
+ DerivedArrayWriteAttribute<MLoopCol, Color4f, get_loop_color, set_loop_color>>(
+ ATTR_DOMAIN_CORNER, MutableSpan((MLoopCol *)data, domain_size));
+}
+
+class VertexWeightWriteAttribute final : public WriteAttribute {
+ private:
+ MDeformVert *dverts_;
+ const int dvert_index_;
+
+ public:
+ VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index)
+ : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
+ dverts_(dverts),
+ dvert_index_(dvert_index)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ get_internal(dverts_, dvert_index_, index, r_value);
+ }
+
+ void set_internal(const int64_t index, const void *value) override
+ {
+ MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
+ weight->weight = *reinterpret_cast<const float *>(value);
+ }
+
+ static void get_internal(const MDeformVert *dverts,
+ const int dvert_index,
+ const int64_t index,
+ void *r_value)
+ {
+ if (dverts == nullptr) {
+ *(float *)r_value = 0.0f;
+ return;
+ }
+ const MDeformVert &dvert = dverts[index];
+ for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
+ if (weight.def_nr == dvert_index) {
+ *(float *)r_value = weight.weight;
+ return;
+ }
+ }
+ *(float *)r_value = 0.0f;
+ }
+};
+
+class VertexWeightReadAttribute final : public ReadAttribute {
+ private:
+ const MDeformVert *dverts_;
+ const int dvert_index_;
+
+ public:
+ VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index)
+ : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
+ dverts_(dverts),
+ dvert_index_(dvert_index)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value);
+ }
+};
+
+/**
+ * This provider makes vertex groups available as float attributes.
+ */
+class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
+ public:
+ ReadAttributePtr try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final
+ {
+ BLI_assert(component.type() == GeometryComponentType::Mesh);
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as(
+ attribute_name, -1);
+ if (vertex_group_index < 0) {
+ return {};
+ }
+ if (mesh == nullptr || mesh->dvert == nullptr) {
+ static const float default_value = 0.0f;
+ return std::make_unique<ConstantReadAttribute>(
+ ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get<float>(), &default_value);
+ }
+ return std::make_unique<VertexWeightReadAttribute>(
+ mesh->dvert, mesh->totvert, vertex_group_index);
+ }
+
+ WriteAttributePtr try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final
+ {
+ BLI_assert(component.type() == GeometryComponentType::Mesh);
+ MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
+ Mesh *mesh = mesh_component.get_for_write();
+ if (mesh == nullptr) {
+ return {};
+ }
+ const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as(
+ attribute_name, -1);
+ if (vertex_group_index < 0) {
+ return {};
+ }
+ if (mesh->dvert == nullptr) {
+ BKE_object_defgroup_data_create(&mesh->id);
+ }
+ else {
+ /* Copy the data layer if it is shared with some other mesh. */
+ mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer(
+ &mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
+ }
+ return std::make_unique<blender::bke::VertexWeightWriteAttribute>(
+ mesh->dvert, mesh->totvert, vertex_group_index);
+ }
+
+ bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
+ {
+ BLI_assert(component.type() == GeometryComponentType::Mesh);
+ MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
+
+ const int vertex_group_index = mesh_component.vertex_group_names().pop_default_as(
+ attribute_name, -1);
+ if (vertex_group_index < 0) {
+ return false;
+ }
+ Mesh *mesh = mesh_component.get_for_write();
+ if (mesh == nullptr) {
+ return true;
+ }
+ if (mesh->dvert == nullptr) {
+ return true;
+ }
+ for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) {
+ MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index);
+ BKE_defvert_remove_group(&dvert, weight);
+ }
+ return true;
+ }
+
+ bool foreach_attribute(const GeometryComponent &component,
+ const AttributeForeachCallback callback) const final
+ {
+ BLI_assert(component.type() == GeometryComponentType::Mesh);
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ for (const auto item : mesh_component.vertex_group_names().items()) {
+ const StringRefNull name = item.key;
+ const int vertex_group_index = item.value;
+ if (vertex_group_index >= 0) {
+ AttributeMetaData meta_data{ATTR_DOMAIN_POINT, CD_PROP_FLOAT};
+ if (!callback(name, meta_data)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ void supported_domains(Vector<AttributeDomain> &r_domains) const final
+ {
+ r_domains.append_non_duplicates(ATTR_DOMAIN_POINT);
+ }
+};
+
+/**
+ * In this function all the attribute providers for a mesh component are created. Most data in this
+ * function is statically allocated, because it does not change over time.
+ */
+static ComponentAttributeProviders create_attribute_providers_for_mesh()
+{
+ static auto update_custom_data_pointers = [](GeometryComponent &component) {
+ Mesh *mesh = get_mesh_from_component_for_write(component);
+ if (mesh != nullptr) {
+ BKE_mesh_update_customdata_pointers(mesh, false);
+ }
+ };
+
+#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \
+ [](GeometryComponent &component) -> CustomData * { \
+ Mesh *mesh = get_mesh_from_component_for_write(component); \
+ return mesh ? &mesh->NAME : nullptr; \
+ }
+#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \
+ [](const GeometryComponent &component) -> const CustomData * { \
+ const Mesh *mesh = get_mesh_from_component_for_read(component); \
+ return mesh ? &mesh->NAME : nullptr; \
+ }
+
+ static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata),
+ MAKE_CONST_CUSTOM_DATA_GETTER(ldata),
+ update_custom_data_pointers};
+ static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata),
+ MAKE_CONST_CUSTOM_DATA_GETTER(vdata),
+ update_custom_data_pointers};
+ static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata),
+ MAKE_CONST_CUSTOM_DATA_GETTER(edata),
+ update_custom_data_pointers};
+ static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata),
+ MAKE_CONST_CUSTOM_DATA_GETTER(pdata),
+ update_custom_data_pointers};
+
+#undef MAKE_CONST_CUSTOM_DATA_GETTER
+#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER
+
+ static BuiltinCustomDataLayerProvider position("position",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT3,
+ CD_MVERT,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ point_access,
+ make_vertex_position_read_attribute,
+ make_vertex_position_write_attribute,
+ nullptr,
+ tag_normals_dirty_when_writing_position);
+
+ static BuiltinCustomDataLayerProvider material_index("material_index",
+ ATTR_DOMAIN_POLYGON,
+ CD_PROP_INT32,
+ CD_MPOLY,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ polygon_access,
+ make_material_index_read_attribute,
+ make_material_index_write_attribute,
+ nullptr,
+ nullptr);
+
+ static BuiltinCustomDataLayerProvider shade_smooth("shade_smooth",
+ ATTR_DOMAIN_POLYGON,
+ CD_PROP_BOOL,
+ CD_MPOLY,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ polygon_access,
+ make_shade_smooth_read_attribute,
+ make_shade_smooth_write_attribute,
+ nullptr,
+ nullptr);
+
+ static BuiltinCustomDataLayerProvider vertex_normal("vertex_normal",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT3,
+ CD_MVERT,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Readonly,
+ BuiltinAttributeProvider::NonDeletable,
+ point_access,
+ make_vertex_normal_read_attribute,
+ nullptr,
+ update_vertex_normals_when_dirty,
+ nullptr);
+
+ static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER,
+ CD_PROP_FLOAT2,
+ CD_MLOOPUV,
+ corner_access,
+ make_uvs_read_attribute,
+ make_uvs_write_attribute);
+
+ static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER,
+ CD_PROP_COLOR,
+ CD_MLOOPCOL,
+ corner_access,
+ make_vertex_color_read_attribute,
+ make_vertex_color_write_attribute);
+
+ static VertexGroupsAttributeProvider vertex_groups;
+ static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
+ static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
+ static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access);
+ static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access);
+
+ return ComponentAttributeProviders({&position, &material_index, &vertex_normal, &shade_smooth},
+ {&uvs,
+ &vertex_colors,
+ &corner_custom_data,
+ &vertex_groups,
+ &point_custom_data,
+ &edge_custom_data,
+ &polygon_custom_data});
+}
+
+} // namespace blender::bke
+
+const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const
+{
+ static blender::bke::ComponentAttributeProviders providers =
+ blender::bke::create_attribute_providers_for_mesh();
+ return &providers;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
new file mode 100644
index 00000000000..d7f0bf55bc9
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
@@ -0,0 +1,207 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_pointcloud_types.h"
+
+#include "BKE_attribute_access.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_pointcloud.h"
+
+#include "attribute_access_intern.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component Implementation
+ * \{ */
+
+PointCloudComponent::PointCloudComponent() : GeometryComponent(GeometryComponentType::PointCloud)
+{
+}
+
+PointCloudComponent::~PointCloudComponent()
+{
+ this->clear();
+}
+
+GeometryComponent *PointCloudComponent::copy() const
+{
+ PointCloudComponent *new_component = new PointCloudComponent();
+ if (pointcloud_ != nullptr) {
+ new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ }
+ return new_component;
+}
+
+void PointCloudComponent::clear()
+{
+ BLI_assert(this->is_mutable());
+ if (pointcloud_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, pointcloud_);
+ }
+ pointcloud_ = nullptr;
+ }
+}
+
+bool PointCloudComponent::has_pointcloud() const
+{
+ return pointcloud_ != nullptr;
+}
+
+/* Clear the component and replace it with the new point cloud. */
+void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ this->clear();
+ pointcloud_ = pointcloud;
+ ownership_ = ownership;
+}
+
+/* Return the point cloud and clear the component. The caller takes over responsibility for freeing
+ * the point cloud (if the component was responsible before). */
+PointCloud *PointCloudComponent::release()
+{
+ BLI_assert(this->is_mutable());
+ PointCloud *pointcloud = pointcloud_;
+ pointcloud_ = nullptr;
+ return pointcloud;
+}
+
+/* Get the point cloud from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned point cloud should not be modified. No ownership is transferred.
+ */
+const PointCloud *PointCloudComponent::get_for_read() const
+{
+ return pointcloud_;
+}
+
+/* Get the point cloud from this component. This method can only be used when the component is
+ * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
+ * transferred. */
+PointCloud *PointCloudComponent::get_for_write()
+{
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
+ ownership_ = GeometryOwnershipType::Owned;
+ }
+ return pointcloud_;
+}
+
+bool PointCloudComponent::is_empty() const
+{
+ return pointcloud_ == nullptr;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Attribute Access
+ * \{ */
+
+int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const
+{
+ BLI_assert(domain == ATTR_DOMAIN_POINT);
+ UNUSED_VARS_NDEBUG(domain);
+ if (pointcloud_ == nullptr) {
+ return 0;
+ }
+ return pointcloud_->totpoint;
+}
+
+namespace blender::bke {
+
+template<typename T, AttributeDomain Domain>
+static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size)
+{
+ return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size));
+}
+
+template<typename T, AttributeDomain Domain>
+static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size)
+{
+ return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size));
+}
+
+/**
+ * In this function all the attribute providers for a point cloud component are created. Most data
+ * in this function is statically allocated, because it does not change over time.
+ */
+static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
+{
+ static auto update_custom_data_pointers = [](GeometryComponent &component) {
+ PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
+ PointCloud *pointcloud = pointcloud_component.get_for_write();
+ if (pointcloud != nullptr) {
+ BKE_pointcloud_update_customdata_pointers(pointcloud);
+ }
+ };
+ static CustomDataAccessInfo point_access = {
+ [](GeometryComponent &component) -> CustomData * {
+ PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
+ PointCloud *pointcloud = pointcloud_component.get_for_write();
+ return pointcloud ? &pointcloud->pdata : nullptr;
+ },
+ [](const GeometryComponent &component) -> const CustomData * {
+ const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>(
+ component);
+ const PointCloud *pointcloud = pointcloud_component.get_for_read();
+ return pointcloud ? &pointcloud->pdata : nullptr;
+ },
+ update_custom_data_pointers};
+
+ static BuiltinCustomDataLayerProvider position(
+ "position",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT3,
+ CD_PROP_FLOAT3,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ point_access,
+ make_array_read_attribute<float3, ATTR_DOMAIN_POINT>,
+ make_array_write_attribute<float3, ATTR_DOMAIN_POINT>,
+ nullptr,
+ nullptr);
+ static BuiltinCustomDataLayerProvider radius(
+ "radius",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<float, ATTR_DOMAIN_POINT>,
+ make_array_write_attribute<float, ATTR_DOMAIN_POINT>,
+ nullptr,
+ nullptr);
+ static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
+ return ComponentAttributeProviders({&position, &radius}, {&point_custom_data});
+}
+
+} // namespace blender::bke
+
+const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers()
+ const
+{
+ static blender::bke::ComponentAttributeProviders providers =
+ blender::bke::create_attribute_providers_for_point_cloud();
+ return &providers;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_volume.cc b/source/blender/blenkernel/intern/geometry_component_volume.cc
new file mode 100644
index 00000000000..5e35a10fe3d
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry_component_volume.cc
@@ -0,0 +1,100 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_volume_types.h"
+
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_volume.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component Implementation
+ * \{ */
+
+VolumeComponent::VolumeComponent() : GeometryComponent(GeometryComponentType::Volume)
+{
+}
+
+VolumeComponent::~VolumeComponent()
+{
+ this->clear();
+}
+
+GeometryComponent *VolumeComponent::copy() const
+{
+ VolumeComponent *new_component = new VolumeComponent();
+ if (volume_ != nullptr) {
+ new_component->volume_ = BKE_volume_copy_for_eval(volume_, false);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ }
+ return new_component;
+}
+
+void VolumeComponent::clear()
+{
+ BLI_assert(this->is_mutable());
+ if (volume_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, volume_);
+ }
+ volume_ = nullptr;
+ }
+}
+
+bool VolumeComponent::has_volume() const
+{
+ return volume_ != nullptr;
+}
+
+/* Clear the component and replace it with the new volume. */
+void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ this->clear();
+ volume_ = volume;
+ ownership_ = ownership;
+}
+
+/* Return the volume and clear the component. The caller takes over responsibility for freeing the
+ * volume (if the component was responsible before). */
+Volume *VolumeComponent::release()
+{
+ BLI_assert(this->is_mutable());
+ Volume *volume = volume_;
+ volume_ = nullptr;
+ return volume;
+}
+
+/* Get the volume from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned volume should not be modified. No ownership is transferred. */
+const Volume *VolumeComponent::get_for_read() const
+{
+ return volume_;
+}
+
+/* Get the volume from this component. This method can only be used when the component is mutable,
+ * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */
+Volume *VolumeComponent::get_for_write()
+{
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ volume_ = BKE_volume_copy_for_eval(volume_, false);
+ ownership_ = GeometryOwnershipType::Owned;
+ }
+ return volume_;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 0274dfdbd1c..e7fb184023d 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -311,437 +311,6 @@ Volume *GeometrySet::get_volume_for_write()
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Mesh Component
- * \{ */
-
-MeshComponent::MeshComponent() : GeometryComponent(GeometryComponentType::Mesh)
-{
-}
-
-MeshComponent::~MeshComponent()
-{
- this->clear();
-}
-
-GeometryComponent *MeshComponent::copy() const
-{
- MeshComponent *new_component = new MeshComponent();
- if (mesh_ != nullptr) {
- new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
- new_component->ownership_ = GeometryOwnershipType::Owned;
- new_component->vertex_group_names_ = blender::Map(vertex_group_names_);
- }
- return new_component;
-}
-
-void MeshComponent::clear()
-{
- BLI_assert(this->is_mutable());
- if (mesh_ != nullptr) {
- if (ownership_ == GeometryOwnershipType::Owned) {
- BKE_id_free(nullptr, mesh_);
- }
- mesh_ = nullptr;
- }
- vertex_group_names_.clear();
-}
-
-bool MeshComponent::has_mesh() const
-{
- return mesh_ != nullptr;
-}
-
-/* Clear the component and replace it with the new mesh. */
-void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
-{
- BLI_assert(this->is_mutable());
- this->clear();
- mesh_ = mesh;
- ownership_ = ownership;
-}
-
-/* This function exists for the same reason as #vertex_group_names_. Non-nodes modifiers need to
- * be able to replace the mesh data without losing the vertex group names, which may have come
- * from another object. */
-void MeshComponent::replace_mesh_but_keep_vertex_group_names(Mesh *mesh,
- GeometryOwnershipType ownership)
-{
- BLI_assert(this->is_mutable());
- if (mesh_ != nullptr) {
- if (ownership_ == GeometryOwnershipType::Owned) {
- BKE_id_free(nullptr, mesh_);
- }
- mesh_ = nullptr;
- }
- mesh_ = mesh;
- ownership_ = ownership;
-}
-
-/* Return the mesh and clear the component. The caller takes over responsibility for freeing the
- * mesh (if the component was responsible before). */
-Mesh *MeshComponent::release()
-{
- BLI_assert(this->is_mutable());
- Mesh *mesh = mesh_;
- mesh_ = nullptr;
- return mesh;
-}
-
-void MeshComponent::copy_vertex_group_names_from_object(const Object &object)
-{
- BLI_assert(this->is_mutable());
- vertex_group_names_.clear();
- int index = 0;
- LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) {
- vertex_group_names_.add(group->name, index);
- index++;
- }
-}
-
-const blender::Map<std::string, int> &MeshComponent::vertex_group_names() const
-{
- return vertex_group_names_;
-}
-
-/* This is only exposed for the internal attribute API. */
-blender::Map<std::string, int> &MeshComponent::vertex_group_names()
-{
- return vertex_group_names_;
-}
-
-/* Get the mesh from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */
-const Mesh *MeshComponent::get_for_read() const
-{
- return mesh_;
-}
-
-/* Get the mesh from this component. This method can only be used when the component is mutable,
- * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */
-Mesh *MeshComponent::get_for_write()
-{
- BLI_assert(this->is_mutable());
- if (ownership_ == GeometryOwnershipType::ReadOnly) {
- mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
- ownership_ = GeometryOwnershipType::Owned;
- }
- return mesh_;
-}
-
-bool MeshComponent::is_empty() const
-{
- return mesh_ == nullptr;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Pointcloud Component
- * \{ */
-
-PointCloudComponent::PointCloudComponent() : GeometryComponent(GeometryComponentType::PointCloud)
-{
-}
-
-PointCloudComponent::~PointCloudComponent()
-{
- this->clear();
-}
-
-GeometryComponent *PointCloudComponent::copy() const
-{
- PointCloudComponent *new_component = new PointCloudComponent();
- if (pointcloud_ != nullptr) {
- new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
- new_component->ownership_ = GeometryOwnershipType::Owned;
- }
- return new_component;
-}
-
-void PointCloudComponent::clear()
-{
- BLI_assert(this->is_mutable());
- if (pointcloud_ != nullptr) {
- if (ownership_ == GeometryOwnershipType::Owned) {
- BKE_id_free(nullptr, pointcloud_);
- }
- pointcloud_ = nullptr;
- }
-}
-
-bool PointCloudComponent::has_pointcloud() const
-{
- return pointcloud_ != nullptr;
-}
-
-/* Clear the component and replace it with the new point cloud. */
-void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership)
-{
- BLI_assert(this->is_mutable());
- this->clear();
- pointcloud_ = pointcloud;
- ownership_ = ownership;
-}
-
-/* Return the point cloud and clear the component. The caller takes over responsibility for freeing
- * the point cloud (if the component was responsible before). */
-PointCloud *PointCloudComponent::release()
-{
- BLI_assert(this->is_mutable());
- PointCloud *pointcloud = pointcloud_;
- pointcloud_ = nullptr;
- return pointcloud;
-}
-
-/* Get the point cloud from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned point cloud should not be modified. No ownership is transferred.
- */
-const PointCloud *PointCloudComponent::get_for_read() const
-{
- return pointcloud_;
-}
-
-/* Get the point cloud from this component. This method can only be used when the component is
- * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
- * transferred. */
-PointCloud *PointCloudComponent::get_for_write()
-{
- BLI_assert(this->is_mutable());
- if (ownership_ == GeometryOwnershipType::ReadOnly) {
- pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
- ownership_ = GeometryOwnershipType::Owned;
- }
- return pointcloud_;
-}
-
-bool PointCloudComponent::is_empty() const
-{
- return pointcloud_ == nullptr;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Instances Component
- * \{ */
-
-InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentType::Instances)
-{
-}
-
-GeometryComponent *InstancesComponent::copy() const
-{
- InstancesComponent *new_component = new InstancesComponent();
- new_component->transforms_ = transforms_;
- new_component->instanced_data_ = instanced_data_;
- return new_component;
-}
-
-void InstancesComponent::clear()
-{
- instanced_data_.clear();
- transforms_.clear();
-}
-
-void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id)
-{
- InstancedData data;
- data.type = INSTANCE_DATA_TYPE_OBJECT;
- data.data.object = object;
- this->add_instance(data, transform, id);
-}
-
-void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id)
-{
- InstancedData data;
- data.type = INSTANCE_DATA_TYPE_COLLECTION;
- data.data.collection = collection;
- this->add_instance(data, transform, id);
-}
-
-void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id)
-{
- instanced_data_.append(data);
- transforms_.append(transform);
- ids_.append(id);
-}
-
-Span<InstancedData> InstancesComponent::instanced_data() const
-{
- return instanced_data_;
-}
-
-Span<float4x4> InstancesComponent::transforms() const
-{
- return transforms_;
-}
-
-Span<int> InstancesComponent::ids() const
-{
- return ids_;
-}
-
-MutableSpan<float4x4> InstancesComponent::transforms()
-{
- return transforms_;
-}
-
-int InstancesComponent::instances_amount() const
-{
- const int size = instanced_data_.size();
- BLI_assert(transforms_.size() == size);
- return size;
-}
-
-bool InstancesComponent::is_empty() const
-{
- return transforms_.size() == 0;
-}
-
-static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
-{
- using namespace blender;
- Array<int> unique_ids(original_ids.size());
-
- Set<int> used_unique_ids;
- used_unique_ids.reserve(original_ids.size());
- Vector<int> instances_with_id_collision;
- for (const int instance_index : original_ids.index_range()) {
- const int original_id = original_ids[instance_index];
- if (used_unique_ids.add(original_id)) {
- /* The original id has not been used by another instance yet. */
- unique_ids[instance_index] = original_id;
- }
- else {
- /* The original id of this instance collided with a previous instance, it needs to be looked
- * at again in a second pass. Don't generate a new random id here, because this might collide
- * with other existing ids. */
- instances_with_id_collision.append(instance_index);
- }
- }
-
- Map<int, RandomNumberGenerator> generator_by_original_id;
- for (const int instance_index : instances_with_id_collision) {
- const int original_id = original_ids[instance_index];
- RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
- RandomNumberGenerator rng;
- rng.seed_random(original_id);
- return rng;
- });
-
- const int max_iteration = 100;
- for (int iteration = 0;; iteration++) {
- /* Try generating random numbers until an unused one has been found. */
- const int random_id = rng.get_int32();
- if (used_unique_ids.add(random_id)) {
- /* This random id is not used by another instance. */
- unique_ids[instance_index] = random_id;
- break;
- }
- if (iteration == max_iteration) {
- /* It seems to be very unlikely that we ever run into this case (assuming there are less
- * than 2^30 instances). However, if that happens, it's better to use an id that is not
- * unique than to be stuck in an infinite loop. */
- unique_ids[instance_index] = original_id;
- break;
- }
- }
- }
-
- return unique_ids;
-}
-
-blender::Span<int> InstancesComponent::almost_unique_ids() const
-{
- std::lock_guard lock(almost_unique_ids_mutex_);
- if (almost_unique_ids_.size() != ids_.size()) {
- almost_unique_ids_ = generate_unique_instance_ids(ids_);
- }
- return almost_unique_ids_;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Volume Component
- * \{ */
-
-VolumeComponent::VolumeComponent() : GeometryComponent(GeometryComponentType::Volume)
-{
-}
-
-VolumeComponent::~VolumeComponent()
-{
- this->clear();
-}
-
-GeometryComponent *VolumeComponent::copy() const
-{
- VolumeComponent *new_component = new VolumeComponent();
- if (volume_ != nullptr) {
- new_component->volume_ = BKE_volume_copy_for_eval(volume_, false);
- new_component->ownership_ = GeometryOwnershipType::Owned;
- }
- return new_component;
-}
-
-void VolumeComponent::clear()
-{
- BLI_assert(this->is_mutable());
- if (volume_ != nullptr) {
- if (ownership_ == GeometryOwnershipType::Owned) {
- BKE_id_free(nullptr, volume_);
- }
- volume_ = nullptr;
- }
-}
-
-bool VolumeComponent::has_volume() const
-{
- return volume_ != nullptr;
-}
-
-/* Clear the component and replace it with the new volume. */
-void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
-{
- BLI_assert(this->is_mutable());
- this->clear();
- volume_ = volume;
- ownership_ = ownership;
-}
-
-/* Return the volume and clear the component. The caller takes over responsibility for freeing the
- * volume (if the component was responsible before). */
-Volume *VolumeComponent::release()
-{
- BLI_assert(this->is_mutable());
- Volume *volume = volume_;
- volume_ = nullptr;
- return volume;
-}
-
-/* Get the volume from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned volume should not be modified. No ownership is transferred. */
-const Volume *VolumeComponent::get_for_read() const
-{
- return volume_;
-}
-
-/* Get the volume from this component. This method can only be used when the component is mutable,
- * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */
-Volume *VolumeComponent::get_for_write()
-{
- BLI_assert(this->is_mutable());
- if (ownership_ == GeometryOwnershipType::ReadOnly) {
- volume_ = BKE_volume_copy_for_eval(volume_, false);
- ownership_ = GeometryOwnershipType::Owned;
- }
- return volume_;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name C API
* \{ */
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 1a260c5d48e..f3006385da3 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -378,7 +378,10 @@ static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups,
/* Don't copy attributes that are stored directly in the mesh data structs. */
Map<std::string, AttributeKind> attributes;
- gather_attribute_info(attributes, component_types, set_groups, {"position", "material_index"});
+ gather_attribute_info(attributes,
+ component_types,
+ set_groups,
+ {"position", "material_index", "vertex_normal", "shade_smooth"});
join_attributes(
set_groups, component_types, attributes, static_cast<GeometryComponent &>(dst_component));
}
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index a511c1f9c4c..af921307bfb 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -171,7 +171,9 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id)
/* Conceptually, an ID made local is not the same as the linked one anymore. Reflect that by
* regenerating its session UUID. */
- BKE_lib_libblock_session_uuid_renew(id);
+ if ((id->tag & LIB_TAG_TEMP_MAIN) == 0) {
+ BKE_lib_libblock_session_uuid_renew(id);
+ }
/* We need to tag this IDs and all of its users, conceptually new local ID and original linked
* ones are two completely different data-blocks that were virtually remapped, even though in
@@ -1139,6 +1141,7 @@ static uint global_session_uuid = 0;
void BKE_lib_libblock_session_uuid_ensure(ID *id)
{
if (id->session_uuid == MAIN_ID_SESSION_UUID_UNSET) {
+ BLI_assert((id->tag & LIB_TAG_TEMP_MAIN) == 0); /* Caller must ensure this. */
id->session_uuid = atomic_add_and_fetch_uint32(&global_session_uuid, 1);
/* In case overflow happens, still assign a valid ID. This way opening files many times works
* correctly. */
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 602c560cedd..702d718f2b9 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -24,6 +24,8 @@
#include <stdlib.h>
#include <string.h>
+#include "CLG_log.h"
+
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
@@ -66,6 +68,8 @@
# include "PIL_time_utildefines.h"
#endif
+static CLG_LogRef LOG = {"bke.liboverride"};
+
static void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
IDOverrideLibraryProperty *op_src);
static void lib_override_library_property_operation_copy(
@@ -1557,17 +1561,15 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
created = true;
}
-#ifndef NDEBUG
if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) {
- printf("We did restore some properties of %s from its reference.\n", local->name);
+ CLOG_INFO(&LOG, 2, "We did restore some properties of %s from its reference", local->name);
}
if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
- printf("We did generate library override rules for %s\n", local->name);
+ CLOG_INFO(&LOG, 2, "We did generate library override rules for %s", local->name);
}
else {
- printf("No new library override rules for %s\n", local->name);
+ CLOG_INFO(&LOG, 2, "No new library override rules for %s", local->name);
}
-#endif
}
return created;
}
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index d9564f91a04..61c9f74531d 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -611,6 +611,9 @@ static void copy_or_interp_loop_attributes(Mesh *dest_mesh,
* A non bmesh version could have the benefit of not copying data into src_blocks_ofs -
* using the contiguous data instead. TODO: add to the custom data API. */
int target_layer_type_index = CustomData_get_named_layer(target_cd, ty, name);
+ if (!CustomData_layer_has_interp(source_cd, source_layer_i)) {
+ continue;
+ }
int source_layer_type_index = source_layer_i - source_cd->typemap[ty];
BLI_assert(target_layer_type_index != -1 && source_layer_type_index >= 0);
for (int j = 0; j < orig_mp->totloop; ++j) {
@@ -759,6 +762,7 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
static Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<const float4x4 *> obmats,
const bool use_self,
+ const bool hole_tolerant,
const BoolOpType boolean_mode)
{
const int dbg_level = 0;
@@ -781,7 +785,8 @@ static Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
}
return static_cast<int>(mim.mesh_poly_offset.size()) - 1;
};
- IMesh m_out = boolean_mesh(m_in, boolean_mode, meshes_len, shape_fn, use_self, nullptr, &arena);
+ IMesh m_out = boolean_mesh(
+ m_in, boolean_mode, meshes_len, shape_fn, use_self, hole_tolerant, nullptr, &arena);
if (dbg_level > 1) {
std::cout << m_out;
write_obj_mesh(m_out, "m_out");
@@ -805,6 +810,7 @@ Mesh *BKE_mesh_boolean(const Mesh **meshes,
const float (*obmats[])[4][4],
const int meshes_len,
const bool use_self,
+ const bool hole_tolerant,
const int boolean_mode)
{
const blender::float4x4 **transforms = (const blender::float4x4 **)obmats;
@@ -812,6 +818,7 @@ Mesh *BKE_mesh_boolean(const Mesh **meshes,
blender::Span(meshes, meshes_len),
blender::Span(transforms, meshes_len),
use_self,
+ hole_tolerant,
static_cast<blender::meshintersect::BoolOpType>(boolean_mode));
}
@@ -820,6 +827,7 @@ Mesh *BKE_mesh_boolean(const Mesh **UNUSED(meshes),
const float (*obmats[])[4][4],
const int UNUSED(meshes_len),
const bool UNUSED(use_self),
+ const bool UNUSED(hole_tolerant),
const int UNUSED(boolean_mode))
{
UNUSED_VARS(obmats);
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 55cb0d5cce4..9615fbc31e7 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -540,18 +540,11 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
- /* Update the matte_id so the files can be opened in versions that don't
- * use `CryptomatteEntry`. */
- MEM_SAFE_FREE(nc->matte_id);
- nc->matte_id = BKE_cryptomatte_entries_to_matte_id(nc);
- if (nc->matte_id) {
- BLO_write_string(writer, nc->matte_id);
- }
+ BLO_write_string(writer, nc->matte_id);
LISTBASE_FOREACH (CryptomatteEntry *, entry, &nc->entries) {
BLO_write_struct(writer, CryptomatteEntry, entry);
}
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
- MEM_SAFE_FREE(nc->matte_id);
}
else if (node->type == FN_NODE_INPUT_STRING) {
NodeInputString *storage = (NodeInputString *)node->storage;
@@ -4482,18 +4475,18 @@ void node_type_group_update(struct bNodeType *ntype,
}
void node_type_exec(struct bNodeType *ntype,
- NodeInitExecFunction initexecfunc,
- NodeFreeExecFunction freeexecfunc,
- NodeExecFunction execfunc)
+ NodeInitExecFunction init_exec_fn,
+ NodeFreeExecFunction free_exec_fn,
+ NodeExecFunction exec_fn)
{
- ntype->initexecfunc = initexecfunc;
- ntype->freeexecfunc = freeexecfunc;
- ntype->execfunc = execfunc;
+ ntype->init_exec_fn = init_exec_fn;
+ ntype->free_exec_fn = free_exec_fn;
+ ntype->exec_fn = exec_fn;
}
-void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc)
+void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn)
{
- ntype->gpufunc = gpufunc;
+ ntype->gpu_fn = gpu_fn;
}
void node_type_internal_links(bNodeType *ntype,
@@ -4816,8 +4809,8 @@ static void registerGeometryNodes()
register_node_type_geo_point_translate();
register_node_type_geo_points_to_volume();
register_node_type_geo_sample_texture();
- register_node_type_geo_subdivision_surface();
- register_node_type_geo_subdivision_surface_simple();
+ register_node_type_geo_subdivide_smooth();
+ register_node_type_geo_subdivide();
register_node_type_geo_transform();
register_node_type_geo_triangulate();
register_node_type_geo_volume_to_mesh();
diff --git a/source/blender/blenkernel/intern/node_ui_storage.cc b/source/blender/blenkernel/intern/node_ui_storage.cc
index 6e0253eca31..97f52dd3727 100644
--- a/source/blender/blenkernel/intern/node_ui_storage.cc
+++ b/source/blender/blenkernel/intern/node_ui_storage.cc
@@ -62,8 +62,12 @@ const NodeUIStorage *BKE_node_tree_ui_storage_get_from_context(const bContext *C
}
const Object *active_object = CTX_data_active_object(C);
+ if (active_object == nullptr) {
+ return nullptr;
+ }
+
const ModifierData *active_modifier = BKE_object_active_modifier(active_object);
- if (active_object == nullptr || active_modifier == nullptr) {
+ if (active_modifier == nullptr) {
return nullptr;
}
diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c
index 05873d20f7f..b9497d389e7 100644
--- a/source/blender/blenkernel/intern/outliner_treehash.c
+++ b/source/blender/blenkernel/intern/outliner_treehash.c
@@ -101,7 +101,7 @@ static unsigned int tse_hash(const void *ptr)
unsigned int u_int;
} hash;
- BLI_assert(tse->type || !tse->nr);
+ BLI_assert((tse->type != TSE_SOME_ID) || !tse->nr);
hash.h_pair[0] = tse->type;
hash.h_pair[1] = tse->nr;
@@ -193,7 +193,7 @@ static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short
{
TreeStoreElem tse_template;
tse_template.type = type;
- tse_template.nr = type ? nr : 0; /* we're picky! :) */
+ tse_template.nr = (type == TSE_SOME_ID) ? 0 : nr; /* we're picky! :) */
tse_template.id = id;
BLI_assert(th);
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 08c5beedbf3..2e81b61ad8c 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1760,7 +1760,7 @@ void BKE_sculpt_update_object_before_eval(Object *ob)
SculptSession *ss = ob->sculpt;
if (ss && ss->building_vp_handle == false) {
- if (!ss->cache && !ss->filter_cache) {
+ if (!ss->cache && !ss->filter_cache && !ss->expand_cache) {
/* We free pbvh on changes, except in the middle of drawing a stroke
* since it can't deal with changing PVBH node organization, we hope
* topology does not change in the meantime .. weak. */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index acda59ce96c..e50b321900a 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -3925,7 +3925,7 @@ static ModifierData *object_add_or_copy_particle_system(
}
if (name == NULL) {
- name = (psys_orig != NULL) ? psys_orig->name : DATA_("ParticleSettings");
+ name = (psys_orig != NULL) ? psys_orig->name : DATA_("ParticleSystem");
}
psys = ob->particlesystem.first;
@@ -3943,7 +3943,7 @@ static ModifierData *object_add_or_copy_particle_system(
id_us_plus(&psys->part->id);
}
else {
- psys->part = BKE_particlesettings_add(bmain, psys->name);
+ psys->part = BKE_particlesettings_add(bmain, DATA_("ParticleSettings"));
}
md = BKE_modifier_new(eModifierType_ParticleSystem);
BLI_strncpy(md->name, psys->name, sizeof(md->name));
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index c3cc9136057..ad617b4198b 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -338,18 +338,18 @@ static void hammersley_create(float *out, int n, int seed, float amount)
{
RNG *rng;
- double offs[2], t;
+ double ofs[2], t;
rng = BLI_rng_new(31415926 + n + seed);
- offs[0] = BLI_rng_get_double(rng) + (double)amount;
- offs[1] = BLI_rng_get_double(rng) + (double)amount;
+ ofs[0] = BLI_rng_get_double(rng) + (double)amount;
+ ofs[1] = BLI_rng_get_double(rng) + (double)amount;
BLI_rng_free(rng);
for (int k = 0; k < n; k++) {
BLI_hammersley_1d(k, &t);
- out[2 * k + 0] = fmod((double)k / (double)n + offs[0], 1.0);
- out[2 * k + 1] = fmod(t + offs[1], 1.0);
+ out[2 * k + 0] = fmod((double)k / (double)n + ofs[0], 1.0);
+ out[2 * k + 1] = fmod(t + ofs[1], 1.0);
}
}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 8b911143668..f0220373678 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -1217,7 +1217,7 @@ static void write_panel_list(BlendWriter *writer, ListBase *lb)
}
}
-static void write_area_regions(BlendWriter *writer, ScrArea *area)
+static void write_area(BlendWriter *writer, ScrArea *area)
{
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
write_region(writer, region, area->spacetype);
@@ -1342,6 +1342,9 @@ static void write_area_regions(BlendWriter *writer, ScrArea *area)
else if (sl->spacetype == SPACE_INFO) {
BLO_write_struct(writer, SpaceInfo, sl);
}
+ else if (sl->spacetype == SPACE_SPREADSHEET) {
+ BLO_write_struct(writer, SpaceSpreadsheet, sl);
+ }
}
}
@@ -1356,7 +1359,7 @@ void BKE_screen_area_map_blend_write(BlendWriter *writer, ScrAreaMap *area_map)
BLO_write_struct(writer, ScrGlobalAreaData, area->global);
- write_area_regions(writer, area);
+ write_area(writer, area);
area->butspacetype = SPACE_EMPTY; /* Unset again, was changed above. */
}
@@ -1681,6 +1684,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
sfile->op = NULL;
sfile->previews_timer = NULL;
sfile->tags = 0;
+ sfile->runtime = NULL;
BLO_read_data_address(reader, &sfile->params);
BLO_read_data_address(reader, &sfile->asset_params);
}
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 6b46804c251..216563b860d 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -54,7 +54,6 @@
#include "BLI_map.hh"
#include "BLT_translation.h"
-#include "FN_attributes_ref.hh"
#include "FN_multi_function_network_evaluation.hh"
#include "FN_multi_function_network_optimization.hh"
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index bd37d22023b..8f4630dd732 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -89,6 +89,14 @@ bool _bli_array_iter_span(const void *arr,
bool _bli_array_is_zeroed(const void *arr, unsigned int arr_len, size_t arr_stride);
#define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr)))
+bool _bli_array_iter_spiral_square(const void *arr_v,
+ const int arr_shape[2],
+ const size_t elem_size,
+ const int center[2],
+ const bool (*test_fn)(const void *arr_item, void *user_data),
+ void *user_data);
+#define BLI_array_iter_spiral_square(arr, arr_shape, center, test_fn, user_data) \
+ _bli_array_iter_spiral_square(arr, arr_shape, sizeof(*(arr)), center, test_fn, user_data)
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh
index a616ec5cf28..47705b1d40b 100644
--- a/source/blender/blenlib/BLI_linear_allocator.hh
+++ b/source/blender/blenlib/BLI_linear_allocator.hh
@@ -38,18 +38,20 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
uintptr_t current_begin_;
uintptr_t current_end_;
- int64_t next_min_alloc_size_;
#ifdef DEBUG
int64_t debug_allocated_amount_ = 0;
#endif
+ /* Buffers larger than that are not packed together with smaller allocations to avoid wasting
+ * memory. */
+ constexpr static inline int64_t large_buffer_threshold = 4096;
+
public:
LinearAllocator()
{
current_begin_ = 0;
current_end_ = 0;
- next_min_alloc_size_ = 64;
}
~LinearAllocator()
@@ -71,23 +73,23 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
BLI_assert(alignment >= 1);
BLI_assert(is_power_of_2_i(alignment));
-#ifdef DEBUG
- debug_allocated_amount_ += size;
-#endif
-
const uintptr_t alignment_mask = alignment - 1;
const uintptr_t potential_allocation_begin = (current_begin_ + alignment_mask) &
~alignment_mask;
const uintptr_t potential_allocation_end = potential_allocation_begin + size;
if (potential_allocation_end <= current_end_) {
+#ifdef DEBUG
+ debug_allocated_amount_ += size;
+#endif
current_begin_ = potential_allocation_end;
return reinterpret_cast<void *>(potential_allocation_begin);
}
- else {
- this->allocate_new_buffer(size + alignment);
+ if (size <= large_buffer_threshold) {
+ this->allocate_new_buffer(size + alignment, alignment);
return this->allocate(size, alignment);
}
+ return this->allocator_large_buffer(size, alignment);
};
/**
@@ -116,14 +118,14 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
*
* Arguments passed to this method will be forwarded to the constructor of T.
*
- * You must not call `delete` on the returned pointer.
- * Instead, the destruct has to be called explicitly.
+ * You must not call `delete` on the returned value.
+ * Instead, only the destructor has to be called.
*/
- template<typename T, typename... Args> T *construct(Args &&... args)
+ template<typename T, typename... Args> destruct_ptr<T> construct(Args &&... args)
{
void *buffer = this->allocate(sizeof(T), alignof(T));
T *value = new (buffer) T(std::forward<Args>(args)...);
- return value;
+ return destruct_ptr<T>(value);
}
/**
@@ -195,7 +197,7 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
}
private:
- void allocate_new_buffer(int64_t min_allocation_size)
+ void allocate_new_buffer(int64_t min_allocation_size, int64_t min_alignment)
{
for (int64_t i : unused_borrowed_buffers_.index_range()) {
Span<char> buffer = unused_borrowed_buffers_[i];
@@ -207,15 +209,29 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
}
}
- const int64_t size_in_bytes = power_of_2_min_u(
- std::max(min_allocation_size, next_min_alloc_size_));
- next_min_alloc_size_ = size_in_bytes * 2;
+ /* Possibly allocate more bytes than necessary for the current allocation. This way more small
+ * allocations can be packed together. Large buffers are allocated exactly to avoid wasting too
+ * much memory. */
+ int64_t size_in_bytes = min_allocation_size;
+ if (size_in_bytes <= large_buffer_threshold) {
+ /* Gradually grow buffer size with each allocation, up to a maximum. */
+ const int grow_size = 1 << std::min<int>(owned_buffers_.size() + 6, 20);
+ size_in_bytes = std::min(large_buffer_threshold,
+ std::max<int64_t>(size_in_bytes, grow_size));
+ }
- void *buffer = allocator_.allocate(size_in_bytes, 8, AT);
+ void *buffer = allocator_.allocate(size_in_bytes, min_alignment, __func__);
owned_buffers_.append(buffer);
current_begin_ = (uintptr_t)buffer;
current_end_ = current_begin_ + size_in_bytes;
}
+
+ void *allocator_large_buffer(const int64_t size, const int64_t alignment)
+ {
+ void *buffer = allocator_.allocate(size, alignment, __func__);
+ owned_buffers_.append(buffer);
+ return buffer;
+ }
};
} // namespace blender
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index eac7f25f11a..6324963f06a 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -331,6 +331,7 @@ void rescale_m4(float mat[4][4], const float scale[3]);
void transform_pivot_set_m3(float mat[3][3], const float pivot[2]);
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
+void mat4_to_rot(float rot[3][3], const float wmat[4][4]);
void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]);
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]);
void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]);
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index b3b6855089e..bdbbda9f0c7 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -28,6 +28,7 @@
#include <type_traits>
#include "BLI_utildefines.h"
+#include "MEM_guardedalloc.h"
namespace blender {
@@ -402,6 +403,50 @@ template<typename T, int64_t Size = 1> class TypedBuffer {
}
};
+/* A dynamic stack buffer can be used instead of #alloca when wants to allocate a dynamic amount of
+ * memory on the stack. Using this class has some advantages:
+ * - It falls back to heap allocation, when the size is too large.
+ * - It can be used in loops safely.
+ * - If the buffer is heap allocated, it is free automatically in the destructor.
+ */
+template<size_t ReservedSize = 64, size_t ReservedAlignment = 64>
+class alignas(ReservedAlignment) DynamicStackBuffer {
+ private:
+ /* Don't create an empty array. This causes problems with some compilers. */
+ char reserved_buffer_[(ReservedSize > 0) ? ReservedSize : 1];
+ void *buffer_;
+
+ public:
+ DynamicStackBuffer(const int64_t size, const int64_t alignment)
+ {
+ BLI_assert(size >= 0);
+ BLI_assert(alignment >= 0);
+ if (size <= ReservedSize && alignment <= ReservedAlignment) {
+ buffer_ = reserved_buffer_;
+ }
+ else {
+ buffer_ = MEM_mallocN_aligned(size, alignment, __func__);
+ }
+ }
+ ~DynamicStackBuffer()
+ {
+ if (buffer_ != reserved_buffer_) {
+ MEM_freeN(buffer_);
+ }
+ }
+
+ /* Don't allow any copying or moving of this type. */
+ DynamicStackBuffer(const DynamicStackBuffer &other) = delete;
+ DynamicStackBuffer(DynamicStackBuffer &&other) = delete;
+ DynamicStackBuffer &operator=(const DynamicStackBuffer &other) = delete;
+ DynamicStackBuffer &operator=(DynamicStackBuffer &&other) = delete;
+
+ void *buffer() const
+ {
+ return buffer_;
+ }
+};
+
/**
* This can be used by container constructors. A parameter of this type should be used to indicate
* that the constructor does not construct the elements.
diff --git a/source/blender/blenlib/BLI_mesh_boolean.hh b/source/blender/blenlib/BLI_mesh_boolean.hh
index 94b2694893b..a55b2175527 100644
--- a/source/blender/blenlib/BLI_mesh_boolean.hh
+++ b/source/blender/blenlib/BLI_mesh_boolean.hh
@@ -59,6 +59,7 @@ IMesh boolean_mesh(IMesh &imesh,
int nshapes,
std::function<int(int)> shape_fn,
bool use_self,
+ bool hole_tolerant,
IMesh *imesh_triangulated,
IMeshArena *arena);
@@ -72,6 +73,7 @@ IMesh boolean_trimesh(IMesh &tm_in,
int nshapes,
std::function<int(int)> shape_fn,
bool use_self,
+ bool hole_tolerant,
IMeshArena *arena);
} // namespace blender::meshintersect
diff --git a/source/blender/blenlib/BLI_resource_collector.hh b/source/blender/blenlib/BLI_resource_collector.hh
index ecae9b8c682..70804ceb1f1 100644
--- a/source/blender/blenlib/BLI_resource_collector.hh
+++ b/source/blender/blenlib/BLI_resource_collector.hh
@@ -130,9 +130,10 @@ class ResourceCollector : NonCopyable, NonMovable {
*/
template<typename T, typename... Args> T &construct(const char *name, Args &&... args)
{
- T *value = m_allocator.construct<T>(std::forward<Args>(args)...);
- this->add(destruct_ptr<T>(value), name);
- return *value;
+ destruct_ptr<T> value_ptr = m_allocator.construct<T>(std::forward<Args>(args)...);
+ T &value_ref = *value_ptr;
+ this->add(std::move(value_ptr), name);
+ return value_ref;
}
/**
diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h
index 46fb096599f..1057e71a6b2 100644
--- a/source/blender/blenlib/BLI_string_utils.h
+++ b/source/blender/blenlib/BLI_string_utils.h
@@ -90,7 +90,7 @@ bool BLI_uniquename(struct ListBase *list,
void *vlink,
const char *defname,
char delim,
- int name_offs,
+ int name_offset,
size_t len);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 2da2bbbc2a5..5d35cf09c30 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -27,13 +27,13 @@
#include "MEM_guardedalloc.h"
-#include "BLI_array_utils.h"
-
#include "BLI_alloca.h"
+#include "BLI_math_base.h"
+#include "BLI_strict_flags.h"
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
-#include "BLI_strict_flags.h"
+#include "BLI_array_utils.h"
/**
*In-place array reverse.
@@ -318,3 +318,94 @@ bool _bli_array_is_zeroed(const void *arr_v, unsigned int arr_len, size_t arr_st
}
return true;
}
+
+/**
+ * Smart function to sample a rect spiraling outside.
+ * Nice for selection ID.
+ *
+ * \param arr_shape: dimensions [w, h].
+ * \param center: coordinates [x, y] indicating where to start transversing.
+ */
+bool _bli_array_iter_spiral_square(const void *arr_v,
+ const int arr_shape[2],
+ size_t elem_size,
+ const int center[2],
+ const bool (*test_fn)(const void *arr_item, void *user_data),
+ void *user_data)
+{
+ BLI_assert(center[0] >= 0 && center[1] >= 0 && center[0] < arr_shape[0] &&
+ center[1] < arr_shape[1]);
+
+ const char *arr = arr_v;
+ const int stride[2] = {arr_shape[1] * (int)elem_size, (int)elem_size};
+
+ /* Test center first. */
+ int ofs[2] = {center[0] * stride[0], center[1] * stride[1]};
+ if (test_fn(arr + ofs[0] + ofs[1], user_data)) {
+ return true;
+ }
+
+ /* #steps_in and #steps_out are the "diameters" of the inscribed and ciscunscript squares in the
+ * rectangle. Each step smaller than #steps_in does not need to check bounds. */
+ int steps_in, steps_out;
+ {
+ int x_minus = center[0];
+ int x_plus = arr_shape[0] - center[0] - 1;
+ int y_minus = center[1];
+ int y_plus = arr_shape[1] - center[1] - 1;
+
+ steps_in = 2 * min_iiii(x_minus, x_plus, y_minus, y_plus);
+ steps_out = 2 * max_iiii(x_minus, x_plus, y_minus, y_plus);
+ }
+
+ /* For check_bounds. */
+ int limits[2] = {(arr_shape[0] - 1) * stride[0], stride[0] - stride[1]};
+
+ int steps = 0;
+ while (steps < steps_out) {
+ steps += 2;
+
+ /* Move one step to the diagonal of the negative quadrant. */
+ ofs[0] -= stride[0];
+ ofs[1] -= stride[1];
+
+ bool check_bounds = steps > steps_in;
+
+ /* sign: 0 neg; 1 pos; */
+ for (int sign = 2; sign--;) {
+ /* axis: 0 x; 1 y; */
+ for (int axis = 2; axis--;) {
+ int ofs_step = stride[axis];
+ if (!sign) {
+ ofs_step *= -1;
+ }
+
+ int ofs_iter = ofs[axis] + ofs_step;
+ int ofs_dest = ofs[axis] + steps * ofs_step;
+ int ofs_other = ofs[!axis];
+
+ ofs[axis] = ofs_dest;
+ if (check_bounds) {
+ if (ofs_other < 0 || ofs_other > limits[!axis]) {
+ /* Out of bounds. */
+ continue;
+ }
+
+ CLAMP(ofs_iter, 0, limits[axis]);
+ CLAMP(ofs_dest, 0, limits[axis]);
+ }
+
+ while (true) {
+ if (test_fn(arr + ofs_other + ofs_iter, user_data)) {
+ return true;
+ }
+ if (ofs_iter == ofs_dest) {
+ break;
+ }
+ ofs_iter += ofs_step;
+ }
+ }
+ }
+ }
+ return false;
+}
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index b460d75d77f..2ada05d2965 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -2140,6 +2140,16 @@ void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3])
}
}
+void mat4_to_rot(float rot[3][3], const float wmat[4][4])
+{
+ normalize_v3_v3(rot[0], wmat[0]);
+ normalize_v3_v3(rot[1], wmat[1]);
+ normalize_v3_v3(rot[2], wmat[2]);
+ if (UNLIKELY(is_negative_m3(rot))) {
+ negate_m3(rot);
+ }
+}
+
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4])
{
float mat3[3][3]; /* wmat -> 3x3 */
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index fcf5c5bfad3..cd7d0a812e4 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -2484,29 +2484,14 @@ static void test_tri_inside_shapes(const IMesh &tm,
}
/**
- * Use the RayCast method for deciding if a triangle of the
- * mesh is supposed to be included or excluded in the boolean result,
- * and return the mesh that is the boolean result.
- * The reason this is done on a triangle-by-triangle basis is that
- * when the input is not PWN, some patches can be both inside and outside
- * some shapes (e.g., a plane cutting through Suzanne's open eyes).
+ * Return a BVH Tree that contains all of the triangles of \a tm.
+ * The caller must free it.
+ * (We could possible reuse the BVH tree(s) built in TriOverlaps,
+ * in the mesh intersect function. A future TODO.)
*/
-static IMesh raycast_boolean(const IMesh &tm,
- BoolOpType op,
- int nshapes,
- std::function<int(int)> shape_fn,
- IMeshArena *arena)
+static BVHTree *raycast_tree(const IMesh &tm)
{
- constexpr int dbg_level = 0;
- if (dbg_level > 0) {
- std::cout << "RAYCAST_BOOLEAN\n";
- }
- IMesh ans;
-
- /* Build a BVH tree of tm's triangles.
- * We could possibly reuse the BVH tree(s) build in TriOverlaps in
- * the mesh intersect function. A future TODO. */
- BVHTree *tree = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 8, 8);
+ BVHTree *tree = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 4, 6);
for (int i : tm.face_index_range()) {
const Face *f = tm.face(i);
float t_cos[9];
@@ -2519,7 +2504,70 @@ static IMesh raycast_boolean(const IMesh &tm,
BLI_bvhtree_insert(tree, i, t_cos, 3);
}
BLI_bvhtree_balance(tree);
+ return tree;
+}
+
+/**
+ * Should a face with given shape and given winding array be removed for given boolean op?
+ * Also return true in *r_do_flip if it retained by normals need to be flipped.
+ */
+static bool raycast_test_remove(BoolOpType op, Array<int> &winding, int shape, bool *r_do_flip)
+{
+ constexpr int dbg_level = 0;
+ /* Find out the "in the output volume" flag for each of the cases of winding[shape] == 0
+ * and winding[shape] == 1. If the flags are different, this patch should be in the output.
+ * Also, if this is a Difference and the shape isn't the first one, need to flip the normals.
+ */
+ winding[shape] = 0;
+ bool in_output_volume_0 = apply_bool_op(op, winding);
+ winding[shape] = 1;
+ bool in_output_volume_1 = apply_bool_op(op, winding);
+ bool do_remove = in_output_volume_0 == in_output_volume_1;
+ bool do_flip = !do_remove && op == BoolOpType::Difference && shape != 0;
+ if (dbg_level > 0) {
+ std::cout << "winding = ";
+ for (int i = 0; i < winding.size(); ++i) {
+ std::cout << winding[i] << " ";
+ }
+ std::cout << "\niv0=" << in_output_volume_0 << ", iv1=" << in_output_volume_1 << "\n";
+ std::cout << " remove=" << do_remove << ", flip=" << do_flip << "\n";
+ }
+ *r_do_flip = do_flip;
+ return do_remove;
+}
+
+/** Add triangle a flipped version of tri to out_faces. */
+static void raycast_add_flipped(Vector<Face *> &out_faces, Face &tri, IMeshArena *arena)
+{
+ Array<const Vert *> flipped_vs = {tri[0], tri[2], tri[1]};
+ Array<int> flipped_e_origs = {tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]};
+ Array<bool> flipped_is_intersect = {
+ tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]};
+ Face *flipped_f = arena->add_face(flipped_vs, tri.orig, flipped_e_origs, flipped_is_intersect);
+ out_faces.append(flipped_f);
+}
+
+/**
+ * Use the RayCast method for deciding if a triangle of the
+ * mesh is supposed to be included or excluded in the boolean result,
+ * and return the mesh that is the boolean result.
+ * The reason this is done on a triangle-by-triangle basis is that
+ * when the input is not PWN, some patches can be both inside and outside
+ * some shapes (e.g., a plane cutting through Suzanne's open eyes).
+ */
+static IMesh raycast_tris_boolean(const IMesh &tm,
+ BoolOpType op,
+ int nshapes,
+ std::function<int(int)> shape_fn,
+ IMeshArena *arena)
+{
+ constexpr int dbg_level = 0;
+ if (dbg_level > 0) {
+ std::cout << "RAYCAST_TRIS_BOOLEAN\n";
+ }
+ IMesh ans;
+ BVHTree *tree = raycast_tree(tm);
Vector<Face *> out_faces;
out_faces.reserve(tm.face_size());
Array<float> in_shape(nshapes, 0);
@@ -2541,47 +2589,95 @@ static IMesh raycast_boolean(const IMesh &tm,
* gives good results, but when shape is a cutter in a Difference
* operation, we want to be pretty sure that the point is inside other_shape.
* E.g., T75827.
+ * Also, when the operation is intersection, we also want high confidence.
*/
- bool need_high_confidence = (op == BoolOpType::Difference) && (shape != 0);
+ bool need_high_confidence = (op == BoolOpType::Difference && shape != 0) ||
+ op == BoolOpType::Intersect;
bool inside = in_shape[other_shape] >= (need_high_confidence ? 0.5f : 0.1f);
if (dbg_level > 0) {
std::cout << "test point is " << (inside ? "inside" : "outside") << " other_shape "
- << other_shape << "\n";
+ << other_shape << " val = " << in_shape[other_shape] << "\n";
}
winding[other_shape] = inside;
}
- /* Find out the "in the output volume" flag for each of the cases of winding[shape] == 0
- * and winding[shape] == 1. If the flags are different, this patch should be in the output.
- * Also, if this is a Difference and the shape isn't the first one, need to flip the normals.
- */
- winding[shape] = 0;
- bool in_output_volume_0 = apply_bool_op(op, winding);
- winding[shape] = 1;
- bool in_output_volume_1 = apply_bool_op(op, winding);
- bool do_remove = in_output_volume_0 == in_output_volume_1;
- bool do_flip = !do_remove && op == BoolOpType::Difference && shape != 0;
- if (dbg_level > 0) {
- std::cout << "winding = ";
- for (int i = 0; i < nshapes; ++i) {
- std::cout << winding[i] << " ";
- }
- std::cout << "\niv0=" << in_output_volume_0 << ", iv1=" << in_output_volume_1 << "\n";
- std::cout << "result for tri " << t << ": remove=" << do_remove << ", flip=" << do_flip
- << "\n";
- }
+ bool do_flip;
+ bool do_remove = raycast_test_remove(op, winding, shape, &do_flip);
if (!do_remove) {
if (!do_flip) {
out_faces.append(&tri);
}
else {
- /* We need flipped version of tri. */
- Array<const Vert *> flipped_vs = {tri[0], tri[2], tri[1]};
- Array<int> flipped_e_origs = {tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]};
- Array<bool> flipped_is_intersect = {
- tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]};
- Face *flipped_f = arena->add_face(
- flipped_vs, tri.orig, flipped_e_origs, flipped_is_intersect);
- out_faces.append(flipped_f);
+ raycast_add_flipped(out_faces, tri, arena);
+ }
+ }
+ }
+ BLI_bvhtree_free(tree);
+ ans.set_faces(out_faces);
+ return ans;
+}
+
+/* This is (sometimes much faster) version of raycast boolean
+ * that does it per patch rather than per triangle.
+ * It may fail in cases where raycast_tri_boolean will succeed,
+ * but the latter can be very slow on huge meshes. */
+static IMesh raycast_patches_boolean(const IMesh &tm,
+ BoolOpType op,
+ int nshapes,
+ std::function<int(int)> shape_fn,
+ const PatchesInfo &pinfo,
+ IMeshArena *arena)
+{
+ constexpr int dbg_level = 0;
+ if (dbg_level > 0) {
+ std::cout << "RAYCAST_PATCHES_BOOLEAN\n";
+ }
+ IMesh ans;
+ BVHTree *tree = raycast_tree(tm);
+ Vector<Face *> out_faces;
+ out_faces.reserve(tm.face_size());
+ Array<float> in_shape(nshapes, 0);
+ Array<int> winding(nshapes, 0);
+ for (int p : pinfo.index_range()) {
+ const Patch &patch = pinfo.patch(p);
+ /* For test triangle, choose one in the middle of patch list
+ * as the ones near the beginning may be very near other patches. */
+ int test_t_index = patch.tri(patch.tot_tri() / 2);
+ Face &tri_test = *tm.face(test_t_index);
+ /* Assume all triangles in a patch are in the same shape. */
+ int shape = shape_fn(tri_test.orig);
+ if (dbg_level > 0) {
+ std::cout << "process patch " << p << " = " << patch << "\n";
+ std::cout << "test tri = " << test_t_index << " = " << &tri_test << "\n";
+ std::cout << "shape = " << shape << "\n";
+ }
+ if (shape == -1) {
+ continue;
+ }
+ test_tri_inside_shapes(tm, shape_fn, nshapes, test_t_index, tree, in_shape);
+ for (int other_shape = 0; other_shape < nshapes; ++other_shape) {
+ if (other_shape == shape) {
+ continue;
+ }
+ bool need_high_confidence = (op == BoolOpType::Difference && shape != 0) ||
+ op == BoolOpType::Intersect;
+ bool inside = in_shape[other_shape] >= (need_high_confidence ? 0.5f : 0.1f);
+ if (dbg_level > 0) {
+ std::cout << "test point is " << (inside ? "inside" : "outside") << " other_shape "
+ << other_shape << " val = " << in_shape[other_shape] << "\n";
+ }
+ winding[other_shape] = inside;
+ }
+ bool do_flip;
+ bool do_remove = raycast_test_remove(op, winding, shape, &do_flip);
+ if (!do_remove) {
+ for (int t : patch.tris()) {
+ Face *f = tm.face(t);
+ if (!do_flip) {
+ out_faces.append(f);
+ }
+ else {
+ raycast_add_flipped(out_faces, *f, arena);
+ }
}
}
}
@@ -3341,6 +3437,7 @@ IMesh boolean_trimesh(IMesh &tm_in,
int nshapes,
std::function<int(int)> shape_fn,
bool use_self,
+ bool hole_tolerant,
IMeshArena *arena)
{
constexpr int dbg_level = 0;
@@ -3391,7 +3488,13 @@ IMesh boolean_trimesh(IMesh &tm_in,
if (dbg_level > 0) {
std::cout << "Input is not PWN, using raycast method\n";
}
- tm_out = raycast_boolean(tm_si, op, nshapes, shape_fn, arena);
+ if (hole_tolerant) {
+ tm_out = raycast_tris_boolean(tm_si, op, nshapes, shape_fn, arena);
+ }
+ else {
+ PatchesInfo pinfo = find_patches(tm_si, tm_si_topo);
+ tm_out = raycast_patches_boolean(tm_si, op, nshapes, shape_fn, pinfo, arena);
+ }
# ifdef PERFDEBUG
double raycast_time = PIL_check_seconds_timer();
std::cout << " raycast_boolean done, time = " << raycast_time - pwn_time << "\n";
@@ -3486,6 +3589,7 @@ IMesh boolean_mesh(IMesh &imesh,
int nshapes,
std::function<int(int)> shape_fn,
bool use_self,
+ bool hole_tolerant,
IMesh *imesh_triangulated,
IMeshArena *arena)
{
@@ -3519,7 +3623,7 @@ IMesh boolean_mesh(IMesh &imesh,
if (dbg_level > 1) {
write_obj_mesh(*tm_in, "boolean_tm_in");
}
- IMesh tm_out = boolean_trimesh(*tm_in, op, nshapes, shape_fn, use_self, arena);
+ IMesh tm_out = boolean_trimesh(*tm_in, op, nshapes, shape_fn, use_self, hole_tolerant, arena);
# ifdef PERFDEBUG
double bool_tri_time = PIL_check_seconds_timer();
std::cout << "boolean_trimesh done, time = " << bool_tri_time - tri_time << "\n";
diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c
index dbeb75570fb..c847f7e1921 100644
--- a/source/blender/blenlib/intern/string_utils.c
+++ b/source/blender/blenlib/intern/string_utils.c
@@ -333,27 +333,22 @@ bool BLI_uniquename_cb(UniquenameCheckCallback unique_check,
return false;
}
-/* little helper macro for BLI_uniquename */
-#ifndef GIVE_STRADDR
-# define GIVE_STRADDR(data, offset) (((char *)data) + offset)
-#endif
-
/**
* Generic function to set a unique name. It is only designed to be used in situations
* where the name is part of the struct.
*
* For places where this is used, see constraint.c for example...
*
- * \param name_offs: should be calculated using offsetof(structname, membername)
- * macro from stddef.h
+ * \param name_offset: should be calculated using `offsetof(structname, membername)`
+ * macro from `stddef.h`
*/
-static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
+static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offset)
{
Link *link;
for (link = list->first; link; link = link->next) {
if (link != vlink) {
- if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
+ if (STREQ(POINTER_OFFSET((const char *)link, name_offset), name)) {
return true;
}
}
@@ -367,9 +362,9 @@ static bool uniquename_unique_check(void *arg, const char *name)
struct {
ListBase *lb;
void *vlink;
- int name_offs;
+ int name_offset;
} *data = arg;
- return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
+ return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offset);
}
/**
@@ -380,20 +375,20 @@ static bool uniquename_unique_check(void *arg, const char *name)
* \param vlink: The block to check the name for
* \param defname: To initialize block name if latter is empty
* \param delim: Delimits numeric suffix in name
- * \param name_offs: Offset of name within block structure
+ * \param name_offset: Offset of name within block structure
* \param name_len: Maximum length of name area
*/
bool BLI_uniquename(
- ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t name_len)
+ ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_len)
{
struct {
ListBase *lb;
void *vlink;
- int name_offs;
+ int name_offset;
} data;
data.lb = list;
data.vlink = vlink;
- data.name_offs = name_offs;
+ data.name_offset = name_offset;
BLI_assert(name_len > 1);
@@ -402,8 +397,12 @@ bool BLI_uniquename(
return false;
}
- return BLI_uniquename_cb(
- uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
+ return BLI_uniquename_cb(uniquename_unique_check,
+ &data,
+ defname,
+ delim,
+ POINTER_OFFSET(vlink, name_offset),
+ name_len);
}
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc
index a35fbf70711..977e5dba497 100644
--- a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc
+++ b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc
@@ -1,6 +1,7 @@
/* Apache License, Version 2.0 */
#include "BLI_linear_allocator.hh"
+#include "BLI_rand.hh"
#include "BLI_strict_flags.h"
#include "testing/testing.h"
@@ -78,7 +79,7 @@ TEST(linear_allocator, Construct)
LinearAllocator<> allocator;
std::array<int, 5> values = {1, 2, 3, 4, 5};
- Vector<int> *vector = allocator.construct<Vector<int>>(values);
+ Vector<int> *vector = allocator.construct<Vector<int>>(values).release();
EXPECT_EQ(vector->size(), 5);
EXPECT_EQ((*vector)[3], 4);
vector->~Vector();
@@ -115,4 +116,24 @@ TEST(linear_allocator, ConstructArrayCopy)
EXPECT_EQ(span2[2], 3);
}
+TEST(linear_allocator, AllocateLarge)
+{
+ LinearAllocator<> allocator;
+ void *buffer1 = allocator.allocate(1024 * 1024, 8);
+ void *buffer2 = allocator.allocate(1024 * 1024, 8);
+ EXPECT_NE(buffer1, buffer2);
+}
+
+TEST(linear_allocator, ManyAllocations)
+{
+ LinearAllocator<> allocator;
+ RandomNumberGenerator rng;
+ for (int i = 0; i < 1000; i++) {
+ int size = rng.get_int32(10000);
+ int alignment = 1 << (rng.get_int32(7));
+ void *buffer = allocator.allocate(size, alignment);
+ EXPECT_NE(buffer, nullptr);
+ }
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
index e503ef8f264..d759f0c3be4 100644
--- a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
+++ b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
@@ -113,7 +113,7 @@ TEST(boolean_trimesh, Empty)
{
IMeshArena arena;
IMesh in;
- IMesh out = boolean_trimesh(in, BoolOpType::None, 1, all_shape_zero, true, &arena);
+ IMesh out = boolean_trimesh(in, BoolOpType::None, 1, all_shape_zero, true, false, &arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 0);
EXPECT_EQ(out.face_size(), 0);
@@ -141,7 +141,8 @@ TEST(boolean_trimesh, TetTetTrimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::None, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::None, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 11);
EXPECT_EQ(out.face_size(), 20);
@@ -150,7 +151,8 @@ TEST(boolean_trimesh, TetTetTrimesh)
}
IMeshBuilder mb2(spec);
- IMesh out2 = boolean_trimesh(mb2.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb2.arena);
+ IMesh out2 = boolean_trimesh(
+ mb2.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb2.arena);
out2.populate_vert();
EXPECT_EQ(out2.vert_size(), 10);
EXPECT_EQ(out2.face_size(), 16);
@@ -160,7 +162,13 @@ TEST(boolean_trimesh, TetTetTrimesh)
IMeshBuilder mb3(spec);
IMesh out3 = boolean_trimesh(
- mb3.imesh, BoolOpType::Union, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb3.arena);
+ mb3.imesh,
+ BoolOpType::Union,
+ 2,
+ [](int t) { return t < 4 ? 0 : 1; },
+ false,
+ false,
+ &mb3.arena);
out3.populate_vert();
EXPECT_EQ(out3.vert_size(), 10);
EXPECT_EQ(out3.face_size(), 16);
@@ -170,7 +178,13 @@ TEST(boolean_trimesh, TetTetTrimesh)
IMeshBuilder mb4(spec);
IMesh out4 = boolean_trimesh(
- mb4.imesh, BoolOpType::Union, 2, [](int t) { return t < 4 ? 0 : 1; }, true, &mb4.arena);
+ mb4.imesh,
+ BoolOpType::Union,
+ 2,
+ [](int t) { return t < 4 ? 0 : 1; },
+ true,
+ false,
+ &mb4.arena);
out4.populate_vert();
EXPECT_EQ(out4.vert_size(), 10);
EXPECT_EQ(out4.face_size(), 16);
@@ -180,7 +194,13 @@ TEST(boolean_trimesh, TetTetTrimesh)
IMeshBuilder mb5(spec);
IMesh out5 = boolean_trimesh(
- mb5.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb5.arena);
+ mb5.imesh,
+ BoolOpType::Intersect,
+ 2,
+ [](int t) { return t < 4 ? 0 : 1; },
+ false,
+ false,
+ &mb5.arena);
out5.populate_vert();
EXPECT_EQ(out5.vert_size(), 4);
EXPECT_EQ(out5.face_size(), 4);
@@ -195,6 +215,7 @@ TEST(boolean_trimesh, TetTetTrimesh)
2,
[](int t) { return t < 4 ? 0 : 1; },
false,
+ false,
&mb6.arena);
out6.populate_vert();
EXPECT_EQ(out6.vert_size(), 6);
@@ -210,6 +231,7 @@ TEST(boolean_trimesh, TetTetTrimesh)
2,
[](int t) { return t < 4 ? 1 : 0; },
false,
+ false,
&mb7.arena);
out7.populate_vert();
EXPECT_EQ(out7.vert_size(), 8);
@@ -241,7 +263,8 @@ TEST(boolean_trimesh, TetTet2Trimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 10);
EXPECT_EQ(out.face_size(), 16);
@@ -284,7 +307,8 @@ TEST(boolean_trimesh, CubeTetTrimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 14);
EXPECT_EQ(out.face_size(), 24);
@@ -316,7 +340,13 @@ TEST(boolean_trimesh, BinaryTetTetTrimesh)
IMeshBuilder mb(spec);
IMesh out = boolean_trimesh(
- mb.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb.arena);
+ mb.imesh,
+ BoolOpType::Intersect,
+ 2,
+ [](int t) { return t < 4 ? 0 : 1; },
+ false,
+ false,
+ &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 4);
EXPECT_EQ(out.face_size(), 4);
@@ -347,7 +377,8 @@ TEST(boolean_trimesh, TetTetCoplanarTrimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 5);
EXPECT_EQ(out.face_size(), 6);
@@ -378,7 +409,8 @@ TEST(boolean_trimesh, TetInsideTetTrimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 4);
EXPECT_EQ(out.face_size(), 4);
@@ -409,7 +441,8 @@ TEST(boolean_trimesh, TetBesideTetTrimesh)
)";
IMeshBuilder mb(spec);
- IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena);
+ IMesh out = boolean_trimesh(
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 8);
EXPECT_EQ(out.face_size(), 8);
@@ -445,7 +478,13 @@ TEST(boolean_trimesh, DegenerateTris)
IMeshBuilder mb(spec);
IMesh out = boolean_trimesh(
- mb.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 5 ? 0 : 1; }, false, &mb.arena);
+ mb.imesh,
+ BoolOpType::Intersect,
+ 2,
+ [](int t) { return t < 5 ? 0 : 1; },
+ false,
+ false,
+ &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 4);
EXPECT_EQ(out.face_size(), 4);
@@ -477,7 +516,7 @@ TEST(boolean_polymesh, TetTet)
IMeshBuilder mb(spec);
IMesh out = boolean_mesh(
- mb.imesh, BoolOpType::None, 1, all_shape_zero, true, nullptr, &mb.arena);
+ mb.imesh, BoolOpType::None, 1, all_shape_zero, true, false, nullptr, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 11);
EXPECT_EQ(out.face_size(), 13);
@@ -492,6 +531,7 @@ TEST(boolean_polymesh, TetTet)
2,
[](int t) { return t < 4 ? 0 : 1; },
false,
+ false,
nullptr,
&mb2.arena);
out2.populate_vert();
@@ -540,7 +580,7 @@ TEST(boolean_polymesh, CubeCube)
write_obj_mesh(mb.imesh, "cube_cube_in");
}
IMesh out = boolean_mesh(
- mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, nullptr, &mb.arena);
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, nullptr, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 20);
EXPECT_EQ(out.face_size(), 12);
@@ -555,6 +595,7 @@ TEST(boolean_polymesh, CubeCube)
2,
[](int t) { return t < 6 ? 0 : 1; },
false,
+ false,
nullptr,
&mb2.arena);
out2.populate_vert();
@@ -597,7 +638,7 @@ TEST(boolean_polymesh, CubeCone)
IMeshBuilder mb(spec);
IMesh out = boolean_mesh(
- mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, nullptr, &mb.arena);
+ mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, nullptr, &mb.arena);
out.populate_vert();
EXPECT_EQ(out.vert_size(), 14);
EXPECT_EQ(out.face_size(), 12);
@@ -646,6 +687,7 @@ TEST(boolean_polymesh, CubeCubeCoplanar)
2,
[](int t) { return t < 6 ? 0 : 1; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
@@ -684,6 +726,7 @@ TEST(boolean_polymesh, TetTeTCoplanarDiff)
2,
[](int t) { return t < 4 ? 0 : 1; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
@@ -734,6 +777,7 @@ TEST(boolean_polymesh, CubeCubeStep)
2,
[](int t) { return t < 6 ? 0 : 1; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
@@ -784,6 +828,7 @@ TEST(boolean_polymesh, CubeCyl4)
2,
[](int t) { return t < 6 ? 1 : 0; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
@@ -855,6 +900,7 @@ TEST(boolean_polymesh, CubeCubesubdivDiff)
2,
[](int t) { return t < 16 ? 1 : 0; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
@@ -896,6 +942,7 @@ TEST(boolean_polymesh, CubePlane)
2,
[](int t) { return t >= 1 ? 0 : 1; },
false,
+ false,
nullptr,
&mb.arena);
out.populate_vert();
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index c7f02de21ea..09f4c405613 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -182,6 +182,8 @@ struct LibraryLink_Params {
struct Main *bmain;
/** Options for linking, used for instantiating. */
int flag;
+ /** Additional tag for #ID.tag. */
+ int id_tag_extra;
/** Context for instancing objects (optional, no instantiation will be performed when NULL). */
struct {
/** The scene in which to instantiate objects/collections. */
@@ -195,10 +197,12 @@ struct LibraryLink_Params {
void BLO_library_link_params_init(struct LibraryLink_Params *params,
struct Main *bmain,
- const int flag);
+ const int flag,
+ const int id_tag_extra);
void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params,
struct Main *bmain,
const int flag,
+ const int id_tag_extra,
struct Scene *scene,
struct ViewLayer *view_layer,
const struct View3D *v3d);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 62188273457..353eb336c42 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -968,15 +968,15 @@ static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock)
/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */
const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead)
{
- return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs);
+ return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offset);
}
/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */
AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead)
{
BLI_assert(BKE_idtype_idcode_is_valid(bhead->code));
- return (fd->id_asset_data_offs >= 0) ?
- *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offs) :
+ return (fd->id_asset_data_offset >= 0) ?
+ *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offset) :
NULL;
}
@@ -1055,9 +1055,9 @@ static bool read_file_dna(FileData *fd, const char **r_error_message)
fd->reconstruct_info = DNA_reconstruct_info_create(
fd->filesdna, fd->memsdna, fd->compflags);
/* used to retrieve ID names from (bhead+1) */
- fd->id_name_offs = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]");
- BLI_assert(fd->id_name_offs != -1);
- fd->id_asset_data_offs = DNA_elem_offset(
+ fd->id_name_offset = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]");
+ BLI_assert(fd->id_name_offset != -1);
+ fd->id_asset_data_offset = DNA_elem_offset(
fd->filesdna, "ID", "AssetMetaData", "*asset_data");
return true;
@@ -2425,7 +2425,9 @@ static void direct_link_id_common(
id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
}
- BKE_lib_libblock_session_uuid_ensure(id);
+ if ((tag & LIB_TAG_TEMP_MAIN) == 0) {
+ BKE_lib_libblock_session_uuid_ensure(id);
+ }
id->lib = current_library;
id->us = ID_FAKE_USERS(id);
@@ -3169,7 +3171,9 @@ static ID *create_placeholder(Main *mainvar, const short idcode, const char *idn
BLI_addtail(lb, ph_id);
id_sort_by_name(lb, ph_id, NULL);
- BKE_lib_libblock_session_uuid_ensure(ph_id);
+ if ((tag & LIB_TAG_TEMP_MAIN) == 0) {
+ BKE_lib_libblock_session_uuid_ensure(ph_id);
+ }
return ph_id;
}
@@ -4412,7 +4416,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
if (id == NULL) {
/* ID has not been read yet, add placeholder to the main of the
* library it belongs to, so that it will be read later. */
- read_libblock(fd, libmain, bhead, LIB_TAG_INDIRECT, false, NULL);
+ read_libblock(fd, libmain, bhead, fd->id_tag_extra | LIB_TAG_INDIRECT, false, NULL);
/* commented because this can print way too much */
// if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->filepath);
@@ -4467,7 +4471,12 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
ID *id = is_yet_read(fd, mainvar, bhead);
if (id == NULL) {
- read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, NULL);
+ read_libblock(fd,
+ mainvar,
+ bhead,
+ fd->id_tag_extra | LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT,
+ false,
+ NULL);
}
else {
/* Convert any previously read weak link to regular link
@@ -4848,7 +4857,7 @@ static ID *link_named_part(
id = is_yet_read(fd, mainl, bhead);
if (id == NULL) {
/* not read yet */
- const int tag = force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN;
+ const int tag = ((force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN) | fd->id_tag_extra);
read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, false, &id);
if (id) {
@@ -4989,10 +4998,18 @@ static void library_link_clear_tag(Main *mainvar, const int flag)
}
}
-static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepath, const int flag)
+static Main *library_link_begin(
+ Main *mainvar, FileData **fd, const char *filepath, const int flag, const int id_tag_extra)
{
Main *mainl;
+ /* Only allow specific tags to be set as extra,
+ * otherwise this could conflict with library loading logic.
+ * Other flags can be added here, as long as they are safe. */
+ BLI_assert((id_tag_extra & ~LIB_TAG_TEMP_MAIN) == 0);
+
+ (*fd)->id_tag_extra = id_tag_extra;
+
(*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
@@ -5018,22 +5035,25 @@ static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepa
void BLO_library_link_params_init(struct LibraryLink_Params *params,
struct Main *bmain,
- const int flag)
+ const int flag,
+ const int id_tag_extra)
{
memset(params, 0, sizeof(*params));
params->bmain = bmain;
params->flag = flag;
+ params->id_tag_extra = id_tag_extra;
}
void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params,
struct Main *bmain,
const int flag,
+ const int id_tag_extra,
/* Context arguments. */
struct Scene *scene,
struct ViewLayer *view_layer,
const struct View3D *v3d)
{
- BLO_library_link_params_init(params, bmain, flag);
+ BLO_library_link_params_init(params, bmain, flag, id_tag_extra);
if (scene != NULL) {
/* Tagging is needed for instancing. */
params->flag |= BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
@@ -5058,7 +5078,7 @@ Main *BLO_library_link_begin(BlendHandle **bh,
const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
- return library_link_begin(params->bmain, &fd, filepath, params->flag);
+ return library_link_begin(params->bmain, &fd, filepath, params->flag, params->id_tag_extra);
}
static void split_main_newid(Main *mainptr, Main *main_newid)
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index b81d8bd9a2b..9682b5456d2 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -110,16 +110,24 @@ typedef struct FileData {
int fileversion;
/** Used to retrieve ID names from (bhead+1). */
- int id_name_offs;
+ int id_name_offset;
/** Used to retrieve asset data from (bhead+1). NOTE: This may not be available in old files,
* will be -1 then! */
- int id_asset_data_offs;
+ int id_asset_data_offset;
/** For do_versions patching. */
int globalf, fileflags;
/** Optionally skip some data-blocks when they're not needed. */
eBLOReadSkip skip_flags;
+ /**
+ * Tag to apply to all loaded ID data-blocks.
+ *
+ * \note This is initialized from #LibraryLink_Params.id_tag_extra since passing it as an
+ * argument would need an additional argument to be passed around when expanding library data.
+ */
+ int id_tag_extra;
+
struct OldNewMap *datamap;
struct OldNewMap *globmap;
struct OldNewMap *libmap;
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 983fdce15f1..467fd8b0399 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -449,7 +449,9 @@ static void versions_gpencil_add_main(ListBase *lb, ID *id, const char *name)
BKE_id_new_name_validate(lb, id, name);
/* alphabetic insertion: is in BKE_id_new_name_validate */
- BKE_lib_libblock_session_uuid_ensure(id);
+ if ((id->tag & LIB_TAG_TEMP_MAIN) == 0) {
+ BKE_lib_libblock_session_uuid_ensure(id);
+ }
if (G.debug & G_DEBUG) {
printf("Converted GPencil to ID: %s\n", id->name + 2);
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index ef2e196094e..1ecaee10e6a 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -3684,7 +3684,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 48)) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
/* Those are not currently used, but are accessible through RNA API and were not
- * properly initialized previously. This is mere copy of BKE_init_scene() code. */
+ * properly initialized previously. This is mere copy of #scene_init_data code. */
if (scene->r.im_format.view_settings.look[0] == '\0') {
BKE_color_managed_display_settings_init(&scene->r.im_format.display_settings);
BKE_color_managed_view_settings_init_render(
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 07357dac69a..fc10e316aa1 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1469,7 +1469,6 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
continue;
}
BKE_cryptomatte_matte_id_to_entries(storage, storage->matte_id);
- MEM_SAFE_FREE(storage->matte_id);
}
}
}
@@ -1817,6 +1816,21 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 11)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (STREQ(node->idname, "GeometryNodeSubdivisionSurfaceSimple")) {
+ STRNCPY(node->idname, "GeometryNodeSubdivide");
+ }
+ if (STREQ(node->idname, "GeometryNodeSubdivisionSurface")) {
+ STRNCPY(node->idname, "GeometryNodeSubdivideSmooth");
+ }
+ }
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 3d39181cd32..ae22c5151cc 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -282,6 +282,8 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_info.info_property);
FROM_DEFAULT_V4_UCHAR(space_info.info_error);
FROM_DEFAULT_V4_UCHAR(space_info.info_operator);
+
+ btheme->space_spreadsheet = btheme->space_outliner;
}
#undef FROM_DEFAULT_V4_UCHAR
diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc
index ea5d66e195c..fec33a04e6f 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.cc
+++ b/source/blender/bmesh/tools/bmesh_boolean.cc
@@ -354,6 +354,7 @@ static bool bmesh_boolean(BMesh *bm,
const bool use_self,
const bool use_separate_all,
const bool keep_hidden,
+ const bool hole_tolerant,
const BoolOpType boolean_mode)
{
IMeshArena arena;
@@ -389,7 +390,7 @@ static bool bmesh_boolean(BMesh *bm,
};
}
IMesh m_out = boolean_mesh(
- m_in, boolean_mode, nshapes, shape_fn, use_self, &m_triangulated, &arena);
+ m_in, boolean_mode, nshapes, shape_fn, use_self, hole_tolerant, &m_triangulated, &arena);
# ifdef PERF_DEBUG
double boolean_time = PIL_check_seconds_timer();
std::cout << "boolean done, time = " << boolean_time - mesh_time << "\n";
@@ -437,6 +438,7 @@ bool BM_mesh_boolean(BMesh *bm,
const int nshapes,
const bool use_self,
const bool keep_hidden,
+ const bool hole_tolerant,
const int boolean_mode)
{
return blender::meshintersect::bmesh_boolean(
@@ -449,6 +451,7 @@ bool BM_mesh_boolean(BMesh *bm,
use_self,
false,
keep_hidden,
+ hole_tolerant,
static_cast<blender::meshintersect::BoolOpType>(boolean_mode));
}
@@ -468,6 +471,7 @@ bool BM_mesh_boolean_knife(BMesh *bm,
const int nshapes,
const bool use_self,
const bool use_separate_all,
+ const bool hole_tolerant,
const bool keep_hidden)
{
return blender::meshintersect::bmesh_boolean(bm,
@@ -479,6 +483,7 @@ bool BM_mesh_boolean_knife(BMesh *bm,
use_self,
use_separate_all,
keep_hidden,
+ hole_tolerant,
blender::meshintersect::BoolOpType::None);
}
#else
@@ -490,6 +495,7 @@ bool BM_mesh_boolean(BMesh *UNUSED(bm),
const int UNUSED(nshapes),
const bool UNUSED(use_self),
const bool UNUSED(keep_hidden),
+ const bool UNUSED(hole_tolerant),
const int UNUSED(boolean_mode))
{
UNUSED_VARS(looptris, test_fn);
@@ -512,6 +518,7 @@ bool BM_mesh_boolean_knife(BMesh *UNUSED(bm),
const int UNUSED(nshapes),
const bool UNUSED(use_self),
const bool UNUSED(use_separate_all),
+ const bool UNUSED(hole_tolerant),
const bool UNUSED(keep_hidden))
{
UNUSED_VARS(looptris, test_fn);
diff --git a/source/blender/bmesh/tools/bmesh_boolean.h b/source/blender/bmesh/tools/bmesh_boolean.h
index 2cc32e143fc..ed77242e14c 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.h
+++ b/source/blender/bmesh/tools/bmesh_boolean.h
@@ -32,6 +32,7 @@ bool BM_mesh_boolean(BMesh *bm,
const int nshapes,
const bool use_self,
const bool keep_hidden,
+ const bool hole_tolerant,
const int boolean_mode);
bool BM_mesh_boolean_knife(BMesh *bm,
@@ -42,6 +43,7 @@ bool BM_mesh_boolean_knife(BMesh *bm,
const int nshapes,
const bool use_self,
const bool use_separate_all,
+ const bool hole_tolerant,
const bool keep_hidden);
#ifdef __cplusplus
diff --git a/source/blender/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/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index ba66d7f0dfe..4aae5471858 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -113,11 +113,11 @@ extern "C" {
*
* When the chunk-order is determined, the first few chunks will be checked if they can be scheduled.
* Chunks can have three states:
- * - [@ref ChunkExecutionState.COM_ES_NOT_SCHEDULED]:
+ * - [@ref eChunkExecutionState.NOT_SCHEDULED]:
* Chunk is not yet scheduled, or dependencies are not met.
- * - [@ref ChunkExecutionState.COM_ES_SCHEDULED]:
+ * - [@ref eChunkExecutionState.SCHEDULED]:
* All dependencies are met, chunk is scheduled, but not finished.
- * - [@ref ChunkExecutionState.COM_ES_EXECUTED]:
+ * - [@ref eChunkExecutionState.EXECUTED]:
* Chunk is finished.
*
* \see ExecutionGroup.execute
diff --git a/source/blender/compositor/intern/COM_CPUDevice.cpp b/source/blender/compositor/intern/COM_CPUDevice.cc
index 7ea12866148..b520a437008 100644
--- a/source/blender/compositor/intern/COM_CPUDevice.cpp
+++ b/source/blender/compositor/intern/COM_CPUDevice.cc
@@ -24,8 +24,8 @@ CPUDevice::CPUDevice(int thread_id) : m_thread_id(thread_id)
void CPUDevice::execute(WorkPackage *work)
{
- const unsigned int chunkNumber = work->getChunkNumber();
- ExecutionGroup *executionGroup = work->getExecutionGroup();
+ const unsigned int chunkNumber = work->chunk_number;
+ ExecutionGroup *executionGroup = work->execution_group;
rcti rect;
executionGroup->determineChunkRect(&rect, chunkNumber);
diff --git a/source/blender/compositor/intern/COM_ChunkOrder.cpp b/source/blender/compositor/intern/COM_ChunkOrder.cc
index 3baa50da487..3baa50da487 100644
--- a/source/blender/compositor/intern/COM_ChunkOrder.cpp
+++ b/source/blender/compositor/intern/COM_ChunkOrder.cc
diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc
index bbc98d086a6..d31ff518ecd 100644
--- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp
+++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc
@@ -19,18 +19,11 @@
#include "COM_ChunkOrderHotspot.h"
#include <cmath>
-ChunkOrderHotspot::ChunkOrderHotspot(int x, int y, float addition)
-{
- x = x;
- y = y;
- addition = addition;
-}
-
double ChunkOrderHotspot::calc_distance(int x, int y)
{
- int dx = x - x;
- int dy = y - y;
+ int dx = this->x - x;
+ int dy = this->y - y;
double result = sqrt((double)(dx * dx + dy * dy));
- result += (double)addition;
+ result += (double)this->addition;
return result;
}
diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.h b/source/blender/compositor/intern/COM_ChunkOrderHotspot.h
index af0cf897673..d7f40921836 100644
--- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.h
+++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.h
@@ -27,8 +27,9 @@ struct ChunkOrderHotspot {
int y;
float addition;
- public:
- ChunkOrderHotspot(int x, int y, float addition);
+ ChunkOrderHotspot(int x, int y, float addition) : x(x), y(y), addition(addition)
+ {
+ }
double calc_distance(int x, int y);
diff --git a/source/blender/compositor/intern/COM_CompositorContext.cpp b/source/blender/compositor/intern/COM_CompositorContext.cc
index 2e168221b7b..2e168221b7b 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.cpp
+++ b/source/blender/compositor/intern/COM_CompositorContext.cc
diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cc
index 08035940667..7d897d29576 100644
--- a/source/blender/compositor/intern/COM_Converter.cpp
+++ b/source/blender/compositor/intern/COM_Converter.cc
@@ -115,9 +115,9 @@
#include "COM_ViewerNode.h"
#include "COM_ZCombineNode.h"
-bool Converter::is_fast_node(bNode *b_node)
+bool COM_bnode_is_fast_node(const bNode &b_node)
{
- return !ELEM(b_node->type,
+ return !ELEM(b_node.type,
CMP_NODE_BLUR,
CMP_NODE_VECBLUR,
CMP_NODE_BILATERALBLUR,
@@ -132,7 +132,7 @@ bool Converter::is_fast_node(bNode *b_node)
CMP_NODE_DENOISE);
}
-Node *Converter::convert(bNode *b_node)
+Node *COM_convert_bnode(bNode *b_node)
{
Node *node = nullptr;
@@ -419,36 +419,37 @@ Node *Converter::convert(bNode *b_node)
return node;
}
-NodeOperation *Converter::convertDataType(NodeOperationOutput *from, NodeOperationInput *to)
+/* TODO(jbakker): make this an std::optional<NodeOperation>. */
+NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, const NodeOperationInput &to)
{
- DataType fromDatatype = from->getDataType();
- DataType toDatatype = to->getDataType();
+ const DataType src_data_type = from.getDataType();
+ const DataType dst_data_type = to.getDataType();
- if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_COLOR) {
+ if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_COLOR) {
return new ConvertValueToColorOperation();
}
- if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_VECTOR) {
+ if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_VECTOR) {
return new ConvertValueToVectorOperation();
}
- if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VALUE) {
+ if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VALUE) {
return new ConvertColorToValueOperation();
}
- if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VECTOR) {
+ if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VECTOR) {
return new ConvertColorToVectorOperation();
}
- if (fromDatatype == COM_DT_VECTOR && toDatatype == COM_DT_VALUE) {
+ if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_VALUE) {
return new ConvertVectorToValueOperation();
}
- if (fromDatatype == COM_DT_VECTOR && toDatatype == COM_DT_COLOR) {
+ if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_COLOR) {
return new ConvertVectorToColorOperation();
}
return nullptr;
}
-void Converter::convertResolution(NodeOperationBuilder &builder,
- NodeOperationOutput *fromSocket,
- NodeOperationInput *toSocket)
+void COM_convert_resolution(NodeOperationBuilder &builder,
+ NodeOperationOutput *fromSocket,
+ NodeOperationInput *toSocket)
{
InputResizeMode mode = toSocket->getResizeMode();
diff --git a/source/blender/compositor/intern/COM_Converter.h b/source/blender/compositor/intern/COM_Converter.h
index fe3b8b75ccc..59be34bf0e3 100644
--- a/source/blender/compositor/intern/COM_Converter.h
+++ b/source/blender/compositor/intern/COM_Converter.h
@@ -31,56 +31,37 @@ class NodeOperationOutput;
class NodeOperationBuilder;
/**
- * \brief Conversion methods for the compositor
+ * \brief Wraps a bNode in its Node instance.
+ *
+ * For all nodetypes a wrapper class is created.
+ *
+ * \note When adding a new node to blender, this method needs to be changed to return the correct
+ * Node instance.
+ *
+ * \see Node
*/
-class Converter {
- public:
- /**
- * \brief Convert/wraps a bNode in its Node instance.
- *
- * For all nodetypes a wrapper class is created.
- *
- * \note When adding a new node to blender, this method needs to be changed to return the correct
- * Node instance.
- *
- * \see Node
- */
- static Node *convert(bNode *b_node);
-
- /**
- * \brief True if the node is considered 'fast'.
- *
- * Slow nodes will be skipped if fast execution is required.
- */
- static bool is_fast_node(bNode *b_node);
+Node *COM_convert_bnode(bNode *b_node);
- /**
- * \brief This method will add a datetype conversion rule when the to-socket does not support the
- * from-socket actual data type.
- *
- * \note this method is called when conversion is needed.
- *
- * \param link: the NodeLink what needs conversion
- * \param system: the ExecutionSystem to add the conversion to.
- * \see NodeLink - a link between two sockets
- */
- static NodeOperation *convertDataType(NodeOperationOutput *from, NodeOperationInput *to);
+/**
+ * \brief True if the node is considered 'fast'.
+ *
+ * Slow nodes will be skipped if fast execution is required.
+ */
+bool COM_bnode_is_fast_node(const bNode &b_node);
- /**
- * \brief This method will add a resolution rule based on the settings of the NodeInput.
- *
- * \note Conversion logic is implemented in this method
- * \see InputSocketResizeMode for the possible conversions.
- *
- * \param link: the NodeLink what needs conversion
- * \param system: the ExecutionSystem to add the conversion to.
- * \see NodeLink - a link between two sockets
- */
- static void convertResolution(NodeOperationBuilder &builder,
- NodeOperationOutput *fromSocket,
- NodeOperationInput *toSocket);
+/**
+ * \brief This function will add a datetype conversion rule when the to-socket does not support the
+ * from-socket actual data type.
+ */
+NodeOperation *COM_convert_data_type(const NodeOperationOutput &from,
+ const NodeOperationInput &to);
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("COM:Converter")
-#endif
-};
+/**
+ * \brief This function will add a resolution rule based on the settings of the NodeInput.
+ *
+ * \note Conversion logic is implemented in this function.
+ * \see InputSocketResizeMode for the possible conversions.
+ */
+void COM_convert_resolution(NodeOperationBuilder &builder,
+ NodeOperationOutput *fromSocket,
+ NodeOperationInput *toSocket);
diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cc
index b49d575cade..b49d575cade 100644
--- a/source/blender/compositor/intern/COM_Debug.cpp
+++ b/source/blender/compositor/intern/COM_Debug.cc
diff --git a/source/blender/compositor/intern/COM_Device.cpp b/source/blender/compositor/intern/COM_Device.cc
index 38a22369005..38a22369005 100644
--- a/source/blender/compositor/intern/COM_Device.cpp
+++ b/source/blender/compositor/intern/COM_Device.cc
diff --git a/source/blender/compositor/intern/COM_Device.h b/source/blender/compositor/intern/COM_Device.h
index bb95f1e953c..0b0f0f5c1c6 100644
--- a/source/blender/compositor/intern/COM_Device.h
+++ b/source/blender/compositor/intern/COM_Device.h
@@ -55,7 +55,7 @@ class Device {
* \brief execute a WorkPackage
* \param work: the WorkPackage to execute
*/
- virtual void execute(WorkPackage *work) = 0;
+ virtual void execute(struct WorkPackage *work) = 0;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:Device")
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cc
index 9c21c91c370..37623228183 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cc
@@ -43,20 +43,19 @@
ExecutionGroup::ExecutionGroup()
{
- this->m_isOutput = false;
+ this->m_is_output = false;
this->m_complex = false;
- this->m_chunkExecutionStates = nullptr;
this->m_bTree = nullptr;
this->m_height = 0;
this->m_width = 0;
- this->m_cachedMaxReadBufferOffset = 0;
- this->m_numberOfXChunks = 0;
- this->m_numberOfYChunks = 0;
- this->m_numberOfChunks = 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_chunksFinished = 0;
+ this->m_chunks_finished = 0;
BLI_rcti_init(&this->m_viewerBorder, 0, 0, 0, 0);
this->m_executionStartTime = 0;
}
@@ -108,7 +107,7 @@ bool ExecutionGroup::addOperation(NodeOperation *operation)
m_initialized = true;
}
- m_operations.push_back(operation);
+ m_operations.append(operation);
return true;
}
@@ -121,45 +120,36 @@ NodeOperation *ExecutionGroup::getOutputOperation() const
void ExecutionGroup::initExecution()
{
- if (this->m_chunkExecutionStates != nullptr) {
- MEM_freeN(this->m_chunkExecutionStates);
- }
- unsigned int index;
+ m_chunk_execution_states.clear();
determineNumberOfChunks();
- this->m_chunkExecutionStates = nullptr;
- if (this->m_numberOfChunks != 0) {
- this->m_chunkExecutionStates = (ChunkExecutionState *)MEM_mallocN(
- sizeof(ChunkExecutionState) * this->m_numberOfChunks, __func__);
- for (index = 0; index < this->m_numberOfChunks; index++) {
- this->m_chunkExecutionStates[index] = COM_ES_NOT_SCHEDULED;
+ 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 maxNumber = 0;
+ unsigned int max_offset = 0;
- for (index = 0; index < this->m_operations.size(); index++) {
- NodeOperation *operation = this->m_operations[index];
+ for (NodeOperation *operation : m_operations) {
if (operation->isReadBufferOperation()) {
- ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
- this->m_cachedReadOperations.push_back(readOperation);
- maxNumber = max(maxNumber, readOperation->getOffset());
+ ReadBufferOperation *readOperation = static_cast<ReadBufferOperation *>(operation);
+ this->m_read_operations.append(readOperation);
+ max_offset = MAX2(max_offset, readOperation->getOffset());
}
}
- maxNumber++;
- this->m_cachedMaxReadBufferOffset = maxNumber;
+ max_offset++;
+ this->m_max_read_buffer_offset = max_offset;
}
void ExecutionGroup::deinitExecution()
{
- if (this->m_chunkExecutionStates != nullptr) {
- MEM_freeN(this->m_chunkExecutionStates);
- this->m_chunkExecutionStates = nullptr;
- }
- this->m_numberOfChunks = 0;
- this->m_numberOfXChunks = 0;
- this->m_numberOfYChunks = 0;
- this->m_cachedReadOperations.clear();
+ 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])
@@ -174,17 +164,17 @@ void ExecutionGroup::determineResolution(unsigned int resolution[2])
void ExecutionGroup::determineNumberOfChunks()
{
if (this->m_singleThreaded) {
- this->m_numberOfXChunks = 1;
- this->m_numberOfYChunks = 1;
- this->m_numberOfChunks = 1;
+ this->m_x_chunks_len = 1;
+ this->m_y_chunks_len = 1;
+ this->m_chunks_len = 1;
}
else {
const float chunkSizef = this->m_chunkSize;
const int border_width = BLI_rcti_size_x(&this->m_viewerBorder);
const int border_height = BLI_rcti_size_y(&this->m_viewerBorder);
- this->m_numberOfXChunks = ceil(border_width / chunkSizef);
- this->m_numberOfYChunks = ceil(border_height / chunkSizef);
- this->m_numberOfChunks = this->m_numberOfXChunks * this->m_numberOfYChunks;
+ this->m_x_chunks_len = ceil(border_width / chunkSizef);
+ this->m_y_chunks_len = ceil(border_height / chunkSizef);
+ this->m_chunks_len = this->m_x_chunks_len * this->m_y_chunks_len;
}
}
@@ -202,20 +192,20 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
if (bTree->test_break && bTree->test_break(bTree->tbh)) {
return;
} /** \note Early break out for blur and preview nodes. */
- if (this->m_numberOfChunks == 0) {
+ if (this->m_chunks_len == 0) {
return;
} /** \note Early break out. */
unsigned int chunkNumber;
this->m_executionStartTime = PIL_check_seconds_timer();
- this->m_chunksFinished = 0;
+ this->m_chunks_finished = 0;
this->m_bTree = bTree;
unsigned int index;
- unsigned int *chunkOrder = (unsigned int *)MEM_mallocN(
- sizeof(unsigned int) * this->m_numberOfChunks, __func__);
+ unsigned int *chunkOrder = (unsigned int *)MEM_mallocN(sizeof(unsigned int) * this->m_chunks_len,
+ __func__);
- for (chunkNumber = 0; chunkNumber < this->m_numberOfChunks; chunkNumber++) {
+ for (chunkNumber = 0; chunkNumber < this->m_chunks_len; chunkNumber++) {
chunkOrder[chunkNumber] = chunkNumber;
}
NodeOperation *operation = this->getOutputOperation();
@@ -235,9 +225,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
switch (chunkorder) {
case COM_TO_RANDOM:
- for (index = 0; index < 2 * this->m_numberOfChunks; index++) {
- int index1 = rand() % this->m_numberOfChunks;
- int index2 = rand() % this->m_numberOfChunks;
+ for (index = 0; index < 2 * this->m_chunks_len; index++) {
+ int index1 = rand() % this->m_chunks_len;
+ int index2 = rand() % this->m_chunks_len;
int s = chunkOrder[index1];
chunkOrder[index1] = chunkOrder[index2];
chunkOrder[index2] = s;
@@ -247,9 +237,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
ChunkOrderHotspot *hotspots[1];
hotspots[0] = new ChunkOrderHotspot(border_width * centerX, border_height * centerY, 0.0f);
rcti rect;
- ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(
- sizeof(ChunkOrder) * this->m_numberOfChunks, __func__);
- for (index = 0; index < this->m_numberOfChunks; index++) {
+ ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len,
+ __func__);
+ for (index = 0; index < this->m_chunks_len; index++) {
determineChunkRect(&rect, index);
chunkOrders[index].number = index;
chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin;
@@ -257,8 +247,8 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
chunkOrders[index].update_distance(hotspots, 1);
}
- std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks - 1]);
- for (index = 0; index < this->m_numberOfChunks; index++) {
+ std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len - 1]);
+ for (index = 0; index < this->m_chunks_len; index++) {
chunkOrder[index] = chunkOrders[index].number;
}
@@ -275,7 +265,7 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
unsigned int bx = mx + 2 * tx;
unsigned int by = my + 2 * ty;
- float addition = this->m_numberOfChunks / COM_RULE_OF_THIRDS_DIVIDER;
+ float addition = this->m_chunks_len / COM_RULE_OF_THIRDS_DIVIDER;
hotspots[0] = new ChunkOrderHotspot(mx, my, addition * 0);
hotspots[1] = new ChunkOrderHotspot(tx, my, addition * 1);
hotspots[2] = new ChunkOrderHotspot(bx, my, addition * 2);
@@ -286,9 +276,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
hotspots[7] = new ChunkOrderHotspot(mx, ty, addition * 7);
hotspots[8] = new ChunkOrderHotspot(mx, by, addition * 8);
rcti rect;
- ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(
- sizeof(ChunkOrder) * this->m_numberOfChunks, __func__);
- for (index = 0; index < this->m_numberOfChunks; index++) {
+ ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len,
+ __func__);
+ for (index = 0; index < this->m_chunks_len; index++) {
determineChunkRect(&rect, index);
chunkOrders[index].number = index;
chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin;
@@ -296,9 +286,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
chunkOrders[index].update_distance(hotspots, 9);
}
- std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks]);
+ std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len]);
- for (index = 0; index < this->m_numberOfChunks; index++) {
+ for (index = 0; index < this->m_chunks_len; index++) {
chunkOrder[index] = chunkOrders[index].number;
}
@@ -332,31 +322,35 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
finished = true;
int numberEvaluated = 0;
- for (index = startIndex;
- index < this->m_numberOfChunks && numberEvaluated < maxNumberEvaluated;
+ for (index = startIndex; index < this->m_chunks_len && numberEvaluated < maxNumberEvaluated;
index++) {
chunkNumber = chunkOrder[index];
- int yChunk = chunkNumber / this->m_numberOfXChunks;
- int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks);
- const ChunkExecutionState state = this->m_chunkExecutionStates[chunkNumber];
- if (state == COM_ES_NOT_SCHEDULED) {
- scheduleChunkWhenPossible(graph, xChunk, yChunk);
- finished = false;
- startEvaluated = true;
- numberEvaluated++;
-
- if (bTree->update_draw) {
- bTree->update_draw(bTree->udh);
+ 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;
}
- }
- else if (state == COM_ES_SCHEDULED) {
- finished = false;
- startEvaluated = true;
- numberEvaluated++;
- }
- else if (state == COM_ES_EXECUTED && !startEvaluated) {
- startIndex = index + 1;
- }
+ case eChunkExecutionState::SCHEDULED: {
+ finished = false;
+ startEvaluated = true;
+ numberEvaluated++;
+ break;
+ }
+ case eChunkExecutionState::EXECUTED: {
+ if (!startEvaluated) {
+ startIndex = index + 1;
+ }
+ }
+ };
}
WorkScheduler::finish();
@@ -374,17 +368,14 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber)
{
rcti rect;
- vector<MemoryProxy *> memoryproxies;
- unsigned int index;
+ std::vector<MemoryProxy *> memoryproxies;
determineChunkRect(&rect, chunkNumber);
this->determineDependingMemoryProxies(&memoryproxies);
MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN(
- sizeof(MemoryBuffer *) * this->m_cachedMaxReadBufferOffset, __func__);
+ sizeof(MemoryBuffer *) * this->m_max_read_buffer_offset, __func__);
rcti output;
- for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
- ReadBufferOperation *readOperation =
- (ReadBufferOperation *)this->m_cachedReadOperations[index];
+ for (ReadBufferOperation *readOperation : m_read_operations) {
MemoryProxy *memoryProxy = readOperation->getMemoryProxy();
this->determineDependingAreaOfInterest(&rect, readOperation, &output);
MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer(
@@ -405,13 +396,13 @@ MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *mem
void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers)
{
- if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) {
- this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED;
+ if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) {
+ this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::EXECUTED;
}
- atomic_add_and_fetch_u(&this->m_chunksFinished, 1);
+ atomic_add_and_fetch_u(&this->m_chunks_finished, 1);
if (memoryBuffers) {
- for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) {
+ for (unsigned int index = 0; index < this->m_max_read_buffer_offset; index++) {
MemoryBuffer *buffer = memoryBuffers[index];
if (buffer) {
if (buffer->isTemporarily()) {
@@ -424,16 +415,16 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo
}
if (this->m_bTree) {
// status report is only performed for top level Execution Groups.
- float progress = this->m_chunksFinished;
- progress /= this->m_numberOfChunks;
+ float progress = this->m_chunks_finished;
+ progress /= this->m_chunks_len;
this->m_bTree->progress(this->m_bTree->prh, progress);
char buf[128];
BLI_snprintf(buf,
sizeof(buf),
TIP_("Compositing | Tile %u-%u"),
- this->m_chunksFinished,
- this->m_numberOfChunks);
+ this->m_chunks_finished,
+ this->m_chunks_len);
this->m_bTree->stats_draw(this->m_bTree->sdh, buf);
}
}
@@ -452,20 +443,20 @@ inline void ExecutionGroup::determineChunkRect(rcti *rect,
else {
const unsigned int minx = xChunk * this->m_chunkSize + this->m_viewerBorder.xmin;
const unsigned int miny = yChunk * this->m_chunkSize + this->m_viewerBorder.ymin;
- const unsigned int width = min((unsigned int)this->m_viewerBorder.xmax, this->m_width);
- const unsigned int height = min((unsigned int)this->m_viewerBorder.ymax, this->m_height);
+ const unsigned int width = MIN2((unsigned int)this->m_viewerBorder.xmax, this->m_width);
+ const unsigned int height = MIN2((unsigned int)this->m_viewerBorder.ymax, this->m_height);
BLI_rcti_init(rect,
- min(minx, this->m_width),
- min(minx + this->m_chunkSize, width),
- min(miny, this->m_height),
- min(miny + this->m_chunkSize, height));
+ MIN2(minx, this->m_width),
+ MIN2(minx + this->m_chunkSize, width),
+ MIN2(miny, this->m_height),
+ MIN2(miny + this->m_chunkSize, height));
}
}
void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumber) const
{
- const unsigned int yChunk = chunkNumber / this->m_numberOfXChunks;
- const unsigned int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks);
+ const unsigned int yChunk = chunkNumber / this->m_x_chunks_len;
+ const unsigned int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len);
determineChunkRect(rect, xChunk, yChunk);
}
@@ -500,8 +491,8 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area
int maxychunk = (maxy + (int)m_chunkSize - 1) / (int)m_chunkSize;
minxchunk = max_ii(minxchunk, 0);
minychunk = max_ii(minychunk, 0);
- maxxchunk = min_ii(maxxchunk, (int)m_numberOfXChunks);
- maxychunk = min_ii(maxychunk, (int)m_numberOfYChunks);
+ maxxchunk = min_ii(maxxchunk, (int)m_x_chunks_len);
+ maxychunk = min_ii(maxychunk, (int)m_y_chunks_len);
bool result = true;
for (indexx = minxchunk; indexx < maxxchunk; indexx++) {
@@ -517,8 +508,8 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area
bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber)
{
- if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_NOT_SCHEDULED) {
- this->m_chunkExecutionStates[chunkNumber] = COM_ES_SCHEDULED;
+ if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::NOT_SCHEDULED) {
+ this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::SCHEDULED;
WorkScheduler::schedule(this, chunkNumber);
return true;
}
@@ -527,25 +518,25 @@ bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber)
bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk)
{
- if (xChunk < 0 || xChunk >= (int)this->m_numberOfXChunks) {
+ if (xChunk < 0 || xChunk >= (int)this->m_x_chunks_len) {
return true;
}
- if (yChunk < 0 || yChunk >= (int)this->m_numberOfYChunks) {
+ if (yChunk < 0 || yChunk >= (int)this->m_y_chunks_len) {
return true;
}
- int chunkNumber = yChunk * this->m_numberOfXChunks + xChunk;
+ int chunkNumber = yChunk * this->m_x_chunks_len + xChunk;
// chunk is already executed
- if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_EXECUTED) {
+ if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::EXECUTED) {
return true;
}
// chunk is scheduled, but not executed
- if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) {
+ if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) {
return false;
}
// chunk is nor executed nor scheduled.
- vector<MemoryProxy *> memoryProxies;
+ std::vector<MemoryProxy *> memoryProxies;
this->determineDependingMemoryProxies(&memoryProxies);
rcti rect;
@@ -554,9 +545,8 @@ bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChun
bool canBeExecuted = true;
rcti area;
- for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
- ReadBufferOperation *readOperation =
- (ReadBufferOperation *)this->m_cachedReadOperations[index];
+ for (index = 0; index < m_read_operations.size(); index++) {
+ ReadBufferOperation *readOperation = m_read_operations[index];
BLI_rcti_init(&area, 0, 0, 0, 0);
MemoryProxy *memoryProxy = memoryProxies[index];
determineDependingAreaOfInterest(&rect, readOperation, &area);
@@ -586,12 +576,9 @@ void ExecutionGroup::determineDependingAreaOfInterest(rcti *input,
this->getOutputOperation()->determineDependingAreaOfInterest(input, readOperation, output);
}
-void ExecutionGroup::determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies)
+void ExecutionGroup::determineDependingMemoryProxies(std::vector<MemoryProxy *> *memoryProxies)
{
- unsigned int index;
- for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
- ReadBufferOperation *readOperation =
- (ReadBufferOperation *)this->m_cachedReadOperations[index];
+ for (ReadBufferOperation *readOperation : m_read_operations) {
memoryProxies->push_back(readOperation->getMemoryProxy());
}
}
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h
index dd079415d09..f73f4473b5d 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.h
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.h
@@ -23,6 +23,8 @@
#endif
#include "BLI_rect.h"
+#include "BLI_vector.hh"
+
#include "COM_CompositorContext.h"
#include "COM_Device.h"
#include "COM_MemoryProxy.h"
@@ -30,8 +32,6 @@
#include "COM_NodeOperation.h"
#include <vector>
-using std::vector;
-
class ExecutionSystem;
class MemoryProxy;
class ReadBufferOperation;
@@ -41,20 +41,20 @@ class Device;
* \brief the execution state of a chunk in an ExecutionGroup
* \ingroup Execution
*/
-typedef enum ChunkExecutionState {
+enum class eChunkExecutionState {
/**
* \brief chunk is not yet scheduled
*/
- COM_ES_NOT_SCHEDULED = 0,
+ NOT_SCHEDULED = 0,
/**
* \brief chunk is scheduled, but not yet executed
*/
- COM_ES_SCHEDULED = 1,
+ SCHEDULED = 1,
/**
* \brief chunk is executed.
*/
- COM_ES_EXECUTED = 2,
-} ChunkExecutionState;
+ EXECUTED = 2,
+};
/**
* \brief Class ExecutionGroup is a group of Operations that are executed as one.
@@ -63,23 +63,20 @@ typedef enum ChunkExecutionState {
* \ingroup Execution
*/
class ExecutionGroup {
- public:
- typedef std::vector<NodeOperation *> Operations;
-
private:
// fields
/**
* \brief list of operations in this ExecutionGroup
*/
- Operations m_operations;
+ blender::Vector<NodeOperation *> m_operations;
/**
* \brief is this ExecutionGroup an input ExecutionGroup
* an input execution group is a group that is at the end of the calculation
* (the output is important for the user).
*/
- int m_isOutput;
+ bool m_is_output;
/**
* \brief Width of the output
@@ -100,17 +97,17 @@ class ExecutionGroup {
/**
* \brief number of chunks in the x-axis
*/
- unsigned int m_numberOfXChunks;
+ unsigned int m_x_chunks_len;
/**
* \brief number of chunks in the y-axis
*/
- unsigned int m_numberOfYChunks;
+ unsigned int m_y_chunks_len;
/**
* \brief total number of chunks
*/
- unsigned int m_numberOfChunks;
+ unsigned int m_chunks_len;
/**
* \brief contains this ExecutionGroup a complex NodeOperation.
@@ -131,12 +128,12 @@ class ExecutionGroup {
* \brief what is the maximum number field of all ReadBufferOperation in this ExecutionGroup.
* \note this is used to construct the MemoryBuffers that will be passed during execution.
*/
- unsigned int m_cachedMaxReadBufferOffset;
+ unsigned int m_max_read_buffer_offset;
/**
- * \brief a cached vector of all read operations in the execution group.
+ * \brief All read operations of this execution group.
*/
- Operations m_cachedReadOperations;
+ blender::Vector<ReadBufferOperation *> m_read_operations;
/**
* \brief reference to the original bNodeTree,
@@ -148,15 +145,15 @@ class ExecutionGroup {
/**
* \brief total number of chunks that have been calculated for this ExecutionGroup
*/
- unsigned int m_chunksFinished;
+ unsigned int m_chunks_finished;
/**
- * \brief the chunkExecutionStates holds per chunk the execution state. this state can be
- * - COM_ES_NOT_SCHEDULED: not scheduled
- * - COM_ES_SCHEDULED: scheduled
- * - COM_ES_EXECUTED: executed
+ * \brief m_chunk_execution_states holds per chunk the execution state. this state can be
+ * - eChunkExecutionState::NOT_SCHEDULED: not scheduled
+ * - eChunkExecutionState::SCHEDULED: scheduled
+ * - eChunkExecutionState::EXECUTED: executed
*/
- ChunkExecutionState *m_chunkExecutionStates;
+ blender::Vector<eChunkExecutionState> m_chunk_execution_states;
/**
* \brief indicator when this ExecutionGroup has valid Operations in its vector for Execution
@@ -272,18 +269,18 @@ class ExecutionGroup {
* \note ViewerOperation, CompositeOperation, PreviewOperation.
* \see NodeOperation.isOutputOperation
*/
- int isOutputExecutionGroup() const
+ bool isOutputExecutionGroup() const
{
- return this->m_isOutput;
+ return this->m_is_output;
}
/**
* \brief set whether this ExecutionGroup is an output
* \param isOutput:
*/
- void setOutputExecutionGroup(int isOutput)
+ void setOutputExecutionGroup(bool is_output)
{
- this->m_isOutput = isOutput;
+ this->m_is_output = is_output;
}
/**
@@ -405,7 +402,7 @@ class ExecutionGroup {
* \note the area of the MemoryProxy.creator that has to be executed.
* \param memoryProxies: result
*/
- void determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies);
+ void determineDependingMemoryProxies(std::vector<MemoryProxy *> *memoryProxies);
/**
* \brief Determine the rect (minx, maxx, miny, maxy) of a chunk.
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cc
index 4c0c7d2103e..6691e5feb5f 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc
@@ -121,7 +121,8 @@ ExecutionSystem::~ExecutionSystem()
this->m_groups.clear();
}
-void ExecutionSystem::set_operations(const Operations &operations, const Groups &groups)
+void ExecutionSystem::set_operations(const blender::Vector<NodeOperation *> &operations,
+ const blender::Vector<ExecutionGroup *> &groups)
{
m_operations = operations;
m_groups = groups;
@@ -135,10 +136,7 @@ void ExecutionSystem::execute()
DebugInfo::execute_started(this);
unsigned int order = 0;
- for (vector<NodeOperation *>::iterator iter = this->m_operations.begin();
- iter != this->m_operations.end();
- ++iter) {
- NodeOperation *operation = *iter;
+ for (NodeOperation *operation : m_operations) {
if (operation->isReadBufferOperation()) {
ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
readOperation->setOffset(order);
@@ -179,10 +177,10 @@ void ExecutionSystem::execute()
WorkScheduler::start(this->m_context);
- executeGroups(COM_PRIORITY_HIGH);
+ execute_groups(COM_PRIORITY_HIGH);
if (!this->getContext().isFastCalculation()) {
- executeGroups(COM_PRIORITY_MEDIUM);
- executeGroups(COM_PRIORITY_LOW);
+ execute_groups(COM_PRIORITY_MEDIUM);
+ execute_groups(COM_PRIORITY_LOW);
}
WorkScheduler::finish();
@@ -199,37 +197,23 @@ void ExecutionSystem::execute()
}
}
-void ExecutionSystem::executeGroups(CompositorPriority priority)
+void ExecutionSystem::execute_groups(CompositorPriority priority)
{
- unsigned int index;
- vector<ExecutionGroup *> executionGroups;
- this->findOutputExecutionGroup(&executionGroups, priority);
-
- for (index = 0; index < executionGroups.size(); index++) {
- ExecutionGroup *group = executionGroups[index];
+ blender::Vector<ExecutionGroup *> execution_groups = find_output_execution_groups(priority);
+ for (ExecutionGroup *group : execution_groups) {
group->execute(this);
}
}
-void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result,
- CompositorPriority priority) const
+blender::Vector<ExecutionGroup *> ExecutionSystem::find_output_execution_groups(
+ CompositorPriority priority) const
{
- unsigned int index;
- for (index = 0; index < this->m_groups.size(); index++) {
- ExecutionGroup *group = this->m_groups[index];
- if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) {
- result->push_back(group);
- }
- }
-}
+ blender::Vector<ExecutionGroup *> result;
-void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result) const
-{
- unsigned int index;
- for (index = 0; index < this->m_groups.size(); index++) {
- ExecutionGroup *group = this->m_groups[index];
- if (group->isOutputExecutionGroup()) {
- result->push_back(group);
+ 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.h b/source/blender/compositor/intern/COM_ExecutionSystem.h
index 44b47787b06..9a51baf55d7 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.h
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.h
@@ -21,12 +21,16 @@ class ExecutionGroup;
#pragma once
#include "BKE_text.h"
+
#include "COM_ExecutionGroup.h"
#include "COM_Node.h"
#include "COM_NodeOperation.h"
+
#include "DNA_color_types.h"
#include "DNA_node_types.h"
+#include "BLI_vector.hh"
+
/**
* \page execution Execution model
* In order to get to an efficient model for execution, several steps are being done. these steps
@@ -79,7 +83,7 @@ class ExecutionGroup;
* - [@ref InputSocketResizeMode.COM_SC_NO_RESIZE]:
* Bottom left of the images are aligned.
*
- * \see Converter.convertDataType Datatype conversions
+ * \see COM_convert_data_type Datatype conversions
* \see Converter.convertResolution Image size conversions
*
* \section EM_Step4 Step4: group operations in executions groups
@@ -113,9 +117,6 @@ class ExecutionGroup;
* \brief the ExecutionSystem contains the whole compositor tree.
*/
class ExecutionSystem {
- public:
- typedef std::vector<NodeOperation *> Operations;
- typedef std::vector<ExecutionGroup *> Groups;
private:
/**
@@ -126,24 +127,19 @@ class ExecutionSystem {
/**
* \brief vector of operations
*/
- Operations m_operations;
+ blender::Vector<NodeOperation *> m_operations;
/**
* \brief vector of groups
*/
- Groups m_groups;
+ blender::Vector<ExecutionGroup *> m_groups;
private: // methods
/**
* find all execution group with output nodes
*/
- void findOutputExecutionGroup(vector<ExecutionGroup *> *result,
- CompositorPriority priority) const;
-
- /**
- * find all execution group with output nodes
- */
- void findOutputExecutionGroup(vector<ExecutionGroup *> *result) const;
+ blender::Vector<ExecutionGroup *> find_output_execution_groups(
+ CompositorPriority priority) const;
public:
/**
@@ -167,7 +163,8 @@ class ExecutionSystem {
*/
~ExecutionSystem();
- void set_operations(const Operations &operations, const Groups &groups);
+ void set_operations(const blender::Vector<NodeOperation *> &operations,
+ const blender::Vector<ExecutionGroup *> &groups);
/**
* \brief execute this system
@@ -186,7 +183,7 @@ class ExecutionSystem {
}
private:
- void executeGroups(CompositorPriority priority);
+ void execute_groups(CompositorPriority priority);
/* allow the DebugInfo class to look at internals */
friend class DebugInfo;
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cc
index a13db6bb09e..17a73efeab2 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc
@@ -20,9 +20,6 @@
#include "MEM_guardedalloc.h"
-using std::max;
-using std::min;
-
static unsigned int determine_num_channels(DataType datatype)
{
switch (datatype) {
@@ -156,10 +153,10 @@ void MemoryBuffer::copyContentFrom(MemoryBuffer *otherBuffer)
return;
}
unsigned int otherY;
- unsigned int minX = max(this->m_rect.xmin, otherBuffer->m_rect.xmin);
- unsigned int maxX = min(this->m_rect.xmax, otherBuffer->m_rect.xmax);
- unsigned int minY = max(this->m_rect.ymin, otherBuffer->m_rect.ymin);
- unsigned int maxY = min(this->m_rect.ymax, otherBuffer->m_rect.ymax);
+ unsigned int minX = MAX2(this->m_rect.xmin, otherBuffer->m_rect.xmin);
+ unsigned int maxX = MIN2(this->m_rect.xmax, otherBuffer->m_rect.xmax);
+ unsigned int minY = MAX2(this->m_rect.ymin, otherBuffer->m_rect.ymin);
+ unsigned int maxY = MIN2(this->m_rect.ymax, otherBuffer->m_rect.ymax);
int offset;
int otherOffset;
diff --git a/source/blender/compositor/intern/COM_MemoryProxy.cpp b/source/blender/compositor/intern/COM_MemoryProxy.cc
index 7d590cd0ef6..7d590cd0ef6 100644
--- a/source/blender/compositor/intern/COM_MemoryProxy.cpp
+++ b/source/blender/compositor/intern/COM_MemoryProxy.cc
diff --git a/source/blender/compositor/intern/COM_MetaData.cpp b/source/blender/compositor/intern/COM_MetaData.cc
index a6306f6c657..a6306f6c657 100644
--- a/source/blender/compositor/intern/COM_MetaData.cpp
+++ b/source/blender/compositor/intern/COM_MetaData.cc
diff --git a/source/blender/compositor/intern/COM_Node.cpp b/source/blender/compositor/intern/COM_Node.cc
index 897d4e1df02..897d4e1df02 100644
--- a/source/blender/compositor/intern/COM_Node.cpp
+++ b/source/blender/compositor/intern/COM_Node.cc
diff --git a/source/blender/compositor/intern/COM_NodeConverter.cpp b/source/blender/compositor/intern/COM_NodeConverter.cc
index 2db31bd4133..2db31bd4133 100644
--- a/source/blender/compositor/intern/COM_NodeConverter.cpp
+++ b/source/blender/compositor/intern/COM_NodeConverter.cc
diff --git a/source/blender/compositor/intern/COM_NodeGraph.cpp b/source/blender/compositor/intern/COM_NodeGraph.cc
index b604b8ced88..421a762d9b5 100644
--- a/source/blender/compositor/intern/COM_NodeGraph.cpp
+++ b/source/blender/compositor/intern/COM_NodeGraph.cc
@@ -90,7 +90,7 @@ void NodeGraph::add_node(Node *node,
void NodeGraph::add_link(NodeOutput *fromSocket, NodeInput *toSocket)
{
- m_links.push_back(Link(fromSocket, toSocket));
+ m_links.append(Link(fromSocket, toSocket));
/* register with the input */
toSocket->setLink(fromSocket);
@@ -132,7 +132,7 @@ void NodeGraph::add_bNode(const CompositorContext &context,
}
/* replace slow nodes with proxies for fast execution */
- if (context.isFastCalculation() && !Converter::is_fast_node(b_node)) {
+ if (context.isFastCalculation() && !COM_bnode_is_fast_node(*b_node)) {
add_proxies_skip(b_ntree, b_node, key, is_active_group);
return;
}
@@ -146,7 +146,7 @@ void NodeGraph::add_bNode(const CompositorContext &context,
}
else {
/* regular nodes, handled in Converter */
- Node *node = Converter::convert(b_node);
+ Node *node = COM_convert_bnode(b_node);
if (node) {
add_node(node, b_ntree, key, is_active_group);
}
diff --git a/source/blender/compositor/intern/COM_NodeGraph.h b/source/blender/compositor/intern/COM_NodeGraph.h
index 7252d546fce..990e3a30831 100644
--- a/source/blender/compositor/intern/COM_NodeGraph.h
+++ b/source/blender/compositor/intern/COM_NodeGraph.h
@@ -18,6 +18,8 @@
#pragma once
+#include "BLI_vector.hh"
+
#include <map>
#include <set>
#include <vector>
@@ -39,33 +41,21 @@ class NodeOutput;
*/
class NodeGraph {
public:
- class Link {
- private:
- NodeOutput *m_from;
- NodeInput *m_to;
-
- public:
- Link(NodeOutput *from, NodeInput *to) : m_from(from), m_to(to)
- {
- }
+ struct Link {
+ NodeOutput *from;
+ NodeInput *to;
- NodeOutput *getFromSocket() const
- {
- return m_from;
- }
- NodeInput *getToSocket() const
+ Link(NodeOutput *from, NodeInput *to) : from(from), to(to)
{
- return m_to;
}
};
typedef std::vector<Node *> Nodes;
typedef Nodes::iterator NodeIterator;
- typedef std::vector<Link> Links;
private:
Nodes m_nodes;
- Links m_links;
+ blender::Vector<Link> m_links;
public:
NodeGraph();
@@ -75,7 +65,7 @@ class NodeGraph {
{
return m_nodes;
}
- const Links &links() const
+ const blender::Vector<Link> &links() const
{
return m_links;
}
diff --git a/source/blender/compositor/intern/COM_NodeOperation.cpp b/source/blender/compositor/intern/COM_NodeOperation.cc
index 1a30806f28c..ce7d3a6389e 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperation.cc
@@ -182,10 +182,10 @@ bool NodeOperation::determineDependingAreaOfInterest(rcti *input,
first = false;
}
else {
- output->xmin = min(output->xmin, tempOutput.xmin);
- output->ymin = min(output->ymin, tempOutput.ymin);
- output->xmax = max(output->xmax, tempOutput.xmax);
- output->ymax = max(output->ymax, tempOutput.ymax);
+ output->xmin = MIN2(output->xmin, tempOutput.xmin);
+ output->ymin = MIN2(output->ymin, tempOutput.ymin);
+ output->xmax = MAX2(output->xmax, tempOutput.xmax);
+ output->ymax = MAX2(output->ymax, tempOutput.ymax);
}
}
}
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index 0ce7c1389bd..f26279e2869 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -33,10 +33,6 @@
#include "clew.h"
-using std::list;
-using std::max;
-using std::min;
-
class OpenCLDevice;
class ReadBufferOperation;
class WriteBufferOperation;
@@ -239,8 +235,8 @@ class NodeOperation : public SocketReader {
MemoryBuffer * /*outputMemoryBuffer*/,
cl_mem /*clOutputBuffer*/,
MemoryBuffer ** /*inputMemoryBuffers*/,
- list<cl_mem> * /*clMemToCleanUp*/,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> * /*clMemToCleanUp*/,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
}
virtual void deinitExecution();
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
index 35a3314db3b..688b693080f 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
@@ -72,11 +72,9 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
inverse_input_map[it->second].push_back(it->first);
}
- for (NodeGraph::Links::const_iterator it = m_graph.links().begin(); it != m_graph.links().end();
- ++it) {
- const NodeGraph::Link &link = *it;
- NodeOutput *from = link.getFromSocket();
- NodeInput *to = link.getToSocket();
+ for (const NodeGraph::Link &link : m_graph.links()) {
+ NodeOutput *from = link.from;
+ NodeInput *to = link.to;
NodeOperationOutput *op_from = find_operation_output(m_output_map, from);
const OpInputs &op_to_list = find_operation_inputs(inverse_input_map, to);
@@ -125,7 +123,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
void NodeOperationBuilder::addOperation(NodeOperation *operation)
{
- m_operations.push_back(operation);
+ m_operations.append(operation);
}
void NodeOperationBuilder::mapInputSocket(NodeInput *node_socket,
@@ -288,7 +286,7 @@ void NodeOperationBuilder::add_datatype_conversions()
}
for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) {
const Link &link = *it;
- NodeOperation *converter = Converter::convertDataType(link.from(), link.to());
+ NodeOperation *converter = COM_convert_data_type(*link.from(), *link.to());
if (converter) {
addOperation(converter);
@@ -306,8 +304,7 @@ void NodeOperationBuilder::add_operation_input_constants()
*/
using Inputs = std::vector<NodeOperationInput *>;
Inputs pending_inputs;
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
+ for (NodeOperation *op : m_operations) {
for (int k = 0; k < op->getNumberOfInputSockets(); ++k) {
NodeOperationInput *input = op->getInputSocket(k);
if (!input->isConnected()) {
@@ -408,9 +405,7 @@ void NodeOperationBuilder::resolve_proxies()
void NodeOperationBuilder::determineResolutions()
{
/* determine all resolutions of the operations (Width/Height) */
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
-
+ for (NodeOperation *op : m_operations) {
if (op->isOutputOperation(m_context->isRendering()) && !op->isPreviewOperation()) {
unsigned int resolution[2] = {0, 0};
unsigned int preferredResolution[2] = {0, 0};
@@ -419,9 +414,7 @@ void NodeOperationBuilder::determineResolutions()
}
}
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
-
+ for (NodeOperation *op : m_operations) {
if (op->isOutputOperation(m_context->isRendering()) && op->isPreviewOperation()) {
unsigned int resolution[2] = {0, 0};
unsigned int preferredResolution[2] = {0, 0};
@@ -446,7 +439,7 @@ void NodeOperationBuilder::determineResolutions()
}
for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) {
const Link &link = *it;
- Converter::convertResolution(*this, link.from(), link.to());
+ COM_convert_resolution(*this, link.from(), link.to());
}
}
}
@@ -575,16 +568,14 @@ void NodeOperationBuilder::add_complex_operation_buffers()
/* note: complex ops and get cached here first, since adding operations
* will invalidate iterators over the main m_operations
*/
- Operations complex_ops;
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- if ((*it)->isComplex()) {
- complex_ops.push_back(*it);
+ blender::Vector<NodeOperation *> complex_ops;
+ for (NodeOperation *operation : m_operations) {
+ if (operation->isComplex()) {
+ complex_ops.append(operation);
}
}
- for (Operations::const_iterator it = complex_ops.begin(); it != complex_ops.end(); ++it) {
- NodeOperation *op = *it;
-
+ for (NodeOperation *op : complex_ops) {
DebugInfo::operation_read_write_buffer(op);
for (int index = 0; index < op->getNumberOfInputSockets(); index++) {
@@ -624,9 +615,7 @@ static void find_reachable_operations_recursive(Tags &reachable, NodeOperation *
void NodeOperationBuilder::prune_operations()
{
Tags reachable;
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
-
+ for (NodeOperation *op : m_operations) {
/* output operations are primary executed operations */
if (op->isOutputOperation(m_context->isRendering())) {
find_reachable_operations_recursive(reachable, op);
@@ -634,12 +623,10 @@ void NodeOperationBuilder::prune_operations()
}
/* delete unreachable operations */
- Operations reachable_ops;
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
-
+ blender::Vector<NodeOperation *> reachable_ops;
+ for (NodeOperation *op : m_operations) {
if (reachable.find(op) != reachable.end()) {
- reachable_ops.push_back(op);
+ reachable_ops.append(op);
}
else {
delete op;
@@ -650,7 +637,7 @@ void NodeOperationBuilder::prune_operations()
}
/* topological (depth-first) sorting of operations */
-static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted,
+static void sort_operations_recursive(blender::Vector<NodeOperation *> &sorted,
Tags &visited,
NodeOperation *op)
{
@@ -666,17 +653,17 @@ static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted,
}
}
- sorted.push_back(op);
+ sorted.append(op);
}
void NodeOperationBuilder::sort_operations()
{
- Operations sorted;
+ blender::Vector<NodeOperation *> sorted;
sorted.reserve(m_operations.size());
Tags visited;
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- sort_operations_recursive(sorted, visited, *it);
+ for (NodeOperation *operation : m_operations) {
+ sort_operations_recursive(sorted, visited, operation);
}
m_operations = sorted;
@@ -705,7 +692,7 @@ static void add_group_operations_recursive(Tags &visited, NodeOperation *op, Exe
ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op)
{
ExecutionGroup *group = new ExecutionGroup();
- m_groups.push_back(group);
+ m_groups.append(group);
Tags visited;
add_group_operations_recursive(visited, op, group);
@@ -715,9 +702,7 @@ ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op)
void NodeOperationBuilder::group_operations()
{
- for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
- NodeOperation *op = *it;
-
+ for (NodeOperation *op : m_operations) {
if (op->isOutputOperation(m_context->isRendering())) {
ExecutionGroup *group = make_group(op);
group->setOutputExecutionGroup(true);
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
index 5dd4022b127..b502a12d9b1 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
@@ -24,8 +24,6 @@
#include "COM_NodeGraph.h"
-using std::vector;
-
class CompositorContext;
class Node;
@@ -64,9 +62,7 @@ class NodeOperationBuilder {
}
};
- typedef std::vector<NodeOperation *> Operations;
typedef std::vector<Link> Links;
- typedef std::vector<ExecutionGroup *> Groups;
typedef std::map<NodeOperationInput *, NodeInput *> InputSocketMap;
typedef std::map<NodeOutput *, NodeOperationOutput *> OutputSocketMap;
@@ -78,9 +74,9 @@ class NodeOperationBuilder {
const CompositorContext *m_context;
NodeGraph m_graph;
- Operations m_operations;
+ blender::Vector<NodeOperation *> m_operations;
Links m_links;
- Groups m_groups;
+ blender::Vector<ExecutionGroup *> m_groups;
/** Maps operation inputs to node inputs */
InputSocketMap m_input_map;
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cc
index acfe800e433..34450366aec 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.cc
@@ -61,8 +61,8 @@ void OpenCLDevice::deinitialize()
void OpenCLDevice::execute(WorkPackage *work)
{
- const unsigned int chunkNumber = work->getChunkNumber();
- ExecutionGroup *executionGroup = work->getExecutionGroup();
+ const unsigned int chunkNumber = work->chunk_number;
+ ExecutionGroup *executionGroup = work->execution_group;
rcti rect;
executionGroup->determineChunkRect(&rect, chunkNumber);
@@ -79,7 +79,7 @@ void OpenCLDevice::execute(WorkPackage *work)
cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
int parameterIndex,
int offsetIndex,
- list<cl_mem> *cleanup,
+ std::list<cl_mem> *cleanup,
MemoryBuffer **inputMemoryBuffers,
SocketReader *reader)
{
@@ -111,7 +111,7 @@ const cl_image_format *OpenCLDevice::determineImageFormat(MemoryBuffer *memoryBu
cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
int parameterIndex,
int offsetIndex,
- list<cl_mem> *cleanup,
+ std::list<cl_mem> *cleanup,
MemoryBuffer **inputMemoryBuffers,
ReadBufferOperation *reader)
{
@@ -258,7 +258,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel,
}
cl_kernel OpenCLDevice::COM_clCreateKernel(const char *kernelname,
- list<cl_kernel> *clKernelsToCleanUp)
+ std::list<cl_kernel> *clKernelsToCleanUp)
{
cl_int error;
cl_kernel kernel = clCreateKernel(this->m_program, kernelname, &error);
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h
index d502f5aa34b..e4fd397b4e8 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.h
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.h
@@ -25,8 +25,6 @@ class OpenCLDevice;
#include "COM_WorkScheduler.h"
#include "clew.h"
-using std::list;
-
/**
* \brief device representing an GPU OpenCL device.
* an instance of this class represents a single cl_device
@@ -107,13 +105,13 @@ class OpenCLDevice : public Device {
cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
int parameterIndex,
int offsetIndex,
- list<cl_mem> *cleanup,
+ std::list<cl_mem> *cleanup,
MemoryBuffer **inputMemoryBuffers,
SocketReader *reader);
cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
int parameterIndex,
int offsetIndex,
- list<cl_mem> *cleanup,
+ std::list<cl_mem> *cleanup,
MemoryBuffer **inputMemoryBuffers,
ReadBufferOperation *reader);
void COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel kernel,
@@ -130,5 +128,5 @@ class OpenCLDevice : public Device {
MemoryBuffer *outputMemoryBuffer,
int offsetIndex,
NodeOperation *operation);
- cl_kernel COM_clCreateKernel(const char *kernelname, list<cl_kernel> *clKernelsToCleanUp);
+ cl_kernel COM_clCreateKernel(const char *kernelname, std::list<cl_kernel> *clKernelsToCleanUp);
};
diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc
index 5febf3802de..5febf3802de 100644
--- a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp
+++ b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc
diff --git a/source/blender/compositor/intern/COM_SocketReader.cpp b/source/blender/compositor/intern/COM_SocketReader.cc
index 93c8a143b86..93c8a143b86 100644
--- a/source/blender/compositor/intern/COM_SocketReader.cpp
+++ b/source/blender/compositor/intern/COM_SocketReader.cc
diff --git a/source/blender/compositor/intern/COM_WorkPackage.cpp b/source/blender/compositor/intern/COM_WorkPackage.cc
index 795f8d88d50..60684f2c45c 100644
--- a/source/blender/compositor/intern/COM_WorkPackage.cpp
+++ b/source/blender/compositor/intern/COM_WorkPackage.cc
@@ -18,8 +18,8 @@
#include "COM_WorkPackage.h"
-WorkPackage::WorkPackage(ExecutionGroup *group, unsigned int chunkNumber)
+WorkPackage::WorkPackage(ExecutionGroup *execution_group, unsigned int chunk_number)
{
- this->m_executionGroup = group;
- this->m_chunkNumber = chunkNumber;
+ this->execution_group = execution_group;
+ this->chunk_number = chunk_number;
}
diff --git a/source/blender/compositor/intern/COM_WorkPackage.h b/source/blender/compositor/intern/COM_WorkPackage.h
index f4370aa41be..db5eb3d3072 100644
--- a/source/blender/compositor/intern/COM_WorkPackage.h
+++ b/source/blender/compositor/intern/COM_WorkPackage.h
@@ -16,8 +16,6 @@
* Copyright 2011, Blender Foundation.
*/
-class WorkPackage;
-
#pragma once
class ExecutionGroup;
@@ -27,41 +25,23 @@ class ExecutionGroup;
* \brief contains data about work that can be scheduled
* \see WorkScheduler
*/
-class WorkPackage {
- private:
+struct WorkPackage {
/**
* \brief executionGroup with the operations-setup to be evaluated
*/
- ExecutionGroup *m_executionGroup;
+ ExecutionGroup *execution_group;
/**
* \brief number of the chunk to be executed
*/
- unsigned int m_chunkNumber;
+ unsigned int chunk_number;
- public:
/**
* constructor
* \param group: the ExecutionGroup
- * \param chunkNumber: the number of the chunk
- */
- WorkPackage(ExecutionGroup *group, unsigned int chunkNumber);
-
- /**
- * \brief get the ExecutionGroup
- */
- ExecutionGroup *getExecutionGroup() const
- {
- return this->m_executionGroup;
- }
-
- /**
- * \brief get the number of the chunk
+ * \param chunk_number: the number of the chunk
*/
- unsigned int getChunkNumber() const
- {
- return this->m_chunkNumber;
- }
+ WorkPackage(ExecutionGroup *group, unsigned int chunk_number);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:WorkPackage")
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cc
index 9ca704afdea..a70b6ba4abe 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cc
@@ -48,7 +48,7 @@ static ThreadLocal(CPUDevice *) g_thread_device;
static struct {
/** \brief list of all CPUDevices. for every hardware thread an instance of CPUDevice is created
*/
- vector<CPUDevice *> cpu_devices;
+ std::vector<CPUDevice *> cpu_devices;
#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
/** \brief list of all thread for every CPUDevice in cpudevices a thread exists. */
@@ -62,7 +62,7 @@ static struct {
cl_program opencl_program;
/** \brief list of all OpenCLDevices. for every OpenCL GPU device an instance of OpenCLDevice is
* created. */
- vector<OpenCLDevice *> gpu_devices;
+ std::vector<OpenCLDevice *> 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. */
diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cc
index 68e4f80f91f..68e4f80f91f 100644
--- a/source/blender/compositor/intern/COM_compositor.cpp
+++ b/source/blender/compositor/intern/COM_compositor.cc
diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp b/source/blender/compositor/nodes/COM_AlphaOverNode.cc
index 640fbf49808..640fbf49808 100644
--- a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp
+++ b/source/blender/compositor/nodes/COM_AlphaOverNode.cc
diff --git a/source/blender/compositor/nodes/COM_BilateralBlurNode.cpp b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc
index e8037f923f2..e8037f923f2 100644
--- a/source/blender/compositor/nodes/COM_BilateralBlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc
diff --git a/source/blender/compositor/nodes/COM_BlurNode.cpp b/source/blender/compositor/nodes/COM_BlurNode.cc
index b82bede8443..b82bede8443 100644
--- a/source/blender/compositor/nodes/COM_BlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_BlurNode.cc
diff --git a/source/blender/compositor/nodes/COM_BokehBlurNode.cpp b/source/blender/compositor/nodes/COM_BokehBlurNode.cc
index 5096dbef608..5096dbef608 100644
--- a/source/blender/compositor/nodes/COM_BokehBlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_BokehBlurNode.cc
diff --git a/source/blender/compositor/nodes/COM_BokehImageNode.cpp b/source/blender/compositor/nodes/COM_BokehImageNode.cc
index 87fe4979c1d..87fe4979c1d 100644
--- a/source/blender/compositor/nodes/COM_BokehImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_BokehImageNode.cc
diff --git a/source/blender/compositor/nodes/COM_BoxMaskNode.cpp b/source/blender/compositor/nodes/COM_BoxMaskNode.cc
index fe59bd32939..fe59bd32939 100644
--- a/source/blender/compositor/nodes/COM_BoxMaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_BoxMaskNode.cc
diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.cpp b/source/blender/compositor/nodes/COM_BrightnessNode.cc
index fcd2a6de1f4..fcd2a6de1f4 100644
--- a/source/blender/compositor/nodes/COM_BrightnessNode.cpp
+++ b/source/blender/compositor/nodes/COM_BrightnessNode.cc
diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc
index 598cd7b7745..598cd7b7745 100644
--- a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc
index 83e88b35f92..83e88b35f92 100644
--- a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc
index 596d9631297..596d9631297 100644
--- a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc
index 92b334fddb9..92b334fddb9 100644
--- a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp b/source/blender/compositor/nodes/COM_ColorCurveNode.cc
index e1888f3f0bc..e1888f3f0bc 100644
--- a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorCurveNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.cpp b/source/blender/compositor/nodes/COM_ColorExposureNode.cc
index cd0285ac373..cd0285ac373 100644
--- a/source/blender/compositor/nodes/COM_ColorExposureNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorExposureNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp b/source/blender/compositor/nodes/COM_ColorMatteNode.cc
index 865eee5427f..865eee5427f 100644
--- a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorNode.cpp b/source/blender/compositor/nodes/COM_ColorNode.cc
index e6f8bfa01fe..e6f8bfa01fe 100644
--- a/source/blender/compositor/nodes/COM_ColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.cpp b/source/blender/compositor/nodes/COM_ColorRampNode.cc
index 1504a76cee7..1504a76cee7 100644
--- a/source/blender/compositor/nodes/COM_ColorRampNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorRampNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp b/source/blender/compositor/nodes/COM_ColorSpillNode.cc
index d1a3099e998..d1a3099e998 100644
--- a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorSpillNode.cc
diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp b/source/blender/compositor/nodes/COM_ColorToBWNode.cc
index 4115bad5d3f..4115bad5d3f 100644
--- a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorToBWNode.cc
diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.cpp b/source/blender/compositor/nodes/COM_CombineColorNode.cc
index 12968f06a10..12968f06a10 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.cc
diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cc
index 32ac1fccec9..32ac1fccec9 100644
--- a/source/blender/compositor/nodes/COM_CompositorNode.cpp
+++ b/source/blender/compositor/nodes/COM_CompositorNode.cc
diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc
index 2921b44c95b..2921b44c95b 100644
--- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp
+++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc
diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cpp b/source/blender/compositor/nodes/COM_CornerPinNode.cc
index efe847bbfbf..efe847bbfbf 100644
--- a/source/blender/compositor/nodes/COM_CornerPinNode.cpp
+++ b/source/blender/compositor/nodes/COM_CornerPinNode.cc
diff --git a/source/blender/compositor/nodes/COM_CropNode.cpp b/source/blender/compositor/nodes/COM_CropNode.cc
index 0f0883b0151..0f0883b0151 100644
--- a/source/blender/compositor/nodes/COM_CropNode.cpp
+++ b/source/blender/compositor/nodes/COM_CropNode.cc
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
index 27ef98af8f3..27ef98af8f3 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_DefocusNode.cpp b/source/blender/compositor/nodes/COM_DefocusNode.cc
index 393b1f2dabb..393b1f2dabb 100644
--- a/source/blender/compositor/nodes/COM_DefocusNode.cpp
+++ b/source/blender/compositor/nodes/COM_DefocusNode.cc
diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.cpp b/source/blender/compositor/nodes/COM_DenoiseNode.cc
index 1aae81e1e7b..1aae81e1e7b 100644
--- a/source/blender/compositor/nodes/COM_DenoiseNode.cpp
+++ b/source/blender/compositor/nodes/COM_DenoiseNode.cc
diff --git a/source/blender/compositor/nodes/COM_DespeckleNode.cpp b/source/blender/compositor/nodes/COM_DespeckleNode.cc
index 58734917831..58734917831 100644
--- a/source/blender/compositor/nodes/COM_DespeckleNode.cpp
+++ b/source/blender/compositor/nodes/COM_DespeckleNode.cc
diff --git a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc
index 3d538e9b4a0..3d538e9b4a0 100644
--- a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_DilateErodeNode.cpp b/source/blender/compositor/nodes/COM_DilateErodeNode.cc
index e90707618e5..e90707618e5 100644
--- a/source/blender/compositor/nodes/COM_DilateErodeNode.cpp
+++ b/source/blender/compositor/nodes/COM_DilateErodeNode.cc
diff --git a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc
index f8d0eaf4675..f8d0eaf4675 100644
--- a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc
diff --git a/source/blender/compositor/nodes/COM_DisplaceNode.cpp b/source/blender/compositor/nodes/COM_DisplaceNode.cc
index 0c0c3aad646..0c0c3aad646 100644
--- a/source/blender/compositor/nodes/COM_DisplaceNode.cpp
+++ b/source/blender/compositor/nodes/COM_DisplaceNode.cc
diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc
index 37aeb5c8504..37aeb5c8504 100644
--- a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc
index 907a9f49353..907a9f49353 100644
--- a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc
diff --git a/source/blender/compositor/nodes/COM_EllipseMaskNode.cpp b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc
index 1ae855c0f1d..1ae855c0f1d 100644
--- a/source/blender/compositor/nodes/COM_EllipseMaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc
diff --git a/source/blender/compositor/nodes/COM_FilterNode.cpp b/source/blender/compositor/nodes/COM_FilterNode.cc
index 1147c11794f..1147c11794f 100644
--- a/source/blender/compositor/nodes/COM_FilterNode.cpp
+++ b/source/blender/compositor/nodes/COM_FilterNode.cc
diff --git a/source/blender/compositor/nodes/COM_FlipNode.cpp b/source/blender/compositor/nodes/COM_FlipNode.cc
index d89e6b7b844..d89e6b7b844 100644
--- a/source/blender/compositor/nodes/COM_FlipNode.cpp
+++ b/source/blender/compositor/nodes/COM_FlipNode.cc
diff --git a/source/blender/compositor/nodes/COM_GammaNode.cpp b/source/blender/compositor/nodes/COM_GammaNode.cc
index 1ce17faa0dc..1ce17faa0dc 100644
--- a/source/blender/compositor/nodes/COM_GammaNode.cpp
+++ b/source/blender/compositor/nodes/COM_GammaNode.cc
diff --git a/source/blender/compositor/nodes/COM_GlareNode.cpp b/source/blender/compositor/nodes/COM_GlareNode.cc
index ef088e42205..ef088e42205 100644
--- a/source/blender/compositor/nodes/COM_GlareNode.cpp
+++ b/source/blender/compositor/nodes/COM_GlareNode.cc
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc
index 00125ba2ea5..00125ba2ea5 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc
index dc2e5187e8f..dc2e5187e8f 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc
diff --git a/source/blender/compositor/nodes/COM_IDMaskNode.cpp b/source/blender/compositor/nodes/COM_IDMaskNode.cc
index 5ba54d75bcd..5ba54d75bcd 100644
--- a/source/blender/compositor/nodes/COM_IDMaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_IDMaskNode.cc
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cc
index 69729e018d7..69729e018d7 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cc
diff --git a/source/blender/compositor/nodes/COM_InpaintNode.cpp b/source/blender/compositor/nodes/COM_InpaintNode.cc
index 40fe63ec9f3..40fe63ec9f3 100644
--- a/source/blender/compositor/nodes/COM_InpaintNode.cpp
+++ b/source/blender/compositor/nodes/COM_InpaintNode.cc
diff --git a/source/blender/compositor/nodes/COM_InvertNode.cpp b/source/blender/compositor/nodes/COM_InvertNode.cc
index 913452c42c8..913452c42c8 100644
--- a/source/blender/compositor/nodes/COM_InvertNode.cpp
+++ b/source/blender/compositor/nodes/COM_InvertNode.cc
diff --git a/source/blender/compositor/nodes/COM_KeyingNode.cpp b/source/blender/compositor/nodes/COM_KeyingNode.cc
index 9b493d3f332..9b493d3f332 100644
--- a/source/blender/compositor/nodes/COM_KeyingNode.cpp
+++ b/source/blender/compositor/nodes/COM_KeyingNode.cc
diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc
index 93a9a071226..93a9a071226 100644
--- a/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp
+++ b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc
diff --git a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp b/source/blender/compositor/nodes/COM_LensDistortionNode.cc
index 34d2fba6433..34d2fba6433 100644
--- a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp
+++ b/source/blender/compositor/nodes/COM_LensDistortionNode.cc
diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc
index 8bfea1eff49..8bfea1eff49 100644
--- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc
diff --git a/source/blender/compositor/nodes/COM_MapRangeNode.cpp b/source/blender/compositor/nodes/COM_MapRangeNode.cc
index 352bc0dd48d..352bc0dd48d 100644
--- a/source/blender/compositor/nodes/COM_MapRangeNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapRangeNode.cc
diff --git a/source/blender/compositor/nodes/COM_MapUVNode.cpp b/source/blender/compositor/nodes/COM_MapUVNode.cc
index feb9c75ec56..feb9c75ec56 100644
--- a/source/blender/compositor/nodes/COM_MapUVNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapUVNode.cc
diff --git a/source/blender/compositor/nodes/COM_MapValueNode.cpp b/source/blender/compositor/nodes/COM_MapValueNode.cc
index e07df8ad367..e07df8ad367 100644
--- a/source/blender/compositor/nodes/COM_MapValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapValueNode.cc
diff --git a/source/blender/compositor/nodes/COM_MaskNode.cpp b/source/blender/compositor/nodes/COM_MaskNode.cc
index a6415a3992e..a6415a3992e 100644
--- a/source/blender/compositor/nodes/COM_MaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_MaskNode.cc
diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cc
index 0edf880400f..0edf880400f 100644
--- a/source/blender/compositor/nodes/COM_MathNode.cpp
+++ b/source/blender/compositor/nodes/COM_MathNode.cc
diff --git a/source/blender/compositor/nodes/COM_MixNode.cpp b/source/blender/compositor/nodes/COM_MixNode.cc
index d082590d21b..d082590d21b 100644
--- a/source/blender/compositor/nodes/COM_MixNode.cpp
+++ b/source/blender/compositor/nodes/COM_MixNode.cc
diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.cpp b/source/blender/compositor/nodes/COM_MovieClipNode.cc
index 7cc8f2ea19c..7cc8f2ea19c 100644
--- a/source/blender/compositor/nodes/COM_MovieClipNode.cpp
+++ b/source/blender/compositor/nodes/COM_MovieClipNode.cc
diff --git a/source/blender/compositor/nodes/COM_MovieDistortionNode.cpp b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc
index ebace6d5fff..ebace6d5fff 100644
--- a/source/blender/compositor/nodes/COM_MovieDistortionNode.cpp
+++ b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc
diff --git a/source/blender/compositor/nodes/COM_NormalNode.cpp b/source/blender/compositor/nodes/COM_NormalNode.cc
index 1f48a26fd75..1f48a26fd75 100644
--- a/source/blender/compositor/nodes/COM_NormalNode.cpp
+++ b/source/blender/compositor/nodes/COM_NormalNode.cc
diff --git a/source/blender/compositor/nodes/COM_NormalizeNode.cpp b/source/blender/compositor/nodes/COM_NormalizeNode.cc
index 72459fd477c..72459fd477c 100644
--- a/source/blender/compositor/nodes/COM_NormalizeNode.cpp
+++ b/source/blender/compositor/nodes/COM_NormalizeNode.cc
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cpp b/source/blender/compositor/nodes/COM_OutputFileNode.cc
index dcc1fbdec67..dcc1fbdec67 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.cpp
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc
diff --git a/source/blender/compositor/nodes/COM_PixelateNode.cpp b/source/blender/compositor/nodes/COM_PixelateNode.cc
index f238f68727e..f238f68727e 100644
--- a/source/blender/compositor/nodes/COM_PixelateNode.cpp
+++ b/source/blender/compositor/nodes/COM_PixelateNode.cc
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc
index 6b9b51631ec..6b9b51631ec 100644
--- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cc
index 6be86c04c4d..6be86c04c4d 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cc
diff --git a/source/blender/compositor/nodes/COM_RotateNode.cpp b/source/blender/compositor/nodes/COM_RotateNode.cc
index cbade778bcb..cbade778bcb 100644
--- a/source/blender/compositor/nodes/COM_RotateNode.cpp
+++ b/source/blender/compositor/nodes/COM_RotateNode.cc
diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cpp b/source/blender/compositor/nodes/COM_ScaleNode.cc
index 9ffcd5306b0..9ffcd5306b0 100644
--- a/source/blender/compositor/nodes/COM_ScaleNode.cpp
+++ b/source/blender/compositor/nodes/COM_ScaleNode.cc
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
index 203aa25c9e9..203aa25c9e9 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
diff --git a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp b/source/blender/compositor/nodes/COM_SetAlphaNode.cc
index 233a5e96ff4..233a5e96ff4 100644
--- a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp
+++ b/source/blender/compositor/nodes/COM_SetAlphaNode.cc
diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp b/source/blender/compositor/nodes/COM_SocketProxyNode.cc
index a84dbf680fe..a84dbf680fe 100644
--- a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
+++ b/source/blender/compositor/nodes/COM_SocketProxyNode.cc
diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp b/source/blender/compositor/nodes/COM_SplitViewerNode.cc
index 75703876d9e..75703876d9e 100644
--- a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp
+++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cc
diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc
index 38db080a154..38db080a154 100644
--- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp
+++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc
diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp b/source/blender/compositor/nodes/COM_SunBeamsNode.cc
index d899a54c03c..d899a54c03c 100644
--- a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp
+++ b/source/blender/compositor/nodes/COM_SunBeamsNode.cc
diff --git a/source/blender/compositor/nodes/COM_SwitchNode.cpp b/source/blender/compositor/nodes/COM_SwitchNode.cc
index 947774e98ae..947774e98ae 100644
--- a/source/blender/compositor/nodes/COM_SwitchNode.cpp
+++ b/source/blender/compositor/nodes/COM_SwitchNode.cc
diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp b/source/blender/compositor/nodes/COM_SwitchViewNode.cc
index e4a946e2e9d..e534ebfac9a 100644
--- a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp
+++ b/source/blender/compositor/nodes/COM_SwitchViewNode.cc
@@ -33,7 +33,7 @@ void SwitchViewNode::convertToOperations(NodeConverter &converter,
/* get the internal index of the socket with a matching name */
int nr = BLI_findstringindex(&bnode->inputs, viewName, offsetof(bNodeSocket, name));
- nr = max(nr, 0);
+ nr = MAX2(nr, 0);
result = converter.addInputProxy(getInputSocket(nr), false);
converter.mapOutputSocket(getOutputSocket(0), result);
diff --git a/source/blender/compositor/nodes/COM_TextureNode.cpp b/source/blender/compositor/nodes/COM_TextureNode.cc
index 3381b5098d7..3381b5098d7 100644
--- a/source/blender/compositor/nodes/COM_TextureNode.cpp
+++ b/source/blender/compositor/nodes/COM_TextureNode.cc
diff --git a/source/blender/compositor/nodes/COM_TimeNode.cpp b/source/blender/compositor/nodes/COM_TimeNode.cc
index 247e0d11df6..247e0d11df6 100644
--- a/source/blender/compositor/nodes/COM_TimeNode.cpp
+++ b/source/blender/compositor/nodes/COM_TimeNode.cc
diff --git a/source/blender/compositor/nodes/COM_TonemapNode.cpp b/source/blender/compositor/nodes/COM_TonemapNode.cc
index db329e56f9b..db329e56f9b 100644
--- a/source/blender/compositor/nodes/COM_TonemapNode.cpp
+++ b/source/blender/compositor/nodes/COM_TonemapNode.cc
diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp b/source/blender/compositor/nodes/COM_TrackPositionNode.cc
index 52e7f7d832b..52e7f7d832b 100644
--- a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp
+++ b/source/blender/compositor/nodes/COM_TrackPositionNode.cc
diff --git a/source/blender/compositor/nodes/COM_TransformNode.cpp b/source/blender/compositor/nodes/COM_TransformNode.cc
index cd5ba8ba201..cd5ba8ba201 100644
--- a/source/blender/compositor/nodes/COM_TransformNode.cpp
+++ b/source/blender/compositor/nodes/COM_TransformNode.cc
diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cpp b/source/blender/compositor/nodes/COM_TranslateNode.cc
index 0e9bf825787..0e9bf825787 100644
--- a/source/blender/compositor/nodes/COM_TranslateNode.cpp
+++ b/source/blender/compositor/nodes/COM_TranslateNode.cc
diff --git a/source/blender/compositor/nodes/COM_ValueNode.cpp b/source/blender/compositor/nodes/COM_ValueNode.cc
index 4227db0d10e..4227db0d10e 100644
--- a/source/blender/compositor/nodes/COM_ValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_ValueNode.cc
diff --git a/source/blender/compositor/nodes/COM_VectorBlurNode.cpp b/source/blender/compositor/nodes/COM_VectorBlurNode.cc
index a92991c8b49..a92991c8b49 100644
--- a/source/blender/compositor/nodes/COM_VectorBlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_VectorBlurNode.cc
diff --git a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp b/source/blender/compositor/nodes/COM_VectorCurveNode.cc
index 1201a9f9613..1201a9f9613 100644
--- a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp
+++ b/source/blender/compositor/nodes/COM_VectorCurveNode.cc
diff --git a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc
index 7b86fb1d64d..7b86fb1d64d 100644
--- a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp
+++ b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc
diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cpp b/source/blender/compositor/nodes/COM_ViewerNode.cc
index fa6c1bc3c28..fa6c1bc3c28 100644
--- a/source/blender/compositor/nodes/COM_ViewerNode.cpp
+++ b/source/blender/compositor/nodes/COM_ViewerNode.cc
diff --git a/source/blender/compositor/nodes/COM_ZCombineNode.cpp b/source/blender/compositor/nodes/COM_ZCombineNode.cc
index b61c018d029..b61c018d029 100644
--- a/source/blender/compositor/nodes/COM_ZCombineNode.cpp
+++ b/source/blender/compositor/nodes/COM_ZCombineNode.cc
diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc
index 668d07c7c3d..668d07c7c3d 100644
--- a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp
+++ b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc
diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc
index b8465ab7ccf..b8465ab7ccf 100644
--- a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp
+++ b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc
diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc
index 4510c027d46..4510c027d46 100644
--- a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp
+++ b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp b/source/blender/compositor/operations/COM_AntiAliasOperation.cc
index 684485c40cb..684485c40cb 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cc
diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc
index 35b0092fa5f..35b0092fa5f 100644
--- a/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cc
index 612a71037f7..612a71037f7 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cc
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp b/source/blender/compositor/operations/COM_BokehBlurOperation.cc
index f7b7816e1a1..a8ad2a11790 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cc
@@ -62,7 +62,7 @@ void BokehBlurOperation::initExecution()
int width = this->m_inputBokehProgram->getWidth();
int height = this->m_inputBokehProgram->getHeight();
- float dimension = min(width, height);
+ float dimension = MIN2(width, height);
this->m_bokehMidX = width / 2.0f;
this->m_bokehMidY = height / 2.0f;
@@ -84,7 +84,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
int bufferwidth = inputBuffer->getWidth();
int bufferstartx = inputBuffer->getRect()->xmin;
int bufferstarty = inputBuffer->getRect()->ymin;
- const float max_dim = max(this->getWidth(), this->getHeight());
+ const float max_dim = MAX2(this->getWidth(), this->getHeight());
int pixelSize = this->m_size * max_dim / 100.0f;
zero_v4(color_accum);
@@ -99,10 +99,10 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
int maxy = y + pixelSize;
int minx = x - pixelSize;
int maxx = x + pixelSize;
- miny = max(miny, inputBuffer->getRect()->ymin);
- minx = max(minx, inputBuffer->getRect()->xmin);
- maxy = min(maxy, inputBuffer->getRect()->ymax);
- maxx = min(maxx, inputBuffer->getRect()->xmax);
+ miny = MAX2(miny, inputBuffer->getRect()->ymin);
+ minx = MAX2(minx, inputBuffer->getRect()->xmin);
+ maxy = MIN2(maxy, inputBuffer->getRect()->ymax);
+ maxx = MIN2(maxx, inputBuffer->getRect()->xmax);
int step = getStep();
int offsetadd = getOffsetAdd() * COM_NUM_CHANNELS_COLOR;
@@ -144,7 +144,7 @@ bool BokehBlurOperation::determineDependingAreaOfInterest(rcti *input,
{
rcti newInput;
rcti bokehInput;
- const float max_dim = max(this->getWidth(), this->getHeight());
+ const float max_dim = MAX2(this->getWidth(), this->getHeight());
if (this->m_sizeavailable) {
newInput.xmax = input->xmax + (this->m_size * max_dim / 100.0f);
@@ -193,14 +193,14 @@ void BokehBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel kernel = device->COM_clCreateKernel("bokehBlurKernel", nullptr);
if (!this->m_sizeavailable) {
updateSize();
}
- const float max_dim = max(this->getWidth(), this->getHeight());
+ const float max_dim = MAX2(this->getWidth(), this->getHeight());
cl_int radius = this->m_size * max_dim / 100.0f;
cl_int step = this->getStep();
@@ -235,7 +235,7 @@ void BokehBlurOperation::determineResolution(unsigned int resolution[2],
{
NodeOperation::determineResolution(resolution, preferredResolution);
if (this->m_extend_bounds) {
- const float max_dim = max(resolution[0], resolution[1]);
+ const float max_dim = MAX2(resolution[0], resolution[1]);
resolution[0] += 2 * this->m_size * max_dim / 100.0f;
resolution[1] += 2 * this->m_size * max_dim / 100.0f;
}
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.h b/source/blender/compositor/operations/COM_BokehBlurOperation.h
index 335574a381d..a2e320dfdad 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.h
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.h
@@ -67,8 +67,8 @@ class BokehBlurOperation : public NodeOperation, public QualityStepHelper {
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
void setExtendBounds(bool extend_bounds)
{
diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.cpp b/source/blender/compositor/operations/COM_BokehImageOperation.cc
index 473a43c1776..473a43c1776 100644
--- a/source/blender/compositor/operations/COM_BokehImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_BokehImageOperation.cc
diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp b/source/blender/compositor/operations/COM_BoxMaskOperation.cc
index 662b08bdee9..bb10f3425e2 100644
--- a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_BoxMaskOperation.cc
@@ -64,7 +64,7 @@ void BoxMaskOperation::executePixelSampled(float output[4], float x, float y, Pi
switch (this->m_maskType) {
case CMP_NODE_MASKTYPE_ADD:
if (inside) {
- output[0] = max(inputMask[0], inputValue[0]);
+ output[0] = MAX2(inputMask[0], inputValue[0]);
}
else {
output[0] = inputMask[0];
diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cpp b/source/blender/compositor/operations/COM_BrightnessOperation.cc
index 3ae1b4aaef4..3ae1b4aaef4 100644
--- a/source/blender/compositor/operations/COM_BrightnessOperation.cpp
+++ b/source/blender/compositor/operations/COM_BrightnessOperation.cc
diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc
index 9ccf9d7f1ef..9ccf9d7f1ef 100644
--- a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp
+++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc
diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc
index 9a1e48177ed..9a1e48177ed 100644
--- a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp
+++ b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc
diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc
index 6bc9fa53c31..6bc9fa53c31 100644
--- a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp
+++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc
diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc
index a2c6fd47771..15375589888 100644
--- a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc
@@ -95,7 +95,7 @@ void ChannelMatteOperation::executePixelSampled(float output[4],
this->m_inputImageProgram->readSampled(inColor, x, y, sampler);
/* matte operation */
- alpha = inColor[this->m_ids[0]] - max(inColor[this->m_ids[1]], inColor[this->m_ids[2]]);
+ alpha = inColor[this->m_ids[0]] - MAX2(inColor[this->m_ids[1]], inColor[this->m_ids[2]]);
/* flip because 0.0 is transparent, not 1.0 */
alpha = 1.0f - alpha;
@@ -116,5 +116,5 @@ void ChannelMatteOperation::executePixelSampled(float output[4],
*/
/* Don't make something that was more transparent less transparent. */
- output[0] = min(alpha, inColor[3]);
+ output[0] = MIN2(alpha, inColor[3]);
}
diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.h b/source/blender/compositor/operations/COM_ChannelMatteOperation.h
index 24a5e03a1bf..9a0b888b5a2 100644
--- a/source/blender/compositor/operations/COM_ChannelMatteOperation.h
+++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.h
@@ -38,12 +38,12 @@ class ChannelMatteOperation : public NodeOperation {
float m_limit_range;
/** ids to use for the operations (max and simple)
- * alpha = in[ids[0]] - max(in[ids[1]], in[ids[2]])
+ * alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]])
* the simple operation is using:
* alpha = in[ids[0]] - in[ids[1]]
* but to use the same formula and operation for both we do:
* ids[2] = ids[1]
- * alpha = in[ids[0]] - max(in[ids[1]], in[ids[2]])
+ * alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]])
*/
int m_ids[3];
diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc
index 52de0198a00..52de0198a00 100644
--- a/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc
index f9eaaf6f7a0..44eef1e19cd 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc
@@ -59,7 +59,7 @@ void ColorBalanceASCCDLOperation::executePixelSampled(float output[4],
this->m_inputColorOperation->readSampled(inputColor, x, y, sampler);
float fac = value[0];
- fac = min(1.0f, fac);
+ fac = MIN2(1.0f, fac);
const float mfac = 1.0f - fac;
output[0] = mfac * inputColor[0] +
diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc
index df44e87a86a..934b7e51aee 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc
@@ -64,7 +64,7 @@ void ColorBalanceLGGOperation::executePixelSampled(float output[4],
this->m_inputColorOperation->readSampled(inputColor, x, y, sampler);
float fac = value[0];
- fac = min(1.0f, fac);
+ fac = MIN2(1.0f, fac);
const float mfac = 1.0f - fac;
output[0] = mfac * inputColor[0] +
diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc
index 60343c28662..02c109e8acd 100644
--- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc
@@ -66,7 +66,7 @@ void ColorCorrectionOperation::executePixelSampled(float output[4],
float r, g, b;
float value = inputMask[0];
- value = min(1.0f, value);
+ value = MIN2(1.0f, value);
const float mvalue = 1.0f - value;
float levelShadows = 0.0;
diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cpp b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
index ed107a88953..ed107a88953 100644
--- a/source/blender/compositor/operations/COM_ColorCurveOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.cpp b/source/blender/compositor/operations/COM_ColorExposureOperation.cc
index a11039852a1..a11039852a1 100644
--- a/source/blender/compositor/operations/COM_ColorExposureOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorExposureOperation.cc
diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.cpp b/source/blender/compositor/operations/COM_ColorMatteOperation.cc
index 17ada8d89b2..17ada8d89b2 100644
--- a/source/blender/compositor/operations/COM_ColorMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorMatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.cpp b/source/blender/compositor/operations/COM_ColorRampOperation.cc
index 4d62a293b78..4d62a293b78 100644
--- a/source/blender/compositor/operations/COM_ColorRampOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorRampOperation.cc
diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp b/source/blender/compositor/operations/COM_ColorSpillOperation.cc
index 050792d8dab..8139d71c637 100644
--- a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorSpillOperation.cc
@@ -90,7 +90,7 @@ void ColorSpillOperation::executePixelSampled(float output[4],
float input[4];
this->m_inputFacReader->readSampled(fac, x, y, sampler);
this->m_inputImageReader->readSampled(input, x, y, sampler);
- float rfac = min(1.0f, fac[0]);
+ float rfac = MIN2(1.0f, fac[0]);
float map;
switch (this->m_spillMethod) {
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cc
index 6a16872cae2..6a16872cae2 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cpp
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cc
diff --git a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc
index 44468e04ae9..44468e04ae9 100644
--- a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc
diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc
index fe395ecae9e..abf423cc48a 100644
--- a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc
@@ -63,13 +63,13 @@ void ConvertDepthToRadiusOperation::initExecution()
(this->getHeight() / (float)this->getWidth()) :
(this->getWidth() / (float)this->getHeight());
this->m_aperture = 0.5f * (this->m_cam_lens / (this->m_aspect * cam_sensor)) / this->m_fStop;
- const float minsz = min(getWidth(), getHeight());
+ const float minsz = MIN2(getWidth(), getHeight());
this->m_dof_sp = minsz /
((cam_sensor / 2.0f) /
- this->m_cam_lens); // <- == aspect * min(img->x, img->y) / tan(0.5f * fov);
+ this->m_cam_lens); // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov);
if (this->m_blurPostOperation) {
- m_blurPostOperation->setSigma(min(m_aperture * 128.0f, this->m_maxRadius));
+ m_blurPostOperation->setSigma(MIN2(m_aperture * 128.0f, this->m_maxRadius));
}
}
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cpp b/source/blender/compositor/operations/COM_ConvertOperation.cc
index cccfd407752..cccfd407752 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertOperation.cc
diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc
index 1c2570cd251..a5f2ae404e3 100644
--- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc
@@ -92,8 +92,8 @@ void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y,
output[3] = in2[3];
/* Make sure we don't return negative color. */
- output[0] = max(output[0], 0.0f);
- output[1] = max(output[1], 0.0f);
- output[2] = max(output[2], 0.0f);
- output[3] = max(output[3], 0.0f);
+ output[0] = MAX2(output[0], 0.0f);
+ output[1] = MAX2(output[1], 0.0f);
+ output[2] = MAX2(output[2], 0.0f);
+ output[3] = MAX2(output[3], 0.0f);
}
diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc
index 7e35f6fb4f6..425e87ffa7e 100644
--- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc
@@ -105,10 +105,10 @@ void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, voi
output[3] = output[3] * value[0] + in2[3] * mval;
/* Make sure we don't return negative color. */
- output[0] = max(output[0], 0.0f);
- output[1] = max(output[1], 0.0f);
- output[2] = max(output[2], 0.0f);
- output[3] = max(output[3], 0.0f);
+ output[0] = MAX2(output[0], 0.0f);
+ output[1] = MAX2(output[1], 0.0f);
+ output[2] = MAX2(output[2], 0.0f);
+ output[3] = MAX2(output[3], 0.0f);
}
bool ConvolutionFilterOperation::determineDependingAreaOfInterest(
diff --git a/source/blender/compositor/operations/COM_CropOperation.cpp b/source/blender/compositor/operations/COM_CropOperation.cc
index 408f588871e..9364557169c 100644
--- a/source/blender/compositor/operations/COM_CropOperation.cpp
+++ b/source/blender/compositor/operations/COM_CropOperation.cc
@@ -54,10 +54,10 @@ void CropBaseOperation::updateArea()
local_settings.y2 = height - 1;
}
- this->m_xmax = max(local_settings.x1, local_settings.x2) + 1;
- this->m_xmin = min(local_settings.x1, local_settings.x2);
- this->m_ymax = max(local_settings.y1, local_settings.y2) + 1;
- this->m_ymin = min(local_settings.y1, local_settings.y2);
+ this->m_xmax = MAX2(local_settings.x1, local_settings.x2) + 1;
+ this->m_xmin = MIN2(local_settings.x1, local_settings.x2);
+ this->m_ymax = MAX2(local_settings.y1, local_settings.y2) + 1;
+ this->m_ymin = MIN2(local_settings.y1, local_settings.y2);
}
else {
this->m_xmax = 0;
diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.cpp b/source/blender/compositor/operations/COM_CryptomatteOperation.cc
index ccd291697cf..ccd291697cf 100644
--- a/source/blender/compositor/operations/COM_CryptomatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_CryptomatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp b/source/blender/compositor/operations/COM_CurveBaseOperation.cc
index b58efcf0cca..b58efcf0cca 100644
--- a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_CurveBaseOperation.cc
diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cpp b/source/blender/compositor/operations/COM_DenoiseOperation.cc
index d08f238c4c1..d08f238c4c1 100644
--- a/source/blender/compositor/operations/COM_DenoiseOperation.cpp
+++ b/source/blender/compositor/operations/COM_DenoiseOperation.cc
diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.cpp b/source/blender/compositor/operations/COM_DespeckleOperation.cc
index 901445c6875..901445c6875 100644
--- a/source/blender/compositor/operations/COM_DespeckleOperation.cpp
+++ b/source/blender/compositor/operations/COM_DespeckleOperation.cc
diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc
index cca99a42c0c..cca99a42c0c 100644
--- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
index b2dfb558028..fbe9fe8ea27 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
@@ -41,7 +41,7 @@ void DilateErodeThresholdOperation::initExecution()
}
else {
if (this->m_inset * 2 > this->m_distance) {
- this->m_scope = max(this->m_inset * 2 - this->m_distance, this->m_distance);
+ this->m_scope = MAX2(this->m_inset * 2 - this->m_distance, this->m_distance);
}
else {
this->m_scope = this->m_distance;
@@ -71,10 +71,10 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y,
MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
float *buffer = inputBuffer->getBuffer();
rcti *rect = inputBuffer->getRect();
- const int minx = max(x - this->m_scope, rect->xmin);
- const int miny = max(y - this->m_scope, rect->ymin);
- const int maxx = min(x + this->m_scope, rect->xmax);
- const int maxy = min(y + this->m_scope, rect->ymax);
+ const int minx = MAX2(x - this->m_scope, rect->xmin);
+ const int miny = MAX2(y - this->m_scope, rect->ymin);
+ const int maxx = MIN2(x + this->m_scope, rect->xmax);
+ const int maxy = MIN2(y + this->m_scope, rect->ymax);
const int bufferWidth = BLI_rcti_size_x(rect);
int offset;
@@ -87,7 +87,7 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y,
if (buffer[offset] < sw) {
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
- mindist = min(mindist, dis);
+ mindist = MIN2(mindist, dis);
}
offset++;
}
@@ -102,7 +102,7 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y,
if (buffer[offset] > sw) {
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
- mindist = min(mindist, dis);
+ mindist = MIN2(mindist, dis);
}
offset++;
}
@@ -191,10 +191,10 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void *
MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
float *buffer = inputBuffer->getBuffer();
rcti *rect = inputBuffer->getRect();
- const int minx = max(x - this->m_scope, rect->xmin);
- const int miny = max(y - this->m_scope, rect->ymin);
- const int maxx = min(x + this->m_scope, rect->xmax);
- const int maxy = min(y + this->m_scope, rect->ymax);
+ const int minx = MAX2(x - this->m_scope, rect->xmin);
+ const int miny = MAX2(y - this->m_scope, rect->ymin);
+ const int maxx = MIN2(x + this->m_scope, rect->xmax);
+ const int maxy = MIN2(y + this->m_scope, rect->ymax);
const int bufferWidth = BLI_rcti_size_x(rect);
int offset;
@@ -207,7 +207,7 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void *
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
if (dis <= mindist) {
- value = max(buffer[offset], value);
+ value = MAX2(buffer[offset], value);
}
offset++;
}
@@ -238,8 +238,8 @@ void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel dilateKernel = device->COM_clCreateKernel("dilateKernel", nullptr);
@@ -270,10 +270,10 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d
MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
float *buffer = inputBuffer->getBuffer();
rcti *rect = inputBuffer->getRect();
- const int minx = max(x - this->m_scope, rect->xmin);
- const int miny = max(y - this->m_scope, rect->ymin);
- const int maxx = min(x + this->m_scope, rect->xmax);
- const int maxy = min(y + this->m_scope, rect->ymax);
+ const int minx = MAX2(x - this->m_scope, rect->xmin);
+ const int miny = MAX2(y - this->m_scope, rect->ymin);
+ const int maxx = MIN2(x + this->m_scope, rect->xmax);
+ const int maxy = MIN2(y + this->m_scope, rect->ymax);
const int bufferWidth = BLI_rcti_size_x(rect);
int offset;
@@ -286,7 +286,7 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
if (dis <= mindist) {
- value = min(buffer[offset], value);
+ value = MIN2(buffer[offset], value);
}
offset++;
}
@@ -298,8 +298,8 @@ void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel erodeKernel = device->COM_clCreateKernel("erodeKernel", nullptr);
@@ -360,10 +360,10 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
int half_window = this->m_iterations;
int window = half_window * 2 + 1;
- int xmin = max(0, rect->xmin - half_window);
- int ymin = max(0, rect->ymin - half_window);
- int xmax = min(width, rect->xmax + half_window);
- int ymax = min(height, rect->ymax + half_window);
+ int xmin = MAX2(0, rect->xmin - half_window);
+ int ymin = MAX2(0, rect->ymin - half_window);
+ int xmax = MIN2(width, rect->xmax + half_window);
+ int ymax = MIN2(height, rect->ymax + half_window);
int bwidth = rect->xmax - rect->xmin;
int bheight = rect->ymax - rect->ymin;
@@ -378,7 +378,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
// single row or column of input values, padded with FLT_MAX's to
// simplify the logic.
float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp");
- float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window),
+ float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window),
"dilate erode buf");
// The following is based on the van Herk/Gil-Werman algorithm for morphology operations.
@@ -396,13 +396,13 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
temp[window - 1] = buf[start];
for (x = 1; x < window; x++) {
- temp[window - 1 - x] = max(temp[window - x], buf[start - x]);
- temp[window - 1 + x] = max(temp[window + x - 2], buf[start + x]);
+ temp[window - 1 - x] = MAX2(temp[window - x], buf[start - x]);
+ temp[window - 1 + x] = MAX2(temp[window + x - 2], buf[start + x]);
}
start = half_window + (i - 1) * window + 1;
- for (x = -min(0, start); x < window - max(0, start + window - bwidth); x++) {
- rectf[bwidth * (y - ymin) + (start + x)] = max(temp[x], temp[x + window - 1]);
+ for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) {
+ rectf[bwidth * (y - ymin) + (start + x)] = MAX2(temp[x], temp[x + window - 1]);
}
}
}
@@ -421,13 +421,14 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
temp[window - 1] = buf[start];
for (y = 1; y < window; y++) {
- temp[window - 1 - y] = max(temp[window - y], buf[start - y]);
- temp[window - 1 + y] = max(temp[window + y - 2], buf[start + y]);
+ temp[window - 1 - y] = MAX2(temp[window - y], buf[start - y]);
+ temp[window - 1 + y] = MAX2(temp[window + y - 2], buf[start + y]);
}
start = half_window + (i - 1) * window + 1;
- for (y = -min(0, start); y < window - max(0, start + window - bheight); y++) {
- rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = max(temp[y], temp[y + window - 1]);
+ for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) {
+ rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MAX2(temp[y],
+ temp[y + window - 1]);
}
}
}
@@ -489,10 +490,10 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
int half_window = this->m_iterations;
int window = half_window * 2 + 1;
- int xmin = max(0, rect->xmin - half_window);
- int ymin = max(0, rect->ymin - half_window);
- int xmax = min(width, rect->xmax + half_window);
- int ymax = min(height, rect->ymax + half_window);
+ int xmin = MAX2(0, rect->xmin - half_window);
+ int ymin = MAX2(0, rect->ymin - half_window);
+ int xmax = MIN2(width, rect->xmax + half_window);
+ int ymax = MIN2(height, rect->ymax + half_window);
int bwidth = rect->xmax - rect->xmin;
int bheight = rect->ymax - rect->ymin;
@@ -507,7 +508,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
// single row or column of input values, padded with FLT_MAX's to
// simplify the logic.
float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp");
- float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window),
+ float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window),
"dilate erode buf");
// The following is based on the van Herk/Gil-Werman algorithm for morphology operations.
@@ -525,13 +526,13 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
temp[window - 1] = buf[start];
for (x = 1; x < window; x++) {
- temp[window - 1 - x] = min(temp[window - x], buf[start - x]);
- temp[window - 1 + x] = min(temp[window + x - 2], buf[start + x]);
+ temp[window - 1 - x] = MIN2(temp[window - x], buf[start - x]);
+ temp[window - 1 + x] = MIN2(temp[window + x - 2], buf[start + x]);
}
start = half_window + (i - 1) * window + 1;
- for (x = -min(0, start); x < window - max(0, start + window - bwidth); x++) {
- rectf[bwidth * (y - ymin) + (start + x)] = min(temp[x], temp[x + window - 1]);
+ for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) {
+ rectf[bwidth * (y - ymin) + (start + x)] = MIN2(temp[x], temp[x + window - 1]);
}
}
}
@@ -550,13 +551,14 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
temp[window - 1] = buf[start];
for (y = 1; y < window; y++) {
- temp[window - 1 - y] = min(temp[window - y], buf[start - y]);
- temp[window - 1 + y] = min(temp[window + y - 2], buf[start + y]);
+ temp[window - 1 - y] = MIN2(temp[window - y], buf[start - y]);
+ temp[window - 1 + y] = MIN2(temp[window + y - 2], buf[start + y]);
}
start = half_window + (i - 1) * window + 1;
- for (y = -min(0, start); y < window - max(0, start + window - bheight); y++) {
- rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = min(temp[y], temp[y + window - 1]);
+ for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) {
+ rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MIN2(temp[y],
+ temp[y + window - 1]);
}
}
}
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.h b/source/blender/compositor/operations/COM_DilateErodeOperation.h
index 2af5c8990ee..35f9be89220 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.h
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.h
@@ -115,8 +115,8 @@ class DilateDistanceOperation : public NodeOperation {
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
};
class ErodeDistanceOperation : public DilateDistanceOperation {
public:
@@ -131,8 +131,8 @@ class ErodeDistanceOperation : public DilateDistanceOperation {
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
};
class DilateStepOperation : public NodeOperation {
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc
index c0b9c9b6f1d..3f0cd4ef255 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc
@@ -100,8 +100,8 @@ void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", nullptr);
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
index fdb7b82779e..0c220f0e239 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
@@ -61,6 +61,6 @@ class DirectionalBlurOperation : public NodeOperation, public QualityStepHelper
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
};
diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cpp b/source/blender/compositor/operations/COM_DisplaceOperation.cc
index fcc8bc4670e..fcc8bc4670e 100644
--- a/source/blender/compositor/operations/COM_DisplaceOperation.cpp
+++ b/source/blender/compositor/operations/COM_DisplaceOperation.cc
diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc
index bbc4d63305b..bbc4d63305b 100644
--- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp
+++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc
diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc
index ecc2fc2e85f..ecc2fc2e85f 100644
--- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc
index f333cc1ecd9..f333cc1ecd9 100644
--- a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc
diff --git a/source/blender/compositor/operations/COM_DotproductOperation.cpp b/source/blender/compositor/operations/COM_DotproductOperation.cc
index 5914be21453..5914be21453 100644
--- a/source/blender/compositor/operations/COM_DotproductOperation.cpp
+++ b/source/blender/compositor/operations/COM_DotproductOperation.cc
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
index b548a684ba5..b548a684ba5 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc
diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
index 38541f91fc8..a6985a40625 100644
--- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc
@@ -73,7 +73,7 @@ void EllipseMaskOperation::executePixelSampled(float output[4],
switch (this->m_maskType) {
case CMP_NODE_MASKTYPE_ADD:
if (inside) {
- output[0] = max(inputMask[0], inputValue[0]);
+ output[0] = MAX2(inputMask[0], inputValue[0]);
}
else {
output[0] = inputMask[0];
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
index 157c595afcb..b3c1b6b4413 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc
@@ -209,7 +209,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src,
(void)0
// intermediate buffers
- sz = max(src_width, src_height);
+ sz = MAX2(src_width, src_height);
X = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss X buf");
Y = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss Y buf");
W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf");
diff --git a/source/blender/compositor/operations/COM_FlipOperation.cpp b/source/blender/compositor/operations/COM_FlipOperation.cc
index 37eaf4868d3..37eaf4868d3 100644
--- a/source/blender/compositor/operations/COM_FlipOperation.cpp
+++ b/source/blender/compositor/operations/COM_FlipOperation.cc
diff --git a/source/blender/compositor/operations/COM_GammaCorrectOperation.cpp b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc
index d67d67f8e57..d67d67f8e57 100644
--- a/source/blender/compositor/operations/COM_GammaCorrectOperation.cpp
+++ b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc
diff --git a/source/blender/compositor/operations/COM_GammaOperation.cpp b/source/blender/compositor/operations/COM_GammaOperation.cc
index 6baa52a290c..6baa52a290c 100644
--- a/source/blender/compositor/operations/COM_GammaOperation.cpp
+++ b/source/blender/compositor/operations/COM_GammaOperation.cc
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc
index 4d3efec7c85..4d3efec7c85 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc
index a722a879b8d..a722a879b8d 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc
diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc
index d489c64953e..ca3173001cb 100644
--- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc
@@ -256,7 +256,7 @@ void GaussianBlurReferenceOperation::initExecution()
void GaussianBlurReferenceOperation::updateGauss()
{
int i;
- int x = max(m_filtersizex, m_filtersizey);
+ int x = MAX2(m_filtersizex, m_filtersizey);
m_maintabs = (float **)MEM_mallocN(x * sizeof(float *), "gauss array");
for (i = 0; i < x; i++) {
m_maintabs[i] = make_gausstab(i + 1, i + 1);
@@ -333,7 +333,7 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y,
void GaussianBlurReferenceOperation::deinitExecution()
{
int x, i;
- x = max(this->m_filtersizex, this->m_filtersizey);
+ x = MAX2(this->m_filtersizex, this->m_filtersizey);
for (i = 0; i < x; i++) {
MEM_freeN(this->m_maintabs[i]);
}
diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc
index 90333f7dd79..596d439658c 100644
--- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc
@@ -122,8 +122,8 @@ void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel gaussianXBlurOperationKernel = device->COM_clCreateKernel(
"gaussianXBlurOperationKernel", nullptr);
diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
index b2bcd79e716..78ea6aa3cc2 100644
--- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
@@ -42,8 +42,8 @@ class GaussianXBlurOperation : public BlurBaseOperation {
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
/**
* \brief initialize the execution
diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc
index c5b3cf24239..55c1551ca42 100644
--- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc
@@ -122,8 +122,8 @@ void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel gaussianYBlurOperationKernel = device->COM_clCreateKernel(
"gaussianYBlurOperationKernel", nullptr);
diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
index d921780876a..8e7440b6fe4 100644
--- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
@@ -42,8 +42,8 @@ class GaussianYBlurOperation : public BlurBaseOperation {
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
/**
* \brief initialize the execution
diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp b/source/blender/compositor/operations/COM_GlareBaseOperation.cc
index 7b4d38fba3e..7b4d38fba3e 100644
--- a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareBaseOperation.cc
diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc
index 362905761bb..362905761bb 100644
--- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc
diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp b/source/blender/compositor/operations/COM_GlareGhostOperation.cc
index 760b833d1e1..760b833d1e1 100644
--- a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cc
diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc
index 75c2ae51bde..75c2ae51bde 100644
--- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc
diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc
index 4fccb62e3df..4fccb62e3df 100644
--- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc
diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc
index 1a1922f828c..cfa4b99cd70 100644
--- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc
@@ -54,9 +54,9 @@ void GlareThresholdOperation::executePixelSampled(float output[4],
output[1] -= threshold;
output[2] -= threshold;
- output[0] = max(output[0], 0.0f);
- output[1] = max(output[1], 0.0f);
- output[2] = max(output[2], 0.0f);
+ output[0] = MAX2(output[0], 0.0f);
+ output[1] = MAX2(output[1], 0.0f);
+ output[2] = MAX2(output[2], 0.0f);
}
else {
zero_v3(output);
diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc
index df30e75cf27..df30e75cf27 100644
--- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp
+++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc
diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.cpp b/source/blender/compositor/operations/COM_IDMaskOperation.cc
index 8113adb9bbc..8113adb9bbc 100644
--- a/source/blender/compositor/operations/COM_IDMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_IDMaskOperation.cc
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cc
index ae5b7293a8c..ae5b7293a8c 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cc
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cpp b/source/blender/compositor/operations/COM_InpaintOperation.cc
index 502b33d7e14..502b33d7e14 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.cpp
+++ b/source/blender/compositor/operations/COM_InpaintOperation.cc
diff --git a/source/blender/compositor/operations/COM_InvertOperation.cpp b/source/blender/compositor/operations/COM_InvertOperation.cc
index d9f436a3e28..d9f436a3e28 100644
--- a/source/blender/compositor/operations/COM_InvertOperation.cpp
+++ b/source/blender/compositor/operations/COM_InvertOperation.cc
diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc
index 72bf86facfb..c9cc8ebc045 100644
--- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc
@@ -50,7 +50,7 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data
float average = 0.0f;
if (this->m_axis == 0) {
- const int start = max(0, x - this->m_size + 1), end = min(bufferWidth, x + this->m_size);
+ const int start = MAX2(0, x - this->m_size + 1), end = MIN2(bufferWidth, x + this->m_size);
for (int cx = start; cx < end; cx++) {
int bufferIndex = (y * bufferWidth + cx);
average += buffer[bufferIndex];
@@ -58,8 +58,8 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data
}
}
else {
- const int start = max(0, y - this->m_size + 1),
- end = min(inputBuffer->getHeight(), y + this->m_size);
+ const int start = MAX2(0, y - this->m_size + 1),
+ end = MIN2(inputBuffer->getHeight(), y + this->m_size);
for (int cy = start; cy < end; cy++) {
int bufferIndex = (cy * bufferWidth + x);
average += buffer[bufferIndex];
diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp b/source/blender/compositor/operations/COM_KeyingClipOperation.cc
index 592f116c451..592f116c451 100644
--- a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cc
diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc
index b9bb316462d..f4d0d6c6a00 100644
--- a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc
@@ -63,8 +63,8 @@ void KeyingDespillOperation::executePixelSampled(float output[4],
const int other_1 = (screen_primary_channel + 1) % 3;
const int other_2 = (screen_primary_channel + 2) % 3;
- const int min_channel = min(other_1, other_2);
- const int max_channel = max(other_1, other_2);
+ const int min_channel = MIN2(other_1, other_2);
+ const int max_channel = MAX2(other_1, other_2);
float average_value, amount;
diff --git a/source/blender/compositor/operations/COM_KeyingOperation.cpp b/source/blender/compositor/operations/COM_KeyingOperation.cc
index 9ef4217d300..94e65181207 100644
--- a/source/blender/compositor/operations/COM_KeyingOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingOperation.cc
@@ -30,8 +30,8 @@ static float get_pixel_saturation(const float pixelColor[4],
const int other_1 = (primary_channel + 1) % 3;
const int other_2 = (primary_channel + 2) % 3;
- const int min_channel = min(other_1, other_2);
- const int max_channel = max(other_1, other_2);
+ const int min_channel = MIN2(other_1, other_2);
+ const int max_channel = MAX2(other_1, other_2);
const float val = screen_balance * pixelColor[min_channel] +
(1.0f - screen_balance) * pixelColor[max_channel];
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
index 463a6fe49c0..463a6fe49c0 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc
index 096930d0a83..2bd7493625e 100644
--- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc
@@ -54,7 +54,7 @@ void LuminanceMatteOperation::executePixelSampled(float output[4],
float alpha;
/* one line thread-friend algorithm:
- * output[0] = min(inputValue[3], min(1.0f, max(0.0f, ((luminance - low) / (high - low))));
+ * output[0] = MIN2(inputValue[3], MIN2(1.0f, MAX2(0.0f, ((luminance - low) / (high - low))));
*/
/* test range */
diff --git a/source/blender/compositor/operations/COM_MapRangeOperation.cpp b/source/blender/compositor/operations/COM_MapRangeOperation.cc
index 95b3c27ac2f..95b3c27ac2f 100644
--- a/source/blender/compositor/operations/COM_MapRangeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapRangeOperation.cc
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cc
index 32ab63ae028..32ab63ae028 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapUVOperation.cc
diff --git a/source/blender/compositor/operations/COM_MapValueOperation.cpp b/source/blender/compositor/operations/COM_MapValueOperation.cc
index 7f2044b9139..7f2044b9139 100644
--- a/source/blender/compositor/operations/COM_MapValueOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapValueOperation.cc
diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cc
index ab908590c55..ab908590c55 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_MaskOperation.cc
diff --git a/source/blender/compositor/operations/COM_MaskOperation.h b/source/blender/compositor/operations/COM_MaskOperation.h
index eba14d10373..67e6b64315c 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.h
+++ b/source/blender/compositor/operations/COM_MaskOperation.h
@@ -84,7 +84,7 @@ class MaskOperation : public NodeOperation {
void setMotionBlurSamples(int samples)
{
- this->m_rasterMaskHandleTot = min(max(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX);
+ this->m_rasterMaskHandleTot = MIN2(MAX2(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX);
}
void setMotionBlurShutter(float shutter)
{
diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cc
index dbec6dd1874..692c1e70462 100644
--- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_MathBaseOperation.cc
@@ -351,7 +351,7 @@ void MathMinimumOperation::executePixelSampled(float output[4],
this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
- output[0] = min(inputValue1[0], inputValue2[0]);
+ output[0] = MIN2(inputValue1[0], inputValue2[0]);
clampIfNeeded(output);
}
@@ -367,7 +367,7 @@ void MathMaximumOperation::executePixelSampled(float output[4],
this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler);
- output[0] = max(inputValue1[0], inputValue2[0]);
+ output[0] = MAX2(inputValue1[0], inputValue2[0]);
clampIfNeeded(output);
}
diff --git a/source/blender/compositor/operations/COM_MixOperation.cpp b/source/blender/compositor/operations/COM_MixOperation.cc
index 76a66727a75..11df0900345 100644
--- a/source/blender/compositor/operations/COM_MixOperation.cpp
+++ b/source/blender/compositor/operations/COM_MixOperation.cc
@@ -523,9 +523,9 @@ void MixGlareOperation::executePixelSampled(float output[4],
inputColor1[2] = 0.0f;
}
- output[0] = mf * max(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f);
- output[1] = mf * max(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f);
- output[2] = mf * max(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f);
+ output[0] = mf * MAX2(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f);
+ output[1] = mf * MAX2(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f);
+ output[2] = mf * MAX2(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f);
output[3] = inputColor1[3];
clampIfNeeded(output);
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
index 725aacc7d34..725aacc7d34 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc
diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cpp b/source/blender/compositor/operations/COM_MovieClipOperation.cc
index 4f819bf27af..4f819bf27af 100644
--- a/source/blender/compositor/operations/COM_MovieClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipOperation.cc
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
index 5031d590720..5031d590720 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc
index 60936ee1939..60936ee1939 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
index f5176b0a4db..bfc59cabdbf 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
@@ -28,7 +28,7 @@ class MultilayerBaseOperation : public BaseImageOperation {
protected:
RenderLayer *m_renderLayer;
RenderPass *m_renderPass;
- ImBuf *getImBuf();
+ ImBuf *getImBuf() override;
public:
/**
@@ -44,7 +44,7 @@ class MultilayerColorOperation : public MultilayerBaseOperation {
{
this->addOutputSocket(COM_DT_COLOR);
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
std::unique_ptr<MetaData> getMetaData() const override;
};
@@ -55,7 +55,7 @@ class MultilayerValueOperation : public MultilayerBaseOperation {
{
this->addOutputSocket(COM_DT_VALUE);
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
};
class MultilayerVectorOperation : public MultilayerBaseOperation {
@@ -65,5 +65,5 @@ class MultilayerVectorOperation : public MultilayerBaseOperation {
{
this->addOutputSocket(COM_DT_VECTOR);
}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
};
diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cpp b/source/blender/compositor/operations/COM_NormalizeOperation.cc
index a8448685332..a8448685332 100644
--- a/source/blender/compositor/operations/COM_NormalizeOperation.cpp
+++ b/source/blender/compositor/operations/COM_NormalizeOperation.cc
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
index 7044fe402eb..7044fe402eb 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cc
index bb1b312ffec..bb1b312ffec 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc
diff --git a/source/blender/compositor/operations/COM_PixelateOperation.cpp b/source/blender/compositor/operations/COM_PixelateOperation.cc
index 0d810c80ab4..0d810c80ab4 100644
--- a/source/blender/compositor/operations/COM_PixelateOperation.cpp
+++ b/source/blender/compositor/operations/COM_PixelateOperation.cc
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc
index d4f2ca7bbe8..d4f2ca7bbe8 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
index c395f795a22..c395f795a22 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
index 81a598e937b..81a598e937b 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cpp b/source/blender/compositor/operations/COM_PreviewOperation.cc
index 063421f6525..063421f6525 100644
--- a/source/blender/compositor/operations/COM_PreviewOperation.cpp
+++ b/source/blender/compositor/operations/COM_PreviewOperation.cc
diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
index 7d459b76cb9..7d459b76cb9 100644
--- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc
diff --git a/source/blender/compositor/operations/COM_QualityStepHelper.cpp b/source/blender/compositor/operations/COM_QualityStepHelper.cc
index 3eb8d528f7a..3eb8d528f7a 100644
--- a/source/blender/compositor/operations/COM_QualityStepHelper.cpp
+++ b/source/blender/compositor/operations/COM_QualityStepHelper.cc
diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp b/source/blender/compositor/operations/COM_ReadBufferOperation.cc
index 2977e6685d2..2977e6685d2 100644
--- a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp
+++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cc
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cc
index 73de60f4c34..73de60f4c34 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc
diff --git a/source/blender/compositor/operations/COM_RotateOperation.cpp b/source/blender/compositor/operations/COM_RotateOperation.cc
index 7a21e960c13..9a1f54a6e10 100644
--- a/source/blender/compositor/operations/COM_RotateOperation.cpp
+++ b/source/blender/compositor/operations/COM_RotateOperation.cc
@@ -93,10 +93,10 @@ bool RotateOperation::determineDependingAreaOfInterest(rcti *input,
const float y2 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymin);
const float y3 = this->m_centerY + (-this->m_sine * dxmin + this->m_cosine * dymax);
const float y4 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymax);
- const float minx = min(x1, min(x2, min(x3, x4)));
- const float maxx = max(x1, max(x2, max(x3, x4)));
- const float miny = min(y1, min(y2, min(y3, y4)));
- const float maxy = max(y1, max(y2, max(y3, y4)));
+ const float minx = MIN2(x1, MIN2(x2, MIN2(x3, x4)));
+ const float maxx = MAX2(x1, MAX2(x2, MAX2(x3, x4)));
+ const float miny = MIN2(y1, MIN2(y2, MIN2(y3, y4)));
+ const float maxy = MAX2(y1, MAX2(y2, MAX2(y3, y4)));
newInput.xmax = ceil(maxx) + 1;
newInput.xmin = floor(minx) - 1;
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cpp b/source/blender/compositor/operations/COM_ScaleOperation.cc
index 9ec4e474ccd..9ec4e474ccd 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScaleOperation.cc
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
index 158ffd4a8c0..158ffd4a8c0 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc
index 17029cb3049..17029cb3049 100644
--- a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc
index cd6e82902cc..cd6e82902cc 100644
--- a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cpp b/source/blender/compositor/operations/COM_SetColorOperation.cc
index ffbc20fde9c..ffbc20fde9c 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetColorOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp b/source/blender/compositor/operations/COM_SetSamplerOperation.cc
index 942d717d19c..942d717d19c 100644
--- a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetSamplerOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetValueOperation.cpp b/source/blender/compositor/operations/COM_SetValueOperation.cc
index d72a2dfe23d..d72a2dfe23d 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetValueOperation.cc
diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cpp b/source/blender/compositor/operations/COM_SetVectorOperation.cc
index a0341dbc4df..a0341dbc4df 100644
--- a/source/blender/compositor/operations/COM_SetVectorOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetVectorOperation.cc
diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp b/source/blender/compositor/operations/COM_SocketProxyOperation.cc
index 53f5fea8795..53f5fea8795 100644
--- a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp
+++ b/source/blender/compositor/operations/COM_SocketProxyOperation.cc
diff --git a/source/blender/compositor/operations/COM_SplitOperation.cpp b/source/blender/compositor/operations/COM_SplitOperation.cc
index fb6214c7522..fb6214c7522 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.cpp
+++ b/source/blender/compositor/operations/COM_SplitOperation.cc
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cc
index 7cfa4de7a61..28811d479a5 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cc
@@ -33,7 +33,7 @@ void SunBeamsOperation::initExecution()
/* convert to pixels */
this->m_source_px[0] = this->m_data.source[0] * this->getWidth();
this->m_source_px[1] = this->m_data.source[1] * this->getHeight();
- this->m_ray_length_px = this->m_data.ray_length * max(this->getWidth(), this->getHeight());
+ this->m_ray_length_px = this->m_data.ray_length * MAX2(this->getWidth(), this->getHeight());
}
/**
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cc
index e66cd57cb3f..e66cd57cb3f 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cpp
+++ b/source/blender/compositor/operations/COM_TextureOperation.cc
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cpp b/source/blender/compositor/operations/COM_TonemapOperation.cc
index cb0fc747dcb..4c1d285a69f 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.cpp
+++ b/source/blender/compositor/operations/COM_TonemapOperation.cc
@@ -51,9 +51,9 @@ void TonemapOperation::executePixel(float output[4], int x, int y, void *data)
output[2] /= ((db == 0.0f) ? 1.0f : db);
const float igm = avg->igm;
if (igm != 0.0f) {
- output[0] = powf(max(output[0], 0.0f), igm);
- output[1] = powf(max(output[1], 0.0f), igm);
- output[2] = powf(max(output[2], 0.0f), igm);
+ output[0] = powf(MAX2(output[0], 0.0f), igm);
+ output[1] = powf(MAX2(output[1], 0.0f), igm);
+ output[2] = powf(MAX2(output[2], 0.0f), igm);
}
}
void PhotoreceptorTonemapOperation::executePixel(float output[4], int x, int y, void *data)
diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp b/source/blender/compositor/operations/COM_TrackPositionOperation.cc
index ddabfb7cf6c..ddabfb7cf6c 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cc
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cpp b/source/blender/compositor/operations/COM_TranslateOperation.cc
index 286004cd49b..286004cd49b 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.cpp
+++ b/source/blender/compositor/operations/COM_TranslateOperation.cc
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
index 414b5bd980a..909a2f73d25 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
@@ -74,7 +74,7 @@ void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect)
this->determineDependingAreaOfInterest(
rect, (ReadBufferOperation *)this->m_inputSizeProgram, &rect2);
- const float max_dim = max(m_width, m_height);
+ const float max_dim = MAX2(m_width, m_height);
const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
data->maxBlurScalar = (int)(data->size->getMaximumValue(&rect2) * scalar);
@@ -102,7 +102,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y,
float multiplier_accum[4];
float color_accum[4];
- const float max_dim = max(m_width, m_height);
+ const float max_dim = MAX2(m_width, m_height);
const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
int maxBlurScalar = tileData->maxBlurScalar;
@@ -120,10 +120,10 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y,
int maxx = search[2];
int maxy = search[3];
#else
- int minx = max(x - maxBlurScalar, 0);
- int miny = max(y - maxBlurScalar, 0);
- int maxx = min(x + maxBlurScalar, (int)m_width);
- int maxy = min(y + maxBlurScalar, (int)m_height);
+ int minx = MAX2(x - maxBlurScalar, 0);
+ int miny = MAX2(y - maxBlurScalar, 0);
+ int maxx = MIN2(x + maxBlurScalar, (int)m_width);
+ int maxy = MIN2(y + maxBlurScalar, (int)m_height);
#endif
{
inputSizeBuffer->readNoCheck(tempSize, x, y);
@@ -145,7 +145,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y,
int offsetColorNxNy = offsetValueNxNy * COM_NUM_CHANNELS_COLOR;
for (int nx = minx; nx < maxx; nx += addXStepValue) {
if (nx != x || ny != y) {
- float size = min(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center);
+ float size = MIN2(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center);
if (size > this->m_threshold) {
float dx = nx - x;
if (size > fabsf(dx) && size > fabsf(dy)) {
@@ -185,8 +185,8 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> * /*clKernelsToCleanUp*/)
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel defocusKernel = device->COM_clCreateKernel("defocusKernel", nullptr);
@@ -197,7 +197,7 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *sizeMemoryBuffer = this->m_inputSizeProgram->getInputMemoryBuffer(
inputMemoryBuffers);
- const float max_dim = max(m_width, m_height);
+ const float max_dim = MAX2(m_width, m_height);
cl_float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
maxBlur = (cl_int)min_ff(sizeMemoryBuffer->getMaximumValue() * scalar, (float)this->m_maxBlur);
@@ -235,7 +235,7 @@ bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest(
rcti newInput;
rcti bokehInput;
- const float max_dim = max(m_width, m_height);
+ const float max_dim = MAX2(m_width, m_height);
const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
int maxBlurScalar = this->m_maxBlur * scalar;
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h
index 258b5d385c0..fe927f791fa 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h
@@ -80,8 +80,8 @@ class VariableSizeBokehBlurOperation : public NodeOperation, public QualityStepH
MemoryBuffer *outputMemoryBuffer,
cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers,
- list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ std::list<cl_mem> *clMemToCleanUp,
+ std::list<cl_kernel> *clKernelsToCleanUp);
};
#ifdef COM_DEFOCUS_SEARCH
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
index d6894dfc8ad..d6894dfc8ad 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp b/source/blender/compositor/operations/COM_VectorCurveOperation.cc
index a883237f870..a883237f870 100644
--- a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp
+++ b/source/blender/compositor/operations/COM_VectorCurveOperation.cc
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cc
index 025dde8e866..025dde8e866 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cpp
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cc
diff --git a/source/blender/compositor/operations/COM_WrapOperation.cpp b/source/blender/compositor/operations/COM_WrapOperation.cc
index 37b7d68d495..37b7d68d495 100644
--- a/source/blender/compositor/operations/COM_WrapOperation.cpp
+++ b/source/blender/compositor/operations/COM_WrapOperation.cc
diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cc
index 9fb995bf463..8d38dbfe180 100644
--- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
+++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cc
@@ -143,9 +143,9 @@ void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device,
}
// STEP 2
- list<cl_mem> *clMemToCleanUp = new list<cl_mem>();
+ std::list<cl_mem> *clMemToCleanUp = new std::list<cl_mem>();
clMemToCleanUp->push_back(clOutputBuffer);
- list<cl_kernel> *clKernelsToCleanUp = new list<cl_kernel>();
+ std::list<cl_kernel> *clKernelsToCleanUp = new std::list<cl_kernel>();
this->m_input->executeOpenCL(device,
outputBuffer,
diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cpp b/source/blender/compositor/operations/COM_ZCombineOperation.cc
index 22a37a4583e..26d3f2c7dc4 100644
--- a/source/blender/compositor/operations/COM_ZCombineOperation.cpp
+++ b/source/blender/compositor/operations/COM_ZCombineOperation.cc
@@ -83,7 +83,7 @@ void ZCombineAlphaOperation::executePixelSampled(float output[4],
output[0] = fac * color1[0] + ifac * color2[0];
output[1] = fac * color1[1] + ifac * color2[1];
output[2] = fac * color1[2] + ifac * color2[2];
- output[3] = max(color1[3], color2[3]);
+ output[3] = MAX2(color1[3], color2[3]);
}
void ZCombineOperation::deinitExecution()
@@ -149,7 +149,7 @@ void ZCombineMaskAlphaOperation::executePixelSampled(float output[4],
output[0] = color1[0] * mfac + color2[0] * fac;
output[1] = color1[1] * mfac + color2[1] * fac;
output[2] = color1[2] * mfac + color2[2] * fac;
- output[3] = max(color1[3], color2[3]);
+ output[3] = MAX2(color1[3], color2[3]);
}
void ZCombineMaskOperation::deinitExecution()
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 18d3e453c5d..25aedd2cdde 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -44,7 +44,7 @@ static struct {
#define SETUP_BUFFER(tex, fb, fb_color) \
{ \
eGPUTextureFormat format = (DRW_state_is_scene_render()) ? GPU_RGBA32F : GPU_RGBA16F; \
- DRW_texture_ensure_fullscreen_2d(&tex, format, DRW_TEX_FILTER | DRW_TEX_MIPMAP); \
+ DRW_texture_ensure_fullscreen_2d(&tex, format, DRW_TEX_FILTER); \
GPU_framebuffer_ensure_config(&fb, \
{ \
GPU_ATTACHMENT_TEXTURE(dtxl->depth), \
@@ -117,20 +117,27 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
/**
* MinMax Pyramid
*/
- const bool half_res_hiz = true;
- int size[2], div;
- common_data->hiz_mip_offset = (half_res_hiz) ? 1 : 0;
- div = (half_res_hiz) ? 2 : 1;
- size[0] = max_ii(size_fs[0] / div, 1);
- size[1] = max_ii(size_fs[1] / div, 1);
+ int div = 1 << MAX_SCREEN_BUFFERS_LOD_LEVEL;
+ effects->hiz_size[0] = divide_ceil_u(size_fs[0], div) * div;
+ effects->hiz_size[1] = divide_ceil_u(size_fs[1], div) * div;
if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
- /* Intel gpu seems to have problem rendering to only depth format */
- DRW_texture_ensure_2d(&txl->maxzbuffer, size[0], size[1], GPU_R32F, DRW_TEX_MIPMAP);
+ /* Intel gpu seems to have problem rendering to only depth hiz_format */
+ DRW_texture_ensure_2d(&txl->maxzbuffer, UNPACK2(effects->hiz_size), GPU_R32F, DRW_TEX_MIPMAP);
+ GPU_framebuffer_ensure_config(&fbl->maxzbuffer_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->maxzbuffer),
+ });
}
else {
DRW_texture_ensure_2d(
- &txl->maxzbuffer, size[0], size[1], GPU_DEPTH_COMPONENT24, DRW_TEX_MIPMAP);
+ &txl->maxzbuffer, UNPACK2(effects->hiz_size), GPU_DEPTH_COMPONENT24, DRW_TEX_MIPMAP);
+ GPU_framebuffer_ensure_config(&fbl->maxzbuffer_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(txl->maxzbuffer),
+ GPU_ATTACHMENT_NONE,
+ });
}
if (fbl->downsample_fb == NULL) {
@@ -138,13 +145,35 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
}
/**
- * Compute Mipmap texel alignment.
+ * Compute hiZ texel alignment.
+ */
+ common_data->hiz_uv_scale[0] = viewport_size[0] / effects->hiz_size[0];
+ common_data->hiz_uv_scale[1] = viewport_size[1] / effects->hiz_size[1];
+ common_data->hiz_uv_scale[2] = 1.0f / effects->hiz_size[0];
+ common_data->hiz_uv_scale[3] = 1.0f / effects->hiz_size[1];
+
+ /* Compute pixel size. Size is multiplied by 2 because it is applied in NDC [-1..1] range. */
+ sldata->common_data.ssr_pixelsize[0] = 2.0f / size_fs[0];
+ sldata->common_data.ssr_pixelsize[1] = 2.0f / size_fs[1];
+
+ /**
+ * Color buffer with correct downsampling alignment.
+ * Used for SSReflections & SSRefractions.
*/
- for (int i = 0; i < 10; i++) {
- int mip_size[3];
- GPU_texture_get_mipmap_size(txl->color, i, mip_size);
- common_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, i));
- common_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, i));
+ if ((effects->enabled_effects & EFFECT_RADIANCE_BUFFER) != 0) {
+ DRW_texture_ensure_2d(&txl->filtered_radiance,
+ UNPACK2(effects->hiz_size),
+ GPU_R11F_G11F_B10F,
+ DRW_TEX_FILTER | DRW_TEX_MIPMAP);
+
+ GPU_framebuffer_ensure_config(&fbl->radiance_filtered_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->filtered_radiance),
+ });
+ }
+ else {
+ txl->filtered_radiance = NULL;
}
/**
@@ -210,7 +239,7 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_TextureList *txl = vedata->txl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
- DRWState downsample_write = DRW_STATE_WRITE_DEPTH;
+ DRWState downsample_write = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS;
DRWShadingGroup *grp;
/* Intel gpu seems to have problem rendering to only depth format.
@@ -221,12 +250,17 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
- {
+ if (effects->enabled_effects & EFFECT_RADIANCE_BUFFER) {
+ DRW_PASS_CREATE(psl->color_copy_ps, DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_create(EEVEE_shaders_effect_color_copy_sh_get(), psl->color_copy_ps);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "source", &e_data.color_src, GPU_SAMPLER_DEFAULT);
+ DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
DRW_PASS_CREATE(psl->color_downsample_ps, DRW_STATE_WRITE_COLOR);
grp = DRW_shgroup_create(EEVEE_shaders_effect_downsample_sh_get(), psl->color_downsample_ps);
- DRW_shgroup_uniform_texture_ref(grp, "source", &e_data.color_src);
- DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1);
- DRW_shgroup_call(grp, quad, NULL);
+ DRW_shgroup_uniform_texture_ex(grp, "source", txl->filtered_radiance, GPU_SAMPLER_FILTER);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
@@ -241,34 +275,21 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
/* Perform min/max down-sample. */
- DRW_PASS_CREATE(psl->maxz_downlevel_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS);
+ DRW_PASS_CREATE(psl->maxz_downlevel_ps, downsample_write);
grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downlevel_sh_get(), psl->maxz_downlevel_ps);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &txl->maxzbuffer);
- DRW_shgroup_call(grp, quad, NULL);
-
- /* Copy depth buffer to halfres top level of HiZ */
-
- DRW_PASS_CREATE(psl->maxz_downdepth_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS);
- grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downdepth_sh_get(), psl->maxz_downdepth_ps);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
- DRW_shgroup_call(grp, quad, NULL);
-
- DRW_PASS_CREATE(psl->maxz_downdepth_layer_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS);
- grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downdepth_layer_sh_get(),
- psl->maxz_downdepth_layer_ps);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
- DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &txl->maxzbuffer, GPU_SAMPLER_DEFAULT);
DRW_shgroup_call(grp, quad, NULL);
- DRW_PASS_CREATE(psl->maxz_copydepth_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS);
+ /* Copy depth buffer to top level of HiZ */
+ DRW_PASS_CREATE(psl->maxz_copydepth_ps, downsample_write);
grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_copydepth_sh_get(), psl->maxz_copydepth_ps);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &e_data.depth_src, GPU_SAMPLER_DEFAULT);
DRW_shgroup_call(grp, quad, NULL);
- DRW_PASS_CREATE(psl->maxz_copydepth_layer_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS);
+ DRW_PASS_CREATE(psl->maxz_copydepth_layer_ps, downsample_write);
grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_copydepth_layer_sh_get(),
psl->maxz_copydepth_layer_ps);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &e_data.depth_src, GPU_SAMPLER_DEFAULT);
DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
DRW_shgroup_call(grp, quad, NULL);
}
@@ -331,12 +352,6 @@ static void max_downsample_cb(void *vedata, int UNUSED(level))
DRW_draw_pass(psl->maxz_downlevel_ps);
}
-static void simple_downsample_cb(void *vedata, int UNUSED(level))
-{
- EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
- DRW_draw_pass(psl->color_downsample_ps);
-}
-
static void simple_downsample_cube_cb(void *vedata, int level)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
@@ -348,58 +363,22 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_FramebufferList *fbl = vedata->fbl;
- EEVEE_TextureList *txl = vedata->txl;
e_data.depth_src = depth_src;
e_data.depth_src_layer = layer;
-#if 0 /* Not required for now */
- DRW_stats_group_start("Min buffer");
- /* Copy depth buffer to min texture top level */
- GPU_framebuffer_texture_attach(fbl->downsample_fb, stl->g_data->minzbuffer, 0, 0);
- GPU_framebuffer_bind(fbl->downsample_fb);
- if (layer >= 0) {
- DRW_draw_pass(psl->minz_downdepth_layer_ps);
- }
- else {
- DRW_draw_pass(psl->minz_downdepth_ps);
- }
- GPU_framebuffer_texture_detach(stl->g_data->minzbuffer);
-
- /* Create lower levels */
- GPU_framebuffer_recursive_downsample(
- fbl->downsample_fb, stl->g_data->minzbuffer, 8, &min_downsample_cb, vedata);
- DRW_stats_group_end();
-#endif
- int minmax_size[3], depth_size[3];
- GPU_texture_get_mipmap_size(depth_src, 0, depth_size);
- GPU_texture_get_mipmap_size(txl->maxzbuffer, 0, minmax_size);
- bool is_full_res_minmaxz = equals_v2v2_int(minmax_size, depth_size);
-
DRW_stats_group_start("Max buffer");
/* Copy depth buffer to max texture top level */
- GPU_framebuffer_texture_attach(fbl->downsample_fb, txl->maxzbuffer, 0, 0);
- GPU_framebuffer_bind(fbl->downsample_fb);
+ GPU_framebuffer_bind(fbl->maxzbuffer_fb);
if (layer >= 0) {
- if (is_full_res_minmaxz) {
- DRW_draw_pass(psl->maxz_copydepth_layer_ps);
- }
- else {
- DRW_draw_pass(psl->maxz_downdepth_layer_ps);
- }
+ DRW_draw_pass(psl->maxz_copydepth_layer_ps);
}
else {
- if (is_full_res_minmaxz) {
- DRW_draw_pass(psl->maxz_copydepth_ps);
- }
- else {
- DRW_draw_pass(psl->maxz_downdepth_ps);
- }
+ DRW_draw_pass(psl->maxz_copydepth_ps);
}
-
/* Create lower levels */
- GPU_framebuffer_recursive_downsample(fbl->downsample_fb, 8, &max_downsample_cb, vedata);
- GPU_framebuffer_texture_detach(fbl->downsample_fb, txl->maxzbuffer);
+ GPU_framebuffer_recursive_downsample(
+ fbl->maxzbuffer_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &max_downsample_cb, vedata);
DRW_stats_group_end();
/* Restore */
@@ -412,19 +391,28 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l
}
}
+static void downsample_radiance_cb(void *vedata, int UNUSED(level))
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ DRW_draw_pass(psl->color_downsample_ps);
+}
+
/**
* Simple down-sampling algorithm. Reconstruct mip chain up to mip level.
*/
-void EEVEE_downsample_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level)
+void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, GPUTexture *texture_src)
{
+ EEVEE_PassList *psl = vedata->psl;
EEVEE_FramebufferList *fbl = vedata->fbl;
+
e_data.color_src = texture_src;
+ DRW_stats_group_start("Downsample Radiance");
- /* Create lower levels */
- DRW_stats_group_start("Downsample buffer");
- GPU_framebuffer_texture_attach(fbl->downsample_fb, texture_src, 0, 0);
- GPU_framebuffer_recursive_downsample(fbl->downsample_fb, level, &simple_downsample_cb, vedata);
- GPU_framebuffer_texture_detach(fbl->downsample_fb, texture_src);
+ GPU_framebuffer_bind(fbl->radiance_filtered_fb);
+ DRW_draw_pass(psl->color_copy_ps);
+
+ GPU_framebuffer_recursive_downsample(
+ fbl->radiance_filtered_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &downsample_radiance_cb, vedata);
DRW_stats_group_end();
}
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 7688039d0a8..0ce94b8f1b1 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -112,19 +112,20 @@ static struct GPUTexture *create_hammersley_sample_texture(int samples)
static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
{
EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *fx = stl->effects;
/* XXX TODO OPTIMIZATION: This is a complete waist of texture memory.
* Instead of allocating each planar probe for each viewport,
* only alloc them once using the biggest viewport resolution. */
- const float *viewport_size = DRW_viewport_size_get();
/* TODO get screen percentage from layer setting */
// const DRWContextState *draw_ctx = DRW_context_state_get();
// ViewLayer *view_layer = draw_ctx->view_layer;
- float screen_percentage = 1.0f;
+ int screen_divider = 1;
- int width = max_ii(1, (int)(viewport_size[0] * screen_percentage));
- int height = max_ii(1, (int)(viewport_size[1] * screen_percentage));
+ int width = max_ii(1, fx->hiz_size[0] / screen_divider);
+ int height = max_ii(1, fx->hiz_size[1] / screen_divider);
/* Fix case were the pool was allocated width the dummy size (1,1,1). */
if (txl->planar_pool && (num_planar_ref > 0) &&
@@ -139,12 +140,12 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
if (num_planar_ref > 0) {
txl->planar_pool = DRW_texture_create_2d_array(width,
height,
- max_ii(1, num_planar_ref),
+ num_planar_ref,
GPU_R11F_G11F_B10F,
DRW_TEX_FILTER | DRW_TEX_MIPMAP,
NULL);
txl->planar_depth = DRW_texture_create_2d_array(
- width, height, max_ii(1, num_planar_ref), GPU_DEPTH_COMPONENT24, 0, NULL);
+ width, height, num_planar_ref, GPU_DEPTH_COMPONENT24, 0, NULL);
}
else if (num_planar_ref == 0) {
/* Makes Opengl Happy : Create a placeholder texture that will never be sampled but still
@@ -674,10 +675,12 @@ static void lightbake_planar_ensure_view(EEVEE_PlanarReflection *eplanar,
const DRWView *main_view,
DRWView **r_planar_view)
{
- float winmat[4][4], viewmat[4][4];
+ float winmat[4][4], viewmat[4][4], persmat[4][4];
DRW_view_viewmat_get(main_view, viewmat, false);
/* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */
DRW_view_winmat_get(main_view, winmat, false);
+ DRW_view_persmat_get(main_view, persmat, false);
+
/* Invert X to avoid flipping the triangle facing direction. */
winmat[0][0] = -winmat[0][0];
winmat[1][0] = -winmat[1][0];
@@ -729,7 +732,6 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
/* For shading, save max level of the octahedron map */
sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len;
- sldata->common_data.prb_lod_planar_max = (float)MAX_PLANAR_LOD_LEVEL;
sldata->common_data.prb_irradiance_vis_size = light_cache->vis_res;
sldata->common_data.prb_irradiance_smooth = square_f(scene_eval->eevee.gi_irradiance_smoothing);
sldata->common_data.prb_num_render_cube = max_ii(1, light_cache->cube_len);
@@ -1220,7 +1222,7 @@ static void EEVEE_lightbake_filter_planar(EEVEE_Data *vedata)
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->planar_pool)});
GPU_framebuffer_recursive_downsample(
- fbl->planar_downsample_fb, MAX_PLANAR_LOD_LEVEL, &downsample_planar, vedata);
+ fbl->planar_downsample_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &downsample_planar, vedata);
DRW_stats_group_end();
}
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 9d74d916265..bc7db4b5df6 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -128,7 +128,7 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
DRW_shgroup_uniform_float_copy(
shgrp, "refractionDepth", (refract_depth) ? *refract_depth : 0.0);
if (use_ssrefraction) {
- DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->refract_color);
+ DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->filtered_radiance);
}
}
if (use_alpha_blend) {
diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c
index a3b581357e0..a7874440895 100644
--- a/source/blender/draw/engines/eevee/eevee_occlusion.c
+++ b/source/blender/draw/engines/eevee/eevee_occlusion.c
@@ -62,7 +62,7 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
common_data->ao_dist = scene_eval->eevee.gtao_distance;
common_data->ao_factor = scene_eval->eevee.gtao_factor;
- common_data->ao_quality = 1.0f - scene_eval->eevee.gtao_quality;
+ common_data->ao_quality = scene_eval->eevee.gtao_quality;
if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) {
common_data->ao_settings = 1.0f; /* USE_AO */
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 4e32854dedc..45afee31591 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -161,7 +161,7 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d)
((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0))))
#define MIN_CUBE_LOD_LEVEL 3
-#define MAX_PLANAR_LOD_LEVEL 9
+#define MAX_SCREEN_BUFFERS_LOD_LEVEL 6
/* All the renderpasses that use the GPUMaterial for accumulation */
#define EEVEE_RENDERPASSES_MATERIAL \
@@ -308,6 +308,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *sss_blur_ps;
struct DRWPass *sss_resolve_ps;
struct DRWPass *sss_translucency_ps;
+ struct DRWPass *color_copy_ps;
struct DRWPass *color_downsample_ps;
struct DRWPass *color_downsample_cube_ps;
struct DRWPass *velocity_object;
@@ -320,13 +321,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *alpha_checker;
/* HiZ */
- struct DRWPass *minz_downlevel_ps;
struct DRWPass *maxz_downlevel_ps;
- struct DRWPass *minz_downdepth_ps;
- struct DRWPass *maxz_downdepth_ps;
- struct DRWPass *minz_downdepth_layer_ps;
- struct DRWPass *maxz_downdepth_layer_ps;
- struct DRWPass *minz_copydepth_ps;
struct DRWPass *maxz_copydepth_ps;
struct DRWPass *maxz_copydepth_layer_ps;
@@ -362,6 +357,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *gtao_fb;
struct GPUFrameBuffer *gtao_debug_fb;
struct GPUFrameBuffer *downsample_fb;
+ struct GPUFrameBuffer *maxzbuffer_fb;
struct GPUFrameBuffer *bloom_blit_fb;
struct GPUFrameBuffer *bloom_down_fb[MAX_BLOOM_STEP];
struct GPUFrameBuffer *bloom_accum_fb[MAX_BLOOM_STEP - 1];
@@ -394,7 +390,6 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *volumetric_integ_fb;
struct GPUFrameBuffer *volumetric_accum_fb;
struct GPUFrameBuffer *screen_tracing_fb;
- struct GPUFrameBuffer *refract_fb;
struct GPUFrameBuffer *mist_accum_fb;
struct GPUFrameBuffer *material_accum_fb;
struct GPUFrameBuffer *renderpass_fb;
@@ -412,6 +407,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *main_color_fb;
struct GPUFrameBuffer *effect_fb;
struct GPUFrameBuffer *effect_color_fb;
+ struct GPUFrameBuffer *radiance_filtered_fb;
struct GPUFrameBuffer *double_buffer_fb;
struct GPUFrameBuffer *double_buffer_color_fb;
struct GPUFrameBuffer *double_buffer_depth_fb;
@@ -436,7 +432,6 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *ssr_accum;
struct GPUTexture *shadow_accum;
struct GPUTexture *cryptomatte;
- struct GPUTexture *refract_color;
struct GPUTexture *taa_history;
/* Could not be pool texture because of mipmapping. */
struct GPUTexture *dof_reduced_color;
@@ -460,6 +455,7 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *planar_depth;
struct GPUTexture *maxzbuffer;
+ struct GPUTexture *filtered_radiance;
struct GPUTexture *renderpass;
@@ -618,7 +614,7 @@ typedef struct EEVEE_LightProbesInfo {
float roughness;
float firefly_fac;
float lodfactor;
- float lod_rt_max, lod_cube_max, lod_planar_max;
+ float lod_rt_max, lod_cube_max;
float visibility_range;
float visibility_blur;
float intensity_fac;
@@ -708,8 +704,9 @@ typedef enum EEVEE_EffectsFlag {
EFFECT_REFRACT = (1 << 6),
EFFECT_GTAO = (1 << 7),
EFFECT_TAA = (1 << 8),
- EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */
- EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */
+ EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */
+ EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */
+ EFFECT_RADIANCE_BUFFER = (1 << 10), /* Not really an effect but a feature */
EFFECT_SSS = (1 << 11),
EFFECT_VELOCITY_BUFFER = (1 << 12), /* Not really an effect but a feature */
EFFECT_TAA_REPROJECT = (1 << 13), /* should be mutually exclusive with EFFECT_TAA */
@@ -817,11 +814,10 @@ typedef struct EEVEE_EffectsInfo {
struct GPUTexture *dof_scatter_src_tx;
struct GPUTexture *dof_reduce_input_coc_tx; /* Just references to actual textures. */
struct GPUTexture *dof_reduce_input_color_tx;
- /* Alpha Checker */
- float color_checker_dark[4];
- float color_checker_light[4];
/* Other */
float prev_persmat[4][4];
+ /* Size used by all fullscreen buffers using mipmaps. */
+ int hiz_size[2];
/* Lookdev */
int sphere_size;
eDRWLevelOfDetail sphere_lod;
@@ -859,7 +855,7 @@ typedef struct EEVEE_EffectsInfo {
* - sizeof(bool) == sizeof(int) in GLSL so use int in C */
typedef struct EEVEE_CommonUniformBuffer {
float prev_persmat[4][4]; /* mat4 */
- float mip_ratio[10][4]; /* vec2[10] */
+ float hiz_uv_scale[4]; /* vec4 */
/* Ambient Occlusion */
/* -- 16 byte aligned -- */
float ao_dist, pad1, ao_factor, pad2; /* vec4 */
@@ -899,15 +895,15 @@ typedef struct EEVEE_CommonUniformBuffer {
int prb_irradiance_vis_size; /* int */
float prb_irradiance_smooth; /* float */
float prb_lod_cube_max; /* float */
- float prb_lod_planar_max; /* float */
/* Misc */
- int hiz_mip_offset; /* int */
int ray_type; /* int */
float ray_depth; /* float */
float alpha_hash_offset; /* float */
float alpha_hash_scale; /* float */
float pad7; /* float */
float pad8; /* float */
+ float pad9; /* float */
+ float pad10; /* float */
} EEVEE_CommonUniformBuffer;
BLI_STATIC_ASSERT_ALIGN(EEVEE_CommonUniformBuffer, 16)
@@ -1201,6 +1197,7 @@ struct GPUShader *EEVEE_shaders_depth_of_field_gather_get(EEVEE_DofGatherPass pa
struct GPUShader *EEVEE_shaders_depth_of_field_filter_get(void);
struct GPUShader *EEVEE_shaders_depth_of_field_scatter_get(bool is_foreground, bool bokeh_tx);
struct GPUShader *EEVEE_shaders_depth_of_field_resolve_get(bool use_bokeh_tx, bool use_hq_gather);
+struct GPUShader *EEVEE_shaders_effect_color_copy_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_downsample_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_downsample_cube_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_minz_downlevel_sh_get(void);
@@ -1472,8 +1469,8 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
const bool minimal);
void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_effects_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src);
void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer);
-void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level);
void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level);
void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index f9e22f5c08d..80a1c9fcbe5 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -42,29 +42,15 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_FramebufferList *fbl = vedata->fbl;
- EEVEE_TextureList *txl = vedata->txl;
EEVEE_EffectsInfo *effects = stl->effects;
const float *viewport_size = DRW_viewport_size_get();
const DRWContextState *draw_ctx = DRW_context_state_get();
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
- /* Compute pixel size, (shared with contact shadows) */
- copy_v2_v2(common_data->ssr_pixelsize, viewport_size);
- invert_v2(common_data->ssr_pixelsize);
-
if (scene_eval->eevee.flag & SCE_EEVEE_SSR_ENABLED) {
const bool use_refraction = (scene_eval->eevee.flag & SCE_EEVEE_SSR_REFRACTION) != 0;
- if (use_refraction) {
- /* TODO: Opti: Could be shared. */
- DRW_texture_ensure_fullscreen_2d(
- &txl->refract_color, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
-
- GPU_framebuffer_ensure_config(
- &fbl->refract_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->refract_color)});
- }
-
const bool is_persp = DRW_view_is_persp_get(NULL);
if (effects->ssr_was_persp != is_persp) {
effects->ssr_was_persp = is_persp;
@@ -117,8 +103,7 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output),
GPU_ATTACHMENT_TEXTURE(effects->ssr_pdf_output)});
- /* Enable double buffering to be able to read previous frame color */
- return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_DOUBLE_BUFFER |
+ return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_RADIANCE_BUFFER | EFFECT_DOUBLE_BUFFER |
((use_refraction) ? EFFECT_REFRACT : 0);
}
@@ -189,7 +174,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth);
DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output);
DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output);
- DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->color_double_buffer);
+ DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->filtered_radiance);
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
@@ -216,8 +201,7 @@ void EEVEE_refraction_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
EEVEE_EffectsInfo *effects = stl->effects;
if ((effects->enabled_effects & EFFECT_REFRACT) != 0) {
- GPU_framebuffer_blit(fbl->main_fb, 0, fbl->refract_fb, 0, GPU_COLOR_BIT);
- EEVEE_downsample_buffer(vedata, txl->refract_color, 9);
+ EEVEE_effects_downsample_radiance_buffer(vedata, txl->color);
/* Restore */
GPU_framebuffer_bind(fbl->main_fb);
@@ -242,7 +226,7 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
GPU_framebuffer_bind(fbl->screen_tracing_fb);
DRW_draw_pass(psl->ssr_raytrace);
- EEVEE_downsample_buffer(vedata, txl->color_double_buffer, 9);
+ EEVEE_effects_downsample_radiance_buffer(vedata, txl->color_double_buffer);
/* Resolve at fullres */
int samp = (DRW_state_is_image_render()) ? effects->taa_render_sample :
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index a3e9236dc79..74c4803928a 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -103,7 +103,8 @@ static struct {
struct GPUShader *minz_copydepth_sh;
struct GPUShader *maxz_copydepth_sh;
- /* Simple Down-sample */
+ /* Simple Down-sample. */
+ struct GPUShader *color_copy_sh;
struct GPUShader *downsample_sh;
struct GPUShader *downsample_cube_sh;
@@ -452,10 +453,20 @@ GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void)
/** \name Down-sampling
* \{ */
+GPUShader *EEVEE_shaders_effect_color_copy_sh_get(void)
+{
+ if (e_data.color_copy_sh == NULL) {
+ e_data.color_copy_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_downsample_frag_glsl, e_data.lib, "#define COPY_SRC\n");
+ }
+ return e_data.color_copy_sh;
+}
+
GPUShader *EEVEE_shaders_effect_downsample_sh_get(void)
{
if (e_data.downsample_sh == NULL) {
- e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL);
+ e_data.downsample_sh = DRW_shader_create_fullscreen_with_shaderlib(
+ datatoc_effect_downsample_frag_glsl, e_data.lib, NULL);
}
return e_data.downsample_sh;
}
@@ -1537,6 +1548,7 @@ void EEVEE_shaders_free(void)
MEM_SAFE_FREE(e_data.surface_geom_barycentric);
DRW_SHADER_FREE_SAFE(e_data.lookdev_background);
DRW_SHADER_FREE_SAFE(e_data.update_noise_sh);
+ DRW_SHADER_FREE_SAFE(e_data.color_copy_sh);
DRW_SHADER_FREE_SAFE(e_data.downsample_sh);
DRW_SHADER_FREE_SAFE(e_data.downsample_cube_sh);
DRW_SHADER_FREE_SAFE(e_data.minz_downlevel_sh);
diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c
index f6fe9a76c70..1f27d2dce34 100644
--- a/source/blender/draw/engines/eevee/eevee_shadows.c
+++ b/source/blender/draw/engines/eevee/eevee_shadows.c
@@ -53,7 +53,7 @@ void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata)
sldata->shadow_ubo = GPU_uniformbuf_create_ex(shadow_ubo_size, NULL, "evShadow");
for (int i = 0; i < 2; i++) {
- sldata->shcasters_buffers[i].bbox = MEM_callocN(
+ sldata->shcasters_buffers[i].bbox = MEM_mallocN(
sizeof(EEVEE_BoundBox) * SH_CASTER_ALLOC_CHUNK, __func__);
sldata->shcasters_buffers[i].update = BLI_BITMAP_NEW(SH_CASTER_ALLOC_CHUNK, __func__);
sldata->shcasters_buffers[i].alloc_count = SH_CASTER_ALLOC_CHUNK;
@@ -133,8 +133,9 @@ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
int id = frontbuffer->count;
/* Make sure shadow_casters is big enough. */
- if (id + 1 >= frontbuffer->alloc_count) {
- frontbuffer->alloc_count += SH_CASTER_ALLOC_CHUNK;
+ if (id >= frontbuffer->alloc_count) {
+ /* Double capacity to prevent exponential slowdown. */
+ frontbuffer->alloc_count *= 2;
frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox,
sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count);
BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count);
@@ -173,6 +174,7 @@ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
}
EEVEE_BoundBox *aabb = &frontbuffer->bbox[id];
+ /* Note that *aabb has not been initialised yet. */
add_v3_v3v3(aabb->center, min, max);
mul_v3_fl(aabb->center, 0.5f);
sub_v3_v3v3(aabb->halfdim, aabb->center, max);
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
index 473990e1683..a0bfd440dd9 100644
--- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -31,7 +31,6 @@ uniform sampler2D horizonBuffer;
#define USE_BENT_NORMAL 2
#define USE_DENOISE 4
-#define MAX_LOD 6.0
#define NO_OCCLUSION_DATA OcclusionData(vec4(M_PI, -M_PI, M_PI, -M_PI), 1.0)
struct OcclusionData {
@@ -61,7 +60,11 @@ vec2 get_ao_area(float view_depth, float radius)
vec2 get_ao_noise(void)
{
- return texelfetch_noise_tex(gl_FragCoord.xy).xy;
+ vec2 noise = texelfetch_noise_tex(gl_FragCoord.xy).xy;
+ /* Decorrelate noise from AA. */
+ /* TODO(fclem) we should use a more general approach for more random number dimentions. */
+ noise = fract(noise * 6.1803402007);
+ return noise;
}
vec2 get_ao_dir(float jitter)
@@ -77,25 +80,37 @@ vec2 get_ao_dir(float jitter)
float search_horizon(vec3 vI,
vec3 vP,
float noise,
- vec2 uv_start,
- vec2 uv_dir,
+ ScreenSpaceRay ssray,
sampler2D depth_tx,
const float inverted,
float radius,
const float sample_count)
{
- float sample_count_inv = 1.0 / sample_count;
/* Init at cos(M_PI). */
float h = (inverted != 0.0) ? 1.0 : -1.0;
- /* TODO(fclem) samples steps should be using the same approach as raytrace. (DDA line algo.) */
- for (float i = 0.0; i < sample_count; i++) {
- float t = ((i + noise) * sample_count_inv);
- vec2 uv = uv_start + uv_dir * t;
- float lod = min(MAX_LOD, max(i - noise, 0.0) * aoQuality);
+ ssray.max_time -= 1.0;
- int mip = int(lod) + hizMipOffset;
- float depth = textureLod(depth_tx, uv * mipRatio[mip].xy, floor(lod)).r;
+ if (ssray.max_time <= 2.0) {
+ /* Produces self shadowing under this threshold. */
+ return fast_acos(h);
+ }
+
+ float prev_time, time = 0.0;
+ for (float iter = 0.0; time < ssray.max_time && iter < sample_count; iter++) {
+ prev_time = time;
+ /* Gives us good precision at center and ensure we cross at least one pixel per iteration. */
+ time = 1.0 + iter + sqr((iter + noise) / sample_count) * ssray.max_time;
+ float stride = time - prev_time;
+ float lod = (log2(stride) - noise) / (1.0 + aoQuality);
+
+ vec2 uv = ssray.origin.xy + ssray.direction.xy * time;
+ float depth = textureLod(depth_tx, uv * hizUvScale.xy, floor(lod)).r;
+
+ if (depth == 1.0 && inverted == 0.0) {
+ /* Skip background. This avoids issues with the thickness heuristic. */
+ continue;
+ }
/* Bias depth a bit to avoid self shadowing issues. */
const float bias = 2.0 * 2.4e-7;
@@ -108,25 +123,16 @@ float search_horizon(vec3 vI,
float s_h = dot(vI, omega_s / len);
/* Blend weight to fade artifacts. */
float dist_ratio = abs(len) / radius;
- /* TODO(fclem) parameter. */
- float dist_fac = sqr(saturate(dist_ratio * 2.0 - 1.0));
+ /* Sphere falloff. */
+ float dist_fac = sqr(saturate(dist_ratio));
+ /* Unbiased, gives too much hard cut behind objects */
+ // float dist_fac = step(0.999, dist_ratio);
- /* Thickness heuristic (Eq. 9). */
if (inverted != 0.0) {
h = min(h, s_h);
}
else {
- /* TODO This need to take the stride distance into account. Now it works because stride is
- * constant. */
- if (s_h < h) {
- /* TODO(fclem) parameter. */
- const float thickness_fac = 0.2;
- s_h = mix(h, s_h, thickness_fac);
- }
- else {
- s_h = max(h, s_h);
- }
- h = mix(s_h, h, dist_fac);
+ h = mix(max(h, s_h), h, dist_fac);
}
}
return fast_acos(h);
@@ -151,22 +157,22 @@ OcclusionData occlusion_search(
NO_OCCLUSION_DATA;
for (int i = 0; i < 2; i++) {
- /* View > NDC > Uv space. */
- vec2 uv_dir = dir * area * 0.5;
- /* Offset the start one pixel to avoid self shadowing. */
- /* TODO(fclem) Using DDA line algo should fix this. */
- vec2 px_dir = uv_dir * textureSize(depth_tx, 0);
- float max_px_dir = max_v2(abs(px_dir));
- vec2 uv_ofs = (px_dir / max_px_dir) / textureSize(depth_tx, 0);
- /* No need to trace more. */
- uv_dir -= uv_ofs;
-
- if (max_px_dir > 1.0) {
- data.horizons[0 + i * 2] = search_horizon(
- vI, vP, noise.y, uv + uv_ofs, uv_dir, depth_tx, inverted, radius, dir_sample_count);
- data.horizons[1 + i * 2] = -search_horizon(
- vI, vP, noise.y, uv - uv_ofs, -uv_dir, depth_tx, inverted, radius, dir_sample_count);
- }
+ Ray ray;
+ ray.origin = vP;
+ ray.direction = vec3(dir * radius, 0.0);
+
+ ScreenSpaceRay ssray;
+
+ ssray = raytrace_screenspace_ray_create(ray);
+ data.horizons[0 + i * 2] = search_horizon(
+ vI, vP, noise.y, ssray, depth_tx, inverted, radius, dir_sample_count);
+
+ ray.direction = -ray.direction;
+
+ ssray = raytrace_screenspace_ray_create(ray);
+ data.horizons[1 + i * 2] = -search_horizon(
+ vI, vP, noise.y, ssray, depth_tx, inverted, radius, dir_sample_count);
+
/* Rotate 90 degrees. */
dir = vec2(-dir.y, dir.x);
}
@@ -389,7 +395,7 @@ OcclusionData occlusion_load(vec3 vP, float custom_occlusion)
data = unpack_occlusion_data(texelFetch(horizonBuffer, ivec2(gl_FragCoord.xy), 0));
}
#else
- /* For blended surfaces and */
+ /* For blended surfaces. */
data = occlusion_search(vP, maxzBuffer, aoDistance, 0.0, 8.0);
#endif
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
index 4abc313d7e3..bbc79a2d05b 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
@@ -36,7 +36,7 @@ vec3 sample_ggx(vec3 rand, float a2)
{
/* Theta is the cone angle. */
float z = sqrt((1.0 - rand.x) / (1.0 + a2 * rand.x - rand.x)); /* cos theta */
- float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */
+ float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */
float x = r * rand.y;
float y = r * rand.z;
@@ -51,6 +51,23 @@ vec3 sample_ggx(vec3 rand, float a2, vec3 N, vec3 T, vec3 B, out float NH)
return tangent_to_world(Ht, N, T, B);
}
+vec3 sample_hemisphere(vec3 rand)
+{
+ /* Theta is the cone angle. */
+ float z = rand.x; /* cos theta */
+ float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */
+ float x = r * rand.y;
+ float y = r * rand.z;
+
+ return vec3(x, y, z);
+}
+
+vec3 sample_hemisphere(vec3 rand, vec3 N, vec3 T, vec3 B)
+{
+ vec3 Ht = sample_hemisphere(rand);
+ return tangent_to_world(Ht, N, T, B);
+}
+
#ifdef HAMMERSLEY_SIZE
vec3 sample_ggx(float nsample, float inv_sample_count, float a2, vec3 N, vec3 T, vec3 B)
{
@@ -62,14 +79,7 @@ vec3 sample_ggx(float nsample, float inv_sample_count, float a2, vec3 N, vec3 T,
vec3 sample_hemisphere(float nsample, float inv_sample_count, vec3 N, vec3 T, vec3 B)
{
vec3 Xi = hammersley_3d(nsample, inv_sample_count);
-
- float z = Xi.x; /* cos theta */
- float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */
- float x = r * Xi.y;
- float y = r * Xi.z;
-
- vec3 Ht = vec3(x, y, z);
-
+ vec3 Ht = sample_hemisphere(Xi);
return tangent_to_world(Ht, N, T, B);
}
@@ -77,8 +87,8 @@ vec3 sample_cone(float nsample, float inv_sample_count, float angle, vec3 N, vec
{
vec3 Xi = hammersley_3d(nsample, inv_sample_count);
- float z = cos(angle * Xi.x); /* cos theta */
- float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */
+ float z = cos(angle * Xi.x); /* cos theta */
+ float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */
float x = r * Xi.y;
float y = r * Xi.z;
diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
index a6c9eebaff2..24de4520207 100644
--- a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
@@ -2,7 +2,7 @@
layout(std140) uniform common_block
{
mat4 pastViewProjectionMatrix;
- vec2 mipRatio[10]; /* To correct mip level texel misalignment */
+ vec4 hizUvScale; /* To correct mip level texel misalignment */
/* Ambient Occlusion */
vec4 aoParameters[2];
/* Volumetric */
@@ -37,15 +37,15 @@ layout(std140) uniform common_block
int prbIrradianceVisSize;
float prbIrradianceSmooth;
float prbLodCubeMax;
- float prbLodPlanarMax;
/* Misc*/
- int hizMipOffset;
int rayType;
float rayDepth;
float alphaHashOffset;
float alphaHashScale;
+ float pad6;
float pad7;
float pad8;
+ float pad9;
};
/* rayType (keep in sync with ray_type) */
@@ -69,9 +69,3 @@ layout(std140) uniform common_block
#define ssrQuality ssrParameters.x
#define ssrThickness ssrParameters.y
#define ssrPixelSize ssrParameters.zw
-
-vec2 mip_ratio_interp(float mip)
-{
- float low_mip = floor(mip);
- return mix(mipRatio[int(low_mip)], mipRatio[int(low_mip + 1.0)], mip - low_mip);
-}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl
index 88d83cd913a..3ad3c90d27a 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl
@@ -62,12 +62,6 @@ const vec2 quad_offsets[4] = vec2[4](
#define dof_coc_from_zdepth(d) calculate_coc(linear_depth(d))
-vec4 safe_color(vec4 c)
-{
- /* Clamp to avoid black square artifacts if a pixel goes NaN. */
- return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */
-}
-
float dof_hdr_color_weight(vec4 color)
{
/* From UE4. Very fast "luma" weighting. */
diff --git a/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl
index a4637b9df91..5bf850fe229 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl
@@ -1,5 +1,9 @@
+
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
/**
- * Simple down-sample shader. Takes the average of the 4 texels of lower mip.
+ * Simple down-sample shader.
+ * Do a gaussian filter using 4 bilinear texture samples.
*/
uniform sampler2D source;
@@ -14,24 +18,25 @@ float brightness(vec3 c)
void main()
{
-#if 0
- /* Reconstructing Target uvs like this avoid missing pixels if NPO2 */
- vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0));
+ vec2 texel_size = 1.0 / vec2(textureSize(source, 0));
+ vec2 uvs = gl_FragCoord.xy * texel_size;
+#ifdef COPY_SRC
FragColor = textureLod(source, uvs, 0.0);
+ FragColor = safe_color(FragColor);
+
+ /* Clamped brightness. */
+ float luma = max(1e-8, brightness(FragColor.rgb));
+ FragColor *= 1.0 - max(0.0, luma - fireflyFactor) / luma;
+
#else
- vec2 texel_size = 1.0 / vec2(textureSize(source, 0));
- vec2 uvs = gl_FragCoord.xy * 2.0 * texel_size;
vec4 ofs = texel_size.xyxy * vec4(0.75, 0.75, -0.75, -0.75);
+ uvs *= 2.0;
FragColor = textureLod(source, uvs + ofs.xy, 0.0);
FragColor += textureLod(source, uvs + ofs.xw, 0.0);
FragColor += textureLod(source, uvs + ofs.zy, 0.0);
FragColor += textureLod(source, uvs + ofs.zw, 0.0);
FragColor *= 0.25;
-
- /* Clamped brightness. */
- float luma = max(1e-8, brightness(FragColor.rgb));
- FragColor *= 1.0 - max(0.0, luma - fireflyFactor) / luma;
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
index 19ae0acc443..16b1a7ffeaa 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
@@ -99,9 +99,12 @@ void main()
OcclusionData data = occlusion_load(vP, 1.0);
- float visibility = diffuse_occlusion(data, V, N, Ng);
-
- FragColor = vec4(visibility);
+ if (min_v4(abs(data.horizons)) != M_PI) {
+ FragColor = vec4(diffuse_occlusion(data, V, N, Ng));
+ }
+ else {
+ FragColor = vec4(1.0);
+ }
}
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
index b99037b1e80..ccb65d2e5a6 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
@@ -2,6 +2,9 @@
* Shader that down-sample depth buffer,
* saving min and max value of each texel in the above mipmaps.
* Adapted from http://rastergrid.com/blog/2010/10/hierarchical-z-map-based-occlusion-culling/
+ *
+ * Major simplification has been made since we pad the buffer to always be bigger than input to
+ * avoid mipmapping misalignement.
*/
#ifdef LAYERED
@@ -12,10 +15,10 @@ uniform sampler2D depthBuffer;
#endif
#ifdef LAYERED
-# define sampleLowerMip(t) texelFetch(depthBuffer, ivec3(t, depthLayer), 0).r
+# define sampleLowerMip(t) texture(depthBuffer, vec3(t, depthLayer)).r
# define gatherLowerMip(t) textureGather(depthBuffer, vec3(t, depthLayer))
#else
-# define sampleLowerMip(t) texelFetch(depthBuffer, t, 0).r
+# define sampleLowerMip(t) texture(depthBuffer, t).r
# define gatherLowerMip(t) textureGather(depthBuffer, t)
#endif
@@ -37,54 +40,27 @@ out vec4 fragColor;
void main()
{
- ivec2 texelPos = ivec2(gl_FragCoord.xy);
- ivec2 mipsize = textureSize(depthBuffer, 0).xy;
-
-#ifndef COPY_DEPTH
- texelPos *= 2;
-#endif
+ vec2 texel = gl_FragCoord.xy;
+ vec2 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy);
#ifdef COPY_DEPTH
- float val = sampleLowerMip(texelPos);
+ vec2 uv = texel * texel_size;
+
+ float val = sampleLowerMip(uv);
#else
+ vec2 uv = texel * 2.0 * texel_size;
+
vec4 samp;
# ifdef GPU_ARB_texture_gather
- /* + 1.0 to gather at the center of target 4 texels. */
- samp = gatherLowerMip((vec2(texelPos) + 1.0) / vec2(mipsize));
+ samp = gatherLowerMip(uv);
# else
- samp.x = sampleLowerMip(texelPos);
- samp.y = sampleLowerMip(texelPos + ivec2(1, 0));
- samp.z = sampleLowerMip(texelPos + ivec2(1, 1));
- samp.w = sampleLowerMip(texelPos + ivec2(0, 1));
+ samp.x = sampleLowerMip(uv + vec2(-0.5, -0.5) * texel_size);
+ samp.y = sampleLowerMip(uv + vec2(-0.5, 0.5) * texel_size);
+ samp.z = sampleLowerMip(uv + vec2(0.5, -0.5) * texel_size);
+ samp.w = sampleLowerMip(uv + vec2(0.5, 0.5) * texel_size);
# endif
float val = minmax4(samp.x, samp.y, samp.z, samp.w);
-
- /* if we are reducing an odd-width texture then fetch the edge texels */
- if (((mipsize.x & 1) != 0) && (texelPos.x == mipsize.x - 3)) {
- /* if both edges are odd, fetch the top-left corner texel */
- if (((mipsize.y & 1) != 0) && (texelPos.y == mipsize.y - 3)) {
- samp.x = sampleLowerMip(texelPos + ivec2(2, 2));
- val = minmax2(val, samp.x);
- }
-# ifdef GPU_ARB_texture_gather
- samp = gatherLowerMip((vec2(texelPos) + vec2(2.0, 1.0)) / vec2(mipsize));
-# else
- samp.y = sampleLowerMip(texelPos + ivec2(2, 0));
- samp.z = sampleLowerMip(texelPos + ivec2(2, 1));
-# endif
- val = minmax3(val, samp.y, samp.z);
- }
- /* if we are reducing an odd-height texture then fetch the edge texels */
- if (((mipsize.y & 1) != 0) && (texelPos.y == mipsize.y - 3)) {
-# ifdef GPU_ARB_texture_gather
- samp = gatherLowerMip((vec2(texelPos) + vec2(1.0, 2.0)) / vec2(mipsize));
-# else
- samp.x = sampleLowerMip(texelPos + ivec2(0, 2));
- samp.y = sampleLowerMip(texelPos + ivec2(1, 2));
-# endif
- val = minmax3(val, samp.x, samp.y);
- }
#endif
#if defined(GPU_INTEL) || defined(GPU_ATI)
diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
index ecff28dcd38..66183e1bc02 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
@@ -63,14 +63,19 @@ void do_planar_ssr(
pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */
- /* Since viewspace hit position can land behind the camera in this case,
- * we save the reflected view position (visualize it as the hit position
- * below the reflection plane). This way it's garanted that the hit will
- * be in front of the camera. That let us tag the bad rays with a negative
- * sign in the Z component. */
- vec3 hit_pos = raycast(index, vP, R * 1e16, 1e16, rand.y, ssrQuality, a2, false);
-
- hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), true);
+ Ray ray;
+ ray.origin = vP;
+ ray.direction = R * 1e16;
+
+ RayTraceParameters params;
+ params.jitter = rand.y;
+ params.trace_quality = ssrQuality;
+ params.roughness = a2;
+
+ vec3 hit_pos;
+ bool hit = raytrace_planar(ray, params, index, hit_pos);
+
+ hitData = encode_hit_data(hit_pos.xy, hit, true);
}
void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand)
@@ -104,22 +109,30 @@ void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand)
pdfData = min(1024e32, pdf_ggx_reflect(NH, a2)); /* Theoretical limit of 16bit float */
- vec3 hit_pos = raycast(-1, vP, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true);
+ vP = raytrace_offset(vP, vNg);
+
+ Ray ray;
+ ray.origin = vP;
+ ray.direction = R * 1e16;
- hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false);
+ RayTraceParameters params;
+ params.thickness = ssrThickness;
+ params.jitter = rand.y;
+ params.trace_quality = ssrQuality;
+ params.roughness = a2;
+
+ vec3 hit_pos;
+ bool hit = raytrace(ray, params, true, hit_pos);
+
+ hitData = encode_hit_data(hit_pos.xy, hit, false);
}
+in vec4 uvcoordsvar;
+
void main()
{
-# ifdef FULLRES
- ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
- ivec2 halfres_texel = fullres_texel;
-# else
- ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2 + halfresOffset;
- ivec2 halfres_texel = ivec2(gl_FragCoord.xy);
-# endif
-
- float depth = texelFetch(depthBuffer, fullres_texel, 0).r;
+ vec2 uvs = uvcoordsvar.xy;
+ float depth = textureLod(depthBuffer, uvs, 0.0).r;
/* Default: not hits. */
hitData = encode_hit_data(vec2(0.5), false, false);
@@ -131,18 +144,16 @@ void main()
return;
}
- vec2 uvs = vec2(fullres_texel) / vec2(textureSize(depthBuffer, 0));
-
/* Using view space */
vec3 vP = get_view_space_from_depth(uvs, depth);
vec3 P = transform_point(ViewMatrixInverse, vP);
vec3 vV = viewCameraVec(vP);
vec3 V = cameraVec(P);
- vec3 vN = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, vV);
+ vec3 vN = normal_decode(texture(normalBuffer, uvs, 0).rg, vV);
vec3 N = transform_direction(ViewMatrixInverse, vN);
/* Retrieve pixel data */
- vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
+ vec4 speccol_roughness = texture(specroughBuffer, uvs, 0).rgba;
/* Early out */
if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
@@ -158,7 +169,7 @@ void main()
return;
}
- vec4 rand = texelfetch_noise_tex(halfres_texel);
+ vec4 rand = texelfetch_noise_tex(vec2(gl_FragCoord.xy));
/* Gives *perfect* reflection for very small roughness */
if (roughness < 0.04) {
@@ -189,11 +200,6 @@ void main()
}
}
- /* Constant bias (due to depth buffer precision). Helps with self intersection. */
- /* Magic numbers for 24bits of precision.
- * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
- vP.z = get_view_z_from_depth(depth - mix(2.4e-7, 4.8e-7, depth));
-
do_ssr(vV, vN, vT, vB, vP, a2, rand);
}
@@ -325,10 +331,10 @@ vec3 get_hit_vector(vec3 hit_pos,
vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar)
{
if (is_planar) {
- return textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, prbLodPlanarMax)).rgb;
+ return textureLod(probePlanars, vec3(ref_uvs, planar_index), mip).rgb;
}
else {
- return textureLod(prevColorBuffer, ref_uvs, mip).rgb;
+ return textureLod(prevColorBuffer, ref_uvs * hizUvScale.xy, mip).rgb;
}
}
@@ -351,6 +357,8 @@ vec4 get_ssr_samples(vec4 hit_pdf,
hit_co[1].xy = decode_hit_data(hit_data[1].xy, has_hit.z, is_planar.z);
hit_co[1].zw = decode_hit_data(hit_data[1].zw, has_hit.w, is_planar.w);
+ /* TODO/FIXME(fclem) This is giving precision issues due to refined intersection. This is most
+ * noticeable on rough surfaces. */
vec4 hit_depth;
hit_depth.x = get_sample_depth(hit_co[0].xy, is_planar.x, planar_index);
hit_depth.y = get_sample_depth(hit_co[0].zw, is_planar.y, planar_index);
@@ -403,12 +411,6 @@ vec4 get_ssr_samples(vec4 hit_pdf,
vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0))));
mip = clamp(mip, 0.0, MAX_MIP);
- /* Correct UVs for mipmaping mis-alignment */
- hit_co[0].xy *= mip_ratio_interp(mip.x);
- hit_co[0].zw *= mip_ratio_interp(mip.y);
- hit_co[1].xy *= mip_ratio_interp(mip.z);
- hit_co[1].zw *= mip_ratio_interp(mip.w);
-
/* Slide 54 */
vec4 bsdf;
bsdf.x = bsdf_ggx(N, hit_pos[0], V, roughnessSquared);
diff --git a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
index 28947e971d2..165aed2a46f 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
@@ -10,12 +10,6 @@ uniform mat4 prevViewProjectionMatrix;
out vec4 FragColor;
-vec4 safe_color(vec4 c)
-{
- /* Clamp to avoid black square artifacts if a pixel goes NaN. */
- return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */
-}
-
#ifdef USE_REPROJECTION
/**
diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
index 04ad53eabb7..bd752d33819 100644
--- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
@@ -276,31 +276,30 @@ float light_contact_shadows(
/* Only compute if not already in shadow. */
if (sd.sh_contact_dist > 0.0) {
/* Contact Shadows. */
- vec3 ray_ori, ray_dir;
- float trace_distance;
+ Ray ray;
if (ld.l_type == SUN) {
- trace_distance = sd.sh_contact_dist;
- ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance;
+ ray.direction = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec *
+ sd.sh_contact_dist;
}
else {
- ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P;
- float len = length(ray_dir);
- trace_distance = min(sd.sh_contact_dist, len);
- ray_dir *= trace_distance / len;
+ ray.direction = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P;
+ ray.direction *= saturate(sd.sh_contact_dist * safe_rcp(length(ray.direction)));
}
- ray_dir = transform_direction(ViewMatrix, ray_dir);
- ray_ori = vec3(vP.xy, tracing_depth) + vNg * sd.sh_contact_offset;
+ ray.direction = transform_direction(ViewMatrix, ray.direction);
+ ray.origin = vP + vNg * sd.sh_contact_offset;
- vec3 hit_pos = raycast(
- -1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false);
+ RayTraceParameters params;
+ params.thickness = sd.sh_contact_thickness;
+ params.jitter = rand_x;
+ params.trace_quality = 0.1;
+ params.roughness = 0.001;
- if (hit_pos.z > 0.0) {
- hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
- float hit_dist = distance(vP, hit_pos);
- float dist_ratio = hit_dist / trace_distance;
- return saturate(dist_ratio * 3.0 - 2.0);
+ vec3 hit_position_unused;
+
+ if (raytrace(ray, params, false, hit_position_unused)) {
+ return 0.0;
}
}
}
diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
index aebd1c3aef3..7c375aabb62 100644
--- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
@@ -3,261 +3,217 @@
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
+/**
+ * Screen-Space Raytracing functions.
+ */
+
uniform sampler2D maxzBuffer;
uniform sampler2DArray planarDepth;
-#define MAX_STEP 256
+struct Ray {
+ vec3 origin;
+ vec3 direction;
+};
-float sample_depth(vec2 uv, int index, float lod)
+vec3 raytrace_offset(vec3 P, vec3 Ng)
{
-#ifdef PLANAR_PROBE_RAYTRACE
- if (index > -1) {
- return textureLod(planarDepth, vec3(uv, index), 0.0).r;
- }
- else {
-#endif
- lod = clamp(floor(lod), 0.0, 8.0);
- /* Correct UVs for mipmaping mis-alignment */
- uv *= mipRatio[int(lod) + hizMipOffset];
- return textureLod(maxzBuffer, uv, lod).r;
-#ifdef PLANAR_PROBE_RAYTRACE
- }
-#endif
+ /* TODO(fclem) better offset */
+ const float epsilon_f = 1e-4;
+ return P + epsilon_f * Ng;
}
-vec4 sample_depth_grouped(vec4 uv1, vec4 uv2, int index, float lod)
+/* Inputs expected to be in viewspace. */
+void raytrace_clip_ray_to_near_plane(inout Ray ray)
{
- vec4 depths;
-#ifdef PLANAR_PROBE_RAYTRACE
- if (index > -1) {
- depths.x = textureLod(planarDepth, vec3(uv1.xy, index), 0.0).r;
- depths.y = textureLod(planarDepth, vec3(uv1.zw, index), 0.0).r;
- depths.z = textureLod(planarDepth, vec3(uv2.xy, index), 0.0).r;
- depths.w = textureLod(planarDepth, vec3(uv2.zw, index), 0.0).r;
+ float near_dist = get_view_z_from_depth(0.0);
+ if ((ray.origin.z + ray.direction.z) > near_dist) {
+ ray.direction *= abs((near_dist - ray.origin.z) / ray.direction.z);
}
- else {
-#endif
- depths.x = textureLod(maxzBuffer, uv1.xy, lod).r;
- depths.y = textureLod(maxzBuffer, uv1.zw, lod).r;
- depths.z = textureLod(maxzBuffer, uv2.xy, lod).r;
- depths.w = textureLod(maxzBuffer, uv2.zw, lod).r;
-#ifdef PLANAR_PROBE_RAYTRACE
- }
-#endif
- return depths;
}
-float refine_isect(float prev_delta, float curr_delta)
-{
- /**
- * Simplification of 2D intersection :
- * r0 = (0.0, prev_ss_ray.z);
- * r1 = (1.0, curr_ss_ray.z);
- * d0 = (0.0, prev_hit_depth_sample);
- * d1 = (1.0, curr_hit_depth_sample);
- * vec2 r = r1 - r0;
- * vec2 d = d1 - d0;
- * vec2 isect = ((d * cross(r1, r0)) - (r * cross(d1, d0))) / cross(r,d);
- *
- * We only want isect.x to know how much stride we need. So it simplifies :
- *
- * isect_x = (cross(r1, r0) - cross(d1, d0)) / cross(r,d);
- * isect_x = (prev_ss_ray.z - prev_hit_depth_sample.z) / cross(r,d);
- */
- return saturate(prev_delta / (prev_delta - curr_delta));
-}
+/* Screenspace ray ([0..1] "uv" range) where direction is normalize to be as small as one
+ * full-resolution pixel. The ray is also clipped to all frustum sides.
+ */
+struct ScreenSpaceRay {
+ vec4 origin;
+ vec4 direction;
+ float max_time;
+};
-void prepare_raycast(vec3 ray_origin,
- vec3 ray_dir,
- float thickness,
- int index,
- out vec4 ss_step,
- out vec4 ss_ray,
- out float max_time)
+void raytrace_screenspace_ray_finalize(inout ScreenSpaceRay ray)
{
- /* Negate the ray direction if it goes towards the camera.
- * This way we don't need to care if the projected point
- * is behind the near plane. */
- float z_sign = -sign(ray_dir.z);
- vec3 ray_end = ray_origin + z_sign * ray_dir;
-
- /* Project into screen space. */
- vec4 ss_start, ss_end;
- ss_start.xyz = project_point(ProjectionMatrix, ray_origin);
- ss_end.xyz = project_point(ProjectionMatrix, ray_end);
-
- /* We interpolate the ray Z + thickness values to check if depth is within threshold. */
- ray_origin.z -= thickness;
- ray_end.z -= thickness;
- ss_start.w = project_point(ProjectionMatrix, ray_origin).z;
- ss_end.w = project_point(ProjectionMatrix, ray_end).z;
-
- /* XXX This is a hack. A better method is welcome! */
- /* We take the delta between the offsetted depth and the depth and subtract it from the ray
- * depth. This will change the world space thickness appearance a bit but we can have negative
- * values without worries. We cannot do this in viewspace because of the perspective division. */
- ss_start.w = 2.0 * ss_start.z - ss_start.w;
- ss_end.w = 2.0 * ss_end.z - ss_end.w;
-
- ss_step = ss_end - ss_start;
- max_time = length(ss_step.xyz);
- ss_step = z_sign * ss_step / length(ss_step.xyz);
-
+ /* Constant bias (due to depth buffer precision). Helps with self intersection. */
+ /* Magic numbers for 24bits of precision.
+ * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
+ const float bias = -2.4e-7 * 2.0;
+ ray.origin.zw += bias;
+ ray.direction.zw += bias;
+
+ ray.direction -= ray.origin;
+ float ray_len_sqr = len_squared(ray.direction.xyz);
/* If the line is degenerate, make it cover at least one pixel
* to not have to handle zero-pixel extent as a special case later */
- if (dot(ss_step.xy, ss_step.xy) < 0.00001) {
- ss_step.xy = vec2(0.0, 0.0001);
+ if (ray_len_sqr < 0.00001) {
+ ray.direction.xy = vec2(0.0, 0.0001);
}
-
- /* Make ss_step cover one pixel. */
- ss_step /= max(abs(ss_step.x), abs(ss_step.y));
- ss_step *= (abs(ss_step.x) > abs(ss_step.y)) ? ssrPixelSize.x : ssrPixelSize.y;
-
+ /* Make ray.direction cover one pixel. */
+ bool is_more_vertical = abs(ray.direction.x) < abs(ray.direction.y);
+ ray.direction /= (is_more_vertical) ? abs(ray.direction.y) : abs(ray.direction.x);
+ ray.direction *= (is_more_vertical) ? ssrPixelSize.y : ssrPixelSize.x;
/* Clip to segment's end. */
- max_time /= length(ss_step.xyz);
+ ray.max_time = sqrt(ray_len_sqr * safe_rcp(len_squared(ray.direction.xyz)));
/* Clipping to frustum sides. */
- max_time = min(max_time, line_unit_box_intersect_dist(ss_start.xyz, ss_step.xyz));
- /* Avoid no iteration. */
- max_time = max(max_time, 1.0);
+ float clip_dist = line_unit_box_intersect_dist(ray.origin.xyz, ray.direction.xyz);
+ ray.max_time = min(ray.max_time, clip_dist);
+ /* Convert to texture coords [0..1] range. */
+ ray.origin = ray.origin * 0.5 + 0.5;
+ ray.direction *= 0.5;
+}
- /* Convert to texture coords. Z component included
- * since this is how it's stored in the depth buffer.
- * 4th component how far we are on the ray */
-#ifdef PLANAR_PROBE_RAYTRACE
- /* Planar Reflections have X mirrored. */
- vec2 m = (index > -1) ? vec2(-0.5, 0.5) : vec2(0.5);
-#else
- const vec2 m = vec2(0.5);
-#endif
- ss_ray = ss_start * m.xyyy + 0.5;
- ss_step *= m.xyyy;
-
- /* take the center of the texel. */
- // ss_ray.xy += sign(ss_ray.xy) * m * ssrPixelSize * (1.0 + hizMipOffset);
+ScreenSpaceRay raytrace_screenspace_ray_create(Ray ray)
+{
+ ScreenSpaceRay ssray;
+ ssray.origin.xyz = project_point(ProjectionMatrix, ray.origin);
+ ssray.direction.xyz = project_point(ProjectionMatrix, ray.origin + ray.direction);
+
+ raytrace_screenspace_ray_finalize(ssray);
+ return ssray;
}
-/* See times_and_deltas. */
-#define curr_time times_and_deltas.x
-#define prev_time times_and_deltas.y
-#define curr_delta times_and_deltas.z
-#define prev_delta times_and_deltas.w
+ScreenSpaceRay raytrace_screenspace_ray_create(Ray ray, float thickness)
+{
+ ScreenSpaceRay ssray;
+ ssray.origin.xyz = project_point(ProjectionMatrix, ray.origin);
+ ssray.direction.xyz = project_point(ProjectionMatrix, ray.origin + ray.direction);
+ /* Interpolate thickness in screen space.
+ * Calculate thickness further away to avoid near plane clipping issues. */
+ ssray.origin.w = get_depth_from_view_z(ray.origin.z - thickness) * 2.0 - 1.0;
+ ssray.direction.w = get_depth_from_view_z(ray.origin.z + ray.direction.z - thickness) * 2.0 -
+ 1.0;
+
+ raytrace_screenspace_ray_finalize(ssray);
+ return ssray;
+}
-// #define GROUPED_FETCHES /* is still slower, need to see where is the bottleneck. */
-/* Return the hit position, and negate the z component (making it positive) if not hit occurred. */
+struct RayTraceParameters {
+ /** ViewSpace thickness the objects */
+ float thickness;
+ /** Jitter along the ray to avoid banding artifact when steps are too large. */
+ float jitter;
+ /** Determine how fast the sample steps are getting bigger. */
+ float trace_quality;
+ /** Determine how we can use lower depth mipmaps to make the tracing faster. */
+ float roughness;
+};
+
+/* Return true on hit. */
/* __ray_dir__ is the ray direction premultiplied by its maximum length */
-vec3 raycast(int index,
- vec3 ray_origin,
- vec3 ray_dir,
- float thickness,
- float ray_jitter,
- float trace_quality,
- float roughness,
- const bool discard_backface)
+/* TODO fclem remove the backface check and do it the SSR resolve code. */
+bool raytrace(Ray ray,
+ RayTraceParameters params,
+ const bool discard_backface,
+ out vec3 hit_position)
{
- vec4 ss_step, ss_start;
- float max_time;
- prepare_raycast(ray_origin, ray_dir, thickness, index, ss_step, ss_start, max_time);
-
- float max_trace_time = max(0.01, max_time - 0.01);
+ /* Clip to near plane for perspective view where there is a singularity at the camera origin. */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ raytrace_clip_ray_to_near_plane(ray);
+ }
-#ifdef GROUPED_FETCHES
- ray_jitter *= 0.25;
-#endif
+ ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray, params.thickness);
+ /* Avoid no iteration. */
+ ssray.max_time = max(ssray.max_time, 1.1);
- /* x : current_time, y: previous_time, z: current_delta, w: previous_delta */
- vec4 times_and_deltas = vec4(0.0);
+ float prev_delta = 0.0, prev_time = 0.0;
+ float depth_sample = get_depth_from_view_z(ray.origin.z);
+ float delta = depth_sample - ssray.origin.z;
- float ray_time = 0.0;
- float depth_sample = sample_depth(ss_start.xy, index, 0.0);
- curr_delta = depth_sample - ss_start.z;
+ float lod_fac = saturate(fast_sqrt(params.roughness) * 2.0 - 0.4);
- float lod_fac = saturate(fast_sqrt(roughness) * 2.0 - 0.4);
+ /* Cross at least one pixel. */
+ float t = 1.001, time = 1.001;
bool hit = false;
- float iter;
- for (iter = 1.0; !hit && (ray_time < max_time) && (iter < MAX_STEP); iter++) {
- /* Minimum stride of 2 because we are using half res minmax zbuffer. */
- /* WORKAROUND: Factor is a bit higher than 2 to avoid some banding. To investigate. */
- float stride = max(1.0, iter * trace_quality) * (2.0 + 0.05);
- float lod = log2(stride * 0.5 * trace_quality) * lod_fac;
- ray_time += stride;
-
- /* Save previous values. */
- times_and_deltas.xyzw = times_and_deltas.yxwz;
-
-#ifdef GROUPED_FETCHES
- stride *= 4.0;
- vec4 jit_stride = mix(vec4(2.0), vec4(stride), vec4(0.0, 0.25, 0.5, 0.75) + ray_jitter);
-
- vec4 times = min(vec4(ray_time) + jit_stride, vec4(max_trace_time));
-
- vec4 uv1 = ss_start.xyxy + ss_step.xyxy * times.xxyy;
- vec4 uv2 = ss_start.xyxy + ss_step.xyxy * times.zzww;
-
- vec4 depth_samples = sample_depth_grouped(uv1, uv2, index, lod);
-
- vec4 ray_z = ss_start.zzzz + ss_step.zzzz * times.xyzw;
- vec4 ray_w = ss_start.wwww + ss_step.wwww * vec4(prev_time, times.xyz);
-
- vec4 deltas = depth_samples - ray_z;
- /* Same as component wise (curr_delta <= 0.0) && (prev_w <= depth_sample). */
- bvec4 test = equal(step(deltas, vec4(0.0)) * step(ray_w, depth_samples), vec4(1.0));
- hit = any(test);
-
- if (hit) {
- vec2 m = vec2(1.0, 0.0); /* Mask */
-
- vec4 ret_times_and_deltas = times.wzzz * m.xxyy + deltas.wwwz * m.yyxx;
- ret_times_and_deltas = (test.z) ? times.zyyy * m.xxyy + deltas.zzzy * m.yyxx :
- ret_times_and_deltas;
- ret_times_and_deltas = (test.y) ? times.yxxx * m.xxyy + deltas.yyyx * m.yyxx :
- ret_times_and_deltas;
- times_and_deltas = (test.x) ? times.xxxx * m.xyyy + deltas.xxxx * m.yyxy +
- times_and_deltas.yyww * m.yxyx :
- ret_times_and_deltas;
-
- depth_sample = depth_samples.w;
- depth_sample = (test.z) ? depth_samples.z : depth_sample;
- depth_sample = (test.y) ? depth_samples.y : depth_sample;
- depth_sample = (test.x) ? depth_samples.x : depth_sample;
- }
- else {
- curr_time = times.w;
- curr_delta = deltas.w;
- }
-#else
- float jit_stride = mix(2.0, stride, ray_jitter);
-
- curr_time = min(ray_time + jit_stride, max_trace_time);
- vec4 ss_ray = ss_start + ss_step * curr_time;
-
- depth_sample = sample_depth(ss_ray.xy, index, lod);
-
- float prev_w = ss_start.w + ss_step.w * prev_time;
- curr_delta = depth_sample - ss_ray.z;
- hit = (curr_delta <= 0.0) && (prev_w <= depth_sample);
-#endif
- }
+ const float max_steps = 255.0;
+ for (float iter = 1.0; !hit && (time < ssray.max_time) && (iter < max_steps); iter++) {
+ float stride = 1.0 + iter * params.trace_quality;
+ float lod = log2(stride) * lod_fac;
- /* Discard backface hits. Only do this if the ray traveled enough to avoid losing intricate
- * contact reflections. This is only used for SSReflections. */
- if (discard_backface && prev_delta < 0.0 && curr_time > 4.1) {
- hit = false;
- }
+ prev_time = time;
+ prev_delta = delta;
+ time = min(t + stride * params.jitter, ssray.max_time);
+ t += stride;
+
+ vec4 ss_p = ssray.origin + ssray.direction * time;
+ depth_sample = textureLod(maxzBuffer, ss_p.xy * hizUvScale.xy, floor(lod)).r;
+
+ delta = depth_sample - ss_p.z;
+ /* Check if the ray is below the surface ... */
+ hit = (delta < 0.0);
+ /* ... and above it with the added thickness. */
+ hit = hit && (delta > ss_p.z - ss_p.w);
+ }
+ /* Discard backface hits. */
+ hit = hit && !(discard_backface && prev_delta < 0.0);
/* Reject hit if background. */
hit = hit && (depth_sample != 1.0);
+ /* Refine hit using intersection between the sampled heightfield and the ray.
+ * This simplifies nicely to this single line. */
+ time = mix(prev_time, time, saturate(prev_delta / (prev_delta - delta)));
+
+ hit_position = ssray.origin.xyz + ssray.direction.xyz * time;
+
+ return hit;
+}
+
+bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out vec3 hit_position)
+{
+ /* Clip to near plane for perspective view where there is a singularity at the camera origin. */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ raytrace_clip_ray_to_near_plane(ray);
+ }
+
+ ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray);
+ /* Avoid no iteration. */
+ ssray.max_time = max(ssray.max_time, 1.1);
- curr_time = (hit) ? mix(prev_time, curr_time, refine_isect(prev_delta, curr_delta)) : curr_time;
- ray_time = (hit) ? curr_time : ray_time;
+ /* Planar Reflections have X mirrored. */
+ ssray.origin.x = 1.0 - ssray.origin.x;
+ ssray.direction.x = -ssray.direction.x;
+
+ float prev_delta = 0.0, prev_time = 0.0;
+ float depth_sample = get_depth_from_view_z(ray.origin.z);
+ float delta = depth_sample - ssray.origin.z;
+
+ /* Cross at least one pixel. */
+ float t = 1.001, time = 1.001;
+ bool hit = false;
+ const float max_steps = 255.0;
+ for (float iter = 1.0; !hit && (time < ssray.max_time) && (iter < max_steps); iter++) {
+ float stride = 1.0 + iter * params.trace_quality;
+
+ prev_time = time;
+ prev_delta = delta;
+
+ time = min(t + stride * params.jitter, ssray.max_time);
+ t += stride;
- /* Clip to frustum. */
- ray_time = max(0.001, min(ray_time, max_time - 1.5));
+ vec4 ss_ray = ssray.origin + ssray.direction * time;
+
+ depth_sample = texture(planarDepth, vec3(ss_ray.xy, planar_ref_id)).r;
+
+ delta = depth_sample - ss_ray.z;
+ /* Check if the ray is below the surface. */
+ hit = (delta < 0.0);
+ }
+ /* Reject hit if background. */
+ hit = hit && (depth_sample != 1.0);
+ /* Refine hit using intersection between the sampled heightfield and the ray.
+ * This simplifies nicely to this single line. */
+ time = mix(prev_time, time, saturate(prev_delta / (prev_delta - delta)));
- vec4 ss_ray = ss_start + ss_step * ray_time;
+ hit_position = ssray.origin.xyz + ssray.direction.xyz * time;
- /* Tag Z if ray failed. */
- ss_ray.z *= (hit) ? 1.0 : -1.0;
- return ss_ray.xyz;
+ return hit;
}
float screen_border_mask(vec2 hit_co)
diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
index 15c28efe622..5a09120916a 100644
--- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
@@ -39,10 +39,20 @@ vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughness
R = transform_direction(ViewMatrix, R);
- vec3 hit_pos = raycast(
- -1, vP, R * 1e16, ssrThickness, rand.y, ssrQuality, roughnessSquared, false);
+ Ray ray;
+ ray.origin = vP;
+ ray.direction = R * 1e16;
- if ((hit_pos.z > 0.0) && (F_eta(ior, dot(H, V)) < 1.0)) {
+ RayTraceParameters params;
+ params.thickness = ssrThickness;
+ params.jitter = rand.y;
+ params.trace_quality = ssrQuality;
+ params.roughness = roughnessSquared;
+
+ vec3 hit_pos;
+ bool hit = raytrace(ray, params, false, hit_pos);
+
+ if (hit && (F_eta(ior, dot(H, V)) < 1.0)) {
hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
float hit_dist = distance(hit_pos, vP);
@@ -68,10 +78,7 @@ vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughness
vec2 texture_size = vec2(textureSize(colorBuffer, 0).xy);
float mip = clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, 9.0);
- /* Correct UVs for mipmaping mis-alignment */
- hit_uvs *= mip_ratio_interp(mip);
-
- vec3 spec = textureLod(colorBuffer, hit_uvs, mip).xyz;
+ vec3 spec = textureLod(colorBuffer, hit_uvs * hizUvScale.xy, mip).xyz;
float mask = screen_border_mask(hit_uvs);
return vec4(spec, mask);
diff --git a/source/blender/draw/intern/draw_select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c
index b5151293c1b..d7438b7e0f0 100644
--- a/source/blender/draw/intern/draw_select_buffer.c
+++ b/source/blender/draw/intern/draw_select_buffer.c
@@ -24,6 +24,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array_utils.h"
#include "BLI_bitmap.h"
#include "BLI_bitmap_draw_2d.h"
#include "BLI_rect.h"
@@ -336,6 +337,26 @@ uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph,
return ret;
}
+struct SelectReadData {
+ const void *val_ptr;
+ uint id_min;
+ uint id_max;
+ uint r_index;
+};
+
+static bool select_buffer_test_fn(const void *__restrict value, void *__restrict userdata)
+{
+ struct SelectReadData *data = userdata;
+ uint hit_id = *(uint *)value;
+ if (hit_id && hit_id >= data->id_min && hit_id < data->id_max) {
+ /* Start at 1 to confirm. */
+ data->val_ptr = value;
+ data->r_index = (hit_id - data->id_min) + 1;
+ return true;
+ }
+ return false;
+}
+
/**
* Find the selection id closest to \a center.
* \param dist: Use to initialize the distance,
@@ -349,13 +370,8 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
const uint id_max,
uint *dist)
{
- /* Smart function to sample a rect spiraling outside, nice for selection ID. */
-
/* Create region around center (typically the mouse cursor).
- * This must be square and have an odd width,
- * the spiraling algorithm does not work with arbitrary rectangles. */
-
- uint index = 0;
+ * This must be square and have an odd width. */
rcti rect;
BLI_rcti_init_pt_radius(&rect, center, *dist);
@@ -364,7 +380,6 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
int width = BLI_rcti_size_x(&rect);
int height = width;
- BLI_assert(width == height);
/* Read from selection framebuffer. */
@@ -372,64 +387,23 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
const uint *buf = DRW_select_buffer_read(depsgraph, region, v3d, &rect, &buf_len);
if (buf == NULL) {
- return index;
+ return 0;
}
- BLI_assert(width * height == buf_len);
-
- /* Spiral, starting from center of buffer. */
- int spiral_offset = height * (int)(width / 2) + (height / 2);
- int spiral_direction = 0;
-
- for (int nr = 1; nr <= height; nr++) {
- for (int a = 0; a < 2; a++) {
- for (int b = 0; b < nr; b++) {
- /* Find hit within the specified range. */
- uint hit_id = buf[spiral_offset];
-
- if (hit_id && hit_id >= id_min && hit_id < id_max) {
- /* Get x/y from spiral offset. */
- int hit_x = spiral_offset % width;
- int hit_y = spiral_offset / width;
-
- int center_x = width / 2;
- int center_y = height / 2;
+ const int shape[2] = {height, width};
+ const int center_yx[2] = {(height - 1) / 2, (width - 1) / 2};
+ struct SelectReadData data = {NULL, id_min, id_max, 0};
+ BLI_array_iter_spiral_square(buf, shape, center_yx, select_buffer_test_fn, &data);
- /* Manhattan distance in keeping with other screen-based selection. */
- *dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y));
-
- /* Indices start at 1 here. */
- index = (hit_id - id_min) + 1;
- goto exit;
- }
-
- /* Next spiral step. */
- if (spiral_direction == 0) {
- spiral_offset += 1; /* right */
- }
- else if (spiral_direction == 1) {
- spiral_offset -= width; /* down */
- }
- else if (spiral_direction == 2) {
- spiral_offset -= 1; /* left */
- }
- else {
- spiral_offset += width; /* up */
- }
-
- /* Stop if we are outside the buffer. */
- if (spiral_offset < 0 || spiral_offset >= buf_len) {
- goto exit;
- }
- }
-
- spiral_direction = (spiral_direction + 1) % 4;
- }
+ if (data.val_ptr) {
+ size_t offset = ((size_t)data.val_ptr - (size_t)buf) / sizeof(*buf);
+ int hit_x = offset % width;
+ int hit_y = offset / width;
+ *dist = (uint)(abs(hit_y - center_yx[0]) + abs(hit_x - center_yx[1]));
}
-exit:
MEM_freeN((void *)buf);
- return index;
+ return data.r_index;
}
/** \} */
diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl
index d02fd27f35f..0344b977139 100644
--- a/source/blender/draw/intern/shaders/common_math_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_lib.glsl
@@ -128,6 +128,12 @@ vec3 normalize_len(vec3 v, out float len)
return v / len;
}
+vec4 safe_color(vec4 c)
+{
+ /* Clamp to avoid black square artifacts if a pixel goes NaN. */
+ return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */
+}
+
/** \} */
/* ---------------------------------------------------------------------- */
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt
index 23f85756e4b..fd54d531eeb 100644
--- a/source/blender/editors/CMakeLists.txt
+++ b/source/blender/editors/CMakeLists.txt
@@ -53,6 +53,7 @@ if(WITH_BLENDER)
add_subdirectory(space_outliner)
add_subdirectory(space_script)
add_subdirectory(space_sequencer)
+ add_subdirectory(space_spreadsheet)
add_subdirectory(space_statusbar)
add_subdirectory(space_text)
add_subdirectory(space_topbar)
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 2ab809c3633..7adddf8f4ae 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -762,9 +762,9 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
MarkerMove *mm = op->customdata;
TimeMarker *marker, *selmarker = NULL;
- const int offs = RNA_int_get(op->ptr, "frames");
+ const int ofs = RNA_int_get(op->ptr, "frames");
char str[UI_MAX_DRAW_STR];
- char str_offs[NUM_STR_REP_LEN];
+ char str_ofs[NUM_STR_REP_LEN];
int totmark;
const bool use_time = ed_marker_move_use_time(mm);
@@ -776,27 +776,27 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op)
}
if (hasNumInput(&mm->num)) {
- outputNumInput(&mm->num, str_offs, &scene->unit);
+ outputNumInput(&mm->num, str_ofs, &scene->unit);
}
else if (use_time) {
- BLI_snprintf(str_offs, sizeof(str_offs), "%.2f", FRA2TIME(offs));
+ BLI_snprintf(str_ofs, sizeof(str_ofs), "%.2f", FRA2TIME(ofs));
}
else {
- BLI_snprintf(str_offs, sizeof(str_offs), "%d", offs);
+ BLI_snprintf(str_ofs, sizeof(str_ofs), "%d", ofs);
}
if (totmark == 1 && selmarker) {
/* we print current marker value */
if (use_time) {
BLI_snprintf(
- str, sizeof(str), TIP_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_offs);
+ str, sizeof(str), TIP_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_ofs);
}
else {
- BLI_snprintf(str, sizeof(str), TIP_("Marker %d offset %s"), selmarker->frame, str_offs);
+ BLI_snprintf(str, sizeof(str), TIP_("Marker %d offset %s"), selmarker->frame, str_ofs);
}
}
else {
- BLI_snprintf(str, sizeof(str), TIP_("Marker offset %s"), str_offs);
+ BLI_snprintf(str, sizeof(str), TIP_("Marker offset %s"), str_ofs);
}
ED_area_status_text(CTX_wm_area(C), str);
@@ -907,12 +907,12 @@ static void ed_marker_move_apply(bContext *C, wmOperator *op)
#endif
MarkerMove *mm = op->customdata;
TimeMarker *marker;
- int a, offs;
+ int a, ofs;
- offs = RNA_int_get(op->ptr, "frames");
+ ofs = RNA_int_get(op->ptr, "frames");
for (a = 0, marker = mm->markers->first; marker; marker = marker->next) {
if (marker->flag & SELECT) {
- marker->frame = mm->oldframe[a] + offs;
+ marker->frame = mm->oldframe[a] + ofs;
a++;
}
}
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 1809daa3fcb..653bd72b364 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -173,15 +173,11 @@ static PanelType *fmodifier_panel_register(ARegionType *region_type,
PanelTypePollFn poll,
const char *id_prefix)
{
- /* Get the name for the modifier's panel. */
- char panel_idname[BKE_ST_MAXNAME];
- const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
- BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_PT_%s", id_prefix, fmi->name);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
/* Intentionally leave the label field blank. The header is filled with buttons. */
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
+ BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_PT_%s", id_prefix, fmi->name);
BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
@@ -215,13 +211,9 @@ static PanelType *fmodifier_subpanel_register(ARegionType *region_type,
PanelTypePollFn poll,
PanelType *parent)
{
- /* Create the subpanel's ID name. */
- char panel_idname[BKE_ST_MAXNAME];
- BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME);
BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 60fe8ee7dee..226253cc063 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -644,8 +644,8 @@ static int selectbuffer_ret_hits_12(uint *UNUSED(buffer), const int hits12)
static int selectbuffer_ret_hits_5(uint *buffer, const int hits12, const int hits5)
{
- const int offs = 4 * hits12;
- memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint));
+ const int ofs = 4 * hits12;
+ memcpy(buffer, buffer + ofs, 4 * hits5 * sizeof(uint));
return hits5;
}
@@ -704,17 +704,12 @@ static EditBone *get_nearest_editbonepoint(
goto cache_end;
}
else if (hits12 > 0) {
- int offs;
+ int ofs;
- offs = 4 * hits12;
+ ofs = 4 * hits12;
BLI_rcti_init_pt_radius(&rect, vc->mval, 5);
- const int hits5 = view3d_opengl_select_with_id_filter(vc,
- buffer + offs,
- MAXPICKBUF - offs,
- &rect,
- select_mode,
- select_filter,
- select_id_ignore);
+ const int hits5 = view3d_opengl_select_with_id_filter(
+ vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter, select_id_ignore);
if (hits5 == 1) {
hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index d636f0d68af..93d36abe792 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -873,12 +873,12 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
if (hasNumInput(&pso->num)) {
Scene *scene = pso->scene;
- char str_offs[NUM_STR_REP_LEN];
+ char str_ofs[NUM_STR_REP_LEN];
- outputNumInput(&pso->num, str_offs, &scene->unit);
+ outputNumInput(&pso->num, str_ofs, &scene->unit);
BLI_snprintf(
- status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str);
+ status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_ofs, limits_str);
}
else {
BLI_snprintf(status_str,
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 7c541f61d75..3b7c80cee07 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -599,10 +599,10 @@ static void gpencil_interpolate_status_indicators(bContext *C, tGPDinterpolate *
BLI_strncpy(msg_str, TIP_("GPencil Interpolation: "), UI_MAX_DRAW_STR);
if (hasNumInput(&p->num)) {
- char str_offs[NUM_STR_REP_LEN];
+ char str_ofs[NUM_STR_REP_LEN];
- outputNumInput(&p->num, str_offs, &scene->unit);
- BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_offs);
+ outputNumInput(&p->num, str_ofs, &scene->unit);
+ BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_ofs);
}
else {
BLI_snprintf(status_str,
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index b29ef2e7ee2..dfff0ce639e 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -466,10 +466,10 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
GP_STROKE_BOX,
GP_STROKE_POLYLINE)) {
if (hasNumInput(&tgpi->num)) {
- char str_offs[NUM_STR_REP_LEN];
+ char str_ofs[NUM_STR_REP_LEN];
- outputNumInput(&tgpi->num, str_offs, &scene->unit);
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
+ outputNumInput(&tgpi->num, str_ofs, &scene->unit);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_ofs);
}
else {
if (tgpi->flag == IN_PROGRESS) {
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 7538dac1354..983ae94b637 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -145,6 +145,13 @@ void ED_fileselect_exit(struct wmWindowManager *wm,
struct SpaceFile *sfile);
bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile);
+struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile);
+
+/* Activate the file that corresponds to the given ID.
+ * Pass deferred=true to wait for the next refresh before activating. */
+void ED_fileselect_activate_by_id(struct SpaceFile *sfile,
+ struct ID *asset_id,
+ const bool deferred);
void ED_fileselect_window_params_get(const struct wmWindow *win,
int win_size[2],
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index fc474ea464d..1a3aa7e5496 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -55,6 +55,7 @@ void ED_spacetype_userpref(void);
void ED_spacetype_clip(void);
void ED_spacetype_statusbar(void);
void ED_spacetype_topbar(void);
+void ED_spacetype_spreadsheet(void);
/* calls for instancing and freeing spacetype static data
* called in WM_init_exit */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 042f10ddded..834be49b2b3 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -5246,8 +5246,8 @@ static bool ui_numedit_but_SLI(uiBut *but,
(but->softmax - but->softmin + but->a1);
}
else {
- const float offs = (BLI_rctf_size_y(&but->rect) / 2.0f);
- cursor_x_range = (BLI_rctf_size_x(&but->rect) - offs);
+ const float ofs = (BLI_rctf_size_y(&but->rect) / 2.0f);
+ cursor_x_range = (BLI_rctf_size_x(&but->rect) - ofs);
}
f = (mx_fl - data->dragstartx) / cursor_x_range + data->dragfstart;
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c
index e1f8f63dcbf..74668b2f3a3 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.c
@@ -642,6 +642,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
SPACE_MENU_NOP(SPACE_SCRIPT);
SPACE_MENU_NOP(SPACE_STATUSBAR);
SPACE_MENU_NOP(SPACE_TOPBAR);
+ SPACE_MENU_NOP(SPACE_SPREADSHEET);
}
}
for (int i = 0; i < idname_array_len; i++) {
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 06b87dd857f..1d7d10b6d0c 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -3667,16 +3667,16 @@ static void widget_progressbar(
/* round corners */
const float value = but_progressbar->progress;
- const float offs = wcol->roundness * BLI_rcti_size_y(&rect_prog);
+ const float ofs = wcol->roundness * BLI_rcti_size_y(&rect_prog);
float w = value * BLI_rcti_size_x(&rect_prog);
/* Ensure minimum size. */
- w = MAX2(w, offs);
+ w = MAX2(w, ofs);
rect_bar.xmax = rect_bar.xmin + w;
- round_box_edges(&wtb, roundboxalign, &rect_prog, offs);
- round_box_edges(&wtb_bar, roundboxalign, &rect_bar, offs);
+ round_box_edges(&wtb, roundboxalign, &rect_prog, ofs);
+ round_box_edges(&wtb_bar, roundboxalign, &rect_bar, ofs);
wtb.draw_outline = true;
widgetbase_draw(&wtb, wcol);
@@ -3733,9 +3733,9 @@ static void widget_numslider(
widget_init(&wtb1);
/* Backdrop first. */
- const float offs = wcol->roundness * BLI_rcti_size_y(rect);
- const float toffs = offs * 0.75f;
- round_box_edges(&wtb, roundboxalign, rect, offs);
+ const float ofs = wcol->roundness * BLI_rcti_size_y(rect);
+ const float toffs = ofs * 0.75f;
+ round_box_edges(&wtb, roundboxalign, rect, ofs);
wtb.draw_outline = false;
widgetbase_draw(&wtb, wcol);
@@ -3768,13 +3768,13 @@ static void widget_numslider(
const float width = (float)BLI_rcti_size_x(rect);
factor_ui = factor * width;
- if (factor_ui <= offs) {
+ if (factor_ui <= ofs) {
/* Left part only. */
roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
- rect1.xmax = rect1.xmin + offs;
- factor_discard = factor_ui / offs;
+ rect1.xmax = rect1.xmin + ofs;
+ factor_discard = factor_ui / ofs;
}
- else if (factor_ui <= width - offs) {
+ else if (factor_ui <= width - ofs) {
/* Left part + middle part. */
roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
rect1.xmax = rect1.xmin + factor_ui;
@@ -3784,7 +3784,7 @@ static void widget_numslider(
factor_discard = factor;
}
- round_box_edges(&wtb1, roundboxalign_slider, &rect1, offs);
+ round_box_edges(&wtb1, roundboxalign_slider, &rect1, ofs);
wtb1.draw_outline = false;
widgetbase_set_uniform_discard_factor(&wtb1, factor_discard);
widgetbase_draw(&wtb1, wcol);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 80e54f4f92f..afac254f542 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -160,6 +160,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case SPACE_STATUSBAR:
ts = &btheme->space_statusbar;
break;
+ case SPACE_SPREADSHEET:
+ ts = &btheme->space_spreadsheet;
+ break;
default:
ts = &btheme->space_view3d;
break;
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index 1e66a86c8fd..bf20c1f6438 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -130,8 +130,8 @@ void CACHEFILE_OT_open(wmOperatorType *ot)
WM_operator_properties_filesel(ot,
FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER,
FILE_BLENDER,
- FILE_SAVE,
- WM_FILESEL_FILEPATH,
+ FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index d60d83850a5..582ff01173a 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -75,11 +75,8 @@ static Object *make_prim_init(bContext *C,
ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat);
- if (scale && !equals_v3v3(scale, (const float[3]){1.0f, 1.0f, 1.0f})) {
- float scale_half[3];
- copy_v3_v3(scale_half, scale);
- mul_v3_fl(scale_half, 0.5f);
- rescale_m4(r_creation_data->mat, scale_half);
+ if (scale) {
+ rescale_m4(r_creation_data->mat, scale);
}
return obedit;
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index b269a4f0514..0e3cc22d358 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -212,6 +212,7 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
nshapes,
use_self,
use_separate_all,
+ false,
true);
}
else {
@@ -375,8 +376,16 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
}
if (use_exact) {
- has_isect = BM_mesh_boolean(
- em->bm, em->looptris, em->tottri, test_fn, NULL, 2, use_self, true, boolean_operation);
+ has_isect = BM_mesh_boolean(em->bm,
+ em->looptris,
+ em->tottri,
+ test_fn,
+ NULL,
+ 2,
+ use_self,
+ true,
+ false,
+ boolean_operation);
}
else {
has_isect = BM_mesh_intersect(em->bm,
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 9811b7caa38..1b7209b164b 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -1342,7 +1342,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
* already there. Very expensive for large images. Need to find a way to
* only get existing ibuf */
ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (ibuf == NULL || ibuf->rect == NULL) {
+ if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index bfad79a1da9..b4cac58db1f 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -1074,6 +1074,11 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ if (view_layer->active_aov == NULL) {
+ return OPERATOR_FINISHED;
+ }
+
BKE_view_layer_remove_aov(view_layer, view_layer->active_aov);
RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 26e2bcc42cf..966f2ace931 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -1292,7 +1292,8 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
BLI_assert(false);
break;
}
- BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, 2, true, true, boolean_mode);
+ BM_mesh_boolean(
+ bm, looptris, tottri, bm_face_isect_pair, NULL, 2, true, true, false, boolean_mode);
}
MEM_freeN(looptris);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 631327ddfe8..0b30303de91 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -76,11 +76,6 @@
#include "IMB_colormanagement.h"
-#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
-#include "GPU_matrix.h"
-#include "GPU_state.h"
-
#include "WM_api.h"
#include "WM_message.h"
#include "WM_toolsystem.h"
@@ -89,7 +84,6 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
-#include "ED_space_api.h"
#include "ED_view3d.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
@@ -9433,335 +9427,6 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
1.0f);
}
-/* -------------------------------------------------------------------- */
-/** \name Dyntopo Detail Size Edit Operator
- * \{ */
-
-/* Defines how much the mouse movement will modify the detail size value. */
-#define DETAIL_SIZE_DELTA_SPEED 0.08f
-#define DETAIL_SIZE_DELTA_ACCURATE_SPEED 0.004f
-
-typedef struct DyntopoDetailSizeEditCustomData {
- void *draw_handle;
- Object *active_object;
-
- float init_mval[2];
- float accurate_mval[2];
-
- float outline_col[4];
-
- bool accurate_mode;
- bool sample_mode;
-
- float init_detail_size;
- float accurate_detail_size;
- float detail_size;
- float radius;
-
- float preview_tri[3][3];
- float gizmo_mat[4][4];
-} DyntopoDetailSizeEditCustomData;
-
-static void dyntopo_detail_size_parallel_lines_draw(uint pos3d,
- DyntopoDetailSizeEditCustomData *cd,
- const float start_co[3],
- const float end_co[3],
- bool flip,
- const float angle)
-{
- float object_space_constant_detail = 1.0f /
- (cd->detail_size * mat4_to_scale(cd->active_object->obmat));
-
- /* The constant detail represents the maximum edge length allowed before subdividing it. If the
- * triangle grid preview is created with this value it will represent an ideal mesh density where
- * all edges have the exact maximum length, which never happens in practice. As the minimum edge
- * length for dyntopo is 0.4 * max_edge_length, this adjust the detail size to the average
- * between max and min edge length so the preview is more accurate. */
- object_space_constant_detail *= 0.7f;
-
- const float total_len = len_v3v3(cd->preview_tri[0], cd->preview_tri[1]);
- const int tot_lines = (int)(total_len / object_space_constant_detail) + 1;
- const float tot_lines_fl = total_len / object_space_constant_detail;
- float spacing_disp[3];
- sub_v3_v3v3(spacing_disp, end_co, start_co);
- normalize_v3(spacing_disp);
-
- float line_disp[3];
- rotate_v2_v2fl(line_disp, spacing_disp, DEG2RAD(angle));
- mul_v3_fl(spacing_disp, total_len / tot_lines_fl);
-
- immBegin(GPU_PRIM_LINES, (uint)tot_lines * 2);
- for (int i = 0; i < tot_lines; i++) {
- float line_length;
- if (flip) {
- line_length = total_len * ((float)i / (float)tot_lines_fl);
- }
- else {
- line_length = total_len * (1.0f - ((float)i / (float)tot_lines_fl));
- }
- float line_start[3];
- copy_v3_v3(line_start, start_co);
- madd_v3_v3v3fl(line_start, line_start, spacing_disp, i);
- float line_end[3];
- madd_v3_v3v3fl(line_end, line_start, line_disp, line_length);
- immVertex3fv(pos3d, line_start);
- immVertex3fv(pos3d, line_end);
- }
- immEnd();
-}
-
-static void dyntopo_detail_size_edit_draw(const bContext *UNUSED(C),
- ARegion *UNUSED(ar),
- void *arg)
-{
- DyntopoDetailSizeEditCustomData *cd = arg;
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_line_smooth(true);
-
- uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- GPU_matrix_push();
- GPU_matrix_mul(cd->gizmo_mat);
-
- /* Draw Cursor */
- immUniformColor4fv(cd->outline_col);
- GPU_line_width(3.0f);
-
- imm_draw_circle_wire_3d(pos3d, 0, 0, cd->radius, 80);
-
- /* Draw Triangle. */
- immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
- immBegin(GPU_PRIM_LINES, 6);
- immVertex3fv(pos3d, cd->preview_tri[0]);
- immVertex3fv(pos3d, cd->preview_tri[1]);
-
- immVertex3fv(pos3d, cd->preview_tri[1]);
- immVertex3fv(pos3d, cd->preview_tri[2]);
-
- immVertex3fv(pos3d, cd->preview_tri[2]);
- immVertex3fv(pos3d, cd->preview_tri[0]);
- immEnd();
-
- /* Draw Grid */
- GPU_line_width(1.0f);
- dyntopo_detail_size_parallel_lines_draw(
- pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], false, 60.0f);
- dyntopo_detail_size_parallel_lines_draw(
- pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], true, 120.0f);
- dyntopo_detail_size_parallel_lines_draw(
- pos3d, cd, cd->preview_tri[0], cd->preview_tri[2], false, -60.0f);
-
- immUnbindProgram();
- GPU_matrix_pop();
- GPU_blend(GPU_BLEND_NONE);
- GPU_line_smooth(false);
-}
-
-static void dyntopo_detail_size_edit_cancel(bContext *C, wmOperator *op)
-{
- Object *active_object = CTX_data_active_object(C);
- SculptSession *ss = active_object->sculpt;
- ARegion *region = CTX_wm_region(C);
- DyntopoDetailSizeEditCustomData *cd = op->customdata;
- ED_region_draw_cb_exit(region->type, cd->draw_handle);
- ss->draw_faded_cursor = false;
- MEM_freeN(op->customdata);
- ED_workspace_status_text(C, NULL);
-}
-
-static void dyntopo_detail_size_sample_from_surface(Object *ob,
- DyntopoDetailSizeEditCustomData *cd)
-{
- SculptSession *ss = ob->sculpt;
- const int active_vertex = SCULPT_active_vertex_get(ss);
-
- float len_accum = 0;
- int num_neighbors = 0;
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) {
- len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex),
- SCULPT_vertex_co_get(ss, ni.index));
- num_neighbors++;
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- if (num_neighbors > 0) {
- const float avg_edge_len = len_accum / num_neighbors;
- /* Use 0.7 as the average of min and max dyntopo edge length. */
- const float detail_size = 0.7f / (avg_edge_len * mat4_to_scale(cd->active_object->obmat));
- cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f);
- }
-}
-
-static void dyntopo_detail_size_update_from_mouse_delta(DyntopoDetailSizeEditCustomData *cd,
- const wmEvent *event)
-{
- const float mval[2] = {event->mval[0], event->mval[1]};
-
- float detail_size_delta;
- if (cd->accurate_mode) {
- detail_size_delta = mval[0] - cd->accurate_mval[0];
- cd->detail_size = cd->accurate_detail_size +
- detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED;
- }
- else {
- detail_size_delta = mval[0] - cd->init_mval[0];
- cd->detail_size = cd->init_detail_size + detail_size_delta * DETAIL_SIZE_DELTA_SPEED;
- }
-
- if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
- cd->accurate_mode = true;
- copy_v2_v2(cd->accurate_mval, mval);
- cd->accurate_detail_size = cd->detail_size;
- }
- if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
- cd->accurate_mode = false;
- cd->accurate_detail_size = 0.0f;
- }
-
- cd->detail_size = clamp_f(cd->detail_size, 1.0f, 500.0f);
-}
-
-static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Object *active_object = CTX_data_active_object(C);
- SculptSession *ss = active_object->sculpt;
- ARegion *region = CTX_wm_region(C);
- DyntopoDetailSizeEditCustomData *cd = op->customdata;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-
- /* Cancel modal operator */
- if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
- (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
- dyntopo_detail_size_edit_cancel(C, op);
- ED_region_tag_redraw(region);
- return OPERATOR_FINISHED;
- }
-
- /* Finish modal operator */
- if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
- (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
- (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
- ED_region_draw_cb_exit(region->type, cd->draw_handle);
- sd->constant_detail = cd->detail_size;
- ss->draw_faded_cursor = false;
- MEM_freeN(op->customdata);
- ED_region_tag_redraw(region);
- ED_workspace_status_text(C, NULL);
- return OPERATOR_FINISHED;
- }
-
- ED_region_tag_redraw(region);
-
- if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) {
- cd->sample_mode = true;
- }
- if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) {
- cd->sample_mode = false;
- }
-
- /* Sample mode sets the detail size sampling the average edge length under the surface. */
- if (cd->sample_mode) {
- dyntopo_detail_size_sample_from_surface(active_object, cd);
- return OPERATOR_RUNNING_MODAL;
- }
- /* Regular mode, changes the detail size by moving the cursor. */
- dyntopo_detail_size_update_from_mouse_delta(cd, event);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ARegion *region = CTX_wm_region(C);
- Object *active_object = CTX_data_active_object(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- DyntopoDetailSizeEditCustomData *cd = MEM_callocN(sizeof(DyntopoDetailSizeEditCustomData),
- "Dyntopo Detail Size Edit OP Custom Data");
-
- /* Initial operator Custom Data setup. */
- cd->draw_handle = ED_region_draw_cb_activate(
- region->type, dyntopo_detail_size_edit_draw, cd, REGION_DRAW_POST_VIEW);
- cd->active_object = active_object;
- cd->init_mval[0] = event->mval[0];
- cd->init_mval[1] = event->mval[1];
- cd->detail_size = sd->constant_detail;
- cd->init_detail_size = sd->constant_detail;
- copy_v4_v4(cd->outline_col, brush->add_col);
- op->customdata = cd;
-
- SculptSession *ss = active_object->sculpt;
- cd->radius = ss->cursor_radius;
-
- /* Generates the matrix to position the gizmo in the surface of the mesh using the same location
- * and orientation as the brush cursor. */
- float cursor_trans[4][4], cursor_rot[4][4];
- const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
- float quat[4];
- copy_m4_m4(cursor_trans, active_object->obmat);
- translate_m4(
- cursor_trans, ss->cursor_location[0], ss->cursor_location[1], ss->cursor_location[2]);
-
- float cursor_normal[3];
- if (!is_zero_v3(ss->cursor_sampled_normal)) {
- copy_v3_v3(cursor_normal, ss->cursor_sampled_normal);
- }
- else {
- copy_v3_v3(cursor_normal, ss->cursor_normal);
- }
-
- rotation_between_vecs_to_quat(quat, z_axis, cursor_normal);
- quat_to_mat4(cursor_rot, quat);
- copy_m4_m4(cd->gizmo_mat, cursor_trans);
- mul_m4_m4_post(cd->gizmo_mat, cursor_rot);
-
- /* Initialize the position of the triangle vertices. */
- const float y_axis[3] = {0.0f, cd->radius, 0.0f};
- for (int i = 0; i < 3; i++) {
- zero_v3(cd->preview_tri[i]);
- rotate_v2_v2fl(cd->preview_tri[i], y_axis, DEG2RAD(120.0f * i));
- }
-
- SCULPT_vertex_random_access_ensure(ss);
-
- WM_event_add_modal_handler(C, op);
- ED_region_tag_redraw(region);
-
- ss->draw_faded_cursor = true;
-
- const char *status_str = TIP_(
- "Move the mouse to change the dyntopo detail size. LMB: confirm size, ESC/RMB: cancel");
- ED_workspace_status_text(C, status_str);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static bool dyntopo_detail_size_edit_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-
- return SCULPT_mode_poll(C) && ob->sculpt->bm && (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT);
-}
-
-static void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Edit Dyntopo Detail Size";
- ot->description = "Modify the constant detail size of dyntopo interactively";
- ot->idname = "SCULPT_OT_dyntopo_detail_size_edit";
-
- /* api callbacks */
- ot->poll = dyntopo_detail_size_edit_poll;
- ot->invoke = dyntopo_detail_size_edit_invoke;
- ot->modal = dyntopo_detail_size_edit_modal;
- ot->cancel = dyntopo_detail_size_edit_cancel;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
void ED_operatortypes_sculpt(void)
{
WM_operatortype_append(SCULPT_OT_brush_stroke);
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index f1fb402ae41..f79621ccffd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -589,6 +589,7 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b
for (int i = 0; i < totvert; i++) {
if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) {
+ continue;
}
sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex],
SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex),
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index ddf7ba1e412..1246c624941 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -37,10 +37,17 @@
#include "DEG_depsgraph.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "WM_api.h"
#include "WM_types.h"
#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_space_api.h"
#include "ED_view3d.h"
#include "sculpt_intern.h"
@@ -359,8 +366,12 @@ void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
/* Dynamic-topology detail size.
*
- * This should be improved further, perhaps by showing a triangle
- * grid rather than brush alpha. */
+ * Currently, there are two operators editing the detail size:
+ * - SCULPT_OT_set_detail_size uses radial control for all methods
+ * - SCULPT_OT_dyntopo_detail_size_edit shows a triangle grid representation of the detail
+ * resolution (for constant detail method, falls back to radial control for the remaining methods).
+ */
+
static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
{
char *path = BLI_sprintfN("tool_settings.sculpt.brush.%s", prop);
@@ -368,7 +379,7 @@ static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
MEM_freeN(path);
}
-static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
+static void sculpt_detail_size_set_radial_control(bContext *C)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -394,6 +405,11 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
+}
+
+static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ sculpt_detail_size_set_radial_control(C);
return OPERATOR_FINISHED;
}
@@ -412,3 +428,334 @@ void SCULPT_OT_set_detail_size(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/* -------------------------------------------------------------------- */
+/** \name Dyntopo Detail Size Edit Operator
+ * \{ */
+
+/* Defines how much the mouse movement will modify the detail size value. */
+#define DETAIL_SIZE_DELTA_SPEED 0.08f
+#define DETAIL_SIZE_DELTA_ACCURATE_SPEED 0.004f
+
+typedef struct DyntopoDetailSizeEditCustomData {
+ void *draw_handle;
+ Object *active_object;
+
+ float init_mval[2];
+ float accurate_mval[2];
+
+ float outline_col[4];
+
+ bool accurate_mode;
+ bool sample_mode;
+
+ float init_detail_size;
+ float accurate_detail_size;
+ float detail_size;
+ float radius;
+
+ float preview_tri[3][3];
+ float gizmo_mat[4][4];
+} DyntopoDetailSizeEditCustomData;
+
+static void dyntopo_detail_size_parallel_lines_draw(uint pos3d,
+ DyntopoDetailSizeEditCustomData *cd,
+ const float start_co[3],
+ const float end_co[3],
+ bool flip,
+ const float angle)
+{
+ float object_space_constant_detail = 1.0f /
+ (cd->detail_size * mat4_to_scale(cd->active_object->obmat));
+
+ /* The constant detail represents the maximum edge length allowed before subdividing it. If the
+ * triangle grid preview is created with this value it will represent an ideal mesh density where
+ * all edges have the exact maximum length, which never happens in practice. As the minimum edge
+ * length for dyntopo is 0.4 * max_edge_length, this adjust the detail size to the average
+ * between max and min edge length so the preview is more accurate. */
+ object_space_constant_detail *= 0.7f;
+
+ const float total_len = len_v3v3(cd->preview_tri[0], cd->preview_tri[1]);
+ const int tot_lines = (int)(total_len / object_space_constant_detail) + 1;
+ const float tot_lines_fl = total_len / object_space_constant_detail;
+ float spacing_disp[3];
+ sub_v3_v3v3(spacing_disp, end_co, start_co);
+ normalize_v3(spacing_disp);
+
+ float line_disp[3];
+ rotate_v2_v2fl(line_disp, spacing_disp, DEG2RAD(angle));
+ mul_v3_fl(spacing_disp, total_len / tot_lines_fl);
+
+ immBegin(GPU_PRIM_LINES, (uint)tot_lines * 2);
+ for (int i = 0; i < tot_lines; i++) {
+ float line_length;
+ if (flip) {
+ line_length = total_len * ((float)i / (float)tot_lines_fl);
+ }
+ else {
+ line_length = total_len * (1.0f - ((float)i / (float)tot_lines_fl));
+ }
+ float line_start[3];
+ copy_v3_v3(line_start, start_co);
+ madd_v3_v3v3fl(line_start, line_start, spacing_disp, i);
+ float line_end[3];
+ madd_v3_v3v3fl(line_end, line_start, line_disp, line_length);
+ immVertex3fv(pos3d, line_start);
+ immVertex3fv(pos3d, line_end);
+ }
+ immEnd();
+}
+
+static void dyntopo_detail_size_edit_draw(const bContext *UNUSED(C),
+ ARegion *UNUSED(ar),
+ void *arg)
+{
+ DyntopoDetailSizeEditCustomData *cd = arg;
+ GPU_blend(GPU_BLEND_ALPHA);
+ GPU_line_smooth(true);
+
+ uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ GPU_matrix_push();
+ GPU_matrix_mul(cd->gizmo_mat);
+
+ /* Draw Cursor */
+ immUniformColor4fv(cd->outline_col);
+ GPU_line_width(3.0f);
+
+ imm_draw_circle_wire_3d(pos3d, 0, 0, cd->radius, 80);
+
+ /* Draw Triangle. */
+ immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
+ immBegin(GPU_PRIM_LINES, 6);
+ immVertex3fv(pos3d, cd->preview_tri[0]);
+ immVertex3fv(pos3d, cd->preview_tri[1]);
+
+ immVertex3fv(pos3d, cd->preview_tri[1]);
+ immVertex3fv(pos3d, cd->preview_tri[2]);
+
+ immVertex3fv(pos3d, cd->preview_tri[2]);
+ immVertex3fv(pos3d, cd->preview_tri[0]);
+ immEnd();
+
+ /* Draw Grid */
+ GPU_line_width(1.0f);
+ dyntopo_detail_size_parallel_lines_draw(
+ pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], false, 60.0f);
+ dyntopo_detail_size_parallel_lines_draw(
+ pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], true, 120.0f);
+ dyntopo_detail_size_parallel_lines_draw(
+ pos3d, cd, cd->preview_tri[0], cd->preview_tri[2], false, -60.0f);
+
+ immUnbindProgram();
+ GPU_matrix_pop();
+ GPU_blend(GPU_BLEND_NONE);
+ GPU_line_smooth(false);
+}
+
+static void dyntopo_detail_size_edit_cancel(bContext *C, wmOperator *op)
+{
+ Object *active_object = CTX_data_active_object(C);
+ SculptSession *ss = active_object->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ DyntopoDetailSizeEditCustomData *cd = op->customdata;
+ ED_region_draw_cb_exit(region->type, cd->draw_handle);
+ ss->draw_faded_cursor = false;
+ MEM_freeN(op->customdata);
+ ED_workspace_status_text(C, NULL);
+}
+
+static void dyntopo_detail_size_sample_from_surface(Object *ob,
+ DyntopoDetailSizeEditCustomData *cd)
+{
+ SculptSession *ss = ob->sculpt;
+ const int active_vertex = SCULPT_active_vertex_get(ss);
+
+ float len_accum = 0;
+ int num_neighbors = 0;
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) {
+ len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex),
+ SCULPT_vertex_co_get(ss, ni.index));
+ num_neighbors++;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ if (num_neighbors > 0) {
+ const float avg_edge_len = len_accum / num_neighbors;
+ /* Use 0.7 as the average of min and max dyntopo edge length. */
+ const float detail_size = 0.7f / (avg_edge_len * mat4_to_scale(cd->active_object->obmat));
+ cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f);
+ }
+}
+
+static void dyntopo_detail_size_update_from_mouse_delta(DyntopoDetailSizeEditCustomData *cd,
+ const wmEvent *event)
+{
+ const float mval[2] = {event->mval[0], event->mval[1]};
+
+ float detail_size_delta;
+ if (cd->accurate_mode) {
+ detail_size_delta = mval[0] - cd->accurate_mval[0];
+ cd->detail_size = cd->accurate_detail_size +
+ detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED;
+ }
+ else {
+ detail_size_delta = mval[0] - cd->init_mval[0];
+ cd->detail_size = cd->init_detail_size + detail_size_delta * DETAIL_SIZE_DELTA_SPEED;
+ }
+
+ if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
+ cd->accurate_mode = true;
+ copy_v2_v2(cd->accurate_mval, mval);
+ cd->accurate_detail_size = cd->detail_size;
+ }
+ if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
+ cd->accurate_mode = false;
+ cd->accurate_detail_size = 0.0f;
+ }
+
+ cd->detail_size = clamp_f(cd->detail_size, 1.0f, 500.0f);
+}
+
+static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *active_object = CTX_data_active_object(C);
+ SculptSession *ss = active_object->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ DyntopoDetailSizeEditCustomData *cd = op->customdata;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ /* Cancel modal operator */
+ if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
+ (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
+ dyntopo_detail_size_edit_cancel(C, op);
+ ED_region_tag_redraw(region);
+ return OPERATOR_FINISHED;
+ }
+
+ /* Finish modal operator */
+ if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
+ (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
+ (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
+ ED_region_draw_cb_exit(region->type, cd->draw_handle);
+ sd->constant_detail = cd->detail_size;
+ ss->draw_faded_cursor = false;
+ MEM_freeN(op->customdata);
+ ED_region_tag_redraw(region);
+ ED_workspace_status_text(C, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ ED_region_tag_redraw(region);
+
+ if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) {
+ cd->sample_mode = true;
+ }
+ if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) {
+ cd->sample_mode = false;
+ }
+
+ /* Sample mode sets the detail size sampling the average edge length under the surface. */
+ if (cd->sample_mode) {
+ dyntopo_detail_size_sample_from_surface(active_object, cd);
+ return OPERATOR_RUNNING_MODAL;
+ }
+ /* Regular mode, changes the detail size by moving the cursor. */
+ dyntopo_detail_size_update_from_mouse_delta(cd, event);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ /* Fallback to radial control for modes other than SCULPT_DYNTOPO_DETAIL_CONSTANT [same as in
+ * SCULPT_OT_set_detail_size]. */
+ if (!(sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL))) {
+ sculpt_detail_size_set_radial_control(C);
+
+ return OPERATOR_FINISHED;
+ }
+
+ /* Special method for SCULPT_DYNTOPO_DETAIL_CONSTANT. */
+ ARegion *region = CTX_wm_region(C);
+ Object *active_object = CTX_data_active_object(C);
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ DyntopoDetailSizeEditCustomData *cd = MEM_callocN(sizeof(DyntopoDetailSizeEditCustomData),
+ "Dyntopo Detail Size Edit OP Custom Data");
+
+ /* Initial operator Custom Data setup. */
+ cd->draw_handle = ED_region_draw_cb_activate(
+ region->type, dyntopo_detail_size_edit_draw, cd, REGION_DRAW_POST_VIEW);
+ cd->active_object = active_object;
+ cd->init_mval[0] = event->mval[0];
+ cd->init_mval[1] = event->mval[1];
+ cd->detail_size = sd->constant_detail;
+ cd->init_detail_size = sd->constant_detail;
+ copy_v4_v4(cd->outline_col, brush->add_col);
+ op->customdata = cd;
+
+ SculptSession *ss = active_object->sculpt;
+ cd->radius = ss->cursor_radius;
+
+ /* Generates the matrix to position the gizmo in the surface of the mesh using the same location
+ * and orientation as the brush cursor. */
+ float cursor_trans[4][4], cursor_rot[4][4];
+ const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+ float quat[4];
+ copy_m4_m4(cursor_trans, active_object->obmat);
+ translate_m4(
+ cursor_trans, ss->cursor_location[0], ss->cursor_location[1], ss->cursor_location[2]);
+
+ float cursor_normal[3];
+ if (!is_zero_v3(ss->cursor_sampled_normal)) {
+ copy_v3_v3(cursor_normal, ss->cursor_sampled_normal);
+ }
+ else {
+ copy_v3_v3(cursor_normal, ss->cursor_normal);
+ }
+
+ rotation_between_vecs_to_quat(quat, z_axis, cursor_normal);
+ quat_to_mat4(cursor_rot, quat);
+ copy_m4_m4(cd->gizmo_mat, cursor_trans);
+ mul_m4_m4_post(cd->gizmo_mat, cursor_rot);
+
+ /* Initize the position of the triangle vertices. */
+ const float y_axis[3] = {0.0f, cd->radius, 0.0f};
+ for (int i = 0; i < 3; i++) {
+ zero_v3(cd->preview_tri[i]);
+ rotate_v2_v2fl(cd->preview_tri[i], y_axis, DEG2RAD(120.0f * i));
+ }
+
+ SCULPT_vertex_random_access_ensure(ss);
+
+ WM_event_add_modal_handler(C, op);
+ ED_region_tag_redraw(region);
+
+ ss->draw_faded_cursor = true;
+
+ const char *status_str = TIP_(
+ "Move the mouse to change the dyntopo detail size. LMB: confirm size, ESC/RMB: cancel");
+ ED_workspace_status_text(C, status_str);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Edit Dyntopo Detail Size";
+ ot->description = "Modify the detail size of dyntopo interactively";
+ ot->idname = "SCULPT_OT_dyntopo_detail_size_edit";
+
+ /* api callbacks */
+ ot->poll = sculpt_and_dynamic_topology_poll;
+ ot->invoke = dyntopo_detail_size_edit_invoke;
+ ot->modal = dyntopo_detail_size_edit_modal;
+ ot->cancel = dyntopo_detail_size_edit_cancel;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index df03d2adeaf..332e551c577 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -447,6 +447,7 @@ typedef enum eSculptFaceSetsInitMode {
SCULPT_FACE_SETS_FROM_SHARP_EDGES = 5,
SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT = 6,
SCULPT_FACE_SETS_FROM_FACE_MAPS = 7,
+ SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES = 8,
} eSculptFaceSetsInitMode;
static EnumPropertyItem prop_sculpt_face_sets_init_types[] = {
@@ -506,6 +507,14 @@ static EnumPropertyItem prop_sculpt_face_sets_init_types[] = {
"Face Sets from Face Maps",
"Create a Face Set per Face Map",
},
+ {
+ SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES,
+ "FACE_SET_BOUNDARIES",
+ 0,
+ "Face Sets from Face Set Boundaries",
+ "Create a Face Set per isolated Face Set",
+ },
+
{0, NULL, 0, NULL, NULL},
};
@@ -557,6 +566,14 @@ static bool sculpt_face_sets_init_sharp_edges_test(BMesh *UNUSED(bm),
return BM_elem_flag_test(from_e, BM_ELEM_SMOOTH);
}
+static bool sculpt_face_sets_init_face_set_boundary_test(
+ BMesh *bm, BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float UNUSED(threshold))
+{
+ const int cd_face_sets_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
+ return BM_ELEM_CD_GET_INT(from_f, cd_face_sets_offset) ==
+ BM_ELEM_CD_GET_INT(to_f, cd_face_sets_offset);
+}
+
static void sculpt_face_sets_init_flood_fill(Object *ob,
face_sets_flood_fill_test test,
const float threshold)
@@ -725,6 +742,10 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
case SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT:
sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_bevel_weight_test, threshold);
break;
+ case SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES:
+ sculpt_face_sets_init_flood_fill(
+ ob, sculpt_face_sets_init_face_set_boundary_test, threshold);
+ break;
case SCULPT_FACE_SETS_FROM_FACE_MAPS:
sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_FACE_MAPS);
break;
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 19c4eda7593..16c2996e392 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -1360,6 +1360,7 @@ void SCULPT_OT_mask_expand(struct wmOperatorType *ot);
void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot);
void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot);
void SCULPT_OT_set_detail_size(struct wmOperatorType *ot);
+void SCULPT_OT_dyntopo_detail_size_edit(struct wmOperatorType *ot);
/* Dyntopo. */
void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_api/CMakeLists.txt b/source/blender/editors/space_api/CMakeLists.txt
index 4b77b4da668..8af28baa5c2 100644
--- a/source/blender/editors/space_api/CMakeLists.txt
+++ b/source/blender/editors/space_api/CMakeLists.txt
@@ -50,6 +50,7 @@ set(LIB
bf_editor_space_outliner
bf_editor_space_script
bf_editor_space_sequencer
+ bf_editor_space_spreadsheet
bf_editor_space_statusbar
bf_editor_space_text
bf_editor_space_topbar
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 54320a02f2f..48e4c4ce575 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -99,6 +99,7 @@ void ED_spacetypes_init(void)
ED_spacetype_clip();
ED_spacetype_statusbar();
ED_spacetype_topbar();
+ ED_spacetype_spreadsheet();
/* Register operator types for screen and all spaces. */
ED_operatortypes_userpref();
@@ -270,7 +271,7 @@ void ED_region_draw_cb_exit(ARegionType *art, void *handle)
void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
{
- LISTBASE_FOREACH (RegionDrawCB *, rdc, &region->type->drawcalls) {
+ LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &region->type->drawcalls) {
if (rdc->type == type) {
rdc->draw(C, region, rdc->customdata);
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 56fb588776e..309b280177c 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -75,6 +75,7 @@ void FILE_OT_rename(struct wmOperatorType *ot);
void FILE_OT_smoothscroll(struct wmOperatorType *ot);
void FILE_OT_filepath_drop(struct wmOperatorType *ot);
void FILE_OT_start_filter(struct wmOperatorType *ot);
+void FILE_OT_view_selected(struct wmOperatorType *ot);
void file_directory_enter_handle(bContext *C, void *arg_unused, void *arg_but);
void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but);
@@ -112,6 +113,21 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v);
void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params);
+typedef void *onReloadFnData;
+typedef void (*onReloadFn)(struct SpaceFile *space_data, onReloadFnData custom_data);
+typedef struct SpaceFile_Runtime {
+ /* Called once after the file browser has reloaded. Reset to NULL after calling.
+ * Use file_on_reload_callback_register() to register a callback. */
+ onReloadFn on_reload;
+ onReloadFnData on_reload_custom_data;
+} SpaceFile_Runtime;
+
+/* Register an on-reload callback function. Note that there can only be one such function at a
+ * time; registering a new one will overwrite the previous one. */
+void file_on_reload_callback_register(struct SpaceFile *sfile,
+ onReloadFn callback,
+ onReloadFnData custom_data);
+
/* file_panels.c */
void file_tool_props_region_panels_register(struct ARegionType *art);
void file_execute_region_panels_register(struct ARegionType *art);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 985c92f19b6..b82290205c7 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -256,6 +256,33 @@ static bool file_is_any_selected(struct FileList *files)
return false;
}
+static FileSelection file_current_selection_range_get(struct FileList *files)
+{
+ const int numfiles = filelist_files_ensure(files);
+ FileSelection selection = {-1, -1};
+
+ /* Iterate over the files once but in two loops, one to find the first selected file, and the
+ * other to find the last. */
+
+ int file_index;
+ for (file_index = 0; file_index < numfiles; file_index++) {
+ if (filelist_entry_is_selected(files, file_index)) {
+ /* First selected entry found. */
+ selection.first = file_index;
+ break;
+ }
+ }
+
+ for (; file_index < numfiles; file_index++) {
+ if (filelist_entry_is_selected(files, file_index)) {
+ selection.last = file_index;
+ /* Keep looping, we may find more selected files. */
+ }
+ }
+
+ return selection;
+}
+
/**
* If \a file is outside viewbounds, this adjusts view to make sure it's inside
*/
@@ -299,6 +326,24 @@ static void file_ensure_inside_viewbounds(ARegion *region, SpaceFile *sfile, con
}
}
+static void file_ensure_selection_inside_viewbounds(ARegion *region,
+ SpaceFile *sfile,
+ FileSelection *sel)
+{
+ const FileLayout *layout = ED_fileselect_get_layout(sfile, region);
+
+ if (((layout->flag & FILE_LAYOUT_HOR) && region->winx <= (1.2f * layout->tile_w)) &&
+ ((layout->flag & FILE_LAYOUT_VER) && region->winy <= (2.0f * layout->tile_h))) {
+ return;
+ }
+
+ /* Adjust view to display selection. Doing iterations for first and last
+ * selected item makes view showing as much of the selection possible.
+ * Not really useful if tiles are (almost) bigger than viewbounds though. */
+ file_ensure_inside_viewbounds(region, sfile, sel->last);
+ file_ensure_inside_viewbounds(region, sfile, sel->first);
+}
+
static FileSelect file_select(
bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
{
@@ -330,16 +375,7 @@ static FileSelect file_select(
}
else if (sel.last >= 0) {
ARegion *region = CTX_wm_region(C);
- const FileLayout *layout = ED_fileselect_get_layout(sfile, region);
-
- /* Adjust view to display selection. Doing iterations for first and last
- * selected item makes view showing as much of the selection possible.
- * Not really useful if tiles are (almost) bigger than viewbounds though. */
- if (((layout->flag & FILE_LAYOUT_HOR) && region->winx > (1.2f * layout->tile_w)) ||
- ((layout->flag & FILE_LAYOUT_VER) && region->winy > (2.0f * layout->tile_h))) {
- file_ensure_inside_viewbounds(region, sfile, sel.last);
- file_ensure_inside_viewbounds(region, sfile, sel.first);
- }
+ file_ensure_selection_inside_viewbounds(region, sfile, &sel);
}
/* update operator for name change event */
@@ -926,6 +962,55 @@ void FILE_OT_select_all(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Select All Operator
+ * \{ */
+
+static int file_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ FileSelection sel = file_current_selection_range_get(sfile->files);
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+
+ if (sel.first == -1 && sel.last == -1 && params->active_file == -1) {
+ /* Nothing was selected. */
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Extend the selection area with the active file, as it may not be selected but still is
+ * important to have in view. */
+ if (sel.first == -1 || params->active_file < sel.first) {
+ sel.first = params->active_file;
+ }
+ if (sel.last == -1 || params->active_file > sel.last) {
+ sel.last = params->active_file;
+ }
+
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ file_ensure_selection_inside_viewbounds(region, sfile, &sel);
+
+ file_draw_check(C);
+ WM_event_add_mousemove(CTX_wm_window(C));
+ ED_area_tag_redraw(area);
+
+ return OPERATOR_FINISHED;
+}
+
+void FILE_OT_view_selected(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Frame Selected";
+ ot->description = "Scroll the selected files into view";
+ ot->idname = "FILE_OT_view_selected";
+
+ /* api callbacks */
+ ot->exec = file_view_selected_exec;
+ ot->poll = ED_operator_file_active;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Select Bookmark Operator
* \{ */
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 33c37875372..f5ec9a0e8a1 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -410,14 +410,14 @@ typedef struct FileList {
/* Set given path as root directory,
* if last bool is true may change given string in place to a valid value.
* Returns True if valid dir. */
- bool (*checkdirf)(struct FileList *, char *, const bool);
+ bool (*check_dir_fn)(struct FileList *, char *, const bool);
/* Fill filelist (to be called by read job). */
- void (*read_jobf)(
+ void (*read_job_fn)(
Main *, struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
/* Filter an entry of current filelist. */
- bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *);
+ bool (*filter_fn)(struct FileListInternEntry *, const char *, FileListFilter *);
short tags; /* FileListTags */
} FileList;
@@ -963,7 +963,7 @@ void filelist_filter(FileList *filelist)
/* Filter remap & count how many files are left after filter in a single loop. */
for (file = filelist->filelist_intern.entries.first; file; file = file->next) {
- if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) {
+ if (filelist->filter_fn(file, filelist->filelist.root, &filelist->filter_data)) {
filtered_tmp[num_filtered++] = file;
}
}
@@ -1742,25 +1742,25 @@ void filelist_settype(FileList *filelist, short type)
filelist->tags = 0;
switch (filelist->type) {
case FILE_MAIN:
- filelist->checkdirf = filelist_checkdir_main;
- filelist->read_jobf = filelist_readjob_main;
- filelist->filterf = is_filtered_main;
+ filelist->check_dir_fn = filelist_checkdir_main;
+ filelist->read_job_fn = filelist_readjob_main;
+ filelist->filter_fn = is_filtered_main;
break;
case FILE_LOADLIB:
- filelist->checkdirf = filelist_checkdir_lib;
- filelist->read_jobf = filelist_readjob_lib;
- filelist->filterf = is_filtered_lib;
+ filelist->check_dir_fn = filelist_checkdir_lib;
+ filelist->read_job_fn = filelist_readjob_lib;
+ filelist->filter_fn = is_filtered_lib;
break;
case FILE_MAIN_ASSET:
- filelist->checkdirf = filelist_checkdir_main_assets;
- filelist->read_jobf = filelist_readjob_main_assets;
- filelist->filterf = is_filtered_main_assets;
+ filelist->check_dir_fn = filelist_checkdir_main_assets;
+ filelist->read_job_fn = filelist_readjob_main_assets;
+ filelist->filter_fn = is_filtered_main_assets;
filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA | FILELIST_TAGS_NO_THREADS;
break;
default:
- filelist->checkdirf = filelist_checkdir_dir;
- filelist->read_jobf = filelist_readjob_dir;
- filelist->filterf = is_filtered_file;
+ filelist->check_dir_fn = filelist_checkdir_dir;
+ filelist->read_job_fn = filelist_readjob_dir;
+ filelist->filter_fn = is_filtered_file;
break;
}
@@ -1867,7 +1867,7 @@ const char *filelist_dir(struct FileList *filelist)
bool filelist_is_dir(struct FileList *filelist, const char *path)
{
- return filelist->checkdirf(filelist, (char *)path, false);
+ return filelist->check_dir_fn(filelist, (char *)path, false);
}
/**
@@ -1879,7 +1879,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir)
BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir);
- const bool is_valid_path = filelist->checkdirf(filelist, r_dir, !allow_invalid);
+ const bool is_valid_path = filelist->check_dir_fn(filelist, r_dir, !allow_invalid);
BLI_assert(is_valid_path || allow_invalid);
UNUSED_VARS_NDEBUG(is_valid_path);
@@ -1990,9 +1990,7 @@ static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry)
filelist_entry_free(entry);
}
-static FileDirEntry *filelist_file_ex(struct FileList *filelist,
- const int index,
- const bool use_request)
+FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request)
{
FileDirEntry *ret = NULL, *old;
FileListEntryCache *cache = &filelist->filelist_cache;
@@ -2703,6 +2701,19 @@ uint filelist_entry_select_index_get(FileList *filelist, const int index, FileCh
return 0;
}
+bool filelist_entry_is_selected(FileList *filelist, const int index)
+{
+ BLI_assert(index >= 0 && index < filelist->filelist.nbr_entries_filtered);
+ FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
+
+ /* BLI_ghash_lookup returns NULL if not found, which gets mapped to 0, which gets mapped to
+ * "not selected". */
+ const uint selection_state = POINTER_AS_UINT(
+ BLI_ghash_lookup(filelist->selection_state, intern_entry->uuid));
+
+ return selection_state != 0;
+}
+
/**
* Set selection of the '..' parent entry, but only if it's actually visible.
*/
@@ -3358,13 +3369,13 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update
BLI_mutex_unlock(&flrj->lock);
- flrj->tmp_filelist->read_jobf(flrj->current_main,
- flrj->tmp_filelist,
- flrj->main_name,
- stop,
- do_update,
- progress,
- &flrj->lock);
+ flrj->tmp_filelist->read_job_fn(flrj->current_main,
+ flrj->tmp_filelist,
+ flrj->main_name,
+ stop,
+ do_update,
+ progress,
+ &flrj->lock);
}
static void filelist_readjob_update(void *flrjv)
@@ -3464,7 +3475,7 @@ void filelist_readjob_start(FileList *filelist, const bContext *C)
filelist_readjob_endjob(flrj);
filelist_readjob_free(flrj);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED, NULL);
return;
}
@@ -3476,7 +3487,10 @@ void filelist_readjob_start(FileList *filelist, const bContext *C)
WM_JOB_PROGRESS,
WM_JOB_TYPE_FILESEL_READDIR);
WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free);
- WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST);
+ WM_jobs_timer(wm_job,
+ 0.01,
+ NC_SPACE | ND_SPACE_FILE_LIST,
+ NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED);
WM_jobs_callbacks(
wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob);
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index 16984bb6e43..9eb70dd8437 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -93,6 +93,8 @@ void filelist_setdir(struct FileList *filelist, char *r_dir);
int filelist_files_ensure(struct FileList *filelist);
int filelist_needs_reading(struct FileList *filelist);
FileDirEntry *filelist_file(struct FileList *filelist, int index);
+FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request);
+
int filelist_file_findpath(struct FileList *filelist, const char *file);
struct ID *filelist_file_get_id(const struct FileDirEntry *file);
FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]);
@@ -126,6 +128,7 @@ unsigned int filelist_entry_select_get(struct FileList *filelist,
unsigned int filelist_entry_select_index_get(struct FileList *filelist,
const int index,
FileCheckType check);
+bool filelist_entry_is_selected(struct FileList *filelist, const int index);
void filelist_entry_parent_select_set(struct FileList *filelist,
FileSelType select,
unsigned int flag,
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 6917893ab5f..7015ca970a3 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -454,6 +454,66 @@ bool ED_fileselect_is_asset_browser(const SpaceFile *sfile)
return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS);
}
+struct ID *ED_fileselect_active_asset_get(const SpaceFile *sfile)
+{
+ if (!ED_fileselect_is_asset_browser(sfile)) {
+ return NULL;
+ }
+
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ const FileDirEntry *file = filelist_file(sfile->files, params->active_file);
+ if (file == NULL) {
+ return NULL;
+ }
+
+ return filelist_file_get_id(file);
+}
+
+static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data)
+{
+ ID *asset_id = (ID *)custom_data;
+ ED_fileselect_activate_by_id(sfile, asset_id, false);
+}
+
+void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool deferred)
+{
+ if (!ED_fileselect_is_asset_browser(sfile)) {
+ return;
+ }
+
+ /* If there are filelist operations running now ("pending" true) or soon ("force reset" true),
+ * there is a fair chance that the to-be-activated ID will only be present after these operations
+ * have completed. Defer activation until then. */
+ if (deferred || filelist_pending(sfile->files) || filelist_needs_force_reset(sfile->files)) {
+ /* This should be thread-safe, as this function is likely called from the main thread, and
+ * notifiers (which cause a call to the on-reload callback function) are handled on the main
+ * thread as well. */
+ file_on_reload_callback_register(sfile, on_reload_activate_by_id, asset_id);
+ return;
+ }
+
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ struct FileList *files = sfile->files;
+
+ const int num_files_filtered = filelist_files_ensure(files);
+ for (int file_index = 0; file_index < num_files_filtered; ++file_index) {
+ const FileDirEntry *file = filelist_file_ex(files, file_index, false);
+
+ if (filelist_file_get_id(file) != asset_id) {
+ filelist_entry_select_set(files, file, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
+ continue;
+ }
+
+ params->active_file = file_index;
+ filelist_entry_select_set(files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
+
+ /* Keep looping to deselect the other files. */
+ }
+
+ WM_main_add_notifier(NC_ASSET | NA_ACTIVATED, NULL);
+ WM_main_add_notifier(NC_ASSET | NA_SELECTED, NULL);
+}
+
/* The subset of FileSelectParams.flag items we store into preferences. Note that FILE_SORT_ALPHA
* may also be remembered, but only conditionally. */
#define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT)
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index b175844a710..83bb8abf5d8 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -173,6 +173,7 @@ static void file_free(SpaceLink *sl)
MEM_SAFE_FREE(sfile->params);
MEM_SAFE_FREE(sfile->asset_params);
+ MEM_SAFE_FREE(sfile->runtime);
if (sfile->layout) {
MEM_freeN(sfile->layout);
@@ -188,6 +189,10 @@ static void file_init(wmWindowManager *UNUSED(wm), ScrArea *area)
if (sfile->layout) {
sfile->layout->dirty = true;
}
+
+ if (sfile->runtime == NULL) {
+ sfile->runtime = MEM_callocN(sizeof(*sfile->runtime), __func__);
+ }
}
static void file_exit(wmWindowManager *wm, ScrArea *area)
@@ -209,6 +214,7 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
/* clear or remove stuff from old */
sfilen->op = NULL; /* file window doesn't own operators */
+ sfilen->runtime = NULL;
sfilen->previews_timer = NULL;
sfilen->smoothscroll_timer = NULL;
@@ -392,6 +398,26 @@ static void file_refresh(const bContext *C, ScrArea *area)
ED_area_tag_redraw(area);
}
+void file_on_reload_callback_register(SpaceFile *sfile,
+ onReloadFn callback,
+ onReloadFnData custom_data)
+{
+ sfile->runtime->on_reload = callback;
+ sfile->runtime->on_reload_custom_data = custom_data;
+}
+
+static void file_on_reload_callback_call(SpaceFile *sfile)
+{
+ if (sfile->runtime->on_reload == NULL) {
+ return;
+ }
+
+ sfile->runtime->on_reload(sfile, sfile->runtime->on_reload_custom_data);
+
+ sfile->runtime->on_reload = NULL;
+ sfile->runtime->on_reload_custom_data = NULL;
+}
+
static void file_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
@@ -419,12 +445,27 @@ static void file_listener(const wmSpaceTypeListenerParams *params)
}
break;
}
+ switch (wmn->action) {
+ case NA_JOB_FINISHED:
+ file_on_reload_callback_call(sfile);
+ break;
+ }
break;
case NC_ASSET: {
- if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) {
- /* Full refresh of the file list if local asset data was changed. Refreshing this view is
- * cheap and users expect this to be updated immediately. */
- file_tag_reset_list(area, sfile);
+ switch (wmn->action) {
+ case NA_SELECTED:
+ case NA_ACTIVATED:
+ ED_area_tag_refresh(area);
+ break;
+ case NA_ADDED:
+ case NA_REMOVED:
+ case NA_EDITED:
+ if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) {
+ /* Full refresh of the file list if local asset data was changed. Refreshing this view
+ * is cheap and users expect this to be updated immediately. */
+ file_tag_reset_list(area, sfile);
+ }
+ break;
}
break;
}
@@ -464,8 +505,7 @@ static void file_main_region_listener(const wmRegionListenerParams *params)
}
break;
case NC_ID:
- if (ELEM(wmn->action, NA_RENAME)) {
- /* In case the filelist shows ID names. */
+ if (ELEM(wmn->action, NA_SELECTED, NA_ACTIVATED, NA_RENAME)) {
ED_region_tag_redraw(region);
}
break;
@@ -620,6 +660,7 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_smoothscroll);
WM_operatortype_append(FILE_OT_filepath_drop);
WM_operatortype_append(FILE_OT_start_filter);
+ WM_operatortype_append(FILE_OT_view_selected);
}
/* NOTE: do not add .blend file reading on this level */
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index 4752f62b58c..c5358cdfa5b 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -35,6 +35,7 @@
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
+#include "BKE_action.h"
#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -579,8 +580,13 @@ static void draw_fcurve_samples(SpaceGraph *sipo, ARegion *region, FCurve *fcu)
/* Helper func - just draw the F-Curve by sampling the visible region
* (for drawing curves with modifiers). */
-static void draw_fcurve_curve(
- bAnimContext *ac, ID *id, FCurve *fcu_, View2D *v2d, uint pos, const bool use_nla_remap)
+static void draw_fcurve_curve(bAnimContext *ac,
+ ID *id,
+ FCurve *fcu_,
+ View2D *v2d,
+ uint pos,
+ const bool use_nla_remap,
+ const bool draw_extrapolation)
{
SpaceGraph *sipo = (SpaceGraph *)ac->sl;
short mapping_flag = ANIM_get_normalization_flags(ac);
@@ -641,40 +647,90 @@ static void draw_fcurve_curve(
/* the start/end times are simply the horizontal extents of the 'cur' rect */
float stime = v2d->cur.xmin;
- float etime = v2d->cur.xmax +
- samplefreq; /* + samplefreq here so that last item gets included... */
+ float etime = v2d->cur.xmax;
- /* at each sampling interval, add a new vertex
- * - apply the unit correction factor to the calculated values so that
- * the displayed values appear correctly in the viewport
- */
+ AnimData *adt = use_nla_remap ? BKE_animdata_from_id(id) : NULL;
+
+ /* If not drawing extrapolation, then change fcurve drawing bounds to its keyframe bounds clamped
+ * by graph editor bounds. */
+ if (!draw_extrapolation) {
+ float fcu_start = 0;
+ float fcu_end = 0;
+ BKE_fcurve_calc_range(fcu_, &fcu_start, &fcu_end, false, false);
- int n = roundf((etime - stime) / samplefreq);
+ fcu_start = BKE_nla_tweakedit_remap(adt, fcu_start, NLATIME_CONVERT_MAP);
+ fcu_end = BKE_nla_tweakedit_remap(adt, fcu_end, NLATIME_CONVERT_MAP);
- if (n > 0) {
- immBegin(GPU_PRIM_LINE_STRIP, (n + 1));
+ /* Account for reversed NLA strip effect. */
+ if (fcu_end < fcu_start) {
+ SWAP(float, fcu_start, fcu_end);
+ }
- AnimData *adt = use_nla_remap ? BKE_animdata_from_id(id) : NULL;
- /* NLA remapping is linear so we don't have to remap per iteration. */
- const float eval_start = BKE_nla_tweakedit_remap(adt, stime, NLATIME_CONVERT_UNMAP);
- const float eval_freq = BKE_nla_tweakedit_remap(
- adt, stime + samplefreq, NLATIME_CONVERT_UNMAP) -
- eval_start;
+ /* Clamp to graph editor rendering bounds. */
+ stime = max_ff(stime, fcu_start);
+ etime = min_ff(etime, fcu_end);
+ }
+
+ const int total_samples = roundf((etime - stime) / samplefreq);
+ if (total_samples <= 0) {
+ return;
+ }
- for (int i = 0; i <= n; i++) {
- float ctime = stime + i * samplefreq;
- const float eval_time = eval_start + i * eval_freq;
- immVertex2f(pos, ctime, (evaluate_fcurve(&fcurve_for_draw, eval_time) + offset) * unitFac);
+ /* NLA remapping is linear so we don't have to remap per iteration. */
+ const float eval_start = BKE_nla_tweakedit_remap(adt, stime, NLATIME_CONVERT_UNMAP);
+ const float eval_freq = BKE_nla_tweakedit_remap(adt, stime + samplefreq, NLATIME_CONVERT_UNMAP) -
+ eval_start;
+ const float eval_end = BKE_nla_tweakedit_remap(adt, etime, NLATIME_CONVERT_UNMAP);
+
+ immBegin(GPU_PRIM_LINE_STRIP, (total_samples + 1));
+
+ /* At each sampling interval, add a new vertex.
+ *
+ * Apply the unit correction factor to the calculated values so that the displayed values appear
+ * correctly in the viewport.
+ */
+ for (int i = 0; i < total_samples; i++) {
+ const float ctime = stime + i * samplefreq;
+ float eval_time = eval_start + i * eval_freq;
+
+ /* Prevent drawing past bounds, due to floating point problems.
+ * User-wise, prevent visual flickering.
+ *
+ * This is to cover the case where:
+ * eval_start + total_samples * eval_freq > eval_end
+ * due to floating point problems.
+ */
+ if (eval_time > eval_end) {
+ eval_time = eval_end;
}
- immEnd();
+ immVertex2f(pos, ctime, (evaluate_fcurve(&fcurve_for_draw, eval_time) + offset) * unitFac);
}
+
+ /* Ensure we include end boundary point.
+ * User-wise, prevent visual flickering.
+ *
+ * This is to cover the case where:
+ * eval_start + total_samples * eval_freq < eval_end
+ * due to floating point problems.
+ */
+ immVertex2f(pos, etime, (evaluate_fcurve(&fcurve_for_draw, eval_end) + offset) * unitFac);
+
+ immEnd();
}
/* helper func - draw a samples-based F-Curve */
-static void draw_fcurve_curve_samples(
- bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, const uint shdr_pos)
+static void draw_fcurve_curve_samples(bAnimContext *ac,
+ ID *id,
+ FCurve *fcu,
+ View2D *v2d,
+ const uint shdr_pos,
+ const bool draw_extrapolation)
{
+ if (!draw_extrapolation && fcu->totvert == 1) {
+ return;
+ }
+
FPoint *prevfpt = fcu->fpt;
FPoint *fpt = prevfpt + 1;
float fac, v[2];
@@ -683,11 +739,13 @@ static void draw_fcurve_curve_samples(
short mapping_flag = ANIM_get_normalization_flags(ac);
int count = fcu->totvert;
- if (prevfpt->vec[0] > v2d->cur.xmin) {
+ const bool extrap_left = draw_extrapolation && prevfpt->vec[0] > v2d->cur.xmin;
+ if (extrap_left) {
count++;
}
- if ((prevfpt + b - 1)->vec[0] < v2d->cur.xmax) {
+ const bool extrap_right = draw_extrapolation && (prevfpt + b - 1)->vec[0] < v2d->cur.xmax;
+ if (extrap_right) {
count++;
}
@@ -700,7 +758,7 @@ static void draw_fcurve_curve_samples(
immBegin(GPU_PRIM_LINE_STRIP, count);
/* extrapolate to left? - left-side of view comes before first keyframe? */
- if (prevfpt->vec[0] > v2d->cur.xmin) {
+ if (extrap_left) {
v[0] = v2d->cur.xmin;
/* y-value depends on the interpolation */
@@ -734,7 +792,7 @@ static void draw_fcurve_curve_samples(
}
/* extrapolate to right? (see code for left-extrapolation above too) */
- if (prevfpt->vec[0] < v2d->cur.xmax) {
+ if (extrap_right) {
v[0] = v2d->cur.xmax;
/* y-value depends on the interpolation */
@@ -779,8 +837,13 @@ static bool fcurve_can_use_simple_bezt_drawing(FCurve *fcu)
}
/* helper func - draw one repeat of an F-Curve (using Bezier curve approximations) */
-static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, uint pos)
+static void draw_fcurve_curve_bezts(
+ bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, uint pos, const bool draw_extrapolation)
{
+ if (!draw_extrapolation && fcu->totvert == 1) {
+ return;
+ }
+
BezTriple *prevbezt = fcu->bezt;
BezTriple *bezt = prevbezt + 1;
float v1[2], v2[2], v3[2], v4[2];
@@ -803,7 +866,7 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
immBeginAtMost(GPU_PRIM_LINE_STRIP, (b * 32 + 3));
/* extrapolate to left? */
- if (prevbezt->vec[1][0] > v2d->cur.xmin) {
+ if (draw_extrapolation && prevbezt->vec[1][0] > v2d->cur.xmin) {
/* left-side of view comes before first keyframe, so need to extend as not cyclic */
v1[0] = v2d->cur.xmin;
@@ -923,7 +986,7 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
}
/* extrapolate to right? (see code for left-extrapolation above too) */
- if (prevbezt->vec[1][0] < v2d->cur.xmax) {
+ if (draw_extrapolation && prevbezt->vec[1][0] < v2d->cur.xmax) {
v1[0] = v2d->cur.xmax;
/* y-value depends on the interpolation */
@@ -1026,6 +1089,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
immUniformColor3fvAlpha(fcu->color, fcurve_display_alpha(fcu));
}
+ const bool draw_extrapolation = (sipo->flag & SIPO_NO_DRAW_EXTRAPOLATION) == 0;
/* draw F-Curve */
if ((fcu->modifiers.first) || (fcu->flag & FCURVE_INT_VALUES)) {
/* draw a curve affected by modifiers or only allowed to have integer values
@@ -1039,25 +1103,25 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
* curve itself. Afterward, we go back and redo the keyframe remapping so the controls are
* drawn properly. */
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, true, false);
- draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, true);
+ draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, true, draw_extrapolation);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, false, false);
}
else {
- draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, false);
+ draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, false, draw_extrapolation);
}
}
else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) {
/* just draw curve based on defined data (i.e. no modifiers) */
if (fcu->bezt) {
if (fcurve_can_use_simple_bezt_drawing(fcu)) {
- draw_fcurve_curve_bezts(ac, ale->id, fcu, &region->v2d, shdr_pos);
+ draw_fcurve_curve_bezts(ac, ale->id, fcu, &region->v2d, shdr_pos, draw_extrapolation);
}
else {
- draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, false);
+ draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, false, draw_extrapolation);
}
}
else if (fcu->fpt) {
- draw_fcurve_curve_samples(ac, ale->id, fcu, &region->v2d, shdr_pos);
+ draw_fcurve_curve_samples(ac, ale->id, fcu, &region->v2d, shdr_pos, draw_extrapolation);
}
}
@@ -1278,6 +1342,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region
immUniform1f("dash_width", 20.0f);
immUniform1f("dash_factor", 0.5f);
+ const bool draw_extrapolation = (sipo->flag & SIPO_NO_DRAW_EXTRAPOLATION) == 0;
/* the ghost curves are simply sampled F-Curves stored in sipo->runtime.ghost_curves */
for (fcu = sipo->runtime.ghost_curves.first; fcu; fcu = fcu->next) {
/* set whatever color the curve has set
@@ -1287,7 +1352,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region
immUniformColor3fvAlpha(fcu->color, 0.5f);
/* simply draw the stored samples */
- draw_fcurve_curve_samples(ac, NULL, fcu, &region->v2d, shdr_pos);
+ draw_fcurve_curve_samples(ac, NULL, fcu, &region->v2d, shdr_pos, draw_extrapolation);
}
immUnbindProgram();
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 3e52dc7377b..4174e1c63ae 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -187,11 +187,11 @@ static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo)
strcpy(mode_str, TIP_("Decimate Keyframes"));
if (hasNumInput(&dgo->num)) {
- char str_offs[NUM_STR_REP_LEN];
+ char str_ofs[NUM_STR_REP_LEN];
- outputNumInput(&dgo->num, str_offs, &dgo->scene->unit);
+ outputNumInput(&dgo->num, str_ofs, &dgo->scene->unit);
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
else {
float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 977c2053187..a9a7ef5a0a2 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -3385,7 +3385,12 @@ static void std_node_socket_draw(
}
}
break;
- case SOCK_RGBA:
+ case SOCK_RGBA: {
+ uiLayout *row = uiLayoutSplit(layout, 0.5f, false);
+ uiItemL(row, text, 0);
+ uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
+ break;
+ }
case SOCK_STRING: {
uiLayout *row = uiLayoutSplit(layout, 0.5f, false);
uiItemL(row, text, 0);
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index 982c57eb3ec..b03346577a8 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -75,15 +75,9 @@ static void attribute_search_update_fn(
UI_search_item_add(items, str, (void *)str, ICON_X, 0, 0);
}
- /* Skip the filter when the menu is first opened, so all of the items are visible. */
- if (is_first) {
- for (const std::string &attribute_name : attribute_name_hints) {
- /* Just use the pointer to the name string as the search data,
- * since it's not used anyway but we need a pointer. */
- UI_search_item_add(items, attribute_name.c_str(), (void *)&attribute_name, ICON_NONE, 0, 0);
- }
- return;
- }
+ /* Don't filter when the menu is first opened, but still run the search
+ * so the items are in the same order they will appear in while searching. */
+ const char *string = is_first ? "" : str;
StringSearch *search = BLI_string_search_new();
for (const std::string &attribute_name : attribute_name_hints) {
@@ -91,7 +85,7 @@ static void attribute_search_update_fn(
}
std::string **filtered_items;
- const int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items);
+ const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
for (const int i : IndexRange(filtered_amount)) {
std::string *item = filtered_items[i];
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index f0e3f5442cc..b0c0f660717 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -826,11 +826,22 @@ static void ui_node_draw_input(
case SOCK_INT:
case SOCK_BOOLEAN:
case SOCK_RGBA:
- case SOCK_STRING:
uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
uiItemDecoratorR(
split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX);
break;
+ case SOCK_STRING: {
+ const bNodeTree *node_tree = (const bNodeTree *)nodeptr.owner_id;
+ if (node_tree->type == NTREE_GEOMETRY) {
+ node_geometry_add_attribute_search_button(node_tree, node, &inputptr, row);
+ }
+ else {
+ uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
+ }
+ uiItemDecoratorR(
+ split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX);
+ break;
+ }
default:
add_dummy_decorator = true;
}
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index d54265aa292..eb3371e989a 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -56,8 +56,15 @@ set(SRC
tree/tree_display_view_layer.cc
tree/tree_element.cc
tree/tree_element_anim_data.cc
- tree/tree_element_driver_base.cc
+ tree/tree_element_collection.cc
+ tree/tree_element_driver.cc
+ tree/tree_element_gpencil_layer.cc
+ tree/tree_element_id.cc
+ tree/tree_element_id_library.cc
+ tree/tree_element_id_scene.cc
tree/tree_element_nla.cc
+ tree/tree_element_scene_objects.cc
+ tree/tree_element_view_layer.cc
outliner_intern.h
tree/tree_display.h
@@ -65,8 +72,15 @@ set(SRC
tree/tree_element.h
tree/tree_element.hh
tree/tree_element_anim_data.hh
- tree/tree_element_driver_base.hh
+ tree/tree_element_collection.hh
+ tree/tree_element_driver.hh
+ tree/tree_element_gpencil_layer.hh
+ tree/tree_element_id.hh
+ tree/tree_element_id_library.hh
+ tree/tree_element_id_scene.hh
tree/tree_element_nla.hh
+ tree/tree_element_scene_objects.hh
+ tree/tree_element_view_layer.hh
)
set(LIB
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index ef5733fe375..d54e35f659c 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -71,7 +71,7 @@ bool outliner_is_collection_tree_element(const TreeElement *te)
TSE_VIEW_COLLECTION_BASE)) {
return true;
}
- if (tselem->type == 0 && te->idcode == ID_GR) {
+ if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_GR) {
return true;
}
@@ -94,7 +94,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
Scene *scene = (Scene *)tselem->id;
return scene->master_collection;
}
- if (tselem->type == 0 && te->idcode == ID_GR) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_GR)) {
return (Collection *)tselem->id;
}
@@ -111,7 +111,7 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu
return TRAVERSE_CONTINUE;
}
- if (tselem->type || (tselem->id && GS(tselem->id->name) != ID_GR)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id && GS(tselem->id->name) != ID_GR)) {
return TRAVERSE_SKIP_CHILDS;
}
@@ -127,7 +127,7 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom
return TRAVERSE_CONTINUE;
}
- if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
return TRAVERSE_SKIP_CHILDS;
}
@@ -1458,7 +1458,7 @@ static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void
BLI_gset_add(data->collections_to_edit, lc);
}
}
- else if (tselem->type == 0 && te->idcode == ID_OB) {
+ else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
Object *ob = (Object *)tselem->id;
Base *base = BKE_view_layer_base_find(data->view_layer, ob);
BLI_gset_add(data->bases_to_edit, base);
diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.c
index e2b3b79e027..4293d8da73e 100644
--- a/source/blender/editors/space_outliner/outliner_context.c
+++ b/source/blender/editors/space_outliner/outliner_context.c
@@ -34,7 +34,7 @@ static void outliner_context_selected_ids_recursive(const ListBase *subtree,
{
LISTBASE_FOREACH (const TreeElement *, te, subtree) {
const TreeStoreElem *tse = TREESTORE(te);
- if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, 0, TSE_LAYER_COLLECTION))) {
+ if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, TSE_SOME_ID, TSE_LAYER_COLLECTION))) {
CTX_data_id_list_add(result, tse->id);
}
outliner_context_selected_ids_recursive(&te->subtree, result);
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index 3090cab75ae..01fb0fc6f78 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -124,7 +124,7 @@ static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode
TreeElement *te = outliner_drop_find(C, event);
TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL;
- if (te && te->idcode == idcode && tselem->type == 0) {
+ if (te && (te->idcode == idcode) && (tselem->type == TSE_SOME_ID)) {
return tselem->id;
}
return NULL;
@@ -215,7 +215,7 @@ static bool is_collection_element(TreeElement *te)
static bool is_object_element(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
- return tselem->type == 0 && te->idcode == ID_OB;
+ return (tselem->type == TSE_SOME_ID) && te->idcode == ID_OB;
}
static bool is_pchan_element(TreeElement *te)
@@ -281,7 +281,7 @@ static int outliner_get_insert_index(TreeElement *drag_te,
static bool parent_drop_allowed(TreeElement *te, Object *potential_child)
{
TreeStoreElem *tselem = TREESTORE(te);
- if (te->idcode != ID_OB || tselem->type != 0) {
+ if ((te->idcode != ID_OB) || (tselem->type != TSE_SOME_ID)) {
return false;
}
@@ -421,7 +421,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
TreeElement *te = outliner_drop_find(C, event);
TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
- if (!(te && te->idcode == ID_OB && tselem->type == 0)) {
+ if (!(te && (te->idcode == ID_OB) && (tselem->type == TSE_SOME_ID))) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 008ae727947..690adb09570 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -675,7 +675,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
if (ts && tselem) {
TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
BLI_libblock_ensure_unique_name(bmain, tselem->id->name);
switch (GS(tselem->id->name)) {
@@ -1100,11 +1100,11 @@ static void outliner_draw_restrictbuts(uiBlock *block,
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
}
- else if ((tselem->type == 0 && te->idcode == ID_OB) &&
+ else if (((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) &&
(te->flag & TE_CHILD_NOT_IN_COLLECTION)) {
/* Don't show restrict columns for children that are not directly inside the collection. */
}
- else if (tselem->type == 0 && te->idcode == ID_OB) {
+ else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
PointerRNA ptr;
Object *ob = (Object *)tselem->id;
RNA_id_pointer_create(&ob->id, &ptr);
@@ -1699,7 +1699,7 @@ static void outliner_draw_userbuts(uiBlock *block,
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
uiBut *bt;
ID *id = tselem->id;
const char *tip = NULL;
@@ -1949,7 +1949,7 @@ static void outliner_draw_mode_column_toggle(uiBlock *block,
TreeStoreElem *tselem,
const bool lock_object_modes)
{
- if (tselem->type != 0 || te->idcode != ID_OB) {
+ if ((tselem->type != TSE_SOME_ID) || (te->idcode != ID_OB)) {
return;
}
@@ -2046,7 +2046,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
{
TreeElementIcon data = {0};
- if (tselem->type) {
+ if (tselem->type != TSE_SOME_ID) {
switch (tselem->type) {
case TSE_ANIM_DATA:
data.icon = ICON_ANIM_DATA; /* XXX */
@@ -2825,7 +2825,8 @@ int tree_element_id_type_to_index(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
- const int id_index = tselem->type == 0 ? BKE_idtype_idcode_to_index(te->idcode) : INDEX_ID_GR;
+ const int id_index = (tselem->type == TSE_SOME_ID) ? BKE_idtype_idcode_to_index(te->idcode) :
+ INDEX_ID_GR;
if (id_index < INDEX_ID_OB) {
return id_index;
}
@@ -2862,9 +2863,9 @@ static void outliner_draw_iconrow(bContext *C,
te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED);
/* object hierarchy always, further constrained on level */
- if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) {
+ if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) {
/* active blocks get white circle */
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
if (te->idcode == ID_OB) {
active = (tvc->obact == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
}
@@ -2879,7 +2880,7 @@ static void outliner_draw_iconrow(bContext *C,
active = tree_element_type_active_state_get(C, tvc, te, tselem);
}
- if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) {
+ if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) {
outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1);
}
else {
@@ -2954,7 +2955,7 @@ static bool element_should_draw_faded(const TreeViewContext *tvc,
const TreeElement *te,
const TreeStoreElem *tselem)
{
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
switch (te->idcode) {
case ID_OB: {
const Object *ob = (const Object *)tselem->id;
@@ -3023,7 +3024,7 @@ static void outliner_draw_tree_element(bContext *C,
GPU_blend(GPU_BLEND_ALPHA);
/* Colors for active/selected data. */
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
if (te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
@@ -3080,7 +3081,7 @@ static void outliner_draw_tree_element(bContext *C,
if (tselem->type == TSE_VIEW_COLLECTION_BASE) {
/* Scene collection in view layer can't expand/collapse. */
}
- else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) ||
+ else if (te->subtree.first || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) ||
(te->flag & TE_LAZY_CLOSED)) {
/* Open/close icon, only when sub-levels, except for scene. */
int icon_x = startx;
@@ -3117,7 +3118,7 @@ static void outliner_draw_tree_element(bContext *C,
offsx += 2 * ufac;
}
- if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) ||
+ if (ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION) ||
((tselem->type == TSE_RNA_STRUCT) && RNA_struct_is_ID(te->rnaptr.type))) {
const BIFIconID lib_icon = UI_icon_from_library(tselem->id);
if (lib_icon != ICON_NONE) {
@@ -3143,7 +3144,7 @@ static void outliner_draw_tree_element(bContext *C,
/* Closed item, we draw the icons, not when it's a scene, or master-server list though. */
if (!TSELEM_OPEN(tselem, space_outliner)) {
if (te->subtree.first) {
- if (tselem->type == 0 && te->idcode == ID_SCE) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) {
/* Pass. */
}
/* this tree element always has same amount of branches, so don't draw */
@@ -3210,7 +3211,7 @@ static bool subtree_contains_object(ListBase *lb)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
return true;
}
}
@@ -3265,7 +3266,7 @@ static void outliner_draw_hierarchy_lines_recursive(uint pos,
y = *starty;
}
- else if (tselem->type == 0 && te->idcode == ID_OB) {
+ else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
if (subtree_contains_object(&te->subtree)) {
draw_hierarchy_line = true;
is_object_line = true;
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 09aa268d856..18abe17d515 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -464,7 +464,8 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
ID *id = tselem->id;
BLI_assert(id != NULL);
- BLI_assert(ELEM(tselem->type, 0 && te->idcode != 0, TSE_LAYER_COLLECTION));
+ BLI_assert(((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
+ (tselem->type == TSE_LAYER_COLLECTION));
UNUSED_VARS_NDEBUG(te);
if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) {
@@ -638,7 +639,7 @@ static bool outliner_id_remap_find_tree_element(bContext *C,
if (y > te->ys && y < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && tselem->id) {
+ if ((tselem->type == TSE_SOME_ID) && tselem->id) {
printf("found id %s (%p)!\n", tselem->id->name, tselem->id);
RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
@@ -763,7 +764,7 @@ static int outliner_id_copy_tag(SpaceOutliner *space_outliner, ListBase *tree)
TreeStoreElem *tselem = TREESTORE(te);
/* if item is selected and is an ID, tag it as needing to be copied. */
- if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
+ if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
ID *id = tselem->id;
if (!(id->tag & LIB_TAG_DOIT)) {
BKE_copybuffer_tag_ID(tselem->id);
@@ -1640,7 +1641,7 @@ static int subtree_has_objects(ListBase *lb)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
return 1;
}
if (subtree_has_objects(&te->subtree)) {
@@ -1658,7 +1659,7 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outli
TreeStoreElem *tselem = TREESTORE(te);
if (ELEM(tselem->type,
- 0,
+ TSE_SOME_ID,
TSE_SCENE_OBJECTS_BASE,
TSE_VIEW_COLLECTION_BASE,
TSE_LAYER_COLLECTION)) {
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index e31af48ab7e..d53a37fa60e 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -198,7 +198,7 @@ void outliner_item_mode_toggle(bContext *C,
{
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
Object *ob = (Object *)tselem->id;
Base *base = BKE_view_layer_base_find(tvc->view_layer, ob);
@@ -301,7 +301,7 @@ static void tree_element_object_activate(bContext *C,
Object *ob = NULL;
/* if id is not object, we search back */
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
ob = (Object *)tselem->id;
}
else {
@@ -443,7 +443,7 @@ static void tree_element_world_activate(bContext *C, Scene *scene, TreeElement *
TreeElement *tep = te->parent;
if (tep) {
TreeStoreElem *tselem = TREESTORE(tep);
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
sce = (Scene *)tselem->id;
}
}
@@ -1165,7 +1165,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
int context = 0;
/* ID Types */
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
RNA_id_pointer_create(tselem->id, &ptr);
switch (te->idcode) {
@@ -1374,12 +1374,12 @@ static void do_outliner_item_activate_tree_element(bContext *C,
tvc->scene,
tvc->view_layer,
te,
- (extend && tselem->type == 0) ? OL_SETSEL_EXTEND :
- OL_SETSEL_NORMAL,
- recursive && tselem->type == 0);
+ (extend && tselem->type == TSE_SOME_ID) ? OL_SETSEL_EXTEND :
+ OL_SETSEL_NORMAL,
+ recursive && tselem->type == TSE_SOME_ID);
}
- if (tselem->type == 0) { /* The lib blocks. */
+ if (tselem->type == TSE_SOME_ID) { /* The lib blocks. */
if (do_activate_data == false) {
/* Only select in outliner. */
}
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c
index 8bd5e3a130a..6543a909a41 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.c
@@ -326,7 +326,7 @@ static void outliner_sync_selection_from_outliner(Scene *scene,
LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
if (sync_types->object) {
outliner_select_sync_to_object(view_layer, te, tselem, selected_items->objects);
}
@@ -503,7 +503,7 @@ static void outliner_sync_selection_to_outliner(ViewLayer *view_layer,
LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) {
if (sync_types->object) {
outliner_select_sync_from_object(view_layer, active_data->object, te, tselem);
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index b735064cfef..9af2ba6a82b 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -106,7 +106,7 @@ static void get_element_operation_type(
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
/* Layer collection points to collection ID. */
- if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
+ if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
if (*datalevel == 0) {
*datalevel = tselem->type;
}
@@ -402,7 +402,8 @@ static void outliner_do_libdata_operation(bContext *C,
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
- if ((tselem->type == 0 && te->idcode != 0) || tselem->type == TSE_LAYER_COLLECTION) {
+ if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
+ tselem->type == TSE_LAYER_COLLECTION) {
TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
operation_fn(C, reports, scene, te, tsep, tselem, user_data);
}
@@ -1044,7 +1045,7 @@ void outliner_do_object_operation_ex(bContext *C,
TreeStoreElem *tselem = TREESTORE(te);
bool select_handled = false;
if (tselem->flag & TSE_SELECTED) {
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
/* When objects selected in other scenes... dunno if that should be allowed. */
Scene *scene_owner = (Scene *)outliner_search_back(te, ID_SCE);
if (scene_owner && scene_act != scene_owner) {
@@ -1601,7 +1602,7 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void
return TRAVERSE_CONTINUE;
}
- if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
return TRAVERSE_SKIP_CHILDS;
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index f94f19246fa..6319b890b3b 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -1,4 +1,4 @@
-/*
+/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@@ -92,9 +92,6 @@
#endif
/* prototypes */
-static TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
- Collection *collection,
- TreeElement *ten);
static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner);
/* ********************************************************* */
@@ -274,7 +271,7 @@ static void outliner_add_bone(SpaceOutliner *space_outliner,
}
}
-static bool outliner_animdata_test(AnimData *adt)
+bool outliner_animdata_test(const AnimData *adt)
{
if (adt) {
return (adt->action || adt->drivers.first || adt->nla_tracks.first);
@@ -307,53 +304,13 @@ static void outliner_add_line_styles(SpaceOutliner *space_outliner,
continue;
}
linestyle->id.tag &= ~LIB_TAG_DOIT;
- outliner_add_element(space_outliner, lb, linestyle, te, 0, 0);
+ outliner_add_element(space_outliner, lb, linestyle, te, TSE_SOME_ID, 0);
}
}
}
}
#endif
-static void outliner_add_scene_contents(SpaceOutliner *space_outliner,
- ListBase *lb,
- Scene *sce,
- TreeElement *te)
-{
- /* View layers */
- TreeElement *ten = outliner_add_element(space_outliner, lb, sce, te, TSE_R_LAYER_BASE, 0);
- ten->name = IFACE_("View Layers");
-
- ViewLayer *view_layer;
- for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
- TreeElement *tenlay = outliner_add_element(
- space_outliner, &ten->subtree, sce, ten, TSE_R_LAYER, 0);
- tenlay->name = view_layer->name;
- tenlay->directdata = view_layer;
- }
-
- /* World */
- outliner_add_element(space_outliner, lb, sce->world, te, 0, 0);
-
- /* Collections */
- ten = outliner_add_element(space_outliner, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0);
- ten->name = IFACE_("Scene Collection");
- outliner_add_collection_recursive(space_outliner, sce->master_collection, ten);
-
- /* Objects */
- ten = outliner_add_element(space_outliner, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0);
- ten->name = IFACE_("Objects");
- FOREACH_SCENE_OBJECT_BEGIN (sce, ob) {
- outliner_add_element(space_outliner, &ten->subtree, ob, ten, 0, 0);
- }
- FOREACH_SCENE_OBJECT_END;
- outliner_make_object_parent_hierarchy(&ten->subtree);
-
- /* Animation Data */
- if (outliner_animdata_test(sce->adt)) {
- outliner_add_element(space_outliner, lb, sce, te, TSE_ANIM_DATA, 0);
- }
-}
-
/* Can be inlined if necessary. */
static void outliner_add_object_contents(SpaceOutliner *space_outliner,
TreeElement *te,
@@ -368,14 +325,14 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
&te->subtree,
ob->poselib,
te,
- 0,
+ TSE_SOME_ID,
0); /* XXX FIXME.. add a special type for this. */
if (ob->proxy && !ID_IS_LINKED(ob)) {
outliner_add_element(space_outliner, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
}
- outliner_add_element(space_outliner, &te->subtree, ob->data, te, 0, 0);
+ outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0);
if (ob->pose) {
bArmature *arm = ob->data;
@@ -458,7 +415,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
for (int a = 0; a < ob->totcol; a++) {
- outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, 0, a);
+ outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, TSE_SOME_ID, a);
}
if (!BLI_listbase_is_empty(&ob->constraints)) {
@@ -624,33 +581,8 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
/* duplicated group */
if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) {
- outliner_add_element(space_outliner, &te->subtree, ob->instance_collection, te, 0, 0);
- }
-}
-
-static void outliner_add_library_override_contents(SpaceOutliner *soops, TreeElement *te, ID *id)
-{
- if (!id->override_library) {
- return;
- }
-
- PointerRNA idpoin;
- RNA_id_pointer_create(id, &idpoin);
-
- PointerRNA override_ptr;
- PropertyRNA *override_prop;
- int index = 0;
- LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
- if (!BKE_lib_override_rna_property_find(&idpoin, op, &override_ptr, &override_prop)) {
- /* This is fine, override properties list is not always fully up-to-date with current
- * RNA/IDProps etc., this gets cleaned up when re-generating the overrides rules,
- * no error here. */
- continue;
- }
-
- TreeElement *ten = outliner_add_element(
- soops, &te->subtree, id, te, TSE_LIBRARY_OVERRIDE, index++);
- ten->name = RNA_property_ui_name(override_prop);
+ outliner_add_element(
+ space_outliner, &te->subtree, ob->instance_collection, te, TSE_SOME_ID, 0);
}
}
@@ -667,14 +599,10 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
/* expand specific data always */
switch (GS(id->name)) {
- case ID_LI: {
- te->name = ((Library *)id)->filepath;
- break;
- }
- case ID_SCE: {
- outliner_add_scene_contents(space_outliner, &te->subtree, (Scene *)id, te);
+ case ID_LI:
+ case ID_SCE:
+ BLI_assert(!"ID type expected to be expanded through new tree-element design");
break;
- }
case ID_OB: {
outliner_add_object_contents(space_outliner, te, tselem, (Object *)id);
break;
@@ -686,9 +614,9 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
outliner_add_element(space_outliner, &te->subtree, me, te, TSE_ANIM_DATA, 0);
}
- outliner_add_element(space_outliner, &te->subtree, me->key, te, 0, 0);
+ outliner_add_element(space_outliner, &te->subtree, me->key, te, TSE_SOME_ID, 0);
for (int a = 0; a < me->totcol; a++) {
- outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, 0, a);
+ outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, TSE_SOME_ID, a);
}
/* could do tfaces with image links, but the images are not grouped nicely.
* would require going over all tfaces, sort images in use. etc... */
@@ -702,7 +630,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
for (int a = 0; a < cu->totcol; a++) {
- outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, 0, a);
+ outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, TSE_SOME_ID, a);
}
break;
}
@@ -714,7 +642,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
for (int a = 0; a < mb->totcol; a++) {
- outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, 0, a);
+ outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, TSE_SOME_ID, a);
}
break;
}
@@ -730,7 +658,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
if (outliner_animdata_test(tex->adt)) {
outliner_add_element(space_outliner, &te->subtree, tex, te, TSE_ANIM_DATA, 0);
}
- outliner_add_element(space_outliner, &te->subtree, tex->ima, te, 0, 0);
+ outliner_add_element(space_outliner, &te->subtree, tex->ima, te, TSE_SOME_ID, 0);
break;
}
case ID_CA: {
@@ -901,17 +829,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
default:
break;
}
-
- const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(space_outliner) ||
- ((space_outliner->filter & SO_FILTER_NO_LIB_OVERRIDE) == 0);
-
- if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY(id)) {
- TreeElement *ten = outliner_add_element(
- space_outliner, &te->subtree, id, te, TSE_LIBRARY_OVERRIDE_BASE, 0);
-
- ten->name = IFACE_("Library Overrides");
- outliner_add_library_override_contents(space_outliner, ten, id);
- }
}
/**
@@ -991,41 +908,43 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
else if (type == TSE_ID_BASE) {
/* pass */
}
+ else if (type == TSE_SOME_ID) {
+ if (!te->type) {
+ BLI_assert(!"Expected this ID type to be ported to new Outliner tree-element design");
+ }
+ }
else {
/* Other cases must be caught above. */
BLI_assert(TSE_IS_REAL_ID(tselem));
- /* do here too, for blend file viewer, own ID_LI then shows file name */
- if (GS(id->name) == ID_LI) {
- te->name = ((Library *)id)->filepath;
- }
- else {
+ /* The new type design sets the name already, don't override that here. We need to figure out
+ * how to deal with the idcode for non-TSE_SOME_ID types still. Some rely on it... */
+ if (!te->type) {
te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */
}
te->idcode = GS(id->name);
}
- if (te->type) {
+ if (te->type && outliner_tree_element_type_is_expand_valid(te->type)) {
outliner_tree_element_type_expand(te->type, space_outliner);
}
- else if (type == 0) {
- TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL;
-
- /* ID data-block. */
- if (tsepar == NULL || tsepar->type != TSE_ID_BASE || space_outliner->filter_id_type) {
+ else if (type == TSE_SOME_ID) {
+ /* ID types not (fully) ported to new design yet. */
+ if (outliner_tree_element_type_expand_poll(te->type, space_outliner)) {
outliner_add_id_contents(space_outliner, te, tselem, id);
+ outliner_tree_element_type_post_expand(te->type, space_outliner);
}
}
- else if (ELEM(type, TSE_ANIM_DATA, TSE_DRIVER_BASE, TSE_NLA, TSE_NLA_ACTION, TSE_NLA_TRACK)) {
+ else if (ELEM(type,
+ TSE_ANIM_DATA,
+ TSE_DRIVER_BASE,
+ TSE_NLA,
+ TSE_NLA_ACTION,
+ TSE_NLA_TRACK,
+ TSE_GP_LAYER)) {
/* Should already use new AbstractTreeElement design. */
BLI_assert(0);
}
- else if (type == TSE_GP_LAYER) {
- bGPDlayer *gpl = (bGPDlayer *)idv;
-
- te->name = gpl->info;
- te->directdata = gpl;
- }
else if (type == TSE_SEQUENCE) {
Sequence *seq = (Sequence *)idv;
@@ -1229,18 +1148,19 @@ BLI_INLINE void outliner_add_collection_objects(SpaceOutliner *space_outliner,
TreeElement *parent)
{
LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
- outliner_add_element(space_outliner, tree, cob->ob, parent, 0, 0);
+ outliner_add_element(space_outliner, tree, cob->ob, parent, TSE_SOME_ID, 0);
}
}
-static TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
- Collection *collection,
- TreeElement *ten)
+TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
+ Collection *collection,
+ TreeElement *ten)
{
outliner_add_collection_init(ten, collection);
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- outliner_add_element(space_outliner, &ten->subtree, &child->collection->id, ten, 0, 0);
+ outliner_add_element(
+ space_outliner, &ten->subtree, &child->collection->id, ten, TSE_SOME_ID, 0);
}
if (space_outliner->outlinevis != SO_SCENES) {
@@ -1265,7 +1185,7 @@ void outliner_make_object_parent_hierarchy(ListBase *lb)
TreeElement *ten = te->next;
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
if (ob->parent && ob->parent->id.newid) {
BLI_remlink(lb, te);
@@ -1406,7 +1326,7 @@ static void outliner_sort(ListBase *lb)
/* sorting rules; only object lists, ID lists, or deformgroups */
if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
- (tselem->type == 0 && te->idcode == ID_OB)) {
+ ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) {
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
@@ -1420,7 +1340,7 @@ static void outliner_sort(ListBase *lb)
tp->name = te->name;
tp->idcode = te->idcode;
- if (tselem->type && tselem->type != TSE_DEFGROUP) {
+ if ((tselem->type != TSE_SOME_ID) && tselem->type != TSE_DEFGROUP) {
tp->idcode = 0; /* Don't sort this. */
}
if (tselem->type == TSE_ID_BASE) {
@@ -1471,7 +1391,7 @@ static void outliner_collections_children_sort(ListBase *lb)
TreeStoreElem *tselem = TREESTORE(te);
/* Sorting rules: only object lists. */
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
@@ -1546,7 +1466,7 @@ static bool test_collection_callback(TreeElement *te)
static bool test_object_callback(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
- return ((tselem->type == 0) && (te->idcode == ID_OB));
+ return ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB));
}
/**
@@ -1707,7 +1627,7 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
}
TreeStoreElem *tselem = TREESTORE(te);
- if ((tselem->type == 0) && (te->idcode == ID_OB)) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
if ((exclude_filter & SO_FILTER_OB_TYPE) == SO_FILTER_OB_TYPE) {
return false;
}
@@ -1790,14 +1710,15 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
return is_visible;
}
- if ((te->parent != NULL) && (TREESTORE(te->parent)->type == 0) &&
+ if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
(te->parent->idcode == ID_OB)) {
if (exclude_filter & SO_FILTER_NO_CHILDREN) {
return false;
}
}
}
- else if (te->parent != NULL && TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB) {
+ else if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
+ (te->parent->idcode == ID_OB)) {
if (exclude_filter & SO_FILTER_NO_OB_CONTENT) {
return false;
}
@@ -1821,7 +1742,7 @@ static bool outliner_element_is_collection_or_object(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
- if ((tselem->type == 0) && (te->idcode == ID_OB)) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
return true;
}
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c
index 92178cfdfc9..562457c62e9 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.c
@@ -226,7 +226,7 @@ TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0) {
+ if (tselem->type == TSE_SOME_ID) {
if (tselem->id == id) {
return te;
}
@@ -266,7 +266,7 @@ TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
}
TreeStoreElem *tselem = TREESTORE(te);
- if (ELEM(tselem->type, 0, TSE_EBONE)) {
+ if (ELEM(tselem->type, TSE_SOME_ID, TSE_EBONE)) {
TreeElement *tes = outliner_find_editbone(&te->subtree, ebone);
if (tes) {
return tes;
@@ -283,7 +283,7 @@ TreeElement *outliner_search_back_te(TreeElement *te, short idcode)
while (te) {
tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == idcode) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == idcode)) {
return te;
}
te = te->parent;
@@ -510,7 +510,7 @@ Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
if (te) {
TreeStoreElem *tselem = TREESTORE(te);
- if ((tselem->type == 0) && (te->idcode == ID_OB)) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
Object *ob = (Object *)tselem->id;
base = (te->directdata) ? (Base *)te->directdata : BKE_view_layer_base_find(view_layer, ob);
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display.h b/source/blender/editors/space_outliner/tree/tree_display.h
index 4ef71ded133..c0a751f2cd5 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.h
+++ b/source/blender/editors/space_outliner/tree/tree_display.h
@@ -56,6 +56,10 @@ struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
short type,
short index);
void outliner_make_object_parent_hierarchy(ListBase *lb);
+bool outliner_animdata_test(const struct AnimData *adt);
+TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
+ struct Collection *collection,
+ TreeElement *ten);
const char *outliner_idcode_to_plural(short idcode);
diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
index a81ce11498a..91b690d35fa 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
@@ -144,7 +144,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
if (!tenlib) {
/* Create library tree element on demand, depending if there are any data-blocks. */
if (lib) {
- tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, 0, 0);
+ tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, TSE_SOME_ID, 0);
}
else {
tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
@@ -168,7 +168,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
for (ID *id : List<ID>(lbarray[a])) {
if (library_id_filter_poll(lib, id)) {
- outliner_add_element(&space_outliner_, &ten->subtree, id, ten, 0, 0);
+ outliner_add_element(&space_outliner_, &ten->subtree, id, ten, TSE_SOME_ID, 0);
}
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
index 559cb289f3f..69ccf014642 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
@@ -76,7 +76,8 @@ ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data)
/* Add the orphaned data-blocks - these will not be added with any subtrees attached. */
for (ID *id : List<ID>(lbarray[a])) {
if (ID_REAL_USERS(id) <= 0) {
- outliner_add_element(&space_outliner_, (te) ? &te->subtree : &tree, id, te, 0, 0);
+ outliner_add_element(
+ &space_outliner_, (te) ? &te->subtree : &tree, id, te, TSE_SOME_ID, 0);
}
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
index f377512d81e..390f81cfcd1 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
@@ -46,7 +46,8 @@ ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data)
for (ID *id : List<ID>(source_data.bmain->scenes)) {
Scene *scene = reinterpret_cast<Scene *>(id);
- TreeElement *te = outliner_add_element(&space_outliner_, &tree, scene, nullptr, 0, 0);
+ TreeElement *te = outliner_add_element(
+ &space_outliner_, &tree, scene, nullptr, TSE_SOME_ID, 0);
TreeStoreElem *tselem = TREESTORE(te);
/* New scene elements open by default */
diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
index a0ebac5f451..89c9960a24f 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
@@ -80,7 +80,7 @@ ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data)
/* Show objects in the view layer. */
for (Base *base : List<Base>(view_layer_->object_bases)) {
TreeElement *te_object = outliner_add_element(
- &space_outliner_, &tree, base->object, nullptr, 0, 0);
+ &space_outliner_, &tree, base->object, nullptr, TSE_SOME_ID, 0);
te_object->directdata = base;
}
@@ -158,7 +158,7 @@ void TreeDisplayViewLayer::add_layer_collection_objects(ListBase &tree,
for (CollectionObject *cob : List<CollectionObject>(lc.collection->gobject)) {
Base *base = BKE_view_layer_base_find(view_layer_, cob->ob);
TreeElement *te_object = outliner_add_element(
- &space_outliner_, &tree, base->object, &ten, 0, 0);
+ &space_outliner_, &tree, base->object, &ten, TSE_SOME_ID, 0);
te_object->directdata = base;
}
}
@@ -203,7 +203,7 @@ void ObjectsChildrenBuilder::object_tree_elements_lookup_create_recursive(TreeEl
continue;
}
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
Object *ob = (Object *)tselem->id;
/* Lookup children or add new, empty children vector. */
Vector<TreeElement *> &tree_elements = object_tree_elements_map_.lookup_or_add(ob, {});
@@ -261,8 +261,12 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
if (!found) {
/* We add the child in the tree even if it is not in the collection.
* We deliberately clear its sub-tree though, to make it less prominent. */
- TreeElement *child_ob_tree_element = outliner_add_element(
- &outliner_, &parent_ob_tree_element->subtree, child, parent_ob_tree_element, 0, 0);
+ TreeElement *child_ob_tree_element = outliner_add_element(&outliner_,
+ &parent_ob_tree_element->subtree,
+ child,
+ parent_ob_tree_element,
+ TSE_SOME_ID,
+ 0);
outliner_free_tree(&child_ob_tree_element->subtree);
child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION;
child_ob_tree_elements.append(child_ob_tree_element);
diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc
index 27846614994..25bd9a53cf8 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element.cc
@@ -21,8 +21,13 @@
#include "DNA_listBase.h"
#include "tree_element_anim_data.hh"
-#include "tree_element_driver_base.hh"
+#include "tree_element_collection.hh"
+#include "tree_element_driver.hh"
+#include "tree_element_gpencil_layer.hh"
+#include "tree_element_id.hh"
#include "tree_element_nla.hh"
+#include "tree_element_scene_objects.hh"
+#include "tree_element_view_layer.hh"
#include "tree_element.h"
#include "tree_element.hh"
@@ -36,6 +41,8 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te
ID &id = *static_cast<ID *>(idv);
switch (type) {
+ case TSE_SOME_ID:
+ return TreeElementID::createFromID(legacy_te, id);
case TSE_ANIM_DATA:
return new TreeElementAnimData(legacy_te, id);
case TSE_DRIVER_BASE:
@@ -46,6 +53,14 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te
return new TreeElementNLATrack(legacy_te, *static_cast<NlaTrack *>(idv));
case TSE_NLA_ACTION:
return new TreeElementNLAAction(legacy_te);
+ case TSE_GP_LAYER:
+ return new TreeElementGPencilLayer(legacy_te, *static_cast<bGPDlayer *>(idv));
+ case TSE_R_LAYER_BASE:
+ return new TreeElementViewLayerBase(legacy_te, *static_cast<Scene *>(idv));
+ case TSE_SCENE_COLLECTION_BASE:
+ return new TreeElementCollectionBase(legacy_te, *static_cast<Scene *>(idv));
+ case TSE_SCENE_OBJECTS_BASE:
+ return new TreeElementSceneObjectsBase(legacy_te, *static_cast<Scene *>(idv));
default:
break;
}
@@ -61,7 +76,33 @@ static void tree_element_free(AbstractTreeElement **tree_element)
static void tree_element_expand(AbstractTreeElement &tree_element, SpaceOutliner &space_outliner)
{
+ /* Most types can just expand. IDs optionally expand (hence the poll) and do additional, common
+ * expanding. Could be done nicer, we could request a small "expander" helper object from the
+ * element type, that the IDs have a more advanced implementation for. */
+ if (!tree_element.expandPoll(space_outliner)) {
+ return;
+ }
tree_element.expand(space_outliner);
+ tree_element.postExpand(space_outliner);
+}
+
+/**
+ * Needed for types that still expand in C, but need to execute the same post-expand logic. Can be
+ * removed once all ID types expand entirely using the new design.
+ */
+static void tree_element_post_expand_only(AbstractTreeElement &tree_element,
+ SpaceOutliner &space_outliner)
+{
+ tree_element.postExpand(space_outliner);
+}
+/**
+ * Needed for types that still expand in C, to poll if they should expand in current context. Can
+ * be removed once all ID types expand entirely using the new design.
+ */
+static bool tree_element_expand_poll(AbstractTreeElement &tree_element,
+ SpaceOutliner &space_outliner)
+{
+ return tree_element.expandPoll(space_outliner);
}
} // namespace blender::ed::outliner
@@ -79,6 +120,22 @@ void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *spa
outliner::tree_element_expand(reinterpret_cast<outliner::AbstractTreeElement &>(*type),
*space_outliner);
}
+bool outliner_tree_element_type_is_expand_valid(TreeElementType *type)
+{
+ outliner::AbstractTreeElement &element = reinterpret_cast<outliner::AbstractTreeElement &>(
+ *type);
+ return element.isExpandValid();
+}
+bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner)
+{
+ return outliner::tree_element_expand_poll(
+ reinterpret_cast<outliner::AbstractTreeElement &>(*type), *space_outliner);
+}
+void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner)
+{
+ outliner::tree_element_post_expand_only(reinterpret_cast<outliner::AbstractTreeElement &>(*type),
+ *space_outliner);
+}
void outliner_tree_element_type_free(TreeElementType **type)
{
diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h
index d88c37180b3..8e5b02278cc 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.h
+++ b/source/blender/editors/space_outliner/tree/tree_element.h
@@ -39,6 +39,9 @@ TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy
void outliner_tree_element_type_free(TreeElementType **type);
void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner);
+bool outliner_tree_element_type_is_expand_valid(TreeElementType *type);
+bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner);
+void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh
index 8a1ebb51eae..4a7e95556db 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element.hh
@@ -37,17 +37,39 @@ class AbstractTreeElement {
TreeElement &legacy_te_;
public:
- AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te)
- {
- }
virtual ~AbstractTreeElement() = default;
/**
+ * Check if the type is expandible in current context.
+ */
+ virtual bool expandPoll(const SpaceOutliner &) const
+ {
+ return true;
+ }
+ /**
* Let the type add its own children.
*/
virtual void expand(SpaceOutliner &) const
{
}
+ virtual void postExpand(SpaceOutliner &) const
+ {
+ }
+
+ /**
+ * Just while transitioning to the new tree-element design: Some types are only partially ported,
+ * and the expanding isn't done yet.
+ */
+ virtual bool isExpandValid() const
+ {
+ return true;
+ }
+
+ protected:
+ /* Pseudo-abstract: Only allow creation through derived types. */
+ AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te)
+ {
+ }
};
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
index 13a25800800..5a9568ea906 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
@@ -44,7 +44,8 @@ TreeElementAnimData::TreeElementAnimData(TreeElement &legacy_te, ID &id)
void TreeElementAnimData::expand(SpaceOutliner &space_outliner) const
{
/* Animation data-block itself. */
- outliner_add_element(&space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, 0, 0);
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, TSE_SOME_ID, 0);
expand_drivers(space_outliner);
expand_NLA_tracks(space_outliner);
diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.cc b/source/blender/editors/space_outliner/tree/tree_element_collection.cc
new file mode 100644
index 00000000000..1add61db7f1
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_collection.cc
@@ -0,0 +1,44 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "DNA_listBase.h"
+
+#include "BLT_translation.h"
+
+#include "../outliner_intern.h"
+#include "tree_display.h"
+
+#include "tree_element_collection.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementCollectionBase::TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene)
+ : AbstractTreeElement(legacy_te), scene_(scene)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SCENE_COLLECTION_BASE);
+ legacy_te.name = IFACE_("Scene Collection");
+}
+
+void TreeElementCollectionBase::expand(SpaceOutliner &space_outliner) const
+{
+ outliner_add_collection_recursive(&space_outliner, scene_.master_collection, &legacy_te_);
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.hh b/source/blender/editors/space_outliner/tree/tree_element_collection.hh
new file mode 100644
index 00000000000..e9584d37dfe
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_collection.hh
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementCollectionBase final : public AbstractTreeElement {
+ Scene &scene_;
+
+ public:
+ TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene);
+
+ void expand(SpaceOutliner &) const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc b/source/blender/editors/space_outliner/tree/tree_element_driver.cc
index a01a3c42531..42f51908eaa 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_driver.cc
@@ -30,7 +30,7 @@
#include "../outliner_intern.h"
#include "tree_display.h"
-#include "tree_element_driver_base.hh"
+#include "tree_element_driver.hh"
namespace blender::ed::outliner {
diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh b/source/blender/editors/space_outliner/tree/tree_element_driver.hh
index 1925e3570be..1925e3570be 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_driver.hh
diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
new file mode 100644
index 00000000000..91e6fdcde4b
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "BLI_utildefines.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "../outliner_intern.h"
+
+#include "tree_element_gpencil_layer.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementGPencilLayer::TreeElementGPencilLayer(TreeElement &legacy_te, bGPDlayer &gplayer)
+ : AbstractTreeElement(legacy_te)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_GP_LAYER);
+ /* this element's info */
+ legacy_te.name = gplayer.info;
+ legacy_te.directdata = &gplayer;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh
new file mode 100644
index 00000000000..da57ef63f1f
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+struct bGPDlayer;
+
+namespace blender::ed::outliner {
+
+class TreeElementGPencilLayer final : public AbstractTreeElement {
+ public:
+ TreeElementGPencilLayer(TreeElement &legacy_te, bGPDlayer &gplayer);
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc
new file mode 100644
index 00000000000..823a7644f38
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc
@@ -0,0 +1,167 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "DNA_ID.h"
+
+#include "BLI_listbase_wrapper.hh"
+#include "BLI_utildefines.h"
+
+#include "BKE_lib_override.h"
+
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+
+#include "../outliner_intern.h"
+#include "tree_display.h"
+#include "tree_element_id_library.hh"
+#include "tree_element_id_scene.hh"
+
+#include "tree_element_id.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
+{
+ switch (ID_Type type = GS(id.name); type) {
+ case ID_LI:
+ return new TreeElementIDLibrary(legacy_te, (Library &)id);
+ case ID_SCE:
+ return new TreeElementIDScene(legacy_te, (Scene &)id);
+ case ID_OB:
+ case ID_ME:
+ case ID_CU:
+ case ID_MB:
+ case ID_MA:
+ case ID_TE:
+ case ID_LT:
+ case ID_LA:
+ case ID_CA:
+ case ID_KE:
+ case ID_SCR:
+ case ID_WO:
+ case ID_SPK:
+ case ID_GR:
+ case ID_NT:
+ case ID_BR:
+ case ID_PA:
+ case ID_MC:
+ case ID_MSK:
+ case ID_LS:
+ case ID_LP:
+ case ID_GD:
+ case ID_WS:
+ case ID_HA:
+ case ID_PT:
+ case ID_VO:
+ case ID_SIM:
+ case ID_WM:
+ case ID_IM:
+ case ID_VF:
+ case ID_TXT:
+ case ID_SO:
+ case ID_AR:
+ case ID_AC:
+ case ID_PAL:
+ case ID_PC:
+ case ID_CF:
+ return new TreeElementID(legacy_te, id);
+ /* Deprecated */
+ case ID_IP:
+ BLI_assert(!"Outliner trying to build tree-element for deprecated ID type");
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
+/* -------------------------------------------------------------------- */
+/* ID Tree-Element Base Class (common/default logic) */
+
+TreeElementID::TreeElementID(TreeElement &legacy_te, ID &id)
+ : AbstractTreeElement(legacy_te), id_(id)
+{
+ BLI_assert(legacy_te_.store_elem->type == TSE_SOME_ID);
+ BLI_assert(TSE_IS_REAL_ID(legacy_te_.store_elem));
+
+ /* Default, some specific types override this. */
+ legacy_te_.name = id.name + 2;
+ legacy_te_.idcode = GS(id.name);
+}
+
+void TreeElementID::expand_library_overrides(SpaceOutliner &space_outliner) const
+{
+ if (!id_.override_library) {
+ return;
+ }
+
+ PointerRNA idpoin;
+ RNA_id_pointer_create(&id_, &idpoin);
+
+ PointerRNA override_rna_ptr;
+ PropertyRNA *override_rna_prop;
+ int index = 0;
+
+ for (auto *override_prop :
+ ListBaseWrapper<IDOverrideLibraryProperty>(id_.override_library->properties)) {
+ if (!BKE_lib_override_rna_property_find(
+ &idpoin, override_prop, &override_rna_ptr, &override_rna_prop)) {
+ /* This is fine, override properties list is not always fully up-to-date with current
+ * RNA/IDProps etc., this gets cleaned up when re-generating the overrides rules,
+ * no error here. */
+ continue;
+ }
+
+ TreeElement *ten = outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_LIBRARY_OVERRIDE, index++);
+ ten->name = RNA_property_ui_name(override_rna_prop);
+ }
+}
+
+void TreeElementID::postExpand(SpaceOutliner &space_outliner) const
+{
+ const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(&space_outliner) ||
+ ((space_outliner.filter & SO_FILTER_NO_LIB_OVERRIDE) == 0);
+
+ if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY(&id_)) {
+ TreeElement *ten = outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_LIBRARY_OVERRIDE_BASE, 0);
+
+ ten->name = IFACE_("Library Overrides");
+ expand_library_overrides(space_outliner);
+ }
+}
+
+bool TreeElementID::expandPoll(const SpaceOutliner &space_outliner) const
+{
+ const TreeStoreElem *tsepar = legacy_te_.parent ? TREESTORE(legacy_te_.parent) : nullptr;
+ return (tsepar == nullptr || tsepar->type != TSE_ID_BASE || space_outliner.filter_id_type);
+}
+
+void TreeElementID::expand_animation_data(SpaceOutliner &space_outliner,
+ const AnimData *anim_data) const
+{
+ if (outliner_animdata_test(anim_data)) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_ANIM_DATA, 0);
+ }
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh
new file mode 100644
index 00000000000..2d077464b6d
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh
@@ -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.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ *
+ * Tree element classes for the tree elements directly representing an ID (#TSE_SOME_ID).
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementID : public AbstractTreeElement {
+ protected:
+ ID &id_;
+
+ public:
+ TreeElementID(TreeElement &legacy_te, ID &id);
+
+ static TreeElementID *createFromID(TreeElement &legacy_te, ID &id);
+
+ void postExpand(SpaceOutliner &) const override;
+ bool expandPoll(const SpaceOutliner &) const override;
+
+ /**
+ * Expanding not implemented for all types yet. Once it is, this can be set to true or
+ * `AbstractTreeElement::expandValid()` can be removed altogether.
+ */
+ bool isExpandValid() const override
+ {
+ return false;
+ }
+
+ protected:
+ /* ID types with animation data can use this. */
+ void expand_animation_data(SpaceOutliner &, const AnimData *) const;
+
+ private:
+ void expand_library_overrides(SpaceOutliner &) const;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
new file mode 100644
index 00000000000..36f536c9845
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "DNA_listBase.h"
+
+#include "../outliner_intern.h"
+
+#include "tree_element_id_library.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementIDLibrary::TreeElementIDLibrary(TreeElement &legacy_te, Library &library)
+ : TreeElementID(legacy_te, library.id)
+{
+ legacy_te.name = library.filepath;
+}
+
+bool TreeElementIDLibrary::isExpandValid() const
+{
+ return true;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
new file mode 100644
index 00000000000..88660cd8aa9
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#pragma once
+
+#include "tree_element_id.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementIDLibrary final : public TreeElementID {
+ public:
+ TreeElementIDLibrary(TreeElement &legacy_te, Library &library);
+
+ bool isExpandValid() const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
new file mode 100644
index 00000000000..ae81b44a1e4
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
@@ -0,0 +1,74 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "DNA_listBase.h"
+
+#include "../outliner_intern.h"
+#include "tree_display.h"
+
+#include "tree_element_id_scene.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementIDScene::TreeElementIDScene(TreeElement &legacy_te, Scene &scene)
+ : TreeElementID(legacy_te, scene.id), scene_(scene)
+{
+}
+
+bool TreeElementIDScene::isExpandValid() const
+{
+ return true;
+}
+
+void TreeElementIDScene::expand(SpaceOutliner &space_outliner) const
+{
+ expandViewLayers(space_outliner);
+ expandWorld(space_outliner);
+ expandCollections(space_outliner);
+ expandObjects(space_outliner);
+
+ expand_animation_data(space_outliner, scene_.adt);
+}
+
+void TreeElementIDScene::expandViewLayers(SpaceOutliner &space_outliner) const
+{
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER_BASE, 0);
+}
+
+void TreeElementIDScene::expandWorld(SpaceOutliner &space_outliner) const
+{
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, scene_.world, &legacy_te_, TSE_SOME_ID, 0);
+}
+
+void TreeElementIDScene::expandCollections(SpaceOutliner &space_outliner) const
+{
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_COLLECTION_BASE, 0);
+}
+
+void TreeElementIDScene::expandObjects(SpaceOutliner &space_outliner) const
+{
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_OBJECTS_BASE, 0);
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh b/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh
new file mode 100644
index 00000000000..3340bacd307
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh
@@ -0,0 +1,43 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#pragma once
+
+#include "tree_element_id.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementIDScene final : public TreeElementID {
+ Scene &scene_;
+
+ public:
+ TreeElementIDScene(TreeElement &legacy_te, Scene &scene);
+
+ void expand(SpaceOutliner &) const override;
+ bool isExpandValid() const override;
+
+ private:
+ void expandViewLayers(SpaceOutliner &) const;
+ void expandWorld(SpaceOutliner &) const;
+ void expandCollections(SpaceOutliner &) const;
+ void expandObjects(SpaceOutliner &) const;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
new file mode 100644
index 00000000000..a46e8de1bdd
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "BKE_collection.h"
+
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "../outliner_intern.h"
+#include "tree_display.h"
+
+#include "tree_element_scene_objects.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementSceneObjectsBase::TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene)
+ : AbstractTreeElement(legacy_te), scene_(scene)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SCENE_OBJECTS_BASE);
+ legacy_te.name = IFACE_("Objects");
+}
+
+void TreeElementSceneObjectsBase::expand(SpaceOutliner &space_outliner) const
+{
+ FOREACH_SCENE_OBJECT_BEGIN (&scene_, ob) {
+ outliner_add_element(&space_outliner, &legacy_te_.subtree, ob, &legacy_te_, TSE_SOME_ID, 0);
+ }
+ FOREACH_SCENE_OBJECT_END;
+ outliner_make_object_parent_hierarchy(&legacy_te_.subtree);
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
new file mode 100644
index 00000000000..a2aa29c4a33
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementSceneObjectsBase final : public AbstractTreeElement {
+ Scene &scene_;
+
+ public:
+ TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene);
+
+ void expand(SpaceOutliner &) const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
new file mode 100644
index 00000000000..7bb9405147e
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "DNA_layer_types.h"
+
+#include "BLI_listbase_wrapper.hh"
+
+#include "BLT_translation.h"
+
+#include "../outliner_intern.h"
+#include "tree_display.h"
+
+#include "tree_element_view_layer.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementViewLayerBase::TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene)
+ : AbstractTreeElement(legacy_te), scene_(scene)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_R_LAYER_BASE);
+ legacy_te_.name = IFACE_("View Layers");
+}
+
+void TreeElementViewLayerBase::expand(SpaceOutliner &space_outliner) const
+{
+ for (auto *view_layer : ListBaseWrapper<ViewLayer>(scene_.view_layers)) {
+ TreeElement *tenlay = outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER, 0);
+ tenlay->name = view_layer->name;
+ tenlay->directdata = view_layer;
+ }
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh b/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh
new file mode 100644
index 00000000000..24e03b265dc
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+namespace blender::ed::outliner {
+
+class TreeElementViewLayerBase final : public AbstractTreeElement {
+ Scene &scene_;
+
+ public:
+ TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene);
+
+ void expand(SpaceOutliner &) const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 9828368ccf7..31d3d0bc1bc 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -2112,7 +2112,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
typedef struct CacheDrawData {
struct View2D *v2d;
- float stripe_offs;
+ float stripe_ofs_y;
float stripe_ht;
int cache_flag;
GPUVertBuf *raw_vbo;
@@ -2151,7 +2151,7 @@ static bool draw_cache_view_iter_fn(void *userdata,
{
CacheDrawData *drawdata = userdata;
struct View2D *v2d = drawdata->v2d;
- float stripe_bot, stripe_top, stripe_offs, stripe_ht;
+ float stripe_bot, stripe_top, stripe_ofs_y, stripe_ht;
GPUVertBuf *vbo;
size_t *vert_count;
@@ -2164,27 +2164,27 @@ static bool draw_cache_view_iter_fn(void *userdata,
vert_count = &drawdata->final_out_vert_count;
}
else if ((cache_type & SEQ_CACHE_STORE_RAW) && (drawdata->cache_flag & SEQ_CACHE_VIEW_RAW)) {
- stripe_offs = drawdata->stripe_offs;
+ stripe_ofs_y = drawdata->stripe_ofs_y;
stripe_ht = drawdata->stripe_ht;
- stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs;
+ stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_ofs_y;
stripe_top = stripe_bot + stripe_ht;
vbo = drawdata->raw_vbo;
vert_count = &drawdata->raw_vert_count;
}
else if ((cache_type & SEQ_CACHE_STORE_PREPROCESSED) &&
(drawdata->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED)) {
- stripe_offs = drawdata->stripe_offs;
+ stripe_ofs_y = drawdata->stripe_ofs_y;
stripe_ht = drawdata->stripe_ht;
- stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + (stripe_offs + stripe_ht) + stripe_offs;
+ stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + (stripe_ofs_y + stripe_ht) + stripe_ofs_y;
stripe_top = stripe_bot + stripe_ht;
vbo = drawdata->preprocessed_vbo;
vert_count = &drawdata->preprocessed_vert_count;
}
else if ((cache_type & SEQ_CACHE_STORE_COMPOSITE) &&
(drawdata->cache_flag & SEQ_CACHE_VIEW_COMPOSITE)) {
- stripe_offs = drawdata->stripe_offs;
+ stripe_ofs_y = drawdata->stripe_ofs_y;
stripe_ht = drawdata->stripe_ht;
- stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_offs;
+ stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y;
stripe_bot = stripe_top - stripe_ht;
vbo = drawdata->composite_vbo;
vert_count = &drawdata->composite_vert_count;
@@ -2237,12 +2237,12 @@ static void draw_cache_view(const bContext *C)
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
float stripe_bot, stripe_top;
- float stripe_offs = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin;
+ float stripe_ofs_y = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin;
float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) -
v2d->cur.ymin;
CLAMP_MAX(stripe_ht, 0.2f);
- CLAMP_MIN(stripe_offs, stripe_ht / 2);
+ CLAMP_MIN(stripe_ofs_y, stripe_ht / 2);
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_FINAL_OUT) {
stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HANDLE_HEIGHT);
@@ -2262,7 +2262,7 @@ static void draw_cache_view(const bContext *C)
continue;
}
- stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs;
+ stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_ofs_y;
stripe_top = stripe_bot + stripe_ht;
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_RAW) {
@@ -2271,7 +2271,7 @@ static void draw_cache_view(const bContext *C)
immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
}
- stripe_bot += stripe_ht + stripe_offs;
+ stripe_bot += stripe_ht + stripe_ofs_y;
stripe_top = stripe_bot + stripe_ht;
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED) {
@@ -2280,7 +2280,7 @@ static void draw_cache_view(const bContext *C)
immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
}
- stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_offs;
+ stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y;
stripe_bot = stripe_top - stripe_ht;
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_COMPOSITE) {
@@ -2297,7 +2297,7 @@ static void draw_cache_view(const bContext *C)
CacheDrawData userdata;
userdata.v2d = v2d;
- userdata.stripe_offs = stripe_offs;
+ userdata.stripe_ofs_y = stripe_ofs_y;
userdata.stripe_ht = stripe_ht;
userdata.cache_flag = scene->ed->cache_flag;
userdata.raw_vert_count = 0;
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
new file mode 100644
index 00000000000..8be5f506dd7
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -0,0 +1,39 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ ../include
+ ../../blenkernel
+ ../../blenlib
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/glew-mx
+ ../../../../intern/guardedalloc
+)
+
+set(SRC
+ space_spreadsheet.cc
+ spreadsheet_ops.cc
+
+ spreadsheet_intern.hh
+)
+
+set(LIB
+)
+
+blender_add_lib(bf_editor_space_spreadsheet "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
new file mode 100644
index 00000000000..27276b4bedc
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -0,0 +1,221 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <cstring>
+
+#include "BLI_listbase.h"
+
+#include "BKE_screen.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "UI_resources.h"
+#include "UI_view2d.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "spreadsheet_intern.hh"
+
+static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
+{
+ SpaceSpreadsheet *spreadsheet_space = (SpaceSpreadsheet *)MEM_callocN(sizeof(SpaceSpreadsheet),
+ "spreadsheet space");
+ spreadsheet_space->spacetype = SPACE_SPREADSHEET;
+
+ {
+ /* header */
+ ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header");
+ BLI_addtail(&spreadsheet_space->regionbase, region);
+ region->regiontype = RGN_TYPE_HEADER;
+ region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
+ }
+
+ {
+ /* main window */
+ ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region");
+ BLI_addtail(&spreadsheet_space->regionbase, region);
+ region->regiontype = RGN_TYPE_WINDOW;
+ }
+
+ return (SpaceLink *)spreadsheet_space;
+}
+
+static void spreadsheet_free(SpaceLink *UNUSED(sl))
+{
+}
+
+static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
+{
+}
+
+static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
+{
+ return (SpaceLink *)MEM_dupallocN(sl);
+}
+
+static void spreadsheet_keymap(wmKeyConfig *UNUSED(keyconf))
+{
+}
+
+static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
+{
+ region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM;
+ region->v2d.align = V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y;
+ region->v2d.keepzoom = V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT;
+ region->v2d.keeptot = V2D_KEEPTOT_STRICT;
+ region->v2d.minzoom = region->v2d.maxzoom = 1.0f;
+
+ UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
+
+ wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D Buttons List", 0, 0);
+ WM_event_add_keymap_handler(&region->handlers, keymap);
+}
+
+static void spreadsheet_main_region_draw(const bContext *UNUSED(C), ARegion *UNUSED(region))
+{
+ UI_ThemeClearColor(TH_BACK);
+}
+
+static void spreadsheet_main_region_listener(const wmRegionListenerParams *params)
+{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
+ switch (wmn->category) {
+ case NC_SCENE: {
+ switch (wmn->data) {
+ case ND_MODE:
+ case ND_OB_ACTIVE: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ }
+ break;
+ }
+ case NC_OBJECT: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ case NC_SPACE: {
+ if (wmn->data == ND_SPACE_SPREADSHEET) {
+ ED_region_tag_redraw(region);
+ }
+ break;
+ }
+ case NC_GEOM: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ }
+}
+
+static void spreadsheet_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
+{
+ ED_region_header_init(region);
+}
+
+static void spreadsheet_header_region_draw(const bContext *C, ARegion *region)
+{
+ ED_region_header(C, region);
+}
+
+static void spreadsheet_header_region_free(ARegion *UNUSED(region))
+{
+}
+
+static void spreadsheet_header_region_listener(const wmRegionListenerParams *params)
+{
+ ARegion *region = params->region;
+ wmNotifier *wmn = params->notifier;
+
+ switch (wmn->category) {
+ case NC_SCENE: {
+ switch (wmn->data) {
+ case ND_MODE:
+ case ND_OB_ACTIVE: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ }
+ break;
+ }
+ case NC_OBJECT: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ case NC_SPACE: {
+ if (wmn->data == ND_SPACE_SPREADSHEET) {
+ ED_region_tag_redraw(region);
+ }
+ break;
+ }
+ case NC_GEOM: {
+ ED_region_tag_redraw(region);
+ break;
+ }
+ }
+}
+
+void ED_spacetype_spreadsheet(void)
+{
+ SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet");
+ ARegionType *art;
+
+ st->spaceid = SPACE_SPREADSHEET;
+ strncpy(st->name, "Spreadsheet", BKE_ST_MAXNAME);
+
+ st->create = spreadsheet_create;
+ st->free = spreadsheet_free;
+ st->init = spreadsheet_init;
+ st->duplicate = spreadsheet_duplicate;
+ st->operatortypes = spreadsheet_operatortypes;
+ st->keymap = spreadsheet_keymap;
+
+ /* regions: main window */
+ art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region");
+ art->regionid = RGN_TYPE_WINDOW;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
+
+ art->init = spreadsheet_main_region_init;
+ art->draw = spreadsheet_main_region_draw;
+ art->listener = spreadsheet_main_region_listener;
+ BLI_addhead(&st->regiontypes, art);
+
+ /* regions: header */
+ art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet header region");
+ art->regionid = RGN_TYPE_HEADER;
+ art->prefsizey = HEADERY;
+ art->keymapflag = 0;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
+
+ art->init = spreadsheet_header_region_init;
+ art->draw = spreadsheet_header_region_draw;
+ art->free = spreadsheet_header_region_free;
+ art->listener = spreadsheet_header_region_listener;
+ BLI_addhead(&st->regiontypes, art);
+
+ BKE_spacetype_register(st);
+}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
new file mode 100644
index 00000000000..10a875e2c14
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
@@ -0,0 +1,19 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+void spreadsheet_operatortypes(void);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
new file mode 100644
index 00000000000..770bd207e8d
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
@@ -0,0 +1,21 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "spreadsheet_intern.hh"
+
+void spreadsheet_operatortypes()
+{
+}
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
index c75d9796265..48f274ca71b 100644
--- a/source/blender/editors/space_view3d/view3d_placement.c
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -1438,6 +1438,8 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve
const int cube_verts[3] = {3, 1, 4};
for (int i = 0; i < 3; i++) {
scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]);
+ /* Primitives have size 2 by default, compensate for this here. */
+ scale[i] /= 2.0f;
}
wmOperatorType *ot = NULL;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 0605ea30806..7dc4a72e510 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1673,8 +1673,8 @@ static int selectbuffer_ret_hits_15(uint *UNUSED(buffer), const int hits15)
static int selectbuffer_ret_hits_9(uint *buffer, const int hits15, const int hits9)
{
- const int offs = 4 * hits15;
- memcpy(buffer, buffer + offs, 4 * hits9 * sizeof(uint));
+ const int ofs = 4 * hits15;
+ memcpy(buffer, buffer + ofs, 4 * hits9 * sizeof(uint));
return hits9;
}
@@ -1683,8 +1683,8 @@ static int selectbuffer_ret_hits_5(uint *buffer,
const int hits9,
const int hits5)
{
- const int offs = 4 * hits15 + 4 * hits9;
- memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint));
+ const int ofs = 4 * hits15 + 4 * hits9;
+ memcpy(buffer, buffer + ofs, 4 * hits5 * sizeof(uint));
return hits5;
}
@@ -1726,30 +1726,30 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc,
goto finally;
}
else if (hits15 > 0) {
- int offs;
+ int ofs;
has_bones15 = selectbuffer_has_bones(buffer, hits15);
- offs = 4 * hits15;
+ ofs = 4 * hits15;
BLI_rcti_init_pt_radius(&rect, mval, 9);
hits9 = view3d_opengl_select(
- vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter);
+ vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter);
if (hits9 == 1) {
hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
goto finally;
}
else if (hits9 > 0) {
- has_bones9 = selectbuffer_has_bones(buffer + offs, hits9);
+ has_bones9 = selectbuffer_has_bones(buffer + ofs, hits9);
- offs += 4 * hits9;
+ ofs += 4 * hits9;
BLI_rcti_init_pt_radius(&rect, mval, 5);
hits5 = view3d_opengl_select(
- vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter);
+ vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter);
if (hits5 == 1) {
hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
goto finally;
}
else if (hits5 > 0) {
- has_bones5 = selectbuffer_has_bones(buffer + offs, hits5);
+ has_bones5 = selectbuffer_has_bones(buffer + ofs, hits5);
}
}
diff --git a/source/blender/editors/util/ed_util_ops.cc b/source/blender/editors/util/ed_util_ops.cc
index 5b2e1a16bc2..06f1b999d58 100644
--- a/source/blender/editors/util/ed_util_ops.cc
+++ b/source/blender/editors/util/ed_util_ops.cc
@@ -92,7 +92,7 @@ static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op)
BKE_previewimg_id_custom_set(id, path);
- WM_event_add_notifier(C, NC_ASSET, nullptr);
+ WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr);
return OPERATOR_FINISHED;
}
@@ -133,7 +133,7 @@ static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op))
}
UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true);
- WM_event_add_notifier(C, NC_ASSET, nullptr);
+ WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 429959f9c33..e4a0b154a07 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -27,7 +27,6 @@ set(INC_SYS
)
set(SRC
- intern/attributes_ref.cc
intern/cpp_types.cc
intern/multi_function.cc
intern/multi_function_builder.cc
@@ -36,7 +35,6 @@ set(SRC
intern/multi_function_network_optimization.cc
FN_array_spans.hh
- FN_attributes_ref.hh
FN_cpp_type.hh
FN_generic_pointer.hh
FN_generic_value_map.hh
@@ -63,7 +61,6 @@ blender_add_lib(bf_functions "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
if(WITH_GTESTS)
set(TEST_SRC
tests/FN_array_spans_test.cc
- tests/FN_attributes_ref_test.cc
tests/FN_cpp_type_test.cc
tests/FN_generic_vector_array_test.cc
tests/FN_multi_function_network_test.cc
diff --git a/source/blender/functions/FN_attributes_ref.hh b/source/blender/functions/FN_attributes_ref.hh
deleted file mode 100644
index a9236f73549..00000000000
--- a/source/blender/functions/FN_attributes_ref.hh
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-/** \file
- * \ingroup fn
- *
- * An AttributesRef references multiple arrays of equal length. Each array has a corresponding name
- * and index.
- */
-
-#include <optional>
-
-#include "FN_spans.hh"
-
-#include "BLI_linear_allocator.hh"
-#include "BLI_map.hh"
-#include "BLI_utility_mixins.hh"
-#include "BLI_vector_set.hh"
-
-namespace blender::fn {
-
-class AttributesInfo;
-
-class AttributesInfoBuilder : NonCopyable, NonMovable {
- private:
- LinearAllocator<> allocator_;
- VectorSet<std::string> names_;
- Vector<const CPPType *> types_;
- Vector<void *> defaults_;
-
- friend AttributesInfo;
-
- public:
- AttributesInfoBuilder() = default;
- ~AttributesInfoBuilder();
-
- template<typename T> bool add(StringRef name, const T &default_value)
- {
- return this->add(name, CPPType::get<T>(), static_cast<const void *>(&default_value));
- }
-
- bool add(StringRef name, const CPPType &type, const void *default_value = nullptr);
-};
-
-/**
- * Stores which attributes are in an AttributesRef. Every attribute has a unique index, a unique
- * name, a type and a default value.
- */
-class AttributesInfo : NonCopyable, NonMovable {
- private:
- LinearAllocator<> allocator_;
- Map<StringRefNull, int> index_by_name_;
- Vector<StringRefNull> name_by_index_;
- Vector<const CPPType *> type_by_index_;
- Vector<void *> defaults_;
-
- public:
- AttributesInfo() = default;
- AttributesInfo(const AttributesInfoBuilder &builder);
- ~AttributesInfo();
-
- int size() const
- {
- return name_by_index_.size();
- }
-
- IndexRange index_range() const
- {
- return name_by_index_.index_range();
- }
-
- StringRefNull name_of(int index) const
- {
- return name_by_index_[index];
- }
-
- int index_of(StringRef name) const
- {
- return index_by_name_.lookup_as(name);
- }
-
- const void *default_of(int index) const
- {
- return defaults_[index];
- }
-
- const void *default_of(StringRef name) const
- {
- return this->default_of(this->index_of(name));
- }
-
- template<typename T> const T &default_of(int index) const
- {
- BLI_assert(type_by_index_[index]->is<T>());
- return *static_cast<T *>(defaults_[index]);
- }
-
- template<typename T> const T &default_of(StringRef name) const
- {
- return this->default_of<T>(this->index_of(name));
- }
-
- const CPPType &type_of(int index) const
- {
- return *type_by_index_[index];
- }
-
- const CPPType &type_of(StringRef name) const
- {
- return this->type_of(this->index_of(name));
- }
-
- bool has_attribute(StringRef name, const CPPType &type) const
- {
- return this->try_index_of(name, type) >= 0;
- }
-
- int try_index_of(StringRef name) const
- {
- return index_by_name_.lookup_default_as(name, -1);
- }
-
- int try_index_of(StringRef name, const CPPType &type) const
- {
- int index = this->try_index_of(name);
- if (index == -1) {
- return -1;
- }
- else if (this->type_of(index) == type) {
- return index;
- }
- else {
- return -1;
- }
- }
-};
-
-/**
- * References multiple arrays that match the description of an AttributesInfo instance. This class
- * is supposed to be relatively cheap to copy. It does not own any of the arrays itself.
- */
-class MutableAttributesRef {
- private:
- const AttributesInfo *info_;
- Span<void *> buffers_;
- IndexRange range_;
-
- friend class AttributesRef;
-
- public:
- MutableAttributesRef(const AttributesInfo &info, Span<void *> buffers, int64_t size)
- : MutableAttributesRef(info, buffers, IndexRange(size))
- {
- }
-
- MutableAttributesRef(const AttributesInfo &info, Span<void *> buffers, IndexRange range)
- : info_(&info), buffers_(buffers), range_(range)
- {
- }
-
- int64_t size() const
- {
- return range_.size();
- }
-
- IndexRange index_range() const
- {
- return IndexRange(this->size());
- }
-
- const AttributesInfo &info() const
- {
- return *info_;
- }
-
- GMutableSpan get(int index) const
- {
- const CPPType &type = info_->type_of(index);
- void *ptr = POINTER_OFFSET(buffers_[index], type.size() * range_.start());
- return GMutableSpan(type, ptr, range_.size());
- }
-
- GMutableSpan get(StringRef name) const
- {
- return this->get(info_->index_of(name));
- }
-
- template<typename T> MutableSpan<T> get(int index) const
- {
- BLI_assert(info_->type_of(index).is<T>());
- return MutableSpan<T>(static_cast<T *>(buffers_[index]) + range_.start(), range_.size());
- }
-
- template<typename T> MutableSpan<T> get(StringRef name) const
- {
- return this->get<T>(info_->index_of(name));
- }
-
- std::optional<GMutableSpan> try_get(StringRef name, const CPPType &type) const
- {
- int index = info_->try_index_of(name, type);
- if (index == -1) {
- return {};
- }
- else {
- return this->get(index);
- }
- }
-
- template<typename T> std::optional<MutableSpan<T>> try_get(StringRef name) const
- {
- int index = info_->try_index_of(name);
- if (index == -1) {
- return {};
- }
- else if (info_->type_of(index).is<T>()) {
- return this->get<T>(index);
- }
- else {
- return {};
- }
- }
-
- MutableAttributesRef slice(IndexRange range) const
- {
- return this->slice(range.start(), range.size());
- }
-
- MutableAttributesRef slice(int64_t start, int64_t size) const
- {
- return MutableAttributesRef(*info_, buffers_, range_.slice(start, size));
- }
-};
-
-class AttributesRef {
- private:
- const AttributesInfo *info_;
- Span<const void *> buffers_;
- IndexRange range_;
-
- public:
- AttributesRef(const AttributesInfo &info, Span<const void *> buffers, int64_t size)
- : AttributesRef(info, buffers, IndexRange(size))
- {
- }
-
- AttributesRef(const AttributesInfo &info, Span<const void *> buffers, IndexRange range)
- : info_(&info), buffers_(buffers), range_(range)
- {
- }
-
- AttributesRef(MutableAttributesRef attributes)
- : info_(attributes.info_), buffers_(attributes.buffers_), range_(attributes.range_)
- {
- }
-
- int64_t size() const
- {
- return range_.size();
- }
-
- const AttributesInfo &info() const
- {
- return *info_;
- }
-
- GSpan get(int index) const
- {
- const CPPType &type = info_->type_of(index);
- const void *ptr = POINTER_OFFSET(buffers_[index], type.size() * range_.start());
- return GSpan(type, ptr, range_.size());
- }
-
- GSpan get(StringRef name) const
- {
- return this->get(info_->index_of(name));
- }
-
- template<typename T> Span<T> get(int index) const
- {
- BLI_assert(info_->type_of(index).is<T>());
- return Span<T>(static_cast<T *>(buffers_[index]) + range_.start(), range_.size());
- }
-
- template<typename T> Span<T> get(StringRef name) const
- {
- return this->get<T>(info_->index_of(name));
- }
-
- std::optional<GSpan> try_get(StringRef name, const CPPType &type) const
- {
- int64_t index = info_->try_index_of(name, type);
- if (index == -1) {
- return {};
- }
- else {
- return this->get(index);
- }
- }
-
- template<typename T> std::optional<Span<T>> try_get(StringRef name) const
- {
- int index = info_->try_index_of(name);
- if (index == -1) {
- return {};
- }
- else if (info_->type_of(index).is<T>()) {
- return this->get<T>(index);
- }
- else {
- return {};
- }
- }
-
- AttributesRef slice(IndexRange range) const
- {
- return this->slice(range.start(), range.size());
- }
-
- AttributesRef slice(int64_t start, int64_t size) const
- {
- return AttributesRef(*info_, buffers_, range_.slice(start, size));
- }
-};
-
-} // namespace blender::fn
diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh
index a854e63288d..b8ac97d6dbd 100644
--- a/source/blender/functions/FN_cpp_type.hh
+++ b/source/blender/functions/FN_cpp_type.hh
@@ -935,3 +935,9 @@ inline std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d
{ \
return blender::fn::CPPType::get<TYPE_NAME>(); \
}
+
+/* Utility for allocating an uninitialized buffer for a single value of the given #CPPType. */
+#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name) \
+ blender::DynamicStackBuffer<64, 64> stack_buffer_for_##variable_name(type.size(), \
+ type.alignment()); \
+ void *variable_name = stack_buffer_for_##variable_name.buffer();
diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh
index 6d5ca7f64ad..0cd1bc262be 100644
--- a/source/blender/functions/FN_multi_function_builder.hh
+++ b/source/blender/functions/FN_multi_function_builder.hh
@@ -170,6 +170,63 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction {
/**
* Generates a multi-function with the following parameters:
+ * 1. single input (SI) of type In1
+ * 2. single input (SI) of type In2
+ * 3. single input (SI) of type In3
+ * 4. single input (SI) of type In4
+ * 5. single output (SO) of type Out1
+ */
+template<typename In1, typename In2, typename In3, typename In4, typename Out1>
+class CustomMF_SI_SI_SI_SI_SO : public MultiFunction {
+ private:
+ using FunctionT = std::function<void(
+ IndexMask, VSpan<In1>, VSpan<In2>, VSpan<In3>, VSpan<In4>, MutableSpan<Out1>)>;
+ FunctionT function_;
+
+ public:
+ CustomMF_SI_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ {
+ MFSignatureBuilder signature = this->get_builder(name);
+ signature.single_input<In1>("In1");
+ signature.single_input<In2>("In2");
+ signature.single_input<In3>("In3");
+ signature.single_input<In4>("In4");
+ signature.single_output<Out1>("Out1");
+ }
+
+ template<typename ElementFuncT>
+ CustomMF_SI_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn)
+ : CustomMF_SI_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SI_SO::create_function(element_fn))
+ {
+ }
+
+ template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn)
+ {
+ return [=](IndexMask mask,
+ VSpan<In1> in1,
+ VSpan<In2> in2,
+ VSpan<In3> in3,
+ VSpan<In4> in4,
+ MutableSpan<Out1> out1) {
+ mask.foreach_index([&](int i) {
+ new (static_cast<void *>(&out1[i])) Out1(element_fn(in1[i], in2[i], in3[i], in4[i]));
+ });
+ };
+ }
+
+ void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
+ {
+ VSpan<In1> in1 = params.readonly_single_input<In1>(0);
+ VSpan<In2> in2 = params.readonly_single_input<In2>(1);
+ VSpan<In3> in3 = params.readonly_single_input<In3>(2);
+ VSpan<In4> in4 = params.readonly_single_input<In4>(3);
+ MutableSpan<Out1> out1 = params.uninitialized_single_output<Out1>(4);
+ function_(mask, in1, in2, in3, in4, out1);
+ }
+};
+
+/**
+ * Generates a multi-function with the following parameters:
* 1. single mutable (SM) of type Mut1
*/
template<typename Mut1> class CustomMF_SM : public MultiFunction {
diff --git a/source/blender/functions/intern/attributes_ref.cc b/source/blender/functions/intern/attributes_ref.cc
deleted file mode 100644
index 9f1e7fa65e5..00000000000
--- a/source/blender/functions/intern/attributes_ref.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "FN_attributes_ref.hh"
-
-namespace blender::fn {
-
-AttributesInfoBuilder::~AttributesInfoBuilder()
-{
- for (int i : defaults_.index_range()) {
- types_[i]->destruct(defaults_[i]);
- }
-}
-
-bool AttributesInfoBuilder::add(StringRef name, const CPPType &type, const void *default_value)
-{
- if (name.size() == 0) {
- std::cout << "Warning: Tried to add an attribute with empty name.\n";
- return false;
- }
- if (names_.add_as(name)) {
- types_.append(&type);
-
- if (default_value == nullptr) {
- default_value = type.default_value();
- }
- void *dst = allocator_.allocate(type.size(), type.alignment());
- type.copy_to_uninitialized(default_value, dst);
- defaults_.append(dst);
- return true;
- }
-
- const CPPType &stored_type = *types_[names_.index_of_as(name)];
- if (stored_type != type) {
- std::cout << "Warning: Tried to add an attribute twice with different types (" << name << ": "
- << stored_type.name() << ", " << type.name() << ").\n";
- }
- return false;
-}
-
-AttributesInfo::AttributesInfo(const AttributesInfoBuilder &builder)
-{
- for (int i : builder.types_.index_range()) {
- StringRefNull name = allocator_.copy_string(builder.names_[i]);
- const CPPType &type = *builder.types_[i];
- const void *default_value = builder.defaults_[i];
-
- index_by_name_.add_new(name, i);
- name_by_index_.append(name);
- type_by_index_.append(&type);
-
- void *dst = allocator_.allocate(type.size(), type.alignment());
- type.copy_to_uninitialized(default_value, dst);
- defaults_.append(dst);
- }
-}
-
-AttributesInfo::~AttributesInfo()
-{
- for (int i : defaults_.index_range()) {
- type_by_index_[i]->destruct(defaults_[i]);
- }
-}
-
-} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_network.cc b/source/blender/functions/intern/multi_function_network.cc
index 77c8ba6373f..b5c2c09a35a 100644
--- a/source/blender/functions/intern/multi_function_network.cc
+++ b/source/blender/functions/intern/multi_function_network.cc
@@ -70,7 +70,7 @@ MFFunctionNode &MFNetwork::add_function(const MultiFunction &function)
}
}
- MFFunctionNode &node = *allocator_.construct<MFFunctionNode>();
+ MFFunctionNode &node = *allocator_.construct<MFFunctionNode>().release();
function_nodes_.add_new(&node);
node.network_ = this;
@@ -129,7 +129,7 @@ MFDummyNode &MFNetwork::add_dummy(StringRef name,
assert_same_size(input_types, input_names);
assert_same_size(output_types, output_names);
- MFDummyNode &node = *allocator_.construct<MFDummyNode>();
+ MFDummyNode &node = *allocator_.construct<MFDummyNode>().release();
dummy_nodes_.add_new(&node);
node.network_ = this;
diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc
index c543d86ad34..5a37a45908f 100644
--- a/source/blender/functions/intern/multi_function_network_evaluation.cc
+++ b/source/blender/functions/intern/multi_function_network_evaluation.cc
@@ -663,7 +663,7 @@ void MFNetworkEvaluationStorage::add_single_input_from_caller(const MFOutputSock
BLI_assert(value_per_output_id_[socket.id()] == nullptr);
BLI_assert(virtual_span.size() >= min_array_size_);
- auto *value = allocator_.construct<InputSingleValue>(virtual_span);
+ auto *value = allocator_.construct<InputSingleValue>(virtual_span).release();
value_per_output_id_[socket.id()] = value;
}
@@ -673,7 +673,7 @@ void MFNetworkEvaluationStorage::add_vector_input_from_caller(const MFOutputSock
BLI_assert(value_per_output_id_[socket.id()] == nullptr);
BLI_assert(virtual_array_span.size() >= min_array_size_);
- auto *value = allocator_.construct<InputVectorValue>(virtual_array_span);
+ auto *value = allocator_.construct<InputVectorValue>(virtual_array_span).release();
value_per_output_id_[socket.id()] = value;
}
@@ -683,7 +683,7 @@ void MFNetworkEvaluationStorage::add_single_output_from_caller(const MFOutputSoc
BLI_assert(value_per_output_id_[socket.id()] == nullptr);
BLI_assert(span.size() >= min_array_size_);
- auto *value = allocator_.construct<OutputSingleValue>(span);
+ auto *value = allocator_.construct<OutputSingleValue>(span).release();
value_per_output_id_[socket.id()] = value;
}
@@ -693,7 +693,7 @@ void MFNetworkEvaluationStorage::add_vector_output_from_caller(const MFOutputSoc
BLI_assert(value_per_output_id_[socket.id()] == nullptr);
BLI_assert(vector_array.size() >= min_array_size_);
- auto *value = allocator_.construct<OutputVectorValue>(vector_array);
+ auto *value = allocator_.construct<OutputVectorValue>(vector_array).release();
value_per_output_id_[socket.id()] = value;
}
@@ -705,7 +705,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_single_output__full(const MFOutputS
void *buffer = MEM_mallocN_aligned(min_array_size_ * type.size(), type.alignment(), AT);
GMutableSpan span(type, buffer, min_array_size_);
- auto *value = allocator_.construct<OwnSingleValue>(span, socket.targets().size(), false);
+ auto *value =
+ allocator_.construct<OwnSingleValue>(span, socket.targets().size(), false).release();
value_per_output_id_[socket.id()] = value;
return span;
@@ -723,7 +724,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_single_output__single(const MFOutpu
void *buffer = allocator_.allocate(type.size(), type.alignment());
GMutableSpan span(type, buffer, 1);
- auto *value = allocator_.construct<OwnSingleValue>(span, socket.targets().size(), true);
+ auto *value =
+ allocator_.construct<OwnSingleValue>(span, socket.targets().size(), true).release();
value_per_output_id_[socket.id()] = value;
return value->span;
@@ -742,7 +744,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_vector_output__full(const MFOutput
const CPPType &type = socket.data_type().vector_base_type();
GVectorArray *vector_array = new GVectorArray(type, min_array_size_);
- auto *value = allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size());
+ auto *value =
+ allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size()).release();
value_per_output_id_[socket.id()] = value;
return *value->vector_array;
@@ -759,7 +762,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_vector_output__single(const MFOutp
const CPPType &type = socket.data_type().vector_base_type();
GVectorArray *vector_array = new GVectorArray(type, 1);
- auto *value = allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size());
+ auto *value =
+ allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size()).release();
value_per_output_id_[socket.id()] = value;
return *value->vector_array;
@@ -806,8 +810,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputS
GMutableSpan new_array_ref(type, new_buffer, min_array_size_);
virtual_span.materialize_to_uninitialized(mask_, new_array_ref.data());
- OwnSingleValue *new_value = allocator_.construct<OwnSingleValue>(
- new_array_ref, to.targets().size(), false);
+ OwnSingleValue *new_value =
+ allocator_.construct<OwnSingleValue>(new_array_ref, to.targets().size(), false).release();
value_per_output_id_[to.id()] = new_value;
return new_array_ref;
}
@@ -850,8 +854,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__single(const MFInpu
type.copy_to_uninitialized(virtual_span.as_single_element(), new_buffer);
GMutableSpan new_array_ref(type, new_buffer, 1);
- OwnSingleValue *new_value = allocator_.construct<OwnSingleValue>(
- new_array_ref, to.targets().size(), true);
+ OwnSingleValue *new_value =
+ allocator_.construct<OwnSingleValue>(new_array_ref, to.targets().size(), true).release();
value_per_output_id_[to.id()] = new_value;
return new_array_ref;
}
@@ -891,8 +895,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__full(const MFInput
GVectorArray *new_vector_array = new GVectorArray(base_type, min_array_size_);
new_vector_array->extend(mask_, virtual_array_span);
- OwnVectorValue *new_value = allocator_.construct<OwnVectorValue>(*new_vector_array,
- to.targets().size());
+ OwnVectorValue *new_value =
+ allocator_.construct<OwnVectorValue>(*new_vector_array, to.targets().size()).release();
value_per_output_id_[to.id()] = new_value;
return *new_vector_array;
@@ -934,8 +938,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__single(const MFInp
GVectorArray *new_vector_array = new GVectorArray(base_type, 1);
new_vector_array->extend(0, virtual_array_span[0]);
- OwnVectorValue *new_value = allocator_.construct<OwnVectorValue>(*new_vector_array,
- to.targets().size());
+ OwnVectorValue *new_value =
+ allocator_.construct<OwnVectorValue>(*new_vector_array, to.targets().size()).release();
value_per_output_id_[to.id()] = new_value;
return *new_vector_array;
}
diff --git a/source/blender/functions/tests/FN_attributes_ref_test.cc b/source/blender/functions/tests/FN_attributes_ref_test.cc
deleted file mode 100644
index 3a5e4743c1e..00000000000
--- a/source/blender/functions/tests/FN_attributes_ref_test.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/* Apache License, Version 2.0 */
-
-#include "BLI_float3.hh"
-#include "FN_attributes_ref.hh"
-
-#include "testing/testing.h"
-
-namespace blender::fn::tests {
-
-TEST(attributes_info, BuildEmpty)
-{
- AttributesInfoBuilder info_builder;
- AttributesInfo info{info_builder};
-
- EXPECT_EQ(info.size(), 0);
-}
-
-TEST(attributes_info, AddSameNameTwice)
-{
- AttributesInfoBuilder info_builder;
- info_builder.add<int>("A", 4);
- info_builder.add<int>("A", 5);
- AttributesInfo info{info_builder};
- EXPECT_EQ(info.size(), 1);
- EXPECT_TRUE(info.has_attribute("A", CPPType::get<int>()));
- EXPECT_FALSE(info.has_attribute("B", CPPType::get<int>()));
- EXPECT_FALSE(info.has_attribute("A", CPPType::get<float>()));
- EXPECT_EQ(info.default_of<int>("A"), 4);
- EXPECT_EQ(info.name_of(0), "A");
- EXPECT_EQ(info.index_range().start(), 0);
- EXPECT_EQ(info.index_range().one_after_last(), 1);
-}
-
-TEST(attributes_info, BuildWithDefaultString)
-{
- AttributesInfoBuilder info_builder;
- info_builder.add("A", CPPType::get<std::string>());
- AttributesInfo info{info_builder};
- EXPECT_EQ(info.default_of<std::string>("A"), "");
-}
-
-TEST(attributes_info, BuildWithGivenDefault)
-{
- AttributesInfoBuilder info_builder;
- info_builder.add<std::string>("A", "hello world");
- AttributesInfo info{info_builder};
- const void *default_value = info.default_of("A");
- EXPECT_EQ(*(const std::string *)default_value, "hello world");
- EXPECT_EQ(info.type_of("A"), CPPType::get<std::string>());
-}
-
-TEST(mutable_attributes_ref, ComplexTest)
-{
- AttributesInfoBuilder info_builder;
- info_builder.add<float3>("Position", {0, 0, 10});
- info_builder.add<uint>("ID", 0);
- info_builder.add<float>("Size", 0.5f);
- info_builder.add<std::string>("Name", "<no name>");
- AttributesInfo info{info_builder};
-
- int amount = 5;
- Array<float3> positions(amount);
- Array<uint> ids(amount, 0);
- Array<float> sizes(amount);
- Array<std::string> names(amount);
-
- Array<void *> buffers = {positions.data(), ids.data(), sizes.data(), names.data()};
- MutableAttributesRef attributes{info, buffers, IndexRange(1, 3)};
- EXPECT_EQ(attributes.size(), 3);
- EXPECT_EQ(attributes.info().size(), 4);
- EXPECT_EQ(attributes.get("Position").data(), positions.data() + 1);
- EXPECT_EQ(attributes.get("ID").data(), ids.data() + 1);
- EXPECT_EQ(attributes.get("Size").data(), sizes.data() + 1);
- EXPECT_EQ(attributes.get("Name").data(), names.data() + 1);
-
- EXPECT_EQ(attributes.get("ID").size(), 3);
- EXPECT_EQ(attributes.get<uint>("ID").size(), 3);
-
- EXPECT_EQ(ids[2], 0);
- MutableSpan<uint> ids_span = attributes.get<uint>("ID");
- ids_span[1] = 42;
- EXPECT_EQ(ids[2], 42);
-
- EXPECT_FALSE(attributes.try_get<int>("not existant").has_value());
- EXPECT_FALSE(attributes.try_get<int>("Position").has_value());
- EXPECT_TRUE(attributes.try_get<float3>("Position").has_value());
- EXPECT_FALSE(attributes.try_get("not existant", CPPType::get<int>()).has_value());
- EXPECT_FALSE(attributes.try_get("Position", CPPType::get<int>()).has_value());
- EXPECT_TRUE(attributes.try_get("Position", CPPType::get<float3>()).has_value());
-
- MutableAttributesRef sliced = attributes.slice(IndexRange(1, 2));
- EXPECT_EQ(sliced.size(), 2);
- sliced.get<uint>("ID")[0] = 100;
- EXPECT_EQ(ids[2], 100);
-}
-
-} // namespace blender::fn::tests
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
index 05e7a23bc82..10383a9417d 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
@@ -371,14 +371,9 @@ PanelType *gpencil_modifier_panel_register(ARegionType *region_type,
GpencilModifierType type,
PanelDrawFn draw)
{
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- /* Get the name for the modifier's panel. */
- char panel_idname[BKE_ST_MAXNAME];
- BKE_gpencil_modifierType_panel_id(type, panel_idname);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
-
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BKE_gpencil_modifierType_panel_id(type, panel_type->idname);
BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
@@ -412,13 +407,9 @@ PanelType *gpencil_modifier_subpanel_register(ARegionType *region_type,
PanelDrawFn draw,
PanelType *parent)
{
- /* Create the subpanel's ID name. */
- char panel_idname[BKE_ST_MAXNAME];
- BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc
index 24cdea74347..2ae50d913da 100644
--- a/source/blender/gpu/intern/gpu_matrix.cc
+++ b/source/blender/gpu/intern/gpu_matrix.cc
@@ -736,7 +736,7 @@ float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float di
int depthbits = 24;
depth_fac = 1.0f / (float)((1 << depthbits) - 1);
}
- offs = (-1.0 / winmat[2][2]) * dist * depth_fac;
+ ofs = (-1.0 / winmat[2][2]) * dist * depth_fac;
UNUSED_VARS(viewdist);
#endif
@@ -765,10 +765,10 @@ void GPU_polygon_offset(float viewdist, float dist)
/* dist is from camera to center point */
- float offs = GPU_polygon_offset_calc(winmat, viewdist, dist);
+ float ofs = GPU_polygon_offset_calc(winmat, viewdist, dist);
- winmat[3][2] -= offs;
- offset += offs;
+ winmat[3][2] -= ofs;
+ offset += ofs;
}
else {
winmat[3][2] += offset;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
index 0231aeca04b..edf2c93c9a0 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
@@ -3,12 +3,13 @@ void node_ambient_occlusion(vec4 color,
float dist,
vec3 normal,
const float inverted,
+ const float sample_count,
out vec4 result_color,
out float result_ao)
{
vec3 bent_normal;
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- OcclusionData data = occlusion_search(viewPosition, maxzBuffer, dist, inverted, 8.0);
+ OcclusionData data = occlusion_search(viewPosition, maxzBuffer, dist, inverted, sample_count);
vec3 V = cameraVec(worldPosition);
vec3 N = normalize(normal);
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 14f0fef5270..c708219cfe8 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -566,6 +566,12 @@ enum {
/* RESET_AFTER_USE Used by undo system to tag unchanged IDs re-used from old Main (instead of
* read from memfile). */
LIB_TAG_UNDO_OLD_ID_REUSED = 1 << 19,
+
+ /* This ID is part of a temporary #Main which is expected to be freed in a short time-frame.
+ * Don't allow assigning this to non-temporary members (since it's likely to cause errors).
+ * When set #ID.session_uuid isn't initialized, since the data isn't part of the session. */
+ LIB_TAG_TEMP_MAIN = 1 << 20,
+
};
/* Tag given ID for an update in all the dependency graphs. */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index dbcb6ce45ea..368b1f93e4a 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -904,6 +904,7 @@ enum {
eBooleanModifierFlag_Self = (1 << 0),
eBooleanModifierFlag_Object = (1 << 1),
eBooleanModifierFlag_Collection = (1 << 2),
+ eBooleanModifierFlag_HoleTolerant = (1 << 3),
};
/* bm_flag only used when G_DEBUG. */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 8b0bc235861..82509599931 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1070,7 +1070,8 @@ typedef struct CryptomatteEntry {
typedef struct NodeCryptomatte {
float add[3];
float remove[3];
- char *matte_id DNA_DEPRECATED;
+ /* Stores `entries` as a string for opening in 2.80-2.91. */
+ char *matte_id;
/* Contains `CryptomatteEntry`. */
ListBase entries;
int num_inputs;
diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h
index 16129768b60..7a39e0caef3 100644
--- a/source/blender/makesdna/DNA_outliner_types.h
+++ b/source/blender/makesdna/DNA_outliner_types.h
@@ -73,6 +73,16 @@ enum {
/** #TreeStoreElem.types */
typedef enum eTreeStoreElemType {
+ /**
+ * If an element is of this type, `TreeStoreElem.id` points to a valid ID and the ID-type can be
+ * received through `TreeElement.idcode` (or `GS(TreeStoreElem.id->name)`). Note however that the
+ * types below may also have a valid ID pointer (see #TSE_IS_REAL_ID()).
+ *
+ * In cases where the type is still checked against "0" (even implicitly), please replace it with
+ * an explicit check against `TSE_SOME_ID`.
+ */
+ TSE_SOME_ID = 0,
+
TSE_NLA = 1, /* NO ID */
TSE_NLA_ACTION = 2,
TSE_DEFGROUP_BASE = 3,
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 8c0660522e0..8fa2951e3d7 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -66,6 +66,9 @@ typedef struct SpaceProperties_Runtime SpaceProperties_Runtime;
/* Defined in `node_intern.h`. */
typedef struct SpaceNode_Runtime SpaceNode_Runtime;
+/* Defined in `file_intern.h`. */
+typedef struct SpaceFile_Runtime SpaceFile_Runtime;
+
/* -------------------------------------------------------------------- */
/** \name SpaceLink (Base)
* \{ */
@@ -490,6 +493,7 @@ typedef enum eGraphEdit_Flag {
SIPO_NORMALIZE_FREEZE = (1 << 15),
/* show markers region */
SIPO_SHOW_MARKERS = (1 << 16),
+ SIPO_NO_DRAW_EXTRAPOLATION = (1 << 17),
} eGraphEdit_Flag;
/* SpaceGraph.mode (Graph Editor Mode) */
@@ -847,6 +851,8 @@ typedef struct SpaceFile {
short recentnr, bookmarknr;
short systemnr, system_bookmarknr;
+
+ SpaceFile_Runtime *runtime;
} SpaceFile;
/* SpaceFile.browse_mode (File Space Browsing Mode) */
@@ -1836,6 +1842,22 @@ typedef struct SpaceStatusBar {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Spreadsheet
+ * \{ */
+
+typedef struct SpaceSpreadsheet {
+ SpaceLink *next, *prev;
+ /** Storage of regions for inactive spaces. */
+ ListBase regionbase;
+ char spacetype;
+ char link_flag;
+ char _pad0[6];
+ /* End 'SpaceLink' header. */
+} SpaceSpreadsheet;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Space Defines (eSpace_Type)
* \{ */
@@ -1872,8 +1894,9 @@ typedef enum eSpace_Type {
SPACE_CLIP = 20,
SPACE_TOPBAR = 21,
SPACE_STATUSBAR = 22,
+ SPACE_SPREADSHEET = 23
-#define SPACE_TYPE_LAST SPACE_STATUSBAR
+#define SPACE_TYPE_LAST SPACE_SPREADSHEET
} eSpace_Type;
/* use for function args */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index d304641e112..bd8f3cd95a7 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -492,6 +492,7 @@ typedef struct bTheme {
ThemeSpace space_clip;
ThemeSpace space_topbar;
ThemeSpace space_statusbar;
+ ThemeSpace space_spreadsheet;
/* 20 sets of bone colors for this theme */
ThemeWireColor tarm[20];
@@ -507,7 +508,7 @@ typedef struct bTheme {
#define UI_THEMESPACE_START(btheme) \
(CHECK_TYPE_INLINE(btheme, bTheme *), &((btheme)->space_properties))
#define UI_THEMESPACE_END(btheme) \
- (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_statusbar) + 1))
+ (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_spreadsheet) + 1))
typedef struct bAddon {
struct bAddon *next, *prev;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index fc9ad7918a4..8e3c94a3ff9 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -603,6 +603,7 @@ extern StructRNA RNA_SpaceOutliner;
extern StructRNA RNA_SpacePreferences;
extern StructRNA RNA_SpaceProperties;
extern StructRNA RNA_SpaceSequenceEditor;
+extern StructRNA RNA_SpaceSpreadsheet;
extern StructRNA RNA_SpaceTextEditor;
extern StructRNA RNA_SpaceUVEditor;
extern StructRNA RNA_SpaceView3D;
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index c12426ffcd0..c49a52ceed7 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -421,7 +421,7 @@ void RNA_def_property_string_funcs(PropertyRNA *prop,
const char *length,
const char *set);
void RNA_def_property_pointer_funcs(
- PropertyRNA *prop, const char *get, const char *set, const char *typef, const char *poll);
+ PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll);
void RNA_def_property_collection_funcs(PropertyRNA *prop,
const char *begin,
const char *next,
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index bec3db10905..1f887c2eec3 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3671,7 +3671,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
}
}
else {
- if (!defaultfound && !(eprop->itemf && eprop->item == DummyRNA_NULL_items)) {
+ if (!defaultfound && !(eprop->item_fn && eprop->item == DummyRNA_NULL_items)) {
CLOG_ERROR(&LOG,
"%s%s.%s, enum default is not in items.",
srna->identifier,
@@ -3992,7 +3992,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
"\t%s, %s, %s, %s, %s, NULL, ",
rna_function_string(eprop->get),
rna_function_string(eprop->set),
- rna_function_string(eprop->itemf),
+ rna_function_string(eprop->item_fn),
rna_function_string(eprop->get_ex),
rna_function_string(eprop->set_ex));
if (eprop->item) {
@@ -4010,7 +4010,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
"\t%s, %s, %s, %s,",
rna_function_string(pprop->get),
rna_function_string(pprop->set),
- rna_function_string(pprop->typef),
+ rna_function_string(pprop->type_fn),
rna_function_string(pprop->poll));
if (pprop->type) {
fprintf(f, "&RNA_%s\n", (const char *)pprop->type);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index c5dd516d16e..8e5e70642cc 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -1571,8 +1571,8 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
if (prop->type == PROP_POINTER) {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
- if (pprop->typef) {
- return pprop->typef(ptr);
+ if (pprop->type_fn) {
+ return pprop->type_fn(ptr);
}
if (pprop->type) {
return pprop->type;
@@ -1623,14 +1623,14 @@ void RNA_property_enum_items_ex(bContext *C,
*r_free = false;
- if (!use_static && eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
+ if (!use_static && eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
const EnumPropertyItem *item;
if (prop->flag & PROP_ENUM_NO_CONTEXT) {
- item = eprop->itemf(NULL, ptr, prop, r_free);
+ item = eprop->item_fn(NULL, ptr, prop, r_free);
}
else {
- item = eprop->itemf(C, ptr, prop, r_free);
+ item = eprop->item_fn(C, ptr, prop, r_free);
}
/* any callbacks returning NULL should be fixed */
@@ -1753,16 +1753,16 @@ void RNA_property_enum_items_gettexted_all(bContext *C,
*r_totitem = eprop->totitem;
}
- if (eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
+ if (eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
const EnumPropertyItem *item;
int i;
bool free = false;
if (prop->flag & PROP_ENUM_NO_CONTEXT) {
- item = eprop->itemf(NULL, ptr, prop, &free);
+ item = eprop->item_fn(NULL, ptr, prop, &free);
}
else {
- item = eprop->itemf(C, ptr, prop, &free);
+ item = eprop->item_fn(C, ptr, prop, &free);
}
/* any callbacks returning NULL should be fixed */
@@ -3662,8 +3662,8 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
}
/* for groups, data is idprop itself */
- if (pprop->typef) {
- return rna_pointer_inherit_refine(ptr, pprop->typef(ptr), idprop);
+ if (pprop->type_fn) {
+ return rna_pointer_inherit_refine(ptr, pprop->type_fn(ptr), idprop);
}
return rna_pointer_inherit_refine(ptr, pprop->type, idprop);
}
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index d6305388cf9..0f3b0a895db 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -20,6 +20,8 @@
#include <string.h>
+#include <CLG_log.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
@@ -53,6 +55,8 @@
#include "rna_access_internal.h"
#include "rna_internal.h"
+static CLG_LogRef LOG = {"rna.access_compare_override"};
+
/**
* Find the actual ID owner of the given \a ptr #PointerRNA, in override sense, and generate the
* full rna path from it to given \a prop #PropertyRNA if \a rna_path is given.
@@ -411,12 +415,11 @@ static int rna_property_override_diff(Main *bmain,
}
if (override_diff == NULL) {
-#ifndef NDEBUG
- printf("'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d).\n",
- rna_path ? rna_path : prop_a->identifier,
- !prop_a->is_idprop,
- !prop_b->is_idprop);
-#endif
+ CLOG_ERROR(&LOG,
+ "'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d)",
+ rna_path ? rna_path : prop_a->identifier,
+ !prop_a->is_idprop,
+ !prop_b->is_idprop);
BLI_assert(0);
return 1;
}
@@ -501,12 +504,11 @@ static bool rna_property_override_operation_store(Main *bmain,
}
if (override_store == NULL) {
-#ifndef NDEBUG
- printf("'%s' gives unmatching or NULL RNA store callbacks, should not happen (%d vs. %d).\n",
- op->rna_path,
- prop_local->magic == RNA_MAGIC,
- prop_reference->magic == RNA_MAGIC);
-#endif
+ CLOG_ERROR(&LOG,
+ "'%s' gives unmatching or NULL RNA store callbacks, should not happen (%d vs. %d)",
+ op->rna_path,
+ prop_local->magic == RNA_MAGIC,
+ prop_reference->magic == RNA_MAGIC);
BLI_assert(0);
return changed;
}
@@ -590,12 +592,12 @@ static bool rna_property_override_operation_apply(Main *bmain,
}
if (override_apply == NULL) {
-#ifndef NDEBUG
- printf("'%s' gives unmatching or NULL RNA copy callbacks, should not happen (%d vs. %d).\n",
- prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name : prop_dst->identifier,
- prop_dst->magic == RNA_MAGIC,
- prop_src->magic == RNA_MAGIC);
-#endif
+ CLOG_ERROR(&LOG,
+ "'%s' gives unmatching or NULL RNA apply callbacks, should not happen (%d vs. %d)",
+ prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name :
+ prop_dst->identifier,
+ prop_dst->magic == RNA_MAGIC,
+ prop_src->magic == RNA_MAGIC);
BLI_assert(0);
return false;
}
@@ -788,7 +790,7 @@ bool RNA_struct_override_matches(Main *bmain,
continue;
}
- // printf("Override Checking %s\n", rna_path);
+ CLOG_INFO(&LOG, 5, "Override Checking %s\n", rna_path);
IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path);
if (ignore_overridden && op != NULL) {
@@ -990,11 +992,9 @@ static void rna_property_override_apply_ex(Main *bmain,
if (!do_insert != !ELEM(opop->operation,
IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE)) {
-#ifndef NDEBUG
if (!do_insert) {
- printf("Skipping insert override operations in first pass (%s)!\n", op->rna_path);
+ CLOG_INFO(&LOG, 5, "Skipping insert override operations in first pass (%s)", op->rna_path);
}
-#endif
continue;
}
@@ -1078,22 +1078,25 @@ static void rna_property_override_apply_ex(Main *bmain,
ptr_item_src = &private_ptr_item_src;
ptr_item_storage = &private_ptr_item_storage;
-#ifndef NDEBUG
if (ptr_item_dst->type == NULL) {
- printf("Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'\n",
- opop->subitem_reference_name,
- opop->subitem_reference_index,
- op->rna_path,
- ptr_dst->owner_id->name);
+ CLOG_INFO(
+ &LOG,
+ 2,
+ "Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'",
+ opop->subitem_reference_name,
+ opop->subitem_reference_index,
+ op->rna_path,
+ ptr_dst->owner_id->name);
}
if (ptr_item_src->type == NULL) {
- printf("Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'\n",
- opop->subitem_local_name,
- opop->subitem_local_index,
- op->rna_path,
- ptr_src->owner_id->name);
+ CLOG_INFO(&LOG,
+ 2,
+ "Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'",
+ opop->subitem_local_name,
+ opop->subitem_local_index,
+ op->rna_path,
+ ptr_src->owner_id->name);
}
-#endif
}
if (!rna_property_override_operation_apply(bmain,
@@ -1107,9 +1110,11 @@ static void rna_property_override_apply_ex(Main *bmain,
ptr_item_src,
ptr_item_storage,
opop)) {
- printf("Failed to apply '%s' override operation on %s\n",
- op->rna_path,
- ptr_src->owner_id->name);
+ CLOG_INFO(&LOG,
+ 2,
+ "Failed to apply '%s' override operation on %s\n",
+ op->rna_path,
+ ptr_src->owner_id->name);
}
}
}
@@ -1166,17 +1171,16 @@ void RNA_struct_override_apply(Main *bmain,
op,
do_insert);
}
-#ifndef NDEBUG
else {
- printf(
- "Failed to apply library override operation to '%s.%s' "
- "(could not resolve some properties, local: %d, override: %d)\n",
- ((ID *)ptr_src->owner_id)->name,
- op->rna_path,
- RNA_path_resolve_property(ptr_dst, op->rna_path, &data_dst, &prop_dst),
- RNA_path_resolve_property(ptr_src, op->rna_path, &data_src, &prop_src));
+ CLOG_INFO(&LOG,
+ 2,
+ "Failed to apply library override operation to '%s.%s' "
+ "(could not resolve some properties, local: %d, override: %d)",
+ ((ID *)ptr_src->owner_id)->name,
+ op->rna_path,
+ RNA_path_resolve_property(ptr_dst, op->rna_path, &data_dst, &prop_dst),
+ RNA_path_resolve_property(ptr_src, op->rna_path, &data_src, &prop_src));
}
-#endif
}
}
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index df3bd0cca29..5e188285e39 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -3267,7 +3267,7 @@ void RNA_def_property_enum_funcs(PropertyRNA *prop,
eprop->set = (PropEnumSetFunc)set;
}
if (item) {
- eprop->itemf = (PropEnumItemFunc)item;
+ eprop->item_fn = (PropEnumItemFunc)item;
}
break;
}
@@ -3292,7 +3292,7 @@ void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop,
eprop->set_ex = setfunc;
}
if (itemfunc) {
- eprop->itemf = itemfunc;
+ eprop->item_fn = itemfunc;
}
if (getfunc || setfunc) {
@@ -3373,7 +3373,7 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
}
void RNA_def_property_pointer_funcs(
- PropertyRNA *prop, const char *get, const char *set, const char *typef, const char *poll)
+ PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll)
{
StructRNA *srna = DefRNA.laststruct;
@@ -3392,8 +3392,8 @@ void RNA_def_property_pointer_funcs(
if (set) {
pprop->set = (PropPointerSetFunc)set;
}
- if (typef) {
- pprop->typef = (PropPointerTypeFunc)typef;
+ if (type_fn) {
+ pprop->type_fn = (PropPointerTypeFunc)type_fn;
}
if (poll) {
pprop->poll = (PropPointerPollFunc)poll;
@@ -3821,7 +3821,7 @@ PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont_,
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
- eprop->itemf = itemfunc;
+ eprop->item_fn = itemfunc;
}
PropertyRNA *RNA_def_float(StructOrFunctionRNA *cont_,
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index bfcb0039ca8..95972dd444f 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -424,6 +424,7 @@ void RNA_api_window(struct StructRNA *srna);
void RNA_api_wm(struct StructRNA *srna);
void RNA_api_space_node(struct StructRNA *srna);
void RNA_api_space_text(struct StructRNA *srna);
+void RNA_api_space_filebrowser(struct StructRNA *srna);
void RNA_api_region_view3d(struct StructRNA *srna);
void RNA_api_texture(struct StructRNA *srna);
void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastrip);
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index e6ed0f69300..1dd08bb1074 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -453,7 +453,7 @@ typedef struct EnumPropertyRNA {
PropEnumGetFunc get;
PropEnumSetFunc set;
- PropEnumItemFunc itemf;
+ PropEnumItemFunc item_fn;
PropEnumGetFuncEx get_ex;
PropEnumSetFuncEx set_ex;
@@ -471,7 +471,7 @@ typedef struct PointerPropertyRNA {
PropPointerGetFunc get;
PropPointerSetFunc set;
- PropPointerTypeFunc typef;
+ PropPointerTypeFunc type_fn;
/** unlike operators, 'set' can still run if poll fails, used for filtering display. */
PropPointerPollFunc poll;
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 5008240ea33..98a2b683f18 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -2789,6 +2789,11 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Self", "Allow self-intersection in operands");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "use_hole_tolerant", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eBooleanModifierFlag_HoleTolerant);
+ RNA_def_property_ui_text(prop, "Hole Tolerant", "Better results when there are holes (slower)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
/* BMesh debugging options, only used when G_DEBUG is set */
/* BMesh intersection options */
@@ -3134,7 +3139,8 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_range(prop, 1, FLT_MAX);
RNA_def_property_ui_range(prop, 1, 1000, 1, 3);
- RNA_def_property_ui_text(prop, "Horizontal Aspect Ratio", "");
+ RNA_def_property_ui_text(
+ prop, "Aspect X", "Horizontal aspect ratio (only used for camera projectors)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "aspect_y", PROP_FLOAT, PROP_NONE);
@@ -3142,7 +3148,8 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_range(prop, 1, FLT_MAX);
RNA_def_property_ui_range(prop, 1, 1000, 1, 3);
- RNA_def_property_ui_text(prop, "Vertical Aspect Ratio", "");
+ RNA_def_property_ui_text(
+ prop, "Aspect Y", "Vertical aspect ratio (only used for camera projectors)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "scale_x", PROP_FLOAT, PROP_NONE);
@@ -3150,7 +3157,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 1000, 1, 3);
- RNA_def_property_ui_text(prop, "Horizontal Scale", "");
+ RNA_def_property_ui_text(prop, "Scale X", "Horizontal scale (only used for camera projectors)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "scale_y", PROP_FLOAT, PROP_NONE);
@@ -3158,7 +3165,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 1000, 1, 3);
- RNA_def_property_ui_text(prop, "Vertical Scale", "");
+ RNA_def_property_ui_text(prop, "Scale Y", "Vertical scale (only used for camera projectors)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
srna = RNA_def_struct(brna, "UVProjector", NULL);
diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c
index 59704b00391..29516830058 100644
--- a/source/blender/makesrna/intern/rna_pose_api.c
+++ b/source/blender/makesrna/intern/rna_pose_api.c
@@ -38,9 +38,14 @@
#ifdef RNA_RUNTIME
-/* #include "DNA_anim_types.h" */
+# include "BKE_animsys.h"
# include "BKE_armature.h"
-# include "DNA_action_types.h" /* bPose */
+# include "BKE_context.h"
+
+# include "DNA_action_types.h"
+# include "DNA_anim_types.h"
+
+# include "BLI_ghash.h"
static float rna_PoseBone_do_envelope(bPoseChannel *chan, float *vec)
{
@@ -102,12 +107,49 @@ static void rna_PoseBone_compute_bbone_handles(bPoseChannel *pchan,
BKE_pchan_bbone_handles_compute(
&params, ret_h1, ret_roll1, ret_h2, ret_roll2, ease || offsets, offsets);
}
+
+static void rna_Pose_apply_pose_from_action(ID *pose_owner,
+ bContext *C,
+ bAction *action,
+ const float evaluation_time)
+{
+ BLI_assert(GS(pose_owner->name) == ID_OB);
+ Object *pose_owner_ob = (Object *)pose_owner;
+
+ AnimationEvalContext anim_eval_context = {CTX_data_depsgraph_pointer(C), evaluation_time};
+ BKE_pose_apply_action(pose_owner_ob, action, &anim_eval_context);
+
+ /* Do NOT tag with ID_RECALC_ANIMATION, as that would overwrite the just-applied pose. */
+ DEG_id_tag_update(pose_owner, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pose_owner);
+}
+
#else
-void RNA_api_pose(StructRNA *UNUSED(srna))
+void RNA_api_pose(StructRNA *srna)
{
- /* FunctionRNA *func; */
- /* PropertyRNA *parm; */
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ func = RNA_def_function(srna, "apply_pose_from_action", "rna_Pose_apply_pose_from_action");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(
+ func,
+ "Apply the given action to this pose by evaluating it at a specific time. Only updates the "
+ "pose of selected bones, or all bones if none are selected.");
+
+ parm = RNA_def_pointer(func, "action", "Action", "Action", "The Action containing the pose");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ parm = RNA_def_float(func,
+ "evaluation_time",
+ 0.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Evaluation Time",
+ "Time at which the given action is evaluated to obtain the pose",
+ -FLT_MAX,
+ FLT_MAX);
}
void RNA_api_pose_channel(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index b0a942cd39e..d553ead1e45 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -910,14 +910,14 @@ static const EnumPropertyItem *rna_EnumProperty_default_itemf(bContext *C,
return DummyRNA_NULL_items;
}
- if ((eprop->itemf == NULL) || (eprop->itemf == rna_EnumProperty_default_itemf) ||
+ if ((eprop->item_fn == NULL) || (eprop->item_fn == rna_EnumProperty_default_itemf) ||
(ptr->type == &RNA_EnumProperty) || (C == NULL)) {
if (eprop->item) {
return eprop->item;
}
}
- return eprop->itemf(C, ptr, prop, r_free);
+ return eprop->item_fn(C, ptr, prop, r_free);
}
/* XXX - not sure this is needed? */
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 6cf1d7a923b..58e446381ad 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -201,6 +201,10 @@ static const EnumPropertyItem *rna_Area_ui_type_itemf(bContext *C,
if (ELEM(item_from->value, SPACE_TOPBAR, SPACE_STATUSBAR)) {
continue;
}
+ /* Hide spreadsheet editor until we want to expose it in the ui. */
+ if (item_from->value == SPACE_SPREADSHEET) {
+ continue;
+ }
SpaceType *st = item_from->identifier[0] ? BKE_spacetype_from_id(item_from->value) : NULL;
int totitem_prev = totitem;
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 89402c3170d..447e11594a7 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -145,6 +145,11 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
"Properties",
"Edit properties of active object and related data-blocks"},
{SPACE_FILE, "FILE_BROWSER", ICON_FILEBROWSER, "File Browser", "Browse for files and assets"},
+ {SPACE_SPREADSHEET,
+ "SPREADSHEET",
+ ICON_SPREADSHEET,
+ "Spreadsheet",
+ "Explore geometry data in a table"},
{SPACE_USERPREF,
"PREFERENCES",
ICON_PREFERENCES,
@@ -572,6 +577,8 @@ static StructRNA *rna_Space_refine(struct PointerRNA *ptr)
return &RNA_SpacePreferences;
case SPACE_CLIP:
return &RNA_SpaceClipEditor;
+ case SPACE_SPREADSHEET:
+ return &RNA_SpaceSpreadsheet;
/* Currently no type info. */
case SPACE_SCRIPT:
@@ -5675,6 +5682,11 @@ static void rna_def_space_graph(BlenderRNA *brna)
"If any exists, show markers in a separate row at the bottom of the editor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+ prop = RNA_def_property(srna, "show_extrapolation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NO_DRAW_EXTRAPOLATION);
+ RNA_def_property_ui_text(prop, "Show Extrapolation", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+
/* editing */
prop = RNA_def_property(srna, "use_auto_merge_keyframes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NOTRANSKEYCULL);
@@ -6570,6 +6582,8 @@ static void rna_def_space_filebrowser(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(
prop, NC_SPACE | ND_SPACE_FILE_PARAMS, "rna_FileBrowser_FSMenu_active_update");
+
+ RNA_api_space_filebrowser(srna);
}
static void rna_def_space_info(BlenderRNA *brna)
@@ -7170,6 +7184,14 @@ static void rna_def_space_clip(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
}
+static void rna_def_space_spreadsheet(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space");
+ RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data");
+}
+
void RNA_def_space(BlenderRNA *brna)
{
rna_def_space(brna);
@@ -7195,6 +7217,7 @@ void RNA_def_space(BlenderRNA *brna)
rna_def_node_tree_path(brna);
rna_def_space_node(brna);
rna_def_space_clip(brna);
+ rna_def_space_spreadsheet(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index e4c0ade1533..205a88edf84 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -27,6 +27,7 @@
# include "BKE_global.h"
+# include "ED_fileselect.h"
# include "ED_screen.h"
# include "ED_text.h"
@@ -115,4 +116,24 @@ void RNA_api_space_text(StructRNA *srna)
RNA_def_function_output(func, parm);
}
+void RNA_api_space_filebrowser(StructRNA *srna)
+{
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ func = RNA_def_function(srna, "activate_asset_by_id", "ED_fileselect_activate_by_id");
+ RNA_def_function_ui_description(func, "Activate the asset entry that represents the given ID");
+
+ parm = RNA_def_property(func, "id_to_activate", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(parm, "ID");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ parm = RNA_def_boolean(
+ func,
+ "deferred",
+ 0,
+ "",
+ "Whether to activate the ID immediately (false) or after the file browser refreshes (true)");
+}
+
#endif
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index b06ec674e81..4097e2dddea 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -3847,6 +3847,26 @@ static void rna_def_userdef_theme_space_statusbar(BlenderRNA *brna)
rna_def_userdef_theme_spaces_main(srna);
}
+static void rna_def_userdef_theme_space_spreadsheet(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* space_spreadsheet */
+
+ srna = RNA_def_struct(brna, "ThemeSpreadsheet", NULL);
+ RNA_def_struct_sdna(srna, "ThemeSpace");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Theme Spreadsheet", "Theme settings for the Spreadsheet");
+
+ prop = RNA_def_property(srna, "row_alternate", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Alternate Rows", "Overlay color on every other row");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+ rna_def_userdef_theme_spaces_main(srna);
+}
+
static void rna_def_userdef_themes(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3873,6 +3893,7 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
{20, "CLIP_EDITOR", ICON_TRACKER, "Movie Clip Editor", ""},
{21, "TOPBAR", ICON_TOPBAR, "Top Bar", ""},
{22, "STATUSBAR", ICON_STATUSBAR, "Status Bar", ""},
+ {23, "SPREADSHEET", ICON_SPREADSHEET, "Spreadsheet"},
{0, NULL, 0, NULL, NULL},
};
@@ -4001,6 +4022,12 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "space_statusbar");
RNA_def_property_struct_type(prop, "ThemeStatusBar");
RNA_def_property_ui_text(prop, "Status Bar", "");
+
+ prop = RNA_def_property(srna, "spreadsheet", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "space_spreadsheet");
+ RNA_def_property_struct_type(prop, "ThemeSpreadsheet");
+ RNA_def_property_ui_text(prop, "Spreadsheet", "");
/* end space types */
prop = RNA_def_property(srna, "bone_color_sets", PROP_COLLECTION, PROP_NONE);
@@ -4254,6 +4281,7 @@ static void rna_def_userdef_dothemes(BlenderRNA *brna)
rna_def_userdef_theme_space_clip(brna);
rna_def_userdef_theme_space_topbar(brna);
rna_def_userdef_theme_space_statusbar(brna);
+ rna_def_userdef_theme_space_spreadsheet(brna);
rna_def_userdef_theme_colorset(brna);
rna_def_userdef_theme_collection_color(brna);
rna_def_userdef_themes(brna);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index cb20b480ee5..e7ca41bb5be 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -1216,6 +1216,11 @@ void RNA_api_keymaps(StructRNA *srna)
func = RNA_def_function(srna, "new", "rna_keymap_new"); /* add_keymap */
RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(
+ func,
+ "Ensure the keymap exists. This will return the one with the given name/space type/region "
+ "type, or create a new one if it does not exist yet.");
+
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_enum(func, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", "");
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 070ba3a1bcf..6ffbf518dd1 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -21,7 +21,7 @@
* \ingroup modifiers
*/
-// #ifdef DEBUG_TIME
+// #define DEBUG_TIME
#include <stdio.h>
@@ -422,7 +422,7 @@ static void BMD_mesh_intersection(BMesh *bm,
if (use_exact) {
BM_mesh_boolean(
- bm, looptris, tottri, bm_face_isect_pair, NULL, 2, use_self, false, bmd->operation);
+ bm, looptris, tottri, bm_face_isect_pair, NULL, 2, use_self, false, false, bmd->operation);
}
else {
BM_mesh_intersect(bm,
@@ -587,8 +587,16 @@ static Mesh *collection_boolean_exact(BooleanModifierData *bmd,
}
BM_mesh_elem_index_ensure(bm, BM_FACE);
- BM_mesh_boolean(
- bm, looptris, tottri, bm_face_isect_nary, shape, num_shapes, true, false, bmd->operation);
+ BM_mesh_boolean(bm,
+ looptris,
+ tottri,
+ bm_face_isect_nary,
+ shape,
+ num_shapes,
+ true,
+ false,
+ false,
+ bmd->operation);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
@@ -651,10 +659,12 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
}
const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
+ const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0;
result = BKE_mesh_boolean((const Mesh **)meshes,
(const float(**)[4][4])obmats,
BLI_array_len(meshes),
use_self,
+ hole_tolerant,
bmd->operation);
BLI_array_free(meshes);
@@ -846,31 +856,44 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "collection", 0, NULL, ICON_NONE);
}
+ uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ modifier_panel_end(layout, ptr);
+}
+
+static void solver_options_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL);
+
const bool use_exact = RNA_enum_get(ptr, "solver") == eBooleanModifierSolver_Exact;
+ const bool operand_object = RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object;
- uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiLayoutSetPropSep(layout, true);
+ uiLayout *col = uiLayoutColumn(layout, true);
if (use_exact) {
/* When operand is collection, we always use_self. */
if (operand_object) {
- uiItemR(layout, ptr, "use_self", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_self", 0, NULL, ICON_NONE);
}
+ uiItemR(col, ptr, "use_hole_tolerant", 0, NULL, ICON_NONE);
}
else {
- uiItemR(layout, ptr, "double_threshold", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "double_threshold", 0, NULL, ICON_NONE);
}
if (G.debug) {
- uiLayout *col = uiLayoutColumn(layout, true);
uiItemR(col, ptr, "debug_options", 0, NULL, ICON_NONE);
}
-
- modifier_panel_end(layout, ptr);
}
static void panelRegister(ARegionType *region_type)
{
- modifier_panel_register(region_type, eModifierType_Boolean, panel_draw);
+ PanelType *panel = modifier_panel_register(region_type, eModifierType_Boolean, panel_draw);
+ modifier_subpanel_register(
+ region_type, "solver_options", "Solver Options", NULL, solver_options_panel_draw, panel);
}
ModifierTypeInfo modifierType_Boolean = {
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index b47f5806c9c..34730292133 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -77,6 +77,7 @@
#include "NOD_type_callbacks.hh"
using blender::float3;
+using blender::FunctionRef;
using blender::IndexRange;
using blender::Map;
using blender::Set;
@@ -90,8 +91,8 @@ using blender::bke::PersistentObjectHandle;
using blender::fn::GMutablePointer;
using blender::fn::GValueMap;
using blender::nodes::GeoNodeExecParams;
-using namespace blender::nodes::derived_node_tree_types;
using namespace blender::fn::multi_function_types;
+using namespace blender::nodes::derived_node_tree_types;
static void initData(ModifierData *md)
{
@@ -254,8 +255,8 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
class GeometryNodesEvaluator {
private:
blender::LinearAllocator<> allocator_;
- Map<std::pair<const DInputSocket *, const DOutputSocket *>, GMutablePointer> value_by_input_;
- Vector<const DInputSocket *> group_outputs_;
+ Map<std::pair<DInputSocket, DOutputSocket>, GMutablePointer> value_by_input_;
+ Vector<DInputSocket> group_outputs_;
blender::nodes::MultiFunctionByNode &mf_by_node_;
const blender::nodes::DataTypeConversions &conversions_;
const PersistentDataHandleMap &handle_map_;
@@ -264,8 +265,8 @@ class GeometryNodesEvaluator {
Depsgraph *depsgraph_;
public:
- GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data,
- Vector<const DInputSocket *> group_outputs,
+ GeometryNodesEvaluator(const Map<DOutputSocket, GMutablePointer> &group_input_data,
+ Vector<DInputSocket> group_outputs,
blender::nodes::MultiFunctionByNode &mf_by_node,
const PersistentDataHandleMap &handle_map,
const Object *self_object,
@@ -280,15 +281,15 @@ class GeometryNodesEvaluator {
depsgraph_(depsgraph)
{
for (auto item : group_input_data.items()) {
- this->forward_to_inputs(*item.key, item.value);
+ this->forward_to_inputs(item.key, item.value);
}
}
Vector<GMutablePointer> execute()
{
Vector<GMutablePointer> results;
- for (const DInputSocket *group_output : group_outputs_) {
- Vector<GMutablePointer> result = this->get_input_values(*group_output);
+ for (const DInputSocket &group_output : group_outputs_) {
+ Vector<GMutablePointer> result = this->get_input_values(group_output);
results.append(result[0]);
}
for (GMutablePointer value : value_by_input_.values()) {
@@ -298,62 +299,63 @@ class GeometryNodesEvaluator {
}
private:
- Vector<GMutablePointer> get_input_values(const DInputSocket &socket_to_compute)
+ Vector<GMutablePointer> get_input_values(const DInputSocket socket_to_compute)
{
+ Vector<DSocket> from_sockets;
+ socket_to_compute.foreach_origin_socket([&](DSocket socket) { from_sockets.append(socket); });
- Span<const DOutputSocket *> from_sockets = socket_to_compute.linked_sockets();
- Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs();
- const int total_inputs = from_sockets.size() + from_group_inputs.size();
+ /* Multi-input sockets contain a vector of inputs. */
+ if (socket_to_compute->is_multi_input_socket()) {
+ Vector<GMutablePointer> values;
+ for (const DSocket &from_socket : from_sockets) {
+ GMutablePointer value = get_input_from_incoming_link(socket_to_compute, from_socket);
+ values.append(value);
+ }
+ return values;
+ }
- if (total_inputs == 0) {
+ if (from_sockets.is_empty()) {
/* The input is not connected, use the value from the socket itself. */
- return {get_unlinked_input_value(socket_to_compute)};
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
+ return {get_unlinked_input_value(socket_to_compute, type)};
}
- if (from_group_inputs.size() == 1) {
- return {get_unlinked_input_value(socket_to_compute)};
- }
+ const DSocket from_socket = from_sockets[0];
+ GMutablePointer value = this->get_input_from_incoming_link(socket_to_compute, from_socket);
+ return {value};
+ }
- /* Multi-input sockets contain a vector of inputs. */
- if (socket_to_compute.is_multi_input_socket()) {
- Vector<GMutablePointer> values;
- for (const DOutputSocket *from_socket : from_sockets) {
- const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
- &socket_to_compute, from_socket);
- std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
- if (value.has_value()) {
- values.append(*value);
- }
- else {
- this->compute_output_and_forward(*from_socket);
- GMutablePointer value = value_by_input_.pop(key);
- values.append(value);
- }
+ GMutablePointer get_input_from_incoming_link(const DInputSocket socket_to_compute,
+ const DSocket from_socket)
+ {
+ if (from_socket->is_output()) {
+ const DOutputSocket from_output_socket{from_socket};
+ const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(socket_to_compute,
+ from_output_socket);
+ std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
+ if (value.has_value()) {
+ /* This input has been computed before, return it directly. */
+ return {*value};
}
- return values;
- }
- const DOutputSocket &from_socket = *from_sockets[0];
- const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
- &socket_to_compute, &from_socket);
- std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
- if (value.has_value()) {
- /* This input has been computed before, return it directly. */
- return {*value};
+ /* Compute the socket now. */
+ this->compute_output_and_forward(from_output_socket);
+ return {value_by_input_.pop(key)};
}
- /* Compute the socket now. */
- this->compute_output_and_forward(from_socket);
- return {value_by_input_.pop(key)};
+ /* Get value from an unlinked input socket. */
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
+ const DInputSocket from_input_socket{from_socket};
+ return {get_unlinked_input_value(from_input_socket, type)};
}
- void compute_output_and_forward(const DOutputSocket &socket_to_compute)
+ void compute_output_and_forward(const DOutputSocket socket_to_compute)
{
- const DNode &node = socket_to_compute.node();
+ const DNode node{socket_to_compute.context(), &socket_to_compute->node()};
- if (!socket_to_compute.is_available()) {
+ if (!socket_to_compute->is_available()) {
/* If the output is not available, use a default value. */
- const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute.typeinfo());
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
void *buffer = allocator_.allocate(type.size(), type.alignment());
type.copy_to_uninitialized(type.default_value(), buffer);
this->forward_to_inputs(socket_to_compute, {type, buffer});
@@ -362,9 +364,9 @@ class GeometryNodesEvaluator {
/* Prepare inputs required to execute the node. */
GValueMap<StringRef> node_inputs_map{allocator_};
- for (const DInputSocket *input_socket : node.inputs()) {
+ for (const InputSocketRef *input_socket : node->inputs()) {
if (input_socket->is_available()) {
- Vector<GMutablePointer> values = this->get_input_values(*input_socket);
+ Vector<GMutablePointer> values = this->get_input_values({node.context(), input_socket});
for (int i = 0; i < values.size(); ++i) {
/* Values from Multi Input Sockets are stored in input map with the format
* <identifier>[<index>]. */
@@ -382,15 +384,15 @@ class GeometryNodesEvaluator {
this->execute_node(node, params);
/* Forward computed outputs to linked input sockets. */
- for (const DOutputSocket *output_socket : node.outputs()) {
+ for (const OutputSocketRef *output_socket : node->outputs()) {
if (output_socket->is_available()) {
GMutablePointer value = node_outputs_map.extract(output_socket->identifier());
- this->forward_to_inputs(*output_socket, value);
+ this->forward_to_inputs({node.context(), output_socket}, value);
}
}
}
- void execute_node(const DNode &node, GeoNodeExecParams params)
+ void execute_node(const DNode node, GeoNodeExecParams params)
{
const bNode &bnode = params.node();
@@ -403,7 +405,7 @@ class GeometryNodesEvaluator {
}
/* Use the multi-function implementation if it exists. */
- const MultiFunction *multi_function = mf_by_node_.lookup_default(&node, nullptr);
+ const MultiFunction *multi_function = mf_by_node_.lookup_default(node, nullptr);
if (multi_function != nullptr) {
this->execute_multi_function_node(node, params, *multi_function);
return;
@@ -413,51 +415,56 @@ class GeometryNodesEvaluator {
this->execute_unknown_node(node, params);
}
- void store_ui_hints(const DNode &node, GeoNodeExecParams params) const
+ void store_ui_hints(const DNode node, GeoNodeExecParams params) const
{
- for (const DInputSocket *dsocket : node.inputs()) {
- if (!dsocket->is_available()) {
+ for (const InputSocketRef *socket_ref : node->inputs()) {
+ if (!socket_ref->is_available()) {
continue;
}
- if (dsocket->bsocket()->type != SOCK_GEOMETRY) {
+ if (socket_ref->bsocket()->type != SOCK_GEOMETRY) {
+ continue;
+ }
+ if (socket_ref->is_multi_input_socket()) {
+ /* Not needed currently. */
continue;
}
- bNodeTree *btree_cow = node.node_ref().tree().btree();
+ bNodeTree *btree_cow = node->btree();
bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
const NodeTreeEvaluationContext context(*self_object_, *modifier_);
- const GeometrySet &geometry_set = params.get_input<GeometrySet>(dsocket->identifier());
+ const GeometrySet &geometry_set = params.get_input<GeometrySet>(socket_ref->identifier());
const Vector<const GeometryComponent *> components = geometry_set.get_components_for_read();
for (const GeometryComponent *component : components) {
- component->attribute_foreach([&](StringRefNull attribute_name,
- const AttributeMetaData &UNUSED(meta_data)) {
- BKE_nodetree_attribute_hint_add(*btree_original, context, *node.bnode(), attribute_name);
- return true;
- });
+ component->attribute_foreach(
+ [&](StringRefNull attribute_name, const AttributeMetaData &UNUSED(meta_data)) {
+ BKE_nodetree_attribute_hint_add(
+ *btree_original, context, *node->bnode(), attribute_name);
+ return true;
+ });
}
}
}
- void execute_multi_function_node(const DNode &node,
+ void execute_multi_function_node(const DNode node,
GeoNodeExecParams params,
const MultiFunction &fn)
{
MFContextBuilder fn_context;
MFParamsBuilder fn_params{fn, 1};
Vector<GMutablePointer> input_data;
- for (const DInputSocket *dsocket : node.inputs()) {
- if (dsocket->is_available()) {
- GMutablePointer data = params.extract_input(dsocket->identifier());
+ for (const InputSocketRef *socket_ref : node->inputs()) {
+ if (socket_ref->is_available()) {
+ GMutablePointer data = params.extract_input(socket_ref->identifier());
fn_params.add_readonly_single_input(GSpan(*data.type(), data.get(), 1));
input_data.append(data);
}
}
Vector<GMutablePointer> output_data;
- for (const DOutputSocket *dsocket : node.outputs()) {
- if (dsocket->is_available()) {
- const CPPType &type = *blender::nodes::socket_cpp_type_get(*dsocket->typeinfo());
+ for (const OutputSocketRef *socket_ref : node->outputs()) {
+ if (socket_ref->is_available()) {
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_ref->typeinfo());
void *buffer = allocator_.allocate(type.size(), type.alignment());
fn_params.add_uninitialized_single_output(GMutableSpan(type, buffer, 1));
output_data.append(GMutablePointer(type, buffer));
@@ -468,19 +475,19 @@ class GeometryNodesEvaluator {
value.destruct();
}
int output_index = 0;
- for (const int i : node.outputs().index_range()) {
- if (node.output(i).is_available()) {
+ for (const int i : node->outputs().index_range()) {
+ if (node->output(i).is_available()) {
GMutablePointer value = output_data[output_index];
- params.set_output_by_move(node.output(i).identifier(), value);
+ params.set_output_by_move(node->output(i).identifier(), value);
value.destruct();
output_index++;
}
}
}
- void execute_unknown_node(const DNode &node, GeoNodeExecParams params)
+ void execute_unknown_node(const DNode node, GeoNodeExecParams params)
{
- for (const DOutputSocket *socket : node.outputs()) {
+ for (const OutputSocketRef *socket : node->outputs()) {
if (socket->is_available()) {
const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo());
params.set_output_by_copy(socket->identifier(), {type, type.default_value()});
@@ -488,17 +495,18 @@ class GeometryNodesEvaluator {
}
}
- void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward)
+ void forward_to_inputs(const DOutputSocket from_socket, GMutablePointer value_to_forward)
{
/* For all sockets that are linked with the from_socket push the value to their node. */
- Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets();
+ Vector<DInputSocket> to_sockets_all;
+ from_socket.foreach_target_socket(
+ [&](DInputSocket to_socket) { to_sockets_all.append(to_socket); });
const CPPType &from_type = *value_to_forward.type();
- Vector<const DInputSocket *> to_sockets_same_type;
- for (const DInputSocket *to_socket : to_sockets_all) {
+ Vector<DInputSocket> to_sockets_same_type;
+ for (const DInputSocket &to_socket : to_sockets_all) {
const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo());
- const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
- to_socket, &from_socket);
+ const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
if (from_type == to_type) {
to_sockets_same_type.append(to_socket);
}
@@ -520,23 +528,21 @@ class GeometryNodesEvaluator {
}
else if (to_sockets_same_type.size() == 1) {
/* This value is only used on one input socket, no need to copy it. */
- const DInputSocket *to_socket = to_sockets_same_type[0];
- const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
- to_socket, &from_socket);
+ const DInputSocket to_socket = to_sockets_same_type[0];
+ const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
add_value_to_input_socket(key, value_to_forward);
}
else {
/* Multiple inputs use the value, make a copy for every input except for one. */
- const DInputSocket *first_to_socket = to_sockets_same_type[0];
- Span<const DInputSocket *> other_to_sockets = to_sockets_same_type.as_span().drop_front(1);
+ const DInputSocket first_to_socket = to_sockets_same_type[0];
+ Span<DInputSocket> other_to_sockets = to_sockets_same_type.as_span().drop_front(1);
const CPPType &type = *value_to_forward.type();
- const std::pair<const DInputSocket *, const DOutputSocket *> first_key = std::make_pair(
- first_to_socket, &from_socket);
+ const std::pair<DInputSocket, DOutputSocket> first_key = std::make_pair(first_to_socket,
+ from_socket);
add_value_to_input_socket(first_key, value_to_forward);
- for (const DInputSocket *to_socket : other_to_sockets) {
- const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair(
- to_socket, &from_socket);
+ for (const DInputSocket &to_socket : other_to_sockets) {
+ const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
void *buffer = allocator_.allocate(type.size(), type.alignment());
type.copy_to_uninitialized(value_to_forward.get(), buffer);
add_value_to_input_socket(key, GMutablePointer{type, buffer});
@@ -544,22 +550,17 @@ class GeometryNodesEvaluator {
}
}
- void add_value_to_input_socket(const std::pair<const DInputSocket *, const DOutputSocket *> key,
+ void add_value_to_input_socket(const std::pair<DInputSocket, DOutputSocket> key,
GMutablePointer value)
{
value_by_input_.add_new(key, value);
}
- GMutablePointer get_unlinked_input_value(const DInputSocket &socket)
+ GMutablePointer get_unlinked_input_value(const DInputSocket &socket,
+ const CPPType &required_type)
{
- bNodeSocket *bsocket;
- if (socket.linked_group_inputs().size() == 0) {
- bsocket = socket.bsocket();
- }
- else {
- bsocket = socket.linked_group_inputs()[0]->bsocket();
- }
- const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket.typeinfo());
+ bNodeSocket *bsocket = socket->bsocket();
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo());
void *buffer = allocator_.allocate(type.size(), type.alignment());
if (bsocket->type == SOCK_OBJECT) {
@@ -576,7 +577,19 @@ class GeometryNodesEvaluator {
blender::nodes::socket_cpp_value_get(*bsocket, buffer);
}
- return {type, buffer};
+ if (type == required_type) {
+ return {type, buffer};
+ }
+ if (conversions_.is_convertible(type, required_type)) {
+ void *converted_buffer = allocator_.allocate(required_type.size(),
+ required_type.alignment());
+ conversions_.convert(type, required_type, buffer, converted_buffer);
+ type.destruct(buffer);
+ return {required_type, converted_buffer};
+ }
+ void *default_buffer = allocator_.allocate(required_type.size(), required_type.alignment());
+ type.copy_to_uninitialized(type.default_value(), default_buffer);
+ return {required_type, default_buffer};
}
};
@@ -985,7 +998,7 @@ static void fill_data_handle_map(const NodesModifierSettings &settings,
{
Set<ID *> used_ids;
find_used_ids_from_settings(settings, used_ids);
- find_used_ids_from_nodes(*tree.btree(), used_ids);
+ find_used_ids_from_nodes(*tree.root_context().tree().btree(), used_ids);
int current_handle = 0;
for (ID *id : used_ids) {
@@ -1013,8 +1026,8 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree
* often than necessary. It's going to be replaced soon.
*/
static GeometrySet compute_geometry(const DerivedNodeTree &tree,
- Span<const DOutputSocket *> group_input_sockets,
- const DInputSocket &socket_to_compute,
+ Span<const OutputSocketRef *> group_input_sockets,
+ const InputSocketRef &socket_to_compute,
GeometrySet input_geometry_set,
NodesModifierData *nmd,
const ModifierEvalContext *ctx)
@@ -1026,32 +1039,33 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
PersistentDataHandleMap handle_map;
fill_data_handle_map(nmd->settings, tree, handle_map);
- Map<const DOutputSocket *, GMutablePointer> group_inputs;
+ Map<DOutputSocket, GMutablePointer> group_inputs;
+ const DTreeContext *root_context = &tree.root_context();
if (group_input_sockets.size() > 0) {
- Span<const DOutputSocket *> remaining_input_sockets = group_input_sockets;
+ Span<const OutputSocketRef *> remaining_input_sockets = group_input_sockets;
/* If the group expects a geometry as first input, use the geometry that has been passed to
* modifier. */
- const DOutputSocket *first_input_socket = group_input_sockets[0];
+ const OutputSocketRef *first_input_socket = group_input_sockets[0];
if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) {
- GeometrySet *geometry_set_in = allocator.construct<GeometrySet>(
- std::move(input_geometry_set));
- group_inputs.add_new(first_input_socket, geometry_set_in);
+ GeometrySet *geometry_set_in =
+ allocator.construct<GeometrySet>(std::move(input_geometry_set)).release();
+ group_inputs.add_new({root_context, first_input_socket}, geometry_set_in);
remaining_input_sockets = remaining_input_sockets.drop_front(1);
}
/* Initialize remaining group inputs. */
- for (const DOutputSocket *socket : remaining_input_sockets) {
+ for (const OutputSocketRef *socket : remaining_input_sockets) {
const CPPType &cpp_type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo());
void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
initialize_group_input(*nmd, handle_map, *socket->bsocket(), cpp_type, value_in);
- group_inputs.add_new(socket, {cpp_type, value_in});
+ group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
}
}
- Vector<const DInputSocket *> group_outputs;
- group_outputs.append(&socket_to_compute);
+ Vector<DInputSocket> group_outputs;
+ group_outputs.append({root_context, &socket_to_compute});
GeometryNodesEvaluator evaluator{group_inputs,
group_outputs,
@@ -1126,16 +1140,17 @@ static void modifyGeometry(ModifierData *md,
check_property_socket_sync(ctx->object, md);
- blender::nodes::NodeTreeRefMap tree_refs;
- DerivedNodeTree tree{nmd->node_group, tree_refs};
+ NodeTreeRefMap tree_refs;
+ DerivedNodeTree tree{*nmd->node_group, tree_refs};
if (tree.has_link_cycles()) {
BKE_modifier_set_error(ctx->object, md, "Node group has cycles");
return;
}
- Span<const DNode *> input_nodes = tree.nodes_by_type("NodeGroupInput");
- Span<const DNode *> output_nodes = tree.nodes_by_type("NodeGroupOutput");
+ const NodeTreeRef &root_tree_ref = tree.root_context().tree();
+ Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput");
+ Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput");
if (input_nodes.size() > 1) {
return;
@@ -1144,16 +1159,18 @@ static void modifyGeometry(ModifierData *md,
return;
}
- Span<const DOutputSocket *> group_inputs = (input_nodes.size() == 1) ?
- input_nodes[0]->outputs().drop_back(1) :
- Span<const DOutputSocket *>{};
- Span<const DInputSocket *> group_outputs = output_nodes[0]->inputs().drop_back(1);
+ Span<const OutputSocketRef *> group_inputs;
+ if (input_nodes.size() == 1) {
+ group_inputs = input_nodes[0]->outputs().drop_back(1);
+ }
+
+ Span<const InputSocketRef *> group_outputs = output_nodes[0]->inputs().drop_back(1);
if (group_outputs.size() == 0) {
return;
}
- const DInputSocket *group_output = group_outputs[0];
+ const InputSocketRef *group_output = group_outputs[0];
if (group_output->idname() != "NodeSocketGeometry") {
return;
}
diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c
index 821c74496f2..6b2facc16a2 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.c
+++ b/source/blender/modifiers/intern/MOD_ui_common.c
@@ -409,13 +409,9 @@ static void modifier_panel_header(const bContext *C, Panel *panel)
*/
PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
{
- /* Get the name for the modifier's panel. */
- char panel_idname[BKE_ST_MAXNAME];
- BKE_modifier_type_panel_id(type, panel_idname);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
-
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BKE_modifier_type_panel_id(type, panel_type->idname);
BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
@@ -450,13 +446,9 @@ PanelType *modifier_subpanel_register(ARegionType *region_type,
PanelDrawFn draw,
PanelType *parent)
{
- /* Create the subpanel's ID name. */
- char panel_idname[BKE_ST_MAXNAME];
- BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index a6b83ed60ea..487250eb4e3 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -331,12 +331,24 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemPointerR(layout, ptr, "uv_layer", &obj_data_ptr, "uv_layers", NULL, ICON_NONE);
+ /* Aspect and Scale are only used for camera projectors. */
+ bool has_camera = false;
+ RNA_BEGIN (ptr, projector_ptr, "projectors") {
+ PointerRNA ob_projector = RNA_pointer_get(&projector_ptr, "object");
+ if (!RNA_pointer_is_null(&ob_projector) && RNA_enum_get(&ob_projector, "type") == OB_CAMERA) {
+ has_camera = true;
+ }
+ }
+ RNA_END;
+
sub = uiLayoutColumn(layout, true);
- uiItemR(sub, ptr, "aspect_x", 0, IFACE_("Aspect X"), ICON_NONE);
+ uiLayoutSetActive(sub, has_camera);
+ uiItemR(sub, ptr, "aspect_x", 0, NULL, ICON_NONE);
uiItemR(sub, ptr, "aspect_y", 0, IFACE_("Y"), ICON_NONE);
sub = uiLayoutColumn(layout, true);
- uiItemR(sub, ptr, "scale_x", 0, IFACE_("Scale X"), ICON_NONE);
+ uiLayoutSetActive(sub, has_camera);
+ uiItemR(sub, ptr, "scale_x", 0, NULL, ICON_NONE);
uiItemR(sub, ptr, "scale_y", 0, IFACE_("Y"), ICON_NONE);
uiItemR(layout, ptr, "projector_count", 0, IFACE_("Projectors"), ICON_NONE);
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 50e29d4a447..d89cf2ecefa 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -168,8 +168,8 @@ set(SRC
geometry/nodes/node_geo_point_separate.cc
geometry/nodes/node_geo_point_translate.cc
geometry/nodes/node_geo_points_to_volume.cc
- geometry/nodes/node_geo_subdivision_surface.cc
- geometry/nodes/node_geo_subdivision_surface_simple.cc
+ geometry/nodes/node_geo_subdivide_smooth.cc
+ geometry/nodes/node_geo_subdivide.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc
geometry/nodes/node_geo_volume_to_mesh.cc
@@ -259,7 +259,7 @@ set(SRC
shader/nodes/node_shader_vectTransform.c
shader/nodes/node_shader_vector_displacement.c
shader/nodes/node_shader_vector_math.cc
- shader/nodes/node_shader_vector_rotate.c
+ shader/nodes/node_shader_vector_rotate.cc
shader/nodes/node_shader_vertex_color.c
shader/nodes/node_shader_volume_absorption.c
shader/nodes/node_shader_volume_info.c
@@ -302,7 +302,6 @@ set(SRC
intern/node_exec.c
intern/node_geometry_exec.cc
intern/node_socket.cc
- intern/node_tree_dependencies.cc
intern/node_tree_multi_function.cc
intern/node_tree_ref.cc
intern/node_util.c
@@ -321,7 +320,6 @@ set(SRC
NOD_geometry.h
NOD_geometry_exec.hh
NOD_math_functions.hh
- NOD_node_tree_dependencies.hh
NOD_node_tree_multi_function.hh
NOD_node_tree_ref.hh
NOD_shader.h
diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh
index ea67f23eade..3529336baf6 100644
--- a/source/blender/nodes/NOD_derived_node_tree.hh
+++ b/source/blender/nodes/NOD_derived_node_tree.hh
@@ -19,544 +19,361 @@
/** \file
* \ingroup nodes
*
- * DerivedNodeTree provides a flattened view on a bNodeTree, i.e. node groups are inlined. It
- * builds on top of NodeTreeRef and supports similar queries efficiently.
- *
- * Every inlined node remembers its path to the parent ("call stack").
- *
- * Unlinked group node inputs are handled separately from other sockets.
- *
- * There is a dot graph exporter for debugging purposes.
+ * DerivedNodeTree builds on top of NodeTreeRef and makes working with (nested) node groups more
+ * convenient and safe. It does so by pairing nodes and sockets with a context. The context
+ * contains information about the current "instance" of the node or socket. A node might be
+ * "instanced" multiple times when it is in a node group that is used multiple times.
*/
-#include "NOD_node_tree_ref.hh"
-
+#include "BLI_function_ref.hh"
#include "BLI_vector_set.hh"
+#include "NOD_node_tree_ref.hh"
+
namespace blender::nodes {
+class DTreeContext;
+class DerivedNodeTree;
+
+class DNode;
class DSocket;
class DInputSocket;
class DOutputSocket;
-class DNode;
-class DParentNode;
-class DGroupInput;
-class DerivedNodeTree;
-class DSocket : NonCopyable, NonMovable {
- protected:
- DNode *node_;
- const SocketRef *socket_ref_;
- int id_;
+/**
+ * The context attached to every node or socket in a derived node tree. It can be used to determine
+ * the place of a node in a hierarchy of node groups.
+ *
+ * Contexts are organized in a tree data structure to avoid having to store the entire path to the
+ * root node group for every node/socket.
+ */
+class DTreeContext {
+ private:
+ /* Null when this context is for the root node group. Otherwise it points to the context one
+ * level up. */
+ DTreeContext *parent_context_;
+ /* Null when this context is for the root node group. Otherwise it points to the group node in
+ * the parent node group that contains this context. */
+ const NodeRef *parent_node_;
+ /* The current node tree. */
+ const NodeTreeRef *tree_;
+ /* All the children contexts of this context. */
+ Map<const NodeRef *, DTreeContext *> children_;
friend DerivedNodeTree;
public:
- const DNode &node() const;
-
- int id() const;
- int index() const;
-
- bool is_input() const;
- bool is_output() const;
-
- const DSocket &as_base() const;
- const DInputSocket &as_input() const;
- const DOutputSocket &as_output() const;
-
- PointerRNA *rna() const;
- StringRefNull idname() const;
- StringRefNull name() const;
- StringRefNull identifier() const;
- bNodeSocketType *typeinfo() const;
-
- const SocketRef &socket_ref() const;
- bNodeSocket *bsocket() const;
-
- bool is_available() const;
+ const NodeTreeRef &tree() const;
+ const DTreeContext *parent_context() const;
+ const NodeRef *parent_node() const;
+ const DTreeContext *child_context(const NodeRef &node) const;
+ bool is_root() const;
};
-class DInputSocket : public DSocket {
+/* A (nullable) reference to a node and the context it is in. It is unique within an entire nested
+ * node group hierarchy. This type is small and can be passed around by value. */
+class DNode {
private:
- Vector<DOutputSocket *> linked_sockets_;
- Vector<DGroupInput *> linked_group_inputs_;
- bool is_multi_input_socket_;
-
- friend DerivedNodeTree;
+ const DTreeContext *context_ = nullptr;
+ const NodeRef *node_ref_ = nullptr;
public:
- const InputSocketRef &socket_ref() const;
-
- Span<const DOutputSocket *> linked_sockets() const;
- Span<const DGroupInput *> linked_group_inputs() const;
-
- bool is_linked() const;
- bool is_multi_input_socket() const;
-};
+ DNode() = default;
+ DNode(const DTreeContext *context, const NodeRef *node);
-class DOutputSocket : public DSocket {
- private:
- Vector<DInputSocket *> linked_sockets_;
+ const DTreeContext *context() const;
+ const NodeRef *node_ref() const;
+ const NodeRef *operator->() const;
- friend DerivedNodeTree;
+ friend bool operator==(const DNode &a, const DNode &b);
+ friend bool operator!=(const DNode &a, const DNode &b);
+ operator bool() const;
- public:
- const OutputSocketRef &socket_ref() const;
- Span<const DInputSocket *> linked_sockets() const;
+ uint64_t hash() const;
};
-class DGroupInput : NonCopyable, NonMovable {
- private:
- const InputSocketRef *socket_ref_;
- DParentNode *parent_;
- Vector<DInputSocket *> linked_sockets_;
- int id_;
-
- friend DerivedNodeTree;
+/* A (nullable) reference to a socket and the context it is in. It is unique within an entire
+ * nested node group hierarchy. This type is small and can be passed around by value.
+ *
+ * A #DSocket can represent an input or an output socket. If the type of a socket is known at
+ * compile time is is preferable to use #DInputSocket or #DOutputSocket instead. */
+class DSocket {
+ protected:
+ const DTreeContext *context_ = nullptr;
+ const SocketRef *socket_ref_ = nullptr;
public:
- const InputSocketRef &socket_ref() const;
- bNodeSocket *bsocket() const;
- const DParentNode *parent() const;
- Span<const DInputSocket *> linked_sockets() const;
- int id() const;
- StringRefNull name() const;
-};
-
-class DNode : NonCopyable, NonMovable {
- private:
- const NodeRef *node_ref_;
- DParentNode *parent_;
+ DSocket() = default;
+ DSocket(const DTreeContext *context, const SocketRef *socket);
+ DSocket(const DInputSocket &input_socket);
+ DSocket(const DOutputSocket &output_socket);
- Span<DInputSocket *> inputs_;
- Span<DOutputSocket *> outputs_;
+ const DTreeContext *context() const;
+ const SocketRef *socket_ref() const;
+ const SocketRef *operator->() const;
- int id_;
+ friend bool operator==(const DSocket &a, const DSocket &b);
+ friend bool operator!=(const DSocket &a, const DSocket &b);
+ operator bool() const;
- friend DerivedNodeTree;
+ uint64_t hash() const;
+};
+/* A (nullable) reference to an input socket and the context it is in. */
+class DInputSocket : public DSocket {
public:
- const NodeRef &node_ref() const;
- const DParentNode *parent() const;
-
- Span<const DInputSocket *> inputs() const;
- Span<const DOutputSocket *> outputs() const;
-
- const DInputSocket &input(int index) const;
- const DOutputSocket &output(int index) const;
-
- const DInputSocket &input(int index, StringRef expected_name) const;
- const DOutputSocket &output(int index, StringRef expected_name) const;
+ DInputSocket() = default;
+ DInputSocket(const DTreeContext *context, const InputSocketRef *socket);
+ explicit DInputSocket(const DSocket &base_socket);
- int id() const;
+ const InputSocketRef *socket_ref() const;
+ const InputSocketRef *operator->() const;
- PointerRNA *rna() const;
- StringRefNull idname() const;
- StringRefNull name() const;
- bNode *bnode() const;
- bNodeType *typeinfo() const;
+ DOutputSocket get_corresponding_group_node_output() const;
+ Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const;
- private:
- void destruct_with_sockets();
+ void foreach_origin_socket(FunctionRef<void(DSocket)> callback,
+ const bool follow_only_first_incoming_link = false) const;
};
-class DParentNode : NonCopyable, NonMovable {
- private:
- const NodeRef *node_ref_;
- DParentNode *parent_;
- int id_;
+/* A (nullable) reference to an output socket and the context it is in. */
+class DOutputSocket : public DSocket {
+ public:
+ DOutputSocket() = default;
+ DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket);
+ explicit DOutputSocket(const DSocket &base_socket);
- friend DerivedNodeTree;
+ const OutputSocketRef *socket_ref() const;
+ const OutputSocketRef *operator->() const;
- public:
- const DParentNode *parent() const;
- const NodeRef &node_ref() const;
- int id() const;
+ DInputSocket get_corresponding_group_node_input() const;
+ DInputSocket get_active_corresponding_group_output_socket() const;
+
+ void foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const;
};
-class DerivedNodeTree : NonCopyable, NonMovable {
+class DerivedNodeTree {
private:
LinearAllocator<> allocator_;
- Vector<DNode *> nodes_by_id_;
- Vector<DGroupInput *> group_inputs_;
- Vector<DParentNode *> parent_nodes_;
-
- Vector<DSocket *> sockets_by_id_;
- Vector<DInputSocket *> input_sockets_;
- Vector<DOutputSocket *> output_sockets_;
-
- MultiValueMap<const bNodeType *, DNode *> nodes_by_type_;
+ DTreeContext *root_context_;
VectorSet<const NodeTreeRef *> used_node_tree_refs_;
- bNodeTree *btree_;
public:
- DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs);
+ DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs);
~DerivedNodeTree();
- bNodeTree *btree() const;
-
- Span<const DNode *> nodes() const;
- Span<const DNode *> nodes_by_type(StringRefNull idname) const;
- Span<const DNode *> nodes_by_type(const bNodeType *nodetype) const;
-
- Span<const DSocket *> sockets() const;
- Span<const DInputSocket *> input_sockets() const;
- Span<const DOutputSocket *> output_sockets() const;
-
- Span<const DGroupInput *> group_inputs() const;
-
+ const DTreeContext &root_context() const;
Span<const NodeTreeRef *> used_node_tree_refs() const;
bool has_link_cycles() const;
-
- std::string to_dot() const;
+ void foreach_node(FunctionRef<void(DNode)> callback) const;
private:
- /* Utility functions used during construction. */
- void insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref,
- DParentNode *parent,
- Vector<DNode *> &all_nodes);
- DNode &create_node(const NodeRef &node_ref,
- DParentNode *parent,
- MutableSpan<DSocket *> r_sockets_map);
- void expand_groups(Vector<DNode *> &all_nodes,
- Vector<DGroupInput *> &all_group_inputs,
- Vector<DParentNode *> &all_parent_nodes,
- NodeTreeRefMap &node_tree_refs);
- void expand_group_node(DNode &group_node,
- Vector<DNode *> &all_nodes,
- Vector<DGroupInput *> &all_group_inputs,
- Vector<DParentNode *> &all_parent_nodes,
- NodeTreeRefMap &node_tree_refs);
- void create_group_inputs_for_unlinked_inputs(DNode &node,
- Vector<DGroupInput *> &all_group_inputs);
- void relink_group_inputs(const NodeTreeRef &group_ref,
- Span<DNode *> nodes_by_id,
- DNode &group_node);
- void relink_group_outputs(const NodeTreeRef &group_ref,
- Span<DNode *> nodes_by_id,
- DNode &group_node);
- void remove_expanded_group_interfaces(Vector<DNode *> &all_nodes);
- void remove_unused_group_inputs(Vector<DGroupInput *> &all_group_inputs);
- void relink_and_remove_muted_nodes(Vector<DNode *> &all_nodes);
- void relink_muted_node(DNode &muted_node);
- void store_in_this_and_init_ids(Vector<DNode *> &&all_nodes,
- Vector<DGroupInput *> &&all_group_inputs,
- Vector<DParentNode *> &&all_parent_nodes);
+ DTreeContext &construct_context_recursively(DTreeContext *parent_context,
+ const NodeRef *parent_node,
+ bNodeTree &btree,
+ NodeTreeRefMap &node_tree_refs);
+ void destruct_context_recursively(DTreeContext *context);
+
+ void foreach_node_in_context_recursive(const DTreeContext &context,
+ FunctionRef<void(DNode)> callback) const;
};
namespace derived_node_tree_types {
+using namespace node_tree_ref_types;
using nodes::DerivedNodeTree;
-using nodes::DGroupInput;
using nodes::DInputSocket;
using nodes::DNode;
using nodes::DOutputSocket;
-using nodes::DParentNode;
-}; // namespace derived_node_tree_types
+using nodes::DSocket;
+using nodes::DTreeContext;
+} // namespace derived_node_tree_types
/* --------------------------------------------------------------------
- * DSocket inline methods.
+ * DTreeContext inline methods.
*/
-inline const DNode &DSocket::node() const
-{
- return *node_;
-}
-
-inline int DSocket::id() const
+inline const NodeTreeRef &DTreeContext::tree() const
{
- return id_;
+ return *tree_;
}
-inline int DSocket::index() const
+inline const DTreeContext *DTreeContext::parent_context() const
{
- return socket_ref_->index();
+ return parent_context_;
}
-inline bool DSocket::is_input() const
+inline const NodeRef *DTreeContext::parent_node() const
{
- return socket_ref_->is_input();
+ return parent_node_;
}
-inline bool DSocket::is_output() const
+inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) const
{
- return socket_ref_->is_output();
+ return children_.lookup_default(&node, nullptr);
}
-inline const DSocket &DSocket::as_base() const
+inline bool DTreeContext::is_root() const
{
- return *this;
+ return parent_context_ == nullptr;
}
-inline const DInputSocket &DSocket::as_input() const
-{
- return static_cast<const DInputSocket &>(*this);
-}
-
-inline const DOutputSocket &DSocket::as_output() const
-{
- return static_cast<const DOutputSocket &>(*this);
-}
+/* --------------------------------------------------------------------
+ * DNode inline methods.
+ */
-inline PointerRNA *DSocket::rna() const
+inline DNode::DNode(const DTreeContext *context, const NodeRef *node_ref)
+ : context_(context), node_ref_(node_ref)
{
- return socket_ref_->rna();
+ BLI_assert(node_ref == nullptr || &node_ref->tree() == &context->tree());
}
-inline StringRefNull DSocket::idname() const
+inline const DTreeContext *DNode::context() const
{
- return socket_ref_->idname();
+ return context_;
}
-inline StringRefNull DSocket::name() const
+inline const NodeRef *DNode::node_ref() const
{
- return socket_ref_->name();
+ return node_ref_;
}
-inline StringRefNull DSocket::identifier() const
+inline bool operator==(const DNode &a, const DNode &b)
{
- return socket_ref_->identifier();
+ return a.context_ == b.context_ && a.node_ref_ == b.node_ref_;
}
-inline bNodeSocketType *DSocket::typeinfo() const
+inline bool operator!=(const DNode &a, const DNode &b)
{
- return socket_ref_->bsocket()->typeinfo;
+ return !(a == b);
}
-inline const SocketRef &DSocket::socket_ref() const
+inline DNode::operator bool() const
{
- return *socket_ref_;
+ return node_ref_ != nullptr;
}
-inline bNodeSocket *DSocket::bsocket() const
+inline const NodeRef *DNode::operator->() const
{
- return socket_ref_->bsocket();
+ return node_ref_;
}
-inline bool DSocket::is_available() const
+inline uint64_t DNode::hash() const
{
- return (socket_ref_->bsocket()->flag & SOCK_UNAVAIL) == 0;
+ return DefaultHash<const DTreeContext *>{}(context_) ^ DefaultHash<const NodeRef *>{}(node_ref_);
}
/* --------------------------------------------------------------------
- * DInputSocket inline methods.
+ * DSocket inline methods.
*/
-inline const InputSocketRef &DInputSocket::socket_ref() const
-{
- return socket_ref_->as_input();
-}
-
-inline Span<const DOutputSocket *> DInputSocket::linked_sockets() const
-{
- return linked_sockets_;
-}
-
-inline Span<const DGroupInput *> DInputSocket::linked_group_inputs() const
-{
- return linked_group_inputs_;
-}
-
-inline bool DInputSocket::is_linked() const
+inline DSocket::DSocket(const DTreeContext *context, const SocketRef *socket_ref)
+ : context_(context), socket_ref_(socket_ref)
{
- return linked_sockets_.size() > 0 || linked_group_inputs_.size() > 0;
+ BLI_assert(socket_ref == nullptr || &socket_ref->tree() == &context->tree());
}
-inline bool DInputSocket::is_multi_input_socket() const
+inline DSocket::DSocket(const DInputSocket &input_socket)
+ : DSocket(input_socket.context_, input_socket.socket_ref_)
{
- return is_multi_input_socket_;
}
-/* --------------------------------------------------------------------
- * DOutputSocket inline methods.
- */
-
-inline const OutputSocketRef &DOutputSocket::socket_ref() const
+inline DSocket::DSocket(const DOutputSocket &output_socket)
+ : DSocket(output_socket.context_, output_socket.socket_ref_)
{
- return socket_ref_->as_output();
}
-inline Span<const DInputSocket *> DOutputSocket::linked_sockets() const
+inline const DTreeContext *DSocket::context() const
{
- return linked_sockets_;
+ return context_;
}
-/* --------------------------------------------------------------------
- * DGroupInput inline methods.
- */
-
-inline const InputSocketRef &DGroupInput::socket_ref() const
+inline const SocketRef *DSocket::socket_ref() const
{
- return *socket_ref_;
+ return socket_ref_;
}
-inline bNodeSocket *DGroupInput::bsocket() const
+inline bool operator==(const DSocket &a, const DSocket &b)
{
- return socket_ref_->bsocket();
+ return a.context_ == b.context_ && a.socket_ref_ == b.socket_ref_;
}
-inline const DParentNode *DGroupInput::parent() const
+inline bool operator!=(const DSocket &a, const DSocket &b)
{
- return parent_;
+ return !(a == b);
}
-inline Span<const DInputSocket *> DGroupInput::linked_sockets() const
+inline DSocket::operator bool() const
{
- return linked_sockets_;
+ return socket_ref_ != nullptr;
}
-inline int DGroupInput::id() const
+inline const SocketRef *DSocket::operator->() const
{
- return id_;
+ return socket_ref_;
}
-inline StringRefNull DGroupInput::name() const
+inline uint64_t DSocket::hash() const
{
- return socket_ref_->name();
+ return DefaultHash<const DTreeContext *>{}(context_) ^
+ DefaultHash<const SocketRef *>{}(socket_ref_);
}
/* --------------------------------------------------------------------
- * DNode inline methods.
+ * DInputSocket inline methods.
*/
-inline const NodeRef &DNode::node_ref() const
-{
- return *node_ref_;
-}
-
-inline const DParentNode *DNode::parent() const
-{
- return parent_;
-}
-
-inline Span<const DInputSocket *> DNode::inputs() const
-{
- return inputs_;
-}
-
-inline Span<const DOutputSocket *> DNode::outputs() const
-{
- return outputs_;
-}
-
-inline const DInputSocket &DNode::input(int index) const
-{
- return *inputs_[index];
-}
-
-inline const DOutputSocket &DNode::output(int index) const
-{
- return *outputs_[index];
-}
-
-inline const DInputSocket &DNode::input(int index, StringRef expected_name) const
+inline DInputSocket::DInputSocket(const DTreeContext *context, const InputSocketRef *socket_ref)
+ : DSocket(context, socket_ref)
{
- const DInputSocket &socket = *inputs_[index];
- BLI_assert(socket.name() == expected_name);
- UNUSED_VARS_NDEBUG(expected_name);
- return socket;
}
-inline const DOutputSocket &DNode::output(int index, StringRef expected_name) const
+inline DInputSocket::DInputSocket(const DSocket &base_socket) : DSocket(base_socket)
{
- const DOutputSocket &socket = *outputs_[index];
- BLI_assert(socket.name() == expected_name);
- UNUSED_VARS_NDEBUG(expected_name);
- return socket;
+ BLI_assert(base_socket->is_input());
}
-inline int DNode::id() const
+inline const InputSocketRef *DInputSocket::socket_ref() const
{
- return id_;
+ return (const InputSocketRef *)socket_ref_;
}
-inline PointerRNA *DNode::rna() const
+inline const InputSocketRef *DInputSocket::operator->() const
{
- return node_ref_->rna();
+ return (const InputSocketRef *)socket_ref_;
}
-inline StringRefNull DNode::idname() const
-{
- return node_ref_->idname();
-}
-
-inline StringRefNull DNode::name() const
-{
- return node_ref_->name();
-}
-
-inline bNode *DNode::bnode() const
-{
- return node_ref_->bnode();
-}
+/* --------------------------------------------------------------------
+ * DOutputSocket inline methods.
+ */
-inline bNodeType *DNode::typeinfo() const
+inline DOutputSocket::DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket_ref)
+ : DSocket(context, socket_ref)
{
- return node_ref_->bnode()->typeinfo;
}
-/* --------------------------------------------------------------------
- * DParentNode inline methods.
- */
-
-inline const DParentNode *DParentNode::parent() const
+inline DOutputSocket::DOutputSocket(const DSocket &base_socket) : DSocket(base_socket)
{
- return parent_;
+ BLI_assert(base_socket->is_output());
}
-inline const NodeRef &DParentNode::node_ref() const
+inline const OutputSocketRef *DOutputSocket::socket_ref() const
{
- return *node_ref_;
+ return (const OutputSocketRef *)socket_ref_;
}
-inline int DParentNode::id() const
+inline const OutputSocketRef *DOutputSocket::operator->() const
{
- return id_;
+ return (const OutputSocketRef *)socket_ref_;
}
/* --------------------------------------------------------------------
* DerivedNodeTree inline methods.
*/
-inline bNodeTree *DerivedNodeTree::btree() const
-{
- return btree_;
-}
-
-inline Span<const DNode *> DerivedNodeTree::nodes() const
-{
- return nodes_by_id_;
-}
-
-inline Span<const DNode *> DerivedNodeTree::nodes_by_type(StringRefNull idname) const
-{
- const bNodeType *nodetype = nodeTypeFind(idname.c_str());
- return this->nodes_by_type(nodetype);
-}
-
-inline Span<const DNode *> DerivedNodeTree::nodes_by_type(const bNodeType *nodetype) const
-{
- return nodes_by_type_.lookup(nodetype);
-}
-
-inline Span<const DSocket *> DerivedNodeTree::sockets() const
-{
- return sockets_by_id_;
-}
-
-inline Span<const DInputSocket *> DerivedNodeTree::input_sockets() const
-{
- return input_sockets_;
-}
-
-inline Span<const DOutputSocket *> DerivedNodeTree::output_sockets() const
-{
- return output_sockets_;
-}
-
-inline Span<const DGroupInput *> DerivedNodeTree::group_inputs() const
+inline const DTreeContext &DerivedNodeTree::root_context() const
{
- return group_inputs_;
+ return *root_context_;
}
inline Span<const NodeTreeRef *> DerivedNodeTree::used_node_tree_refs() const
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 3ee8067e81a..b094256190c 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -51,8 +51,8 @@ void register_node_type_geo_point_separate(void);
void register_node_type_geo_point_translate(void);
void register_node_type_geo_points_to_volume(void);
void register_node_type_geo_sample_texture(void);
-void register_node_type_geo_subdivision_surface(void);
-void register_node_type_geo_subdivision_surface_simple(void);
+void register_node_type_geo_subdivide_smooth(void);
+void register_node_type_geo_subdivide(void);
void register_node_type_geo_transform(void);
void register_node_type_geo_triangulate(void);
void register_node_type_geo_volume_to_mesh(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index e648d77337b..5b123e68fe2 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -59,7 +59,7 @@ using fn::GValueMap;
class GeoNodeExecParams {
private:
- const DNode &node_;
+ const DNode node_;
GValueMap<StringRef> &input_values_;
GValueMap<StringRef> &output_values_;
const PersistentDataHandleMap &handle_map_;
@@ -68,7 +68,7 @@ class GeoNodeExecParams {
Depsgraph *depsgraph_;
public:
- GeoNodeExecParams(const DNode &node,
+ GeoNodeExecParams(const DNode node,
GValueMap<StringRef> &input_values,
GValueMap<StringRef> &output_values,
const PersistentDataHandleMap &handle_map,
@@ -120,13 +120,17 @@ class GeoNodeExecParams {
template<typename T> Vector<T> extract_multi_input(StringRef identifier)
{
Vector<T> values;
- values.append(input_values_.extract<T>(identifier));
- int i = 1;
- std::string sub_identifier = identifier + "[1]";
- while (input_values_.contains(sub_identifier)) {
+ int index = 0;
+ while (true) {
+ std::string sub_identifier = identifier;
+ if (index > 0) {
+ sub_identifier += "[" + std::to_string(index) + "]";
+ }
+ if (!input_values_.contains(sub_identifier)) {
+ break;
+ }
values.append(input_values_.extract<T>(sub_identifier));
- i++;
- sub_identifier = identifier + "[" + std::to_string(i) + "]";
+ index++;
}
return values;
}
@@ -182,7 +186,7 @@ class GeoNodeExecParams {
*/
const bNode &node() const
{
- return *node_.bnode();
+ return *node_->bnode();
}
const PersistentDataHandleMap &handle_map() const
diff --git a/source/blender/nodes/NOD_node_tree_dependencies.hh b/source/blender/nodes/NOD_node_tree_dependencies.hh
deleted file mode 100644
index 13bb2bde2f3..00000000000
--- a/source/blender/nodes/NOD_node_tree_dependencies.hh
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include "BLI_vector_set.hh"
-
-#include "DNA_ID.h"
-#include "DNA_object_types.h"
-
-struct bNodeTree;
-
-namespace blender::nodes {
-
-class NodeTreeDependencies {
- private:
- VectorSet<Object *> transform_deps_;
- VectorSet<Object *> geometry_deps_;
- VectorSet<ID *> id_deps_;
-
- public:
- void add_transform_dependency(Object *object)
- {
- if (object == nullptr) {
- return;
- }
- transform_deps_.add(object);
- id_deps_.add(&object->id);
- }
-
- void add_geometry_dependency(Object *object)
- {
- if (object == nullptr) {
- return;
- }
- geometry_deps_.add(object);
- id_deps_.add(&object->id);
- }
-
- bool depends_on(ID *id) const
- {
- return id_deps_.contains(id);
- }
-
- Span<Object *> transform_dependencies()
- {
- return transform_deps_;
- }
-
- Span<Object *> geometry_dependencies()
- {
- return geometry_deps_;
- }
-
- Span<ID *> id_dependencies()
- {
- return id_deps_;
- }
-};
-
-NodeTreeDependencies find_node_tree_dependencies(bNodeTree &ntree);
-
-} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_node_tree_multi_function.hh b/source/blender/nodes/NOD_node_tree_multi_function.hh
index 552ef5509fa..df31ee18369 100644
--- a/source/blender/nodes/NOD_node_tree_multi_function.hh
+++ b/source/blender/nodes/NOD_node_tree_multi_function.hh
@@ -28,14 +28,15 @@
#include "NOD_derived_node_tree.hh"
#include "NOD_type_callbacks.hh"
+#include "BLI_multi_value_map.hh"
#include "BLI_resource_collector.hh"
namespace blender::nodes {
/**
- * A MFNetworkTreeMap maps various components of a DerivedNodeTree to components of a
- * fn::MFNetwork. This is necessary for further processing of a multi-function network that has
- * been generated from a node tree.
+ * A MFNetworkTreeMap maps various components of a node tree to components of a fn::MFNetwork. This
+ * is necessary for further processing of a multi-function network that has been generated from a
+ * node tree.
*/
class MFNetworkTreeMap {
private:
@@ -47,15 +48,11 @@ class MFNetworkTreeMap {
*/
const DerivedNodeTree &tree_;
fn::MFNetwork &network_;
- Array<Vector<fn::MFSocket *, 1>> sockets_by_dsocket_id_;
- Array<fn::MFOutputSocket *> socket_by_group_input_id_;
+ MultiValueMap<DSocket, fn::MFSocket *> sockets_by_dsocket_;
public:
MFNetworkTreeMap(const DerivedNodeTree &tree, fn::MFNetwork &network)
- : tree_(tree),
- network_(network),
- sockets_by_dsocket_id_(tree.sockets().size()),
- socket_by_group_input_id_(tree.group_inputs().size(), nullptr)
+ : tree_(tree), network_(network)
{
}
@@ -76,96 +73,95 @@ class MFNetworkTreeMap {
void add(const DSocket &dsocket, fn::MFSocket &socket)
{
- BLI_assert(dsocket.is_input() == socket.is_input());
- BLI_assert(dsocket.is_input() || sockets_by_dsocket_id_[dsocket.id()].size() == 0);
- sockets_by_dsocket_id_[dsocket.id()].append(&socket);
+ BLI_assert(dsocket->is_input() == socket.is_input());
+ BLI_assert(dsocket->is_input() || sockets_by_dsocket_.lookup(dsocket).is_empty());
+ sockets_by_dsocket_.add(dsocket, &socket);
}
void add(const DInputSocket &dsocket, fn::MFInputSocket &socket)
{
- sockets_by_dsocket_id_[dsocket.id()].append(&socket);
+ sockets_by_dsocket_.add(dsocket, &socket);
}
void add(const DOutputSocket &dsocket, fn::MFOutputSocket &socket)
{
/* There can be at most one matching output socket. */
- BLI_assert(sockets_by_dsocket_id_[dsocket.id()].size() == 0);
- sockets_by_dsocket_id_[dsocket.id()].append(&socket);
+ BLI_assert(sockets_by_dsocket_.lookup(dsocket).is_empty());
+ sockets_by_dsocket_.add(dsocket, &socket);
}
- void add(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets)
+ void add(const DTreeContext &context,
+ Span<const InputSocketRef *> dsockets,
+ Span<fn::MFInputSocket *> sockets)
{
assert_same_size(dsockets, sockets);
for (int i : dsockets.index_range()) {
- this->add(*dsockets[i], *sockets[i]);
+ this->add(DInputSocket(&context, dsockets[i]), *sockets[i]);
}
}
- void add(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets)
+ void add(const DTreeContext &context,
+ Span<const OutputSocketRef *> dsockets,
+ Span<fn::MFOutputSocket *> sockets)
{
assert_same_size(dsockets, sockets);
for (int i : dsockets.index_range()) {
- this->add(*dsockets[i], *sockets[i]);
+ this->add(DOutputSocket(&context, dsockets[i]), *sockets[i]);
}
}
- void add(const DGroupInput &group_input, fn::MFOutputSocket &socket)
- {
- BLI_assert(socket_by_group_input_id_[group_input.id()] == nullptr);
- socket_by_group_input_id_[group_input.id()] = &socket;
- }
-
void add_try_match(const DNode &dnode, fn::MFNode &node)
{
- this->add_try_match(dnode.inputs().cast<const DSocket *>(),
+ this->add_try_match(*dnode.context(),
+ dnode->inputs().cast<const SocketRef *>(),
node.inputs().cast<fn::MFSocket *>());
- this->add_try_match(dnode.outputs().cast<const DSocket *>(),
+ this->add_try_match(*dnode.context(),
+ dnode->outputs().cast<const SocketRef *>(),
node.outputs().cast<fn::MFSocket *>());
}
- void add_try_match(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets)
+ void add_try_match(const DTreeContext &context,
+ Span<const InputSocketRef *> dsockets,
+ Span<fn::MFInputSocket *> sockets)
{
- this->add_try_match(dsockets.cast<const DSocket *>(), sockets.cast<fn::MFSocket *>());
+ this->add_try_match(
+ context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>());
}
- void add_try_match(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets)
+ void add_try_match(const DTreeContext &context,
+ Span<const OutputSocketRef *> dsockets,
+ Span<fn::MFOutputSocket *> sockets)
{
- this->add_try_match(dsockets.cast<const DSocket *>(), sockets.cast<fn::MFSocket *>());
+ this->add_try_match(
+ context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>());
}
- void add_try_match(Span<const DSocket *> dsockets, Span<fn::MFSocket *> sockets)
+ void add_try_match(const DTreeContext &context,
+ Span<const SocketRef *> dsockets,
+ Span<fn::MFSocket *> sockets)
{
int used_sockets = 0;
- for (const DSocket *dsocket : dsockets) {
+ for (const SocketRef *dsocket : dsockets) {
if (!dsocket->is_available()) {
continue;
}
- if (!socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) {
+ if (!socket_is_mf_data_socket(*dsocket->typeinfo())) {
continue;
}
fn::MFSocket *socket = sockets[used_sockets];
- this->add(*dsocket, *socket);
+ this->add(DSocket(&context, dsocket), *socket);
used_sockets++;
}
}
- fn::MFOutputSocket &lookup(const DGroupInput &group_input)
- {
- fn::MFOutputSocket *socket = socket_by_group_input_id_[group_input.id()];
- BLI_assert(socket != nullptr);
- return *socket;
- }
-
fn::MFOutputSocket &lookup(const DOutputSocket &dsocket)
{
- auto &sockets = sockets_by_dsocket_id_[dsocket.id()];
- BLI_assert(sockets.size() == 1);
- return sockets[0]->as_output();
+ return sockets_by_dsocket_.lookup(dsocket)[0]->as_output();
}
Span<fn::MFInputSocket *> lookup(const DInputSocket &dsocket)
{
- return sockets_by_dsocket_id_[dsocket.id()].as_span().cast<fn::MFInputSocket *>();
+ return sockets_by_dsocket_.lookup(dsocket).cast<fn::MFInputSocket *>();
}
fn::MFInputSocket &lookup_dummy(const DInputSocket &dsocket)
@@ -186,7 +182,7 @@ class MFNetworkTreeMap {
bool is_mapped(const DSocket &dsocket) const
{
- return sockets_by_dsocket_id_[dsocket.id()].size() >= 1;
+ return !sockets_by_dsocket_.lookup(dsocket).is_empty();
}
};
@@ -258,12 +254,7 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase {
public:
SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DSocket &dsocket)
- : MFNetworkBuilderBase(common), bsocket_(dsocket.bsocket())
- {
- }
-
- SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DGroupInput &group_input)
- : MFNetworkBuilderBase(common), bsocket_(group_input.bsocket())
+ : MFNetworkBuilderBase(common), bsocket_(dsocket->bsocket())
{
}
@@ -331,10 +322,10 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase {
*/
class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
private:
- const DNode &dnode_;
+ DNode dnode_;
public:
- NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DNode &dnode)
+ NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, DNode dnode)
: MFNetworkBuilderBase(common), dnode_(dnode)
{
}
@@ -352,7 +343,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
const fn::MultiFunction &get_not_implemented_fn()
{
- return this->get_default_fn("Not Implemented (" + dnode_.name() + ")");
+ return this->get_default_fn("Not Implemented (" + dnode_->name() + ")");
}
const fn::MultiFunction &get_default_fn(StringRef name);
@@ -377,7 +368,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
*/
bNode &bnode()
{
- return *dnode_.node_ref().bnode();
+ return *dnode_->bnode();
}
/**
@@ -393,7 +384,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
const DerivedNodeTree &tree,
ResourceCollector &resources);
-using MultiFunctionByNode = Map<const DNode *, const fn::MultiFunction *>;
+using MultiFunctionByNode = Map<DNode, const fn::MultiFunction *>;
MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
ResourceCollector &resources);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 35550bdec48..22204d7204e 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -272,7 +272,7 @@ DefNode(FunctionNode, FN_NODE_INPUT_STRING, def_fn_input_string, "INPUT_STRING",
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "")
DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "")
-DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "")
+DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_SMOOTH, 0, "SUBDIVIDE_SMOOTH", SubdivideSmooth, "Subdivide Smooth", "")
DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Boolean", "")
DefNode(GeometryNode, GEO_NODE_POINT_DISTRIBUTE, def_geo_point_distribute, "POINT_DISTRIBUTE", PointDistribute, "Point Distribute", "")
DefNode(GeometryNode, GEO_NODE_POINT_INSTANCE, def_geo_point_instance, "POINT_INSTANCE", PointInstance, "Point Instance", "")
@@ -298,7 +298,7 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_PROXIMITY, def_geo_attribute_proximity,
DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMBINE_XYZ, def_geo_attribute_combine_xyz, "ATTRIBUTE_COMBINE_XYZ", AttributeCombineXYZ, "Attribute Combine XYZ", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "ATTRIBUTE_SEPARATE_XYZ", AttributeSeparateXYZ, "Attribute Separate XYZ", "")
-DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE_SIMPLE, 0, "SUBDIVISION_SURFACE_SIMPLE", SubdivisionSurfaceSimple, "Simple Subdivision Surface", "")
+DefNode(GeometryNode, GEO_NODE_SUBDIVIDE, 0, "SUBDIVIDE", Subdivide, "Subdivide", "")
/* undefine macros */
#undef DefNode
diff --git a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
index 1e22cde721d..3d0ea201239 100644
--- a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
+++ b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
@@ -26,9 +26,10 @@ static void fn_node_group_instance_id_expand_in_mf_network(
{
const blender::nodes::DNode &node = builder.dnode();
std::string id = "/";
- for (const blender::nodes::DParentNode *parent = node.parent(); parent;
- parent = parent->parent()) {
- id = "/" + parent->node_ref().name() + id;
+ for (const blender::nodes::DTreeContext *context = node.context();
+ context->parent_node() != nullptr;
+ context = context->parent_context()) {
+ id = "/" + context->parent_node()->name() + id;
}
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<std::string>>(
std::move(id));
diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/node_fn_random_float.cc
index f3401a2c00d..d0ecb5592da 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_float.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_float.cc
@@ -67,12 +67,13 @@ static void fn_node_random_float_expand_in_mf_network(
blender::nodes::NodeMFNetworkBuilder &builder)
{
uint32_t function_seed = 1746872341u;
- const blender::nodes::DNode &node = builder.dnode();
+ blender::nodes::DNode node = builder.dnode();
const blender::DefaultHash<blender::StringRefNull> hasher;
- function_seed = 33 * function_seed + hasher(node.name());
- for (const blender::nodes::DParentNode *parent = node.parent(); parent != nullptr;
- parent = parent->parent()) {
- function_seed = 33 * function_seed + hasher(parent->node_ref().name());
+ function_seed = 33 * function_seed + hasher(node->name());
+ for (const blender::nodes::DTreeContext *context = node.context();
+ context->parent_node() != nullptr;
+ context = context->parent_context()) {
+ function_seed = 33 * function_seed + hasher(context->parent_node()->name());
}
builder.construct_and_set_matching_fn<RandomFloatFunction>(function_seed);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index 38215b54640..9f331190420 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -100,7 +100,7 @@ static Mesh *mesh_boolean_calc(const Mesh *mesh_a, const Mesh *mesh_b, int boole
}
BM_mesh_boolean(
- bm, looptris, tottri, bm_face_isect_pair, nullptr, 2, false, false, boolean_mode);
+ bm, looptris, tottri, bm_face_isect_pair, nullptr, 2, false, false, false, boolean_mode);
Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh_a);
BM_mesh_free(bm);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index 4e15f232934..45aaf81d63f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -222,8 +222,9 @@ static void join_components(Span<const MeshComponent *> src_components, Geometry
dst_component.replace(new_mesh);
/* Don't copy attributes that are stored directly in the mesh data structs. */
- join_attributes(
- to_base_components(src_components), dst_component, {"position", "material_index"});
+ join_attributes(to_base_components(src_components),
+ dst_component,
+ {"position", "material_index", "vertex_normal", "shade_smooth"});
}
static void join_components(Span<const PointCloudComponent *> src_components, GeometrySet &result)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
index c40cb2bb0ae..742383f5b46 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
@@ -29,6 +29,7 @@
#include "BKE_attribute_math.hh"
#include "BKE_bvhutils.h"
#include "BKE_deform.h"
+#include "BKE_geometry_set_instances.hh"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_pointcloud.h"
@@ -38,6 +39,9 @@
#include "node_geometry_util.hh"
+using blender::bke::AttributeKind;
+using blender::bke::GeometryInstanceGroup;
+
static bNodeSocketTemplate geo_node_point_distribute_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_FLOAT, N_("Distance Min"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE},
@@ -89,6 +93,7 @@ static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
}
static void sample_mesh_surface(const Mesh &mesh,
+ const float4x4 &transform,
const float base_density,
const FloatReadAttribute *density_factors,
const int seed,
@@ -106,9 +111,9 @@ static void sample_mesh_surface(const Mesh &mesh,
const int v0_index = mesh.mloop[v0_loop].v;
const int v1_index = mesh.mloop[v1_loop].v;
const int v2_index = mesh.mloop[v2_loop].v;
- const float3 v0_pos = mesh.mvert[v0_index].co;
- const float3 v1_pos = mesh.mvert[v1_index].co;
- const float3 v2_pos = mesh.mvert[v2_index].co;
+ const float3 v0_pos = transform * float3(mesh.mvert[v0_index].co);
+ const float3 v1_pos = transform * float3(mesh.mvert[v1_index].co);
+ const float3 v2_pos = transform * float3(mesh.mvert[v2_index].co);
float looptri_density_factor = 1.0f;
if (density_factors != nullptr) {
@@ -138,47 +143,64 @@ static void sample_mesh_surface(const Mesh &mesh,
}
}
-BLI_NOINLINE static KDTree_3d *build_kdtree(Span<float3> positions)
+BLI_NOINLINE static KDTree_3d *build_kdtree(Span<Vector<float3>> positions_all,
+ const int initial_points_len)
{
- KDTree_3d *kdtree = BLI_kdtree_3d_new(positions.size());
- for (const int i : positions.index_range()) {
- BLI_kdtree_3d_insert(kdtree, i, positions[i]);
+ KDTree_3d *kdtree = BLI_kdtree_3d_new(initial_points_len);
+
+ int i_point = 0;
+ for (const Vector<float3> &positions : positions_all) {
+ for (const float3 position : positions) {
+ BLI_kdtree_3d_insert(kdtree, i_point, position);
+ i_point++;
+ }
}
BLI_kdtree_3d_balance(kdtree);
return kdtree;
}
BLI_NOINLINE static void update_elimination_mask_for_close_points(
- Span<float3> positions, const float minimum_distance, MutableSpan<bool> elimination_mask)
+ Span<Vector<float3>> positions_all,
+ Span<int> instance_start_offsets,
+ const float minimum_distance,
+ MutableSpan<bool> elimination_mask,
+ const int initial_points_len)
{
if (minimum_distance <= 0.0f) {
return;
}
- KDTree_3d *kdtree = build_kdtree(positions);
+ KDTree_3d *kdtree = build_kdtree(positions_all, initial_points_len);
- for (const int i : positions.index_range()) {
- if (elimination_mask[i]) {
- continue;
- }
+ /* The elimination mask is a flattened array for every point,
+ * so keep track of the index to it separately. */
+ for (const int i_instance : positions_all.index_range()) {
+ Span<float3> positions = positions_all[i_instance];
+ const int offset = instance_start_offsets[i_instance];
+
+ for (const int i : positions.index_range()) {
+ if (elimination_mask[offset + i]) {
+ continue;
+ }
- struct CallbackData {
- int index;
- MutableSpan<bool> elimination_mask;
- } callback_data = {i, elimination_mask};
-
- BLI_kdtree_3d_range_search_cb(
- kdtree,
- positions[i],
- minimum_distance,
- [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) {
- CallbackData &callback_data = *static_cast<CallbackData *>(user_data);
- if (index != callback_data.index) {
- callback_data.elimination_mask[index] = true;
- }
- return true;
- },
- &callback_data);
+ struct CallbackData {
+ int index;
+ MutableSpan<bool> elimination_mask;
+ } callback_data = {offset + i, elimination_mask};
+
+ BLI_kdtree_3d_range_search_cb(
+ kdtree,
+ positions[i],
+ minimum_distance,
+ [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) {
+ CallbackData &callback_data = *static_cast<CallbackData *>(user_data);
+ if (index != callback_data.index) {
+ callback_data.elimination_mask[index] = true;
+ }
+ return true;
+ },
+ &callback_data);
+ }
}
BLI_kdtree_3d_free(kdtree);
}
@@ -287,73 +309,106 @@ BLI_NOINLINE static void interpolate_attribute_corner(const Mesh &mesh,
}
}
+template<typename T>
BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
Span<float3> bary_coords,
Span<int> looptri_indices,
- const StringRef attribute_name,
- const ReadAttribute &attribute_in,
- GeometryComponent &component)
+ const AttributeDomain source_domain,
+ Span<T> source_span,
+ MutableSpan<T> output_span)
{
- const CustomDataType data_type = attribute_in.custom_data_type();
- const AttributeDomain domain = attribute_in.domain();
- if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
- /* Not supported currently. */
- return;
- }
-
- OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
- attribute_name, ATTR_DOMAIN_POINT, data_type);
- if (!attribute_out) {
- return;
- }
-
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
-
- Span data_in = attribute_in.get_span<T>();
- MutableSpan data_out = attribute_out->get_span_for_write_only<T>();
-
- switch (domain) {
- case ATTR_DOMAIN_POINT: {
- interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, data_in, data_out);
- break;
- }
- case ATTR_DOMAIN_CORNER: {
- interpolate_attribute_corner<T>(mesh, bary_coords, looptri_indices, data_in, data_out);
- break;
- }
- default: {
- BLI_assert(false);
- break;
- }
+ switch (source_domain) {
+ case ATTR_DOMAIN_POINT: {
+ interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, source_span, output_span);
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ interpolate_attribute_corner<T>(
+ mesh, bary_coords, looptri_indices, source_span, output_span);
+ break;
}
- });
- attribute_out.apply_span_and_save();
+ default: {
+ /* Not supported currently. */
+ return;
+ }
+ }
}
-BLI_NOINLINE static void interpolate_existing_attributes(const MeshComponent &mesh_component,
- GeometryComponent &component,
- Span<float3> bary_coords,
- Span<int> looptri_indices)
+BLI_NOINLINE static void interpolate_existing_attributes(
+ Span<GeometryInstanceGroup> set_groups,
+ Span<int> instance_start_offsets,
+ const Map<std::string, AttributeKind> &attributes,
+ GeometryComponent &component,
+ Span<Vector<float3>> bary_coords_array,
+ Span<Vector<int>> looptri_indices_array)
{
- const Mesh &mesh = *mesh_component.get_for_read();
-
- Set<std::string> attribute_names = mesh_component.attribute_names();
- for (StringRefNull attribute_name : attribute_names) {
- if (ELEM(attribute_name, "position", "normal", "id")) {
+ for (Map<std::string, AttributeKind>::Item entry : attributes.items()) {
+ StringRef attribute_name = entry.key;
+ const CustomDataType output_data_type = entry.value.data_type;
+ /* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
+ OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
+ attribute_name, ATTR_DOMAIN_POINT, output_data_type);
+ if (!attribute_out) {
continue;
}
- ReadAttributePtr attribute_in = mesh_component.attribute_try_get_for_read(attribute_name);
- interpolate_attribute(
- mesh, bary_coords, looptri_indices, attribute_name, *attribute_in, component);
+ fn::GMutableSpan out_span = attribute_out->get_span_for_write_only();
+
+ int i_instance = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ const MeshComponent &source_component = *set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *source_component.get_for_read();
+
+ /* Use a dummy read without specifying a domain or data type in order to
+ * get the existing attribute's domain. Interpolation is done manually based
+ * on the bary coords in #interpolate_attribute. */
+ ReadAttributePtr dummy_attribute = source_component.attribute_try_get_for_read(
+ attribute_name);
+ if (!dummy_attribute) {
+ i_instance += set_group.transforms.size();
+ continue;
+ }
+
+ const AttributeDomain source_domain = dummy_attribute->domain();
+ ReadAttributePtr source_attribute = source_component.attribute_get_for_read(
+ attribute_name, source_domain, output_data_type, nullptr);
+ if (!source_attribute) {
+ i_instance += set_group.transforms.size();
+ continue;
+ }
+ fn::GSpan source_span = source_attribute->get_span();
+
+ attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+
+ for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
+ const int offset = instance_start_offsets[i_instance];
+ Span<float3> bary_coords = bary_coords_array[i_instance];
+ Span<int> looptri_indices = looptri_indices_array[i_instance];
+
+ MutableSpan<T> instance_span = out_span.typed<T>().slice(offset, bary_coords.size());
+ interpolate_attribute<T>(mesh,
+ bary_coords,
+ looptri_indices,
+ source_domain,
+ source_span.typed<T>(),
+ instance_span);
+
+ i_instance++;
+ }
+ });
+ }
+
+ attribute_out.apply_span_and_save();
}
}
-BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh,
+BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup> sets,
+ Span<int> instance_start_offsets,
GeometryComponent &component,
- Span<float3> bary_coords,
- Span<int> looptri_indices)
+ Span<Vector<float3>> bary_coords_array,
+ Span<Vector<int>> looptri_indices_array)
{
OutputAttributePtr id_attribute = component.attribute_try_get_for_output(
"id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
@@ -362,26 +417,50 @@ BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh,
OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
- MutableSpan<int> ids = id_attribute->get_span_for_write_only<int>();
- MutableSpan<float3> normals = normal_attribute->get_span_for_write_only<float3>();
- MutableSpan<float3> rotations = rotation_attribute->get_span_for_write_only<float3>();
-
- Span<MLoopTri> looptris = get_mesh_looptris(mesh);
- for (const int i : bary_coords.index_range()) {
- const int looptri_index = looptri_indices[i];
- const MLoopTri &looptri = looptris[looptri_index];
- const float3 &bary_coord = bary_coords[i];
-
- const int v0_index = mesh.mloop[looptri.tri[0]].v;
- const int v1_index = mesh.mloop[looptri.tri[1]].v;
- const int v2_index = mesh.mloop[looptri.tri[2]].v;
- const float3 v0_pos = mesh.mvert[v0_index].co;
- const float3 v1_pos = mesh.mvert[v1_index].co;
- const float3 v2_pos = mesh.mvert[v2_index].co;
+ MutableSpan<int> result_ids = id_attribute->get_span_for_write_only<int>();
+ MutableSpan<float3> result_normals = normal_attribute->get_span_for_write_only<float3>();
+ MutableSpan<float3> result_rotations = rotation_attribute->get_span_for_write_only<float3>();
+
+ int i_instance = 0;
+ for (const GeometryInstanceGroup &set_group : sets) {
+ const GeometrySet &set = set_group.geometry_set;
+ const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *component.get_for_read();
+ Span<MLoopTri> looptris = get_mesh_looptris(mesh);
+
+ for (const float4x4 &transform : set_group.transforms) {
+ const int offset = instance_start_offsets[i_instance];
+
+ Span<float3> bary_coords = bary_coords_array[i_instance];
+ Span<int> looptri_indices = looptri_indices_array[i_instance];
+ MutableSpan<int> ids = result_ids.slice(offset, bary_coords.size());
+ MutableSpan<float3> normals = result_normals.slice(offset, bary_coords.size());
+ MutableSpan<float3> rotations = result_rotations.slice(offset, bary_coords.size());
+
+ /* Use one matrix multiplication per point instead of three (for each triangle corner). */
+ float rotation_matrix[3][3];
+ mat4_to_rot(rotation_matrix, transform.values);
+
+ for (const int i : bary_coords.index_range()) {
+ const int looptri_index = looptri_indices[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+ const float3 &bary_coord = bary_coords[i];
+
+ const int v0_index = mesh.mloop[looptri.tri[0]].v;
+ const int v1_index = mesh.mloop[looptri.tri[1]].v;
+ const int v2_index = mesh.mloop[looptri.tri[2]].v;
+ const float3 v0_pos = float3(mesh.mvert[v0_index].co);
+ const float3 v1_pos = float3(mesh.mvert[v1_index].co);
+ const float3 v2_pos = float3(mesh.mvert[v2_index].co);
+
+ ids[i] = (int)(bary_coord.hash() + (uint64_t)looptri_index);
+ normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos);
+ mul_m3_v3(rotation_matrix, normals[i]);
+ rotations[i] = normal_to_euler_rotation(normals[i]);
+ }
- ids[i] = (int)(bary_coord.hash() + (uint64_t)looptri_index);
- normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos);
- rotations[i] = normal_to_euler_rotation(normals[i]);
+ i_instance++;
+ }
}
id_attribute.apply_span_and_save();
@@ -389,109 +468,244 @@ BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh,
rotation_attribute.apply_span_and_save();
}
-BLI_NOINLINE static void add_remaining_point_attributes(const MeshComponent &mesh_component,
- GeometryComponent &component,
- Span<float3> bary_coords,
- Span<int> looptri_indices)
+BLI_NOINLINE static void add_remaining_point_attributes(
+ Span<GeometryInstanceGroup> set_groups,
+ Span<int> instance_start_offsets,
+ const Map<std::string, AttributeKind> &attributes,
+ GeometryComponent &component,
+ Span<Vector<float3>> bary_coords_array,
+ Span<Vector<int>> looptri_indices_array)
{
- interpolate_existing_attributes(mesh_component, component, bary_coords, looptri_indices);
+ interpolate_existing_attributes(set_groups,
+ instance_start_offsets,
+ attributes,
+ component,
+ bary_coords_array,
+ looptri_indices_array);
compute_special_attributes(
- *mesh_component.get_for_read(), component, bary_coords, looptri_indices);
+ set_groups, instance_start_offsets, component, bary_coords_array, looptri_indices_array);
}
-static void sample_mesh_surface_with_minimum_distance(const Mesh &mesh,
- const float max_density,
- const float minimum_distance,
- const FloatReadAttribute &density_factors,
- const int seed,
- Vector<float3> &r_positions,
- Vector<float3> &r_bary_coords,
- Vector<int> &r_looptri_indices)
+static void distribute_points_random(Span<GeometryInstanceGroup> set_groups,
+ const StringRef density_attribute_name,
+ const float density,
+ const int seed,
+ MutableSpan<Vector<float3>> positions_all,
+ MutableSpan<Vector<float3>> bary_coords_all,
+ MutableSpan<Vector<int>> looptri_indices_all)
{
- sample_mesh_surface(
- mesh, max_density, nullptr, seed, r_positions, r_bary_coords, r_looptri_indices);
- Array<bool> elimination_mask(r_positions.size(), false);
- update_elimination_mask_for_close_points(r_positions, minimum_distance, elimination_mask);
- update_elimination_mask_based_on_density_factors(
- mesh, density_factors, r_bary_coords, r_looptri_indices, elimination_mask);
- eliminate_points_based_on_mask(elimination_mask, r_positions, r_bary_coords, r_looptri_indices);
+ /* If there is an attribute name, the default value for the densities should be zero so that
+ * points are only scattered where the attribute exists. Otherwise, just "ignore" the density
+ * factors. */
+ const bool use_one_default = density_attribute_name.is_empty();
+
+ int i_instance = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
+ const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
+ density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
+ const Mesh &mesh = *component.get_for_read();
+ for (const float4x4 &transform : set_group.transforms) {
+ Vector<float3> &positions = positions_all[i_instance];
+ Vector<float3> &bary_coords = bary_coords_all[i_instance];
+ Vector<int> &looptri_indices = looptri_indices_all[i_instance];
+ sample_mesh_surface(mesh,
+ transform,
+ density,
+ &density_factors,
+ seed,
+ positions,
+ bary_coords,
+ looptri_indices);
+ i_instance++;
+ }
+ }
+}
+
+static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_groups,
+ const StringRef density_attribute_name,
+ const float density,
+ const int seed,
+ const float minimum_distance,
+ MutableSpan<Vector<float3>> positions_all,
+ MutableSpan<Vector<float3>> bary_coords_all,
+ MutableSpan<Vector<int>> looptri_indices_all)
+{
+ Array<int> instance_start_offsets(positions_all.size());
+ int initial_points_len = 0;
+ int i_instance = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *component.get_for_read();
+ for (const float4x4 &transform : set_group.transforms) {
+ Vector<float3> &positions = positions_all[i_instance];
+ Vector<float3> &bary_coords = bary_coords_all[i_instance];
+ Vector<int> &looptri_indices = looptri_indices_all[i_instance];
+ sample_mesh_surface(
+ mesh, transform, density, nullptr, seed, positions, bary_coords, looptri_indices);
+
+ instance_start_offsets[i_instance] = initial_points_len;
+ initial_points_len += positions.size();
+ i_instance++;
+ }
+ }
+
+ /* If there is an attribute name, the default value for the densities should be zero so that
+ * points are only scattered where the attribute exists. Otherwise, just "ignore" the density
+ * factors. */
+ const bool use_one_default = density_attribute_name.is_empty();
+
+ /* Unlike the other result arrays, the elimination mask in stored as a flat array for every
+ * point, in order to simplify culling points from the KDTree (which needs to know about all
+ * points at once). */
+ Array<bool> elimination_mask(initial_points_len, false);
+ update_elimination_mask_for_close_points(positions_all,
+ instance_start_offsets,
+ minimum_distance,
+ elimination_mask,
+ initial_points_len);
+
+ i_instance = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *component.get_for_read();
+ const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
+ density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
+
+ for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
+ Vector<float3> &positions = positions_all[i_instance];
+ Vector<float3> &bary_coords = bary_coords_all[i_instance];
+ Vector<int> &looptri_indices = looptri_indices_all[i_instance];
+
+ const int offset = instance_start_offsets[i_instance];
+ update_elimination_mask_based_on_density_factors(
+ mesh,
+ density_factors,
+ bary_coords,
+ looptri_indices,
+ elimination_mask.as_mutable_span().slice(offset, positions.size()));
+
+ eliminate_points_based_on_mask(elimination_mask.as_span().slice(offset, positions.size()),
+ positions,
+ bary_coords,
+ looptri_indices);
+
+ i_instance++;
+ }
+ }
}
static void geo_node_point_distribute_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- GeometrySet geometry_set_out;
- /* TODO: This node only needs read-only access to input instances. */
- geometry_set = geometry_set_realize_instances(geometry_set);
+ const GeometryNodePointDistributeMode distribute_method =
+ static_cast<GeometryNodePointDistributeMode>(params.node().custom1);
- GeometryNodePointDistributeMode distribute_method = static_cast<GeometryNodePointDistributeMode>(
- params.node().custom1);
+ const int seed = params.get_input<int>("Seed");
+ const float density = params.extract_input<float>("Density Max");
+ const std::string density_attribute_name = params.extract_input<std::string>(
+ "Density Attribute");
- if (!geometry_set.has_mesh()) {
- params.error_message_add(NodeWarningType::Error, TIP_("Geometry must contain a mesh"));
- params.set_output("Geometry", std::move(geometry_set_out));
+ if (density <= 0.0f) {
+ params.set_output("Geometry", GeometrySet());
return;
}
- const float density = params.extract_input<float>("Density Max");
- const std::string density_attribute = params.extract_input<std::string>("Density Attribute");
-
- if (density <= 0.0f) {
- params.set_output("Geometry", std::move(geometry_set_out));
+ Vector<GeometryInstanceGroup> set_groups = bke::geometry_set_gather_instances(geometry_set);
+ if (set_groups.is_empty()) {
+ params.set_output("Geometry", GeometrySet());
return;
}
- const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
- const Mesh *mesh_in = mesh_component.get_for_read();
+ /* Remove any set inputs that don't contain a mesh, to avoid checking later on. */
+ for (int i = set_groups.size() - 1; i >= 0; i--) {
+ const GeometrySet &set = set_groups[i].geometry_set;
+ if (!set.has_mesh()) {
+ set_groups.remove_and_reorder(i);
+ }
+ }
- if (mesh_in->mpoly == nullptr) {
- params.error_message_add(NodeWarningType::Error, TIP_("Mesh has no faces"));
- params.set_output("Geometry", std::move(geometry_set_out));
+ if (set_groups.is_empty()) {
+ params.error_message_add(NodeWarningType::Error, TIP_("Input geometry must contain a mesh"));
+ params.set_output("Geometry", GeometrySet());
return;
}
- const FloatReadAttribute density_factors = mesh_component.attribute_get_for_read<float>(
- density_attribute, ATTR_DOMAIN_CORNER, 1.0f);
- const int seed = params.get_input<int>("Seed");
+ int instances_len = 0;
+ for (GeometryInstanceGroup &set_group : set_groups) {
+ instances_len += set_group.transforms.size();
+ }
+
+ /* Store data per-instance in order to simplify attribute access after the scattering,
+ * and to make the point elimination simpler for the poisson disk mode. Note that some
+ * vectors will be empty if any instances don't contain mesh data. */
+ Array<Vector<float3>> positions_all(instances_len);
+ Array<Vector<float3>> bary_coords_all(instances_len);
+ Array<Vector<int>> looptri_indices_all(instances_len);
- Vector<float3> positions;
- Vector<float3> bary_coords;
- Vector<int> looptri_indices;
switch (distribute_method) {
- case GEO_NODE_POINT_DISTRIBUTE_RANDOM:
- sample_mesh_surface(
- *mesh_in, density, &density_factors, seed, positions, bary_coords, looptri_indices);
+ case GEO_NODE_POINT_DISTRIBUTE_RANDOM: {
+ distribute_points_random(set_groups,
+ density_attribute_name,
+ density,
+ seed,
+ positions_all,
+ bary_coords_all,
+ looptri_indices_all);
break;
- case GEO_NODE_POINT_DISTRIBUTE_POISSON:
+ }
+ case GEO_NODE_POINT_DISTRIBUTE_POISSON: {
const float minimum_distance = params.extract_input<float>("Distance Min");
- sample_mesh_surface_with_minimum_distance(*mesh_in,
- density,
- minimum_distance,
- density_factors,
- seed,
- positions,
- bary_coords,
- looptri_indices);
+ distribute_points_poisson_disk(set_groups,
+ density_attribute_name,
+ density,
+ seed,
+ minimum_distance,
+ positions_all,
+ bary_coords_all,
+ looptri_indices_all);
break;
+ }
}
- const int tot_points = positions.size();
- PointCloud *pointcloud = BKE_pointcloud_new_nomain(tot_points);
- memcpy(pointcloud->co, positions.data(), sizeof(float3) * tot_points);
- for (const int i : positions.index_range()) {
- *(float3 *)(pointcloud->co + i) = positions[i];
- pointcloud->radius[i] = 0.05f;
+ int final_points_len = 0;
+ Array<int> instance_start_offsets(set_groups.size());
+ for (const int i : positions_all.index_range()) {
+ Vector<float3> &positions = positions_all[i];
+ instance_start_offsets[i] = final_points_len;
+ final_points_len += positions.size();
}
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(final_points_len);
+ for (const int instance_index : positions_all.index_range()) {
+ const int offset = instance_start_offsets[instance_index];
+ Span<float3> positions = positions_all[instance_index];
+ memcpy(pointcloud->co + offset, positions.data(), sizeof(float3) * positions.size());
+ }
+
+ uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
+
+ GeometrySet geometry_set_out = GeometrySet::create_with_pointcloud(pointcloud);
PointCloudComponent &point_component =
geometry_set_out.get_component_for_write<PointCloudComponent>();
- point_component.replace(pointcloud);
- add_remaining_point_attributes(mesh_component, point_component, bary_coords, looptri_indices);
+ Map<std::string, AttributeKind> attributes;
+ bke::gather_attribute_info(
+ attributes, {GeometryComponentType::Mesh}, set_groups, {"position", "normal", "id"});
+ add_remaining_point_attributes(set_groups,
+ instance_start_offsets,
+ attributes,
+ point_component,
+ bary_coords_all,
+ looptri_indices_all);
params.set_output("Geometry", std::move(geometry_set_out));
}
+
} // namespace blender::nodes
void register_node_type_geo_point_distribute()
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
index cb3cd012c77..015f4cd38e7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
@@ -46,6 +46,9 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
{
OutputAttributePtr position_attribute = component.attribute_try_get_for_output(
"position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ if (!position_attribute) {
+ return;
+ }
ReadAttributePtr attribute = params.get_input_attribute(
"Translation", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr);
if (!attribute) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc
index 38560d277e3..b5731851229 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc
@@ -25,20 +25,20 @@
#include "node_geometry_util.hh"
-static bNodeSocketTemplate geo_node_subdivision_surface_simple_in[] = {
+static bNodeSocketTemplate geo_node_subdivide_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6},
{-1, ""},
};
-static bNodeSocketTemplate geo_node_subdivision_surface_simple_out[] = {
+static bNodeSocketTemplate geo_node_subdivide_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
-static void geo_node_subdivision_surface_simple_exec(GeoNodeExecParams params)
+static void geo_node_subdivide_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -99,17 +99,12 @@ static void geo_node_subdivision_surface_simple_exec(GeoNodeExecParams params)
}
} // namespace blender::nodes
-void register_node_type_geo_subdivision_surface_simple()
+void register_node_type_geo_subdivide()
{
static bNodeType ntype;
- geo_node_type_base(&ntype,
- GEO_NODE_SUBDIVISION_SURFACE_SIMPLE,
- "Simple Subdivision Surface",
- NODE_CLASS_GEOMETRY,
- 0);
- node_type_socket_templates(
- &ntype, geo_node_subdivision_surface_simple_in, geo_node_subdivision_surface_simple_out);
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_simple_exec;
+ geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE, "Subdivide", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_subdivide_in, geo_node_subdivide_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivide_smooth.cc
index 47304a0de68..4d9b8110d65 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivide_smooth.cc
@@ -25,7 +25,7 @@
#include "node_geometry_util.hh"
-static bNodeSocketTemplate geo_node_subdivision_surface_in[] = {
+static bNodeSocketTemplate geo_node_subdivide_smooth_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6},
{SOCK_BOOLEAN, N_("Use Creases")},
@@ -34,14 +34,14 @@ static bNodeSocketTemplate geo_node_subdivision_surface_in[] = {
{-1, ""},
};
-static bNodeSocketTemplate geo_node_subdivision_surface_out[] = {
+static bNodeSocketTemplate geo_node_subdivide_smooth_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
-static void geo_node_subdivision_surface_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr))
+static void geo_node_subdivide_smooth_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr))
{
#ifndef WITH_OPENSUBDIV
uiItemL(layout, IFACE_("Disabled, built without OpenSubdiv"), ICON_ERROR);
@@ -51,7 +51,7 @@ static void geo_node_subdivision_surface_layout(uiLayout *layout,
}
namespace blender::nodes {
-static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
+static void geo_node_subdivide_smooth_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -120,15 +120,14 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
}
} // namespace blender::nodes
-void register_node_type_geo_subdivision_surface()
+void register_node_type_geo_subdivide_smooth()
{
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0);
- node_type_socket_templates(
- &ntype, geo_node_subdivision_surface_in, geo_node_subdivision_surface_out);
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec;
- ntype.draw_buttons = geo_node_subdivision_surface_layout;
+ &ntype, GEO_NODE_SUBDIVIDE_SMOOTH, "Subdivide Smooth", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_subdivide_smooth_in, geo_node_subdivide_smooth_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_smooth_exec;
+ ntype.draw_buttons = geo_node_subdivide_smooth_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc
index a65641bca2a..36c64b00f47 100644
--- a/source/blender/nodes/intern/derived_node_tree.cc
+++ b/source/blender/nodes/intern/derived_node_tree.cc
@@ -16,518 +16,261 @@
#include "NOD_derived_node_tree.hh"
-#include "BLI_dot_export.hh"
-
-#define UNINITIALIZED_ID UINT32_MAX
-
namespace blender::nodes {
-DerivedNodeTree::DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs) : btree_(btree)
+/* Construct a new derived node tree for a given root node tree. The generated derived node tree
+ * does not own the used node tree refs (so that those can be used by others as well). The caller
+ * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
+ * derived node tree. */
+DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs)
{
- BLI_assert(btree != nullptr);
-
- const NodeTreeRef &main_tree_ref = get_tree_ref_from_map(node_tree_refs, *btree);
- used_node_tree_refs_.add_new(&main_tree_ref);
-
- Vector<DNode *> all_nodes;
- Vector<DGroupInput *> all_group_inputs;
- Vector<DParentNode *> all_parent_nodes;
-
- this->insert_nodes_and_links_in_id_order(main_tree_ref, nullptr, all_nodes);
- this->expand_groups(all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs);
- this->relink_and_remove_muted_nodes(all_nodes);
- this->remove_expanded_group_interfaces(all_nodes);
- this->remove_unused_group_inputs(all_group_inputs);
- this->store_in_this_and_init_ids(
- std::move(all_nodes), std::move(all_group_inputs), std::move(all_parent_nodes));
+ /* Construct all possible contexts immediately. This is significantly cheaper than inlining all
+ * node groups. If it still becomes a performance issue in the future, contexts could be
+ * constructed lazily when they are needed. */
+ root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs);
}
-BLI_NOINLINE void DerivedNodeTree::insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref,
- DParentNode *parent,
- Vector<DNode *> &all_nodes)
+DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context,
+ const NodeRef *parent_node,
+ bNodeTree &btree,
+ NodeTreeRefMap &node_tree_refs)
{
- Array<DSocket *, 64> sockets_map(tree_ref.sockets().size());
-
- /* Insert nodes. */
- for (const NodeRef *node_ref : tree_ref.nodes()) {
- DNode &node = this->create_node(*node_ref, parent, sockets_map);
- all_nodes.append(&node);
- }
-
- /* Insert links. */
- for (const NodeRef *node_ref : tree_ref.nodes()) {
- for (const InputSocketRef *to_socket_ref : node_ref->inputs()) {
- DInputSocket *to_socket = static_cast<DInputSocket *>(sockets_map[to_socket_ref->id()]);
- for (const OutputSocketRef *from_socket_ref : to_socket_ref->linked_sockets()) {
- DOutputSocket *from_socket = static_cast<DOutputSocket *>(
- sockets_map[from_socket_ref->id()]);
- to_socket->linked_sockets_.append(from_socket);
- from_socket->linked_sockets_.append(to_socket);
+ DTreeContext &context = *allocator_.construct<DTreeContext>().release();
+ context.parent_context_ = parent_context;
+ context.parent_node_ = parent_node;
+ context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree);
+ used_node_tree_refs_.add(context.tree_);
+
+ for (const NodeRef *node : context.tree_->nodes()) {
+ if (node->is_group_node()) {
+ bNode *bnode = node->bnode();
+ bNodeTree *child_btree = reinterpret_cast<bNodeTree *>(bnode->id);
+ if (child_btree != nullptr) {
+ DTreeContext &child = this->construct_context_recursively(
+ &context, node, *child_btree, node_tree_refs);
+ context.children_.add_new(node, &child);
}
}
}
+
+ return context;
}
-DNode &DerivedNodeTree::create_node(const NodeRef &node_ref,
- DParentNode *parent,
- MutableSpan<DSocket *> r_sockets_map)
+DerivedNodeTree::~DerivedNodeTree()
{
- DNode &node = *allocator_.construct<DNode>();
- node.node_ref_ = &node_ref;
- node.parent_ = parent;
- node.id_ = UNINITIALIZED_ID;
-
- node.inputs_ = allocator_.construct_elements_and_pointer_array<DInputSocket>(
- node_ref.inputs().size());
- node.outputs_ = allocator_.construct_elements_and_pointer_array<DOutputSocket>(
- node_ref.outputs().size());
-
- for (int i : node.inputs_.index_range()) {
- const InputSocketRef &socket_ref = node_ref.input(i);
- DInputSocket &socket = *node.inputs_[i];
- socket.is_multi_input_socket_ = socket_ref.bsocket()->flag & SOCK_MULTI_INPUT;
- socket.id_ = UNINITIALIZED_ID;
- socket.node_ = &node;
- socket.socket_ref_ = &socket_ref;
-
- r_sockets_map[socket_ref.id()] = &socket;
- }
-
- for (int i : node.outputs_.index_range()) {
- const OutputSocketRef &socket_ref = node_ref.output(i);
- DOutputSocket &socket = *node.outputs_[i];
-
- socket.id_ = UNINITIALIZED_ID;
- socket.node_ = &node;
- socket.socket_ref_ = &socket_ref;
-
- r_sockets_map[socket_ref.id()] = &socket;
- }
-
- return node;
+ /* Has to be destructed manually, because the context info is allocated in a linear allocator. */
+ this->destruct_context_recursively(root_context_);
}
-BLI_NOINLINE void DerivedNodeTree::expand_groups(Vector<DNode *> &all_nodes,
- Vector<DGroupInput *> &all_group_inputs,
- Vector<DParentNode *> &all_parent_nodes,
- NodeTreeRefMap &node_tree_refs)
+void DerivedNodeTree::destruct_context_recursively(DTreeContext *context)
{
- for (int i = 0; i < all_nodes.size(); i++) {
- DNode &node = *all_nodes[i];
- if (node.node_ref_->is_group_node()) {
- /* Muted nodes are relinked in a separate step. */
- if (!node.node_ref_->is_muted()) {
- this->expand_group_node(
- node, all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs);
- }
- }
+ for (DTreeContext *child : context->children_.values()) {
+ this->destruct_context_recursively(child);
}
+ context->~DTreeContext();
}
-BLI_NOINLINE void DerivedNodeTree::expand_group_node(DNode &group_node,
- Vector<DNode *> &all_nodes,
- Vector<DGroupInput *> &all_group_inputs,
- Vector<DParentNode *> &all_parent_nodes,
- NodeTreeRefMap &node_tree_refs)
+/* Returns true if there are any cycles in the node tree. */
+bool DerivedNodeTree::has_link_cycles() const
{
- const NodeRef &group_node_ref = *group_node.node_ref_;
- BLI_assert(group_node_ref.is_group_node());
-
- bNodeTree *btree = reinterpret_cast<bNodeTree *>(group_node_ref.bnode()->id);
- if (btree == nullptr) {
- return;
+ for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
+ if (tree_ref->has_link_cycles()) {
+ return true;
+ }
}
-
- const NodeTreeRef &group_ref = get_tree_ref_from_map(node_tree_refs, *btree);
- used_node_tree_refs_.add(&group_ref);
-
- DParentNode &parent = *allocator_.construct<DParentNode>();
- parent.id_ = all_parent_nodes.append_and_get_index(&parent);
- parent.parent_ = group_node.parent_;
- parent.node_ref_ = &group_node_ref;
-
- this->insert_nodes_and_links_in_id_order(group_ref, &parent, all_nodes);
- Span<DNode *> new_nodes_by_id = all_nodes.as_span().take_back(group_ref.nodes().size());
-
- this->create_group_inputs_for_unlinked_inputs(group_node, all_group_inputs);
- this->relink_group_inputs(group_ref, new_nodes_by_id, group_node);
- this->relink_group_outputs(group_ref, new_nodes_by_id, group_node);
+ return false;
}
-BLI_NOINLINE void DerivedNodeTree::create_group_inputs_for_unlinked_inputs(
- DNode &node, Vector<DGroupInput *> &all_group_inputs)
+/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */
+void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const
{
- for (DInputSocket *input_socket : node.inputs_) {
- if (input_socket->is_linked()) {
- continue;
- }
-
- DGroupInput &group_input = *allocator_.construct<DGroupInput>();
- group_input.id_ = UNINITIALIZED_ID;
- group_input.socket_ref_ = &input_socket->socket_ref();
- group_input.parent_ = node.parent_;
-
- group_input.linked_sockets_.append(input_socket);
- input_socket->linked_group_inputs_.append(&group_input);
- all_group_inputs.append(&group_input);
- }
+ this->foreach_node_in_context_recursive(*root_context_, callback);
}
-BLI_NOINLINE void DerivedNodeTree::relink_group_inputs(const NodeTreeRef &group_ref,
- Span<DNode *> nodes_by_id,
- DNode &group_node)
+void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context,
+ FunctionRef<void(DNode)> callback) const
{
- Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupInput");
- if (node_refs.size() == 0) {
- return;
+ for (const NodeRef *node_ref : context.tree_->nodes()) {
+ callback(DNode(&context, node_ref));
}
-
- int input_amount = group_node.inputs().size();
-
- for (int input_index : IndexRange(input_amount)) {
- DInputSocket *outside_group = group_node.inputs_[input_index];
-
- for (DOutputSocket *outside_connected : outside_group->linked_sockets_) {
- outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group);
- }
-
- for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) {
- outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group);
- }
-
- for (const NodeRef *input_node_ref : node_refs) {
- DNode &input_node = *nodes_by_id[input_node_ref->id()];
- DOutputSocket *inside_group = input_node.outputs_[input_index];
-
- for (DInputSocket *inside_connected : inside_group->linked_sockets_) {
- inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group);
-
- for (DOutputSocket *outside_connected : outside_group->linked_sockets_) {
- inside_connected->linked_sockets_.append(outside_connected);
- outside_connected->linked_sockets_.append(inside_connected);
- }
-
- for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) {
- inside_connected->linked_group_inputs_.append(outside_connected);
- outside_connected->linked_sockets_.append(inside_connected);
- }
- }
-
- inside_group->linked_sockets_.clear();
- }
-
- outside_group->linked_sockets_.clear();
- outside_group->linked_group_inputs_.clear();
+ for (const DTreeContext *child_context : context.children_.values()) {
+ this->foreach_node_in_context_recursive(*child_context, callback);
}
}
-BLI_NOINLINE void DerivedNodeTree::relink_group_outputs(const NodeTreeRef &group_ref,
- Span<DNode *> nodes_by_id,
- DNode &group_node)
+DOutputSocket DInputSocket::get_corresponding_group_node_output() const
{
- Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupOutput");
- if (node_refs.size() == 0) {
- return;
- }
- /* TODO: Pick correct group output node if there are more than one. */
- const NodeRef &output_node_ref = *node_refs[0];
- DNode &output_node = *nodes_by_id[output_node_ref.id()];
+ BLI_assert(*this);
+ BLI_assert(socket_ref_->node().is_group_output_node());
+ BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1);
- int output_amount = group_node.outputs().size();
- BLI_assert(output_amount == output_node_ref.inputs().size() - 1);
+ const DTreeContext *parent_context = context_->parent_context();
+ const NodeRef *parent_node = context_->parent_node();
+ BLI_assert(parent_context != nullptr);
+ BLI_assert(parent_node != nullptr);
- for (int output_index : IndexRange(output_amount)) {
- DOutputSocket *outside_group = group_node.outputs_[output_index];
- DInputSocket *inside_group = output_node.inputs_[output_index];
-
- for (DInputSocket *outside_connected : outside_group->linked_sockets_) {
- outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group);
- }
-
- for (DOutputSocket *inside_connected : inside_group->linked_sockets_) {
- inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group);
-
- for (DInputSocket *outside_connected : outside_group->linked_sockets_) {
- inside_connected->linked_sockets_.append(outside_connected);
- outside_connected->linked_sockets_.append(inside_connected);
- }
- }
-
- for (DGroupInput *inside_connected : inside_group->linked_group_inputs_) {
- inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group);
-
- for (DInputSocket *outside_connected : outside_group->linked_sockets_) {
- inside_connected->linked_sockets_.append(outside_connected);
- outside_connected->linked_group_inputs_.append(inside_connected);
- }
- }
-
- outside_group->linked_sockets_.clear();
- inside_group->linked_sockets_.clear();
- }
+ const int socket_index = socket_ref_->index();
+ return {parent_context, &parent_node->output(socket_index)};
}
-BLI_NOINLINE void DerivedNodeTree::remove_expanded_group_interfaces(Vector<DNode *> &all_nodes)
+Vector<DOutputSocket> DInputSocket::get_corresponding_group_input_sockets() const
{
- int index = 0;
- while (index < all_nodes.size()) {
- DNode &node = *all_nodes[index];
- const NodeRef &node_ref = *node.node_ref_;
- if (node_ref.is_group_node() ||
- (node.parent_ != nullptr &&
- (node_ref.is_group_input_node() || node_ref.is_group_output_node()))) {
- all_nodes.remove_and_reorder(index);
- node.destruct_with_sockets();
- }
- else {
- index++;
- }
+ BLI_assert(*this);
+ BLI_assert(socket_ref_->node().is_group_node());
+
+ const DTreeContext *child_context = context_->child_context(socket_ref_->node());
+ BLI_assert(child_context != nullptr);
+
+ const NodeTreeRef &child_tree = child_context->tree();
+ Span<const NodeRef *> group_input_nodes = child_tree.nodes_by_type("NodeGroupInput");
+ const int socket_index = socket_ref_->index();
+ Vector<DOutputSocket> sockets;
+ for (const NodeRef *group_input_node : group_input_nodes) {
+ sockets.append(DOutputSocket(child_context, &group_input_node->output(socket_index)));
}
+ return sockets;
}
-BLI_NOINLINE void DerivedNodeTree::remove_unused_group_inputs(
- Vector<DGroupInput *> &all_group_inputs)
+DInputSocket DOutputSocket::get_corresponding_group_node_input() const
{
- int index = 0;
- while (index < all_group_inputs.size()) {
- DGroupInput &group_input = *all_group_inputs[index];
- if (group_input.linked_sockets_.is_empty()) {
- all_group_inputs.remove_and_reorder(index);
- group_input.~DGroupInput();
- }
- else {
- index++;
- }
- }
+ BLI_assert(*this);
+ BLI_assert(socket_ref_->node().is_group_input_node());
+ BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1);
+
+ const DTreeContext *parent_context = context_->parent_context();
+ const NodeRef *parent_node = context_->parent_node();
+ BLI_assert(parent_context != nullptr);
+ BLI_assert(parent_node != nullptr);
+
+ const int socket_index = socket_ref_->index();
+ return {parent_context, &parent_node->input(socket_index)};
}
-BLI_NOINLINE void DerivedNodeTree::relink_and_remove_muted_nodes(Vector<DNode *> &all_nodes)
+DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
{
- int index = 0;
- while (index < all_nodes.size()) {
- DNode &node = *all_nodes[index];
- const NodeRef &node_ref = *node.node_ref_;
- if (node_ref.is_muted()) {
- this->relink_muted_node(node);
- all_nodes.remove_and_reorder(index);
- node.destruct_with_sockets();
- }
- else {
- index++;
+ BLI_assert(*this);
+ BLI_assert(socket_ref_->node().is_group_node());
+
+ const DTreeContext *child_context = context_->child_context(socket_ref_->node());
+ BLI_assert(child_context != nullptr);
+
+ const NodeTreeRef &child_tree = child_context->tree();
+ Span<const NodeRef *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput");
+ const int socket_index = socket_ref_->index();
+ for (const NodeRef *group_output_node : group_output_nodes) {
+ if (group_output_node->bnode()->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) {
+ return {child_context, &group_output_node->input(socket_index)};
}
}
+ return {};
}
-BLI_NOINLINE void DerivedNodeTree::relink_muted_node(DNode &node)
+/* Call the given callback for every "real" origin socket. "Real" means that reroutes, muted nodes
+ * and node groups are handled by this function. Origin sockets are ones where a node gets its
+ * inputs from. */
+void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback,
+ const bool follow_only_first_incoming_link) const
{
- const bNode &bnode = *node.bnode();
- LISTBASE_FOREACH (const bNodeLink *, internal_link, &bnode.internal_links) {
- BLI_assert(internal_link->fromnode == &bnode);
- BLI_assert(internal_link->tonode == &bnode);
- bNodeSocket *input_bsocket = internal_link->fromsock;
- bNodeSocket *output_bsocket = internal_link->tosock;
-
- /* Find internally linked sockets. */
- DInputSocket *input_socket = nullptr;
- DOutputSocket *output_socket = nullptr;
- for (DInputSocket *socket : node.inputs_) {
- if (socket->bsocket() == input_bsocket) {
- input_socket = socket;
- break;
- }
- }
- for (DOutputSocket *socket : node.outputs_) {
- if (socket->bsocket() == output_bsocket) {
- output_socket = socket;
- break;
+ BLI_assert(*this);
+ Span<const OutputSocketRef *> linked_sockets_to_check = socket_ref_->as_input().linked_sockets();
+ if (follow_only_first_incoming_link) {
+ linked_sockets_to_check = linked_sockets_to_check.take_front(1);
+ }
+ for (const OutputSocketRef *linked_socket : linked_sockets_to_check) {
+ const NodeRef &linked_node = linked_socket->node();
+ DOutputSocket linked_dsocket{context_, linked_socket};
+
+ if (linked_node.is_muted()) {
+ /* If the node is muted, follow the internal links of the node. */
+ for (const InternalLinkRef *internal_link : linked_node.internal_links()) {
+ if (&internal_link->to() == linked_socket) {
+ DInputSocket input_of_muted_node{context_, &internal_link->from()};
+ input_of_muted_node.foreach_origin_socket(callback, true);
+ }
}
}
- BLI_assert(input_socket != nullptr);
- BLI_assert(output_socket != nullptr);
-
- /* Link sockets connected to the input to sockets that are connected to the internally linked
- * output. */
- for (DInputSocket *to_socket : output_socket->linked_sockets_) {
- for (DOutputSocket *from_socket : input_socket->linked_sockets_) {
- from_socket->linked_sockets_.append_non_duplicates(to_socket);
- to_socket->linked_sockets_.append_non_duplicates(from_socket);
+ else if (linked_node.is_group_input_node()) {
+ if (context_->is_root()) {
+ /* This is a group input in the root node group. */
+ callback(linked_dsocket);
}
- for (DGroupInput *group_input : input_socket->linked_group_inputs_) {
- group_input->linked_sockets_.append_non_duplicates(to_socket);
- to_socket->linked_group_inputs_.append_non_duplicates(group_input);
+ else {
+ DInputSocket socket_in_parent_group = linked_dsocket.get_corresponding_group_node_input();
+ if (socket_in_parent_group->is_linked()) {
+ /* Follow the links coming into the corresponding socket on the parent group node. */
+ socket_in_parent_group.foreach_origin_socket(callback);
+ }
+ else {
+ /* The corresponding input on the parent group node is not connected. Therefore, we use
+ * the value of that input socket directly. */
+ callback(socket_in_parent_group);
+ }
}
}
- }
-
- /* Remove remaining links from muted node. */
- for (DInputSocket *to_socket : node.inputs_) {
- for (DOutputSocket *from_socket : to_socket->linked_sockets_) {
- from_socket->linked_sockets_.remove_first_occurrence_and_reorder(to_socket);
- }
- for (DGroupInput *from_group_input : to_socket->linked_group_inputs_) {
- from_group_input->linked_sockets_.remove_first_occurrence_and_reorder(to_socket);
- }
- to_socket->linked_sockets_.clear();
- to_socket->linked_group_inputs_.clear();
- }
- for (DOutputSocket *from_socket : node.outputs_) {
- for (DInputSocket *to_socket : from_socket->linked_sockets_) {
- to_socket->linked_sockets_.remove_first_occurrence_and_reorder(from_socket);
- }
- from_socket->linked_sockets_.clear();
- }
-}
-
-void DNode::destruct_with_sockets()
-{
- for (DInputSocket *socket : inputs_) {
- socket->~DInputSocket();
- }
- for (DOutputSocket *socket : outputs_) {
- socket->~DOutputSocket();
- }
- this->~DNode();
-}
-
-BLI_NOINLINE void DerivedNodeTree::store_in_this_and_init_ids(
- Vector<DNode *> &&all_nodes,
- Vector<DGroupInput *> &&all_group_inputs,
- Vector<DParentNode *> &&all_parent_nodes)
-{
- nodes_by_id_ = std::move(all_nodes);
- group_inputs_ = std::move(all_group_inputs);
- parent_nodes_ = std::move(all_parent_nodes);
-
- for (int node_index : nodes_by_id_.index_range()) {
- DNode *node = nodes_by_id_[node_index];
- node->id_ = node_index;
-
- const bNodeType *nodetype = node->node_ref_->bnode()->typeinfo;
- nodes_by_type_.add(nodetype, node);
-
- for (DInputSocket *socket : node->inputs_) {
- socket->id_ = sockets_by_id_.append_and_get_index(socket);
- input_sockets_.append(socket);
- }
- for (DOutputSocket *socket : node->outputs_) {
- socket->id_ = sockets_by_id_.append_and_get_index(socket);
- output_sockets_.append(socket);
+ else if (linked_node.is_group_node()) {
+ DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket();
+ if (socket_in_group) {
+ if (socket_in_group->is_linked()) {
+ /* Follow the links coming into the group output node of the child node group. */
+ socket_in_group.foreach_origin_socket(callback);
+ }
+ else {
+ /* The output of the child node group is not connected, so we have to get the value from
+ * that socket. */
+ callback(socket_in_group);
+ }
+ }
}
- }
-
- for (int i : group_inputs_.index_range()) {
- group_inputs_[i]->id_ = i;
- }
-}
-
-DerivedNodeTree::~DerivedNodeTree()
-{
- for (DInputSocket *socket : input_sockets_) {
- socket->~DInputSocket();
- }
- for (DOutputSocket *socket : output_sockets_) {
- socket->~DOutputSocket();
- }
- for (DNode *node : nodes_by_id_) {
- node->~DNode();
- }
- for (DGroupInput *group_input : group_inputs_) {
- group_input->~DGroupInput();
- }
- for (DParentNode *parent : parent_nodes_) {
- parent->~DParentNode();
- }
-}
-
-bool DerivedNodeTree::has_link_cycles() const
-{
- for (const NodeTreeRef *tree : used_node_tree_refs_) {
- if (tree->has_link_cycles()) {
- return true;
+ else {
+ /* The normal case: just use the value of a linked output socket. */
+ callback(linked_dsocket);
}
}
- return false;
-}
-
-static dot::Cluster *get_cluster_for_parent(dot::DirectedGraph &graph,
- Map<const DParentNode *, dot::Cluster *> &clusters,
- const DParentNode *parent)
-{
- if (parent == nullptr) {
- return nullptr;
- }
- return clusters.lookup_or_add_cb(parent, [&]() {
- dot::Cluster *parent_cluster = get_cluster_for_parent(graph, clusters, parent->parent());
- bNodeTree *btree = reinterpret_cast<bNodeTree *>(parent->node_ref().bnode()->id);
- dot::Cluster *new_cluster = &graph.new_cluster(parent->node_ref().name() + " / " +
- StringRef(btree->id.name + 2));
- new_cluster->set_parent_cluster(parent_cluster);
- return new_cluster;
- });
}
-std::string DerivedNodeTree::to_dot() const
+/* Calls the given callback for every "real" target socket. "Real" means that reroutes, muted nodes
+ * and node groups are handled by this function. Target sockets are on the nodes that use the value
+ * from this socket. */
+void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const
{
- dot::DirectedGraph digraph;
- digraph.set_rankdir(dot::Attr_rankdir::LeftToRight);
-
- Map<const DNode *, dot::NodeWithSocketsRef> dot_nodes;
- Map<const DGroupInput *, dot::NodeWithSocketsRef> dot_group_inputs;
- Map<const DParentNode *, dot::Cluster *> dot_clusters;
-
- for (const DNode *node : nodes_by_id_) {
- dot::Node &dot_node = digraph.new_node("");
- dot_node.set_background_color("white");
-
- Vector<std::string> input_names;
- for (const DInputSocket *socket : node->inputs()) {
- input_names.append(socket->name());
- }
- Vector<std::string> output_names;
- for (const DOutputSocket *socket : node->outputs()) {
- output_names.append(socket->name());
+ for (const InputSocketRef *linked_socket : socket_ref_->as_output().linked_sockets()) {
+ const NodeRef &linked_node = linked_socket->node();
+ DInputSocket linked_dsocket{context_, linked_socket};
+
+ if (linked_node.is_muted()) {
+ /* If the target node is muted, follow its internal links. */
+ for (const InternalLinkRef *internal_link : linked_node.internal_links()) {
+ if (&internal_link->from() == linked_socket) {
+ DOutputSocket output_of_muted_node{context_, &internal_link->to()};
+ output_of_muted_node.foreach_target_socket(callback);
+ }
+ }
}
-
- dot_nodes.add_new(node,
- dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names));
-
- dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, node->parent());
- dot_node.set_parent_cluster(cluster);
- }
-
- for (const DGroupInput *group_input : group_inputs_) {
- dot::Node &dot_node = digraph.new_node("");
- dot_node.set_background_color("white");
-
- std::string group_input_name = group_input->name();
- dot_group_inputs.add_new(
- group_input, dot::NodeWithSocketsRef(dot_node, "Group Input", {}, {group_input_name}));
-
- dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, group_input->parent());
- dot_node.set_parent_cluster(cluster);
- }
-
- for (const DNode *to_node : nodes_by_id_) {
- dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(to_node);
-
- for (const DInputSocket *to_socket : to_node->inputs()) {
- for (const DOutputSocket *from_socket : to_socket->linked_sockets()) {
- const DNode *from_node = &from_socket->node();
- dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(from_node);
-
- digraph.new_edge(from_dot_node.output(from_socket->index()),
- to_dot_node.input(to_socket->index()));
+ else if (linked_node.is_group_output_node()) {
+ if (context_->is_root()) {
+ /* This is a group output in the root node group. */
+ callback(linked_dsocket);
}
- for (const DGroupInput *group_input : to_socket->linked_group_inputs()) {
- dot::NodeWithSocketsRef &from_dot_node = dot_group_inputs.lookup(group_input);
-
- digraph.new_edge(from_dot_node.output(0), to_dot_node.input(to_socket->index()));
+ else {
+ /* Follow the links going out of the group node in the parent node group. */
+ DOutputSocket socket_in_parent_group =
+ linked_dsocket.get_corresponding_group_node_output();
+ socket_in_parent_group.foreach_target_socket(callback);
}
}
+ else if (linked_node.is_group_node()) {
+ /* Follow the links within the nested node group. */
+ Vector<DOutputSocket> sockets_in_group =
+ linked_dsocket.get_corresponding_group_input_sockets();
+ for (DOutputSocket socket_in_group : sockets_in_group) {
+ socket_in_group.foreach_target_socket(callback);
+ }
+ }
+ else {
+ /* The normal case: just use the linked input socket as target. */
+ callback(linked_dsocket);
+ }
}
-
- digraph.set_random_cluster_bgcolors();
- return digraph.to_dot_string();
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 0d46119ab60..6207a1bf024 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -218,7 +218,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
/* prepare all nodes for execution */
for (n = 0, nodeexec = exec->nodeexec; n < totnodes; n++, nodeexec++) {
node = nodeexec->node = nodelist[n];
- nodeexec->freeexecfunc = node->typeinfo->freeexecfunc;
+ nodeexec->free_exec_fn = node->typeinfo->free_exec_fn;
/* tag inputs */
for (sock = node->inputs.first; sock; sock = sock->next) {
@@ -242,8 +242,8 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
nodeexec->data.preview = context->previews ?
BKE_node_instance_hash_lookup(context->previews, nodekey) :
NULL;
- if (node->typeinfo->initexecfunc) {
- nodeexec->data.data = node->typeinfo->initexecfunc(context, node, nodekey);
+ if (node->typeinfo->init_exec_fn) {
+ nodeexec->data.data = node->typeinfo->init_exec_fn(context, node, nodekey);
}
}
@@ -264,8 +264,8 @@ void ntree_exec_end(bNodeTreeExec *exec)
}
for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
- if (nodeexec->freeexecfunc) {
- nodeexec->freeexecfunc(nodeexec->data.data);
+ if (nodeexec->free_exec_fn) {
+ nodeexec->free_exec_fn(nodeexec->data.data);
}
}
@@ -323,8 +323,8 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call
* If the mute func is not set, assume the node should never be muted,
* and hence execute it!
*/
- if (node->typeinfo->execfunc && !(node->flag & NODE_MUTED)) {
- node->typeinfo->execfunc(callerdata, thread, node, &nodeexec->data, nsin, nsout);
+ if (node->typeinfo->exec_fn && !(node->flag & NODE_MUTED)) {
+ node->typeinfo->exec_fn(callerdata, thread, node, &nodeexec->data, nsin, nsout);
}
}
}
diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h
index 806dd10d9bf..de7cbb8cedb 100644
--- a/source/blender/nodes/intern/node_exec.h
+++ b/source/blender/nodes/intern/node_exec.h
@@ -48,7 +48,7 @@ typedef struct bNodeExec {
bNodeExecData data;
/** Free function, stored in exec itself to avoid dangling node pointer access. */
- NodeFreeExecFunction freeexecfunc;
+ NodeFreeExecFunction free_exec_fn;
} bNodeExec;
/* Execution Data for each instance of node tree execution */
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index 9e62b7d7312..a4fb99a988e 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -20,7 +20,6 @@
#include "DEG_depsgraph_query.h"
-#include "NOD_derived_node_tree.hh"
#include "NOD_geometry_exec.hh"
#include "NOD_type_callbacks.hh"
@@ -30,7 +29,7 @@ namespace blender::nodes {
void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const
{
- bNodeTree *btree_cow = node_.node_ref().tree().btree();
+ bNodeTree *btree_cow = node_->btree();
BLI_assert(btree_cow != nullptr);
if (btree_cow == nullptr) {
return;
@@ -40,12 +39,12 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin
const NodeTreeEvaluationContext context(*self_object_, *modifier_);
BKE_nodetree_error_message_add(
- *btree_original, context, *node_.bnode(), type, std::move(message));
+ *btree_original, context, *node_->bnode(), type, std::move(message));
}
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
{
- for (const DSocket *socket : node_.inputs()) {
+ for (const InputSocketRef *socket : node_->inputs()) {
if (socket->is_available() && socket->name() == name) {
return socket->bsocket();
}
@@ -176,7 +175,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier,
const CPPType *requested_type) const
{
bNodeSocket *found_socket = nullptr;
- for (const DSocket *socket : node_.inputs()) {
+ for (const InputSocketRef *socket : node_->inputs()) {
if (socket->identifier() == identifier) {
found_socket = socket->bsocket();
break;
@@ -186,7 +185,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier,
if (found_socket == nullptr) {
std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n";
std::cout << "Possible identifiers are: ";
- for (const DSocket *socket : node_.inputs()) {
+ for (const InputSocketRef *socket : node_->inputs()) {
if (socket->is_available()) {
std::cout << "'" << socket->identifier() << "', ";
}
@@ -218,7 +217,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier,
void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &value_type) const
{
bNodeSocket *found_socket = nullptr;
- for (const DSocket *socket : node_.outputs()) {
+ for (const OutputSocketRef *socket : node_->outputs()) {
if (socket->identifier() == identifier) {
found_socket = socket->bsocket();
break;
@@ -228,7 +227,7 @@ void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &va
if (found_socket == nullptr) {
std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n";
std::cout << "Possible identifiers are: ";
- for (const DSocket *socket : node_.outputs()) {
+ for (const OutputSocketRef *socket : node_->outputs()) {
if (socket->is_available()) {
std::cout << "'" << socket->identifier() << "', ";
}
diff --git a/source/blender/nodes/intern/node_tree_dependencies.cc b/source/blender/nodes/intern/node_tree_dependencies.cc
deleted file mode 100644
index 9d279dd4d75..00000000000
--- a/source/blender/nodes/intern/node_tree_dependencies.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "NOD_node_tree_dependencies.hh"
-
-#include "DNA_node_types.h"
-
-#include "BKE_node.h"
-
-namespace blender::nodes {
-
-static void add_dependencies_of_node_tree(bNodeTree &ntree, NodeTreeDependencies &r_dependencies)
-{
- /* TODO: Do a bit more sophisticated parsing to see which dependencies are really required. */
- LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (socket->type == SOCK_OBJECT) {
- Object *object = reinterpret_cast<bNodeSocketValueObject *>(socket->default_value)->value;
- if (object != nullptr) {
- r_dependencies.add_transform_dependency(object);
- if (object->type == OB_MESH) {
- r_dependencies.add_geometry_dependency(object);
- }
- }
- }
- }
-
- if (node->type == NODE_GROUP) {
- bNodeTree *group = reinterpret_cast<bNodeTree *>(node->id);
- if (group != nullptr) {
- add_dependencies_of_node_tree(*group, r_dependencies);
- }
- }
- }
-}
-
-NodeTreeDependencies find_node_tree_dependencies(bNodeTree &ntree)
-{
- NodeTreeDependencies dependencies;
- add_dependencies_of_node_tree(ntree, dependencies);
- return dependencies;
-}
-
-} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc
index c2391667e86..bb1367573f8 100644
--- a/source/blender/nodes/intern/node_tree_multi_function.cc
+++ b/source/blender/nodes/intern/node_tree_multi_function.cc
@@ -29,17 +29,17 @@ const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name)
Vector<fn::MFDataType, 10> input_types;
Vector<fn::MFDataType, 10> output_types;
- for (const DInputSocket *dsocket : dnode_.inputs()) {
+ for (const InputSocketRef *dsocket : dnode_->inputs()) {
if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
+ std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo());
if (data_type.has_value()) {
input_types.append(*data_type);
}
}
}
- for (const DOutputSocket *dsocket : dnode_.outputs()) {
+ for (const OutputSocketRef *dsocket : dnode_->outputs()) {
if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
+ std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo());
if (data_type.has_value()) {
output_types.append(*data_type);
}
@@ -57,9 +57,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
Vector<fn::MFDataType, stack_capacity> input_types;
Vector<StringRef, stack_capacity> input_names;
- Vector<const DInputSocket *, stack_capacity> input_dsockets;
+ Vector<const InputSocketRef *, stack_capacity> input_dsockets;
- for (const DInputSocket *dsocket : dnode.inputs()) {
+ for (const InputSocketRef *dsocket : dnode->inputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
@@ -72,9 +72,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
Vector<fn::MFDataType, stack_capacity> output_types;
Vector<StringRef, stack_capacity> output_names;
- Vector<const DOutputSocket *, stack_capacity> output_dsockets;
+ Vector<const OutputSocketRef *, stack_capacity> output_dsockets;
- for (const DOutputSocket *dsocket : dnode.outputs()) {
+ for (const OutputSocketRef *dsocket : dnode->outputs()) {
if (dsocket->is_available()) {
std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
@@ -86,20 +86,20 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
}
fn::MFDummyNode &dummy_node = common.network.add_dummy(
- dnode.name(), input_types, output_types, input_names, output_names);
+ dnode->name(), input_types, output_types, input_names, output_names);
- common.network_map.add(input_dsockets, dummy_node.inputs());
- common.network_map.add(output_dsockets, dummy_node.outputs());
+ common.network_map.add(*dnode.context(), input_dsockets, dummy_node.inputs());
+ common.network_map.add(*dnode.context(), output_dsockets, dummy_node.outputs());
}
static bool has_data_sockets(const DNode &dnode)
{
- for (const DInputSocket *socket : dnode.inputs()) {
+ for (const InputSocketRef *socket : dnode->inputs()) {
if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
return true;
}
}
- for (const DOutputSocket *socket : dnode.outputs()) {
+ for (const OutputSocketRef *socket : dnode->outputs()) {
if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
return true;
}
@@ -107,70 +107,39 @@ static bool has_data_sockets(const DNode &dnode)
return false;
}
+static void foreach_node_to_insert(CommonMFNetworkBuilderData &common,
+ FunctionRef<void(DNode)> callback)
+{
+ common.tree.foreach_node([&](const DNode dnode) {
+ if (dnode->is_group_node()) {
+ return;
+ }
+ /* Don't insert non-root group input/output nodes, because they will be inlined. */
+ if (!dnode.context()->is_root()) {
+ if (dnode->is_group_input_node() || dnode->is_group_output_node()) {
+ return;
+ }
+ }
+ callback(dnode);
+ });
+}
+
/**
* Expands all function nodes in the multi-function network. Nodes that don't have an expand
* function, but do have data sockets, will get corresponding dummy nodes.
*/
static void insert_nodes(CommonMFNetworkBuilderData &common)
{
- for (const DNode *dnode : common.tree.nodes()) {
- const bNodeType *node_type = dnode->node_ref().bnode()->typeinfo;
+ foreach_node_to_insert(common, [&](const DNode dnode) {
+ const bNodeType *node_type = dnode->typeinfo();
if (node_type->expand_in_mf_network != nullptr) {
- NodeMFNetworkBuilder builder{common, *dnode};
+ NodeMFNetworkBuilder builder{common, dnode};
node_type->expand_in_mf_network(builder);
}
- else if (has_data_sockets(*dnode)) {
- insert_dummy_node(common, *dnode);
- }
- }
-}
-
-static void insert_group_inputs(CommonMFNetworkBuilderData &common)
-{
- for (const DGroupInput *group_input : common.tree.group_inputs()) {
- bNodeSocket *bsocket = group_input->bsocket();
- if (socket_is_mf_data_socket(*bsocket->typeinfo)) {
- bNodeSocketType *socktype = bsocket->typeinfo;
- BLI_assert(socktype->expand_in_mf_network != nullptr);
-
- SocketMFNetworkBuilder builder{common, *group_input};
- socktype->expand_in_mf_network(builder);
-
- fn::MFOutputSocket *from_socket = builder.built_socket();
- BLI_assert(from_socket != nullptr);
- common.network_map.add(*group_input, *from_socket);
- }
- }
-}
-
-static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common,
- const DInputSocket &to_dsocket)
-{
- Span<const DOutputSocket *> from_dsockets = to_dsocket.linked_sockets();
- Span<const DGroupInput *> from_group_inputs = to_dsocket.linked_group_inputs();
- int total_linked_amount = from_dsockets.size() + from_group_inputs.size();
- BLI_assert(total_linked_amount <= 1);
-
- if (total_linked_amount == 0) {
- return nullptr;
- }
-
- if (from_dsockets.size() == 1) {
- const DOutputSocket &from_dsocket = *from_dsockets[0];
- if (!from_dsocket.is_available()) {
- return nullptr;
- }
- if (socket_is_mf_data_socket(*from_dsocket.bsocket()->typeinfo)) {
- return &common.network_map.lookup(from_dsocket);
+ else if (has_data_sockets(dnode)) {
+ insert_dummy_node(common, dnode);
}
- return nullptr;
- }
-
- const DGroupInput &from_group_input = *from_group_inputs[0];
- if (socket_is_mf_data_socket(*from_group_input.bsocket()->typeinfo)) {
- return &common.network_map.lookup(from_group_input);
- }
- return nullptr;
+ });
}
template<typename From, typename To>
@@ -286,78 +255,82 @@ static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderD
return node.output(0);
}
-static void insert_links(CommonMFNetworkBuilderData &common)
+static fn::MFOutputSocket *insert_unlinked_input(CommonMFNetworkBuilderData &common,
+ const DInputSocket &dsocket)
{
- for (const DInputSocket *to_dsocket : common.tree.input_sockets()) {
- if (!to_dsocket->is_available()) {
- continue;
- }
- if (!to_dsocket->is_linked()) {
- continue;
- }
- if (!socket_is_mf_data_socket(*to_dsocket->bsocket()->typeinfo)) {
- continue;
- }
-
- Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(*to_dsocket);
- BLI_assert(to_sockets.size() >= 1);
- fn::MFDataType to_type = to_sockets[0]->data_type();
+ BLI_assert(socket_is_mf_data_socket(*dsocket->typeinfo()));
- fn::MFOutputSocket *from_socket = try_find_origin(common, *to_dsocket);
- if (from_socket == nullptr) {
- from_socket = &insert_default_value_for_type(common, to_type);
- }
-
- fn::MFDataType from_type = from_socket->data_type();
-
- if (from_type != to_type) {
- const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion(
- from_type, to_type);
- if (conversion_fn != nullptr) {
- fn::MFNode &node = common.network.add_function(*conversion_fn);
- common.network.add_link(*from_socket, node.input(0));
- from_socket = &node.output(0);
- }
- else {
- from_socket = &insert_default_value_for_type(common, to_type);
- }
- }
+ SocketMFNetworkBuilder builder{common, dsocket};
+ socket_expand_in_mf_network(builder);
- for (fn::MFInputSocket *to_socket : to_sockets) {
- common.network.add_link(*from_socket, *to_socket);
- }
- }
+ fn::MFOutputSocket *built_socket = builder.built_socket();
+ BLI_assert(built_socket != nullptr);
+ return built_socket;
}
-static void insert_unlinked_input(CommonMFNetworkBuilderData &common, const DInputSocket &dsocket)
+static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common)
{
- bNodeSocket *bsocket = dsocket.bsocket();
- bNodeSocketType *socktype = bsocket->typeinfo;
- BLI_assert(socktype->expand_in_mf_network != nullptr);
-
- SocketMFNetworkBuilder builder{common, dsocket};
- socktype->expand_in_mf_network(builder);
-
- fn::MFOutputSocket *from_socket = builder.built_socket();
- BLI_assert(from_socket != nullptr);
+ foreach_node_to_insert(common, [&](const DNode dnode) {
+ for (const InputSocketRef *socket_ref : dnode->inputs()) {
+ const DInputSocket to_dsocket{dnode.context(), socket_ref};
+ if (!to_dsocket->is_available()) {
+ continue;
+ }
+ if (!socket_is_mf_data_socket(*to_dsocket->typeinfo())) {
+ continue;
+ }
- for (fn::MFInputSocket *to_socket : common.network_map.lookup(dsocket)) {
- common.network.add_link(*from_socket, *to_socket);
- }
-}
+ Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(to_dsocket);
+ BLI_assert(to_sockets.size() >= 1);
+ const fn::MFDataType to_type = to_sockets[0]->data_type();
-static void insert_unlinked_inputs(CommonMFNetworkBuilderData &common)
-{
- Vector<const DInputSocket *> unlinked_data_inputs;
- for (const DInputSocket *dsocket : common.tree.input_sockets()) {
- if (dsocket->is_available()) {
- if (socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) {
- if (!dsocket->is_linked()) {
- insert_unlinked_input(common, *dsocket);
+ Vector<DSocket> from_dsockets;
+ to_dsocket.foreach_origin_socket([&](DSocket socket) { from_dsockets.append(socket); });
+ if (from_dsockets.size() > 1) {
+ fn::MFOutputSocket &from_socket = insert_default_value_for_type(common, to_type);
+ for (fn::MFInputSocket *to_socket : to_sockets) {
+ common.network.add_link(from_socket, *to_socket);
+ }
+ continue;
+ }
+ if (from_dsockets.is_empty()) {
+ /* The socket is not linked. Need to use the value of the socket itself. */
+ fn::MFOutputSocket *built_socket = insert_unlinked_input(common, to_dsocket);
+ for (fn::MFInputSocket *to_socket : to_sockets) {
+ common.network.add_link(*built_socket, *to_socket);
}
+ continue;
+ }
+ if (from_dsockets[0]->is_input()) {
+ DInputSocket from_dsocket{from_dsockets[0]};
+ fn::MFOutputSocket *built_socket = insert_unlinked_input(common, from_dsocket);
+ for (fn::MFInputSocket *to_socket : to_sockets) {
+ common.network.add_link(*built_socket, *to_socket);
+ }
+ continue;
+ }
+ DOutputSocket from_dsocket{from_dsockets[0]};
+ fn::MFOutputSocket *from_socket = &common.network_map.lookup(from_dsocket);
+ const fn::MFDataType from_type = from_socket->data_type();
+
+ if (from_type != to_type) {
+ const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion(
+ from_type, to_type);
+ if (conversion_fn != nullptr) {
+ fn::MFNode &node = common.network.add_function(*conversion_fn);
+ common.network.add_link(*from_socket, node.input(0));
+ from_socket = &node.output(0);
+ }
+ else {
+ from_socket = &insert_default_value_for_type(common, to_type);
+ }
+ }
+
+ for (fn::MFInputSocket *to_socket : to_sockets) {
+ common.network.add_link(*from_socket, *to_socket);
}
}
- }
+ });
}
/**
@@ -376,9 +349,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
CommonMFNetworkBuilderData common{resources, network, network_map, tree};
insert_nodes(common);
- insert_group_inputs(common);
- insert_links(common);
- insert_unlinked_inputs(common);
+ insert_links_and_unlinked_inputs(common);
return network_map;
}
@@ -420,16 +391,17 @@ static NodeExpandType get_node_expand_type(MFNetworkTreeMap &network_map,
}
};
- for (const DInputSocket *dsocket : dnode.inputs()) {
+ for (const InputSocketRef *dsocket : dnode->inputs()) {
if (dsocket->is_available()) {
- for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) {
+ for (fn::MFInputSocket *mf_input :
+ network_map.lookup(DInputSocket(dnode.context(), dsocket))) {
check_mf_node(mf_input->node());
}
}
}
- for (const DOutputSocket *dsocket : dnode.outputs()) {
+ for (const OutputSocketRef *dsocket : dnode->outputs()) {
if (dsocket->is_available()) {
- fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket);
+ fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket));
check_mf_node(mf_output.node());
}
}
@@ -451,20 +423,21 @@ static const fn::MultiFunction &create_function_for_node_that_expands_into_multi
ResourceCollector &resources)
{
Vector<const fn::MFOutputSocket *> dummy_fn_inputs;
- for (const DInputSocket *dsocket : dnode.inputs()) {
+ for (const InputSocketRef *dsocket : dnode->inputs()) {
if (dsocket->is_available()) {
MFDataType data_type = *socket_mf_type_get(*dsocket->typeinfo());
fn::MFOutputSocket &fn_input = network.add_input(data_type.to_string(), data_type);
- for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) {
+ for (fn::MFInputSocket *mf_input :
+ network_map.lookup(DInputSocket(dnode.context(), dsocket))) {
network.add_link(fn_input, *mf_input);
dummy_fn_inputs.append(&fn_input);
}
}
}
Vector<const fn::MFInputSocket *> dummy_fn_outputs;
- for (const DOutputSocket *dsocket : dnode.outputs()) {
+ for (const OutputSocketRef *dsocket : dnode->outputs()) {
if (dsocket->is_available()) {
- fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket);
+ fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket));
MFDataType data_type = mf_output.data_type();
fn::MFInputSocket &fn_output = network.add_output(data_type.to_string(), data_type);
network.add_link(mf_output, fn_output);
@@ -492,18 +465,18 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
CommonMFNetworkBuilderData common{resources, network, network_map, tree};
- for (const DNode *dnode : tree.nodes()) {
+ tree.foreach_node([&](DNode dnode) {
const bNodeType *node_type = dnode->typeinfo();
if (node_type->expand_in_mf_network == nullptr) {
/* This node does not have a multi-function implementation. */
- continue;
+ return;
}
- NodeMFNetworkBuilder builder{common, *dnode};
+ NodeMFNetworkBuilder builder{common, dnode};
node_type->expand_in_mf_network(builder);
const fn::MultiFunction *single_function = nullptr;
- const NodeExpandType expand_type = get_node_expand_type(network_map, *dnode, &single_function);
+ const NodeExpandType expand_type = get_node_expand_type(network_map, dnode, &single_function);
switch (expand_type) {
case NodeExpandType::HasDummyNodes: {
@@ -519,12 +492,12 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
/* If a node expanded into multiple functions, a new function has to be created that
* combines those. */
const fn::MultiFunction &fn = create_function_for_node_that_expands_into_multiple(
- *dnode, network, network_map, resources);
+ dnode, network, network_map, resources);
functions_by_node.add_new(dnode, &fn);
break;
}
}
- }
+ });
return functions_by_node;
}
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 7fe21ec8582..0ea2538d6f1 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -25,7 +25,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
Map<bNode *, NodeRef *> node_mapping;
LISTBASE_FOREACH (bNode *, bnode, &btree->nodes) {
- NodeRef &node = *allocator_.construct<NodeRef>();
+ NodeRef &node = *allocator_.construct<NodeRef>().release();
node.tree_ = this;
node.bnode_ = bnode;
@@ -33,7 +33,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
RNA_pointer_create(&btree->id, &RNA_Node, bnode, &node.rna_);
LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->inputs) {
- InputSocketRef &socket = *allocator_.construct<InputSocketRef>();
+ InputSocketRef &socket = *allocator_.construct<InputSocketRef>().release();
socket.node_ = &node;
socket.index_ = node.inputs_.append_and_get_index(&socket);
socket.is_input_ = true;
@@ -43,7 +43,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
}
LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->outputs) {
- OutputSocketRef &socket = *allocator_.construct<OutputSocketRef>();
+ OutputSocketRef &socket = *allocator_.construct<OutputSocketRef>().release();
socket.node_ = &node;
socket.index_ = node.outputs_.append_and_get_index(&socket);
socket.is_input_ = false;
@@ -53,7 +53,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
}
LISTBASE_FOREACH (bNodeLink *, blink, &bnode->internal_links) {
- InternalLinkRef &internal_link = *allocator_.construct<InternalLinkRef>();
+ InternalLinkRef &internal_link = *allocator_.construct<InternalLinkRef>().release();
internal_link.blink_ = blink;
for (InputSocketRef *socket_ref : node.inputs_) {
if (socket_ref->bsocket_ == blink->fromsock) {
@@ -82,7 +82,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
InputSocketRef &to_socket = this->find_input_socket(
node_mapping, blink->tonode, blink->tosock);
- LinkRef &link = *allocator_.construct<LinkRef>();
+ LinkRef &link = *allocator_.construct<LinkRef>().release();
link.from_ = &from_socket;
link.to_ = &to_socket;
link.blink_ = blink;
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 25d6aef69e5..1a2405e021f 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -257,11 +257,11 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
}
if (do_it) {
- if (node->typeinfo->gpufunc) {
+ if (node->typeinfo->gpu_fn) {
node_get_stack(node, stack, nsin, nsout);
gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
- if (node->typeinfo->gpufunc(mat, node, &nodeexec->data, gpuin, gpuout)) {
+ if (node->typeinfo->gpu_fn(mat, node, &nodeexec->data, gpuin, gpuout)) {
data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
index 36971d4e799..abe80ebcefb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
+++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
@@ -47,8 +47,15 @@ static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
float inverted = node->custom2 ? 1.0f : 0.0f;
+ float f_samples = divide_ceil_u(node->custom1, 4);
- return GPU_stack_link(mat, node, "node_ambient_occlusion", in, out, GPU_constant(&inverted));
+ return GPU_stack_link(mat,
+ node,
+ "node_ambient_occlusion",
+ in,
+ out,
+ GPU_constant(&inverted),
+ GPU_constant(&f_samples));
}
static void node_shader_init_ambient_occlusion(bNodeTree *UNUSED(ntree), bNode *node)
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
index f54914ceba9..7a846031456 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -116,7 +116,7 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild
blender::fn::MFNetwork &network = builder.network();
blender::fn::MFFunctionNode &base_node = network.add_function(base_function);
- builder.network_map().add_try_match(dnode.inputs(), base_node.inputs());
+ builder.network_map().add_try_match(*dnode.context(), dnode->inputs(), base_node.inputs());
const bool clamp_output = builder.bnode().custom2 != 0;
if (clamp_output) {
@@ -126,10 +126,12 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild
}};
blender::fn::MFFunctionNode &clamp_node = network.add_function(clamp_fn);
network.add_link(base_node.output(0), clamp_node.input(0));
- builder.network_map().add(dnode.output(0), clamp_node.output(0));
+ builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)),
+ clamp_node.output(0));
}
else {
- builder.network_map().add(dnode.output(0), base_node.output(0));
+ builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)),
+ base_node.output(0));
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 41c978e75ba..26a1db1f3a6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -90,7 +90,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
sampler &= ~GPU_SAMPLER_REPEAT;
}
- const char *gpufunc;
+ const char *gpu_fn;
static const char *names[] = {
"node_tex_image_linear",
"node_tex_image_cubic",
@@ -98,19 +98,19 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
switch (tex->interpolation) {
case SHD_INTERP_LINEAR:
- gpufunc = names[0];
+ gpu_fn = names[0];
break;
case SHD_INTERP_CLOSEST:
sampler &= ~(GPU_SAMPLER_FILTER | GPU_SAMPLER_MIPMAP);
- gpufunc = names[0];
+ gpu_fn = names[0];
break;
default:
- gpufunc = names[1];
+ gpu_fn = names[1];
break;
}
/* Sample texture with correct interpolation. */
- GPU_link(mat, gpufunc, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha);
+ GPU_link(mat, gpu_fn, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha);
if (out[0].hasoutput) {
if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) ||
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc
index 5a8a1b847cc..495c8d12824 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_value.cc
@@ -41,7 +41,7 @@ static int gpu_shader_value(GPUMaterial *mat,
static void sh_node_value_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
{
- const bNodeSocket *bsocket = builder.dnode().output(0).bsocket();
+ const bNodeSocket *bsocket = builder.dnode()->output(0).bsocket();
const bNodeSocketValueFloat *value = (const bNodeSocketValueFloat *)bsocket->default_value;
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c
deleted file mode 100644
index b2132c59cde..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "../node_shader_util.h"
-
-/* **************** Vector Rotate ******************** */
-static bNodeSocketTemplate sh_node_vector_rotate_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_VECTOR, N_("Center"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE},
- {SOCK_VECTOR, N_("Axis"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, PROP_NONE},
- {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_ANGLE, PROP_NONE},
- {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
- {-1, ""}};
-
-static bNodeSocketTemplate sh_node_vector_rotate_out[] = {{SOCK_VECTOR, N_("Vector")}, {-1, ""}};
-
-static int gpu_shader_vector_rotate(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
-
- static const char *names[] = {
- [NODE_VECTOR_ROTATE_TYPE_AXIS] = "node_vector_rotate_axis_angle",
- [NODE_VECTOR_ROTATE_TYPE_AXIS_X] = "node_vector_rotate_axis_x",
- [NODE_VECTOR_ROTATE_TYPE_AXIS_Y] = "node_vector_rotate_axis_y",
- [NODE_VECTOR_ROTATE_TYPE_AXIS_Z] = "node_vector_rotate_axis_z",
- [NODE_VECTOR_ROTATE_TYPE_EULER_XYZ] = "node_vector_rotate_euler_xyz",
- };
-
- if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
- float invert = (node->custom2) ? -1.0 : 1.0;
- return GPU_stack_link(mat, node, names[node->custom1], in, out, GPU_constant(&invert));
- }
-
- return 0;
-}
-
-static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node)
-{
- bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation");
- nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
- bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis");
- nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS));
- bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle");
- nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
-}
-
-void register_node_type_sh_vector_rotate(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_vector_rotate_in, sh_node_vector_rotate_out);
- node_type_gpu(&ntype, gpu_shader_vector_rotate);
- node_type_update(&ntype, node_shader_update_vector_rotate);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
new file mode 100644
index 00000000000..30b043439b8
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -0,0 +1,217 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** Vector Rotate ******************** */
+static bNodeSocketTemplate sh_node_vector_rotate_in[] = {
+ {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_VECTOR, N_("Center"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE},
+ {SOCK_VECTOR, N_("Axis"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, PROP_NONE},
+ {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_ANGLE, PROP_NONE},
+ {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {-1, ""}};
+
+static bNodeSocketTemplate sh_node_vector_rotate_out[] = {
+ {SOCK_VECTOR, N_("Vector")},
+ {-1, ""},
+};
+
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_VECTOR_ROTATE_TYPE_AXIS:
+ return "node_vector_rotate_axis_angle";
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_X:
+ return "node_vector_rotate_axis_x";
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_Y:
+ return "node_vector_rotate_axis_y";
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_Z:
+ return "node_vector_rotate_axis_z";
+ case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ:
+ return "node_vector_rotate_euler_xyz";
+ }
+
+ return nullptr;
+}
+
+static int gpu_shader_vector_rotate(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ const char *name = gpu_shader_get_name(node->custom1);
+
+ if (name != nullptr) {
+ float invert = (node->custom2) ? -1.0 : 1.0;
+ return GPU_stack_link(mat, node, name, in, out, GPU_constant(&invert));
+ }
+
+ return 0;
+}
+
+using blender::float3;
+
+static float3 sh_node_vector_rotate_around_axis(const float3 vector,
+ const float3 center,
+ const float3 axis,
+ const float angle)
+{
+ float3 result = vector - center;
+ float mat[3][3];
+ axis_angle_to_mat3(mat, axis, angle);
+ mul_m3_v3(mat, result);
+ return result + center;
+}
+
+static float3 sh_node_vector_rotate_euler(const float3 vector,
+ const float3 center,
+ const float3 rotation,
+ const bool invert)
+{
+ float mat[3][3];
+ float3 result = vector - center;
+ eul_to_mat3(mat, rotation);
+ if (invert) {
+ invert_m3(mat);
+ }
+ mul_m3_v3(mat, result);
+ return result + center;
+}
+
+static const blender::fn::MultiFunction &get_multi_function(
+ blender::nodes::NodeMFNetworkBuilder &builder)
+{
+ bool invert = builder.bnode().custom2;
+ const int mode = builder.bnode().custom1;
+
+ switch (mode) {
+ case NODE_VECTOR_ROTATE_TYPE_AXIS: {
+ if (invert) {
+ static blender::fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{
+ "Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
+ }};
+ return fn;
+ }
+ static blender::fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{
+ "Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, angle);
+ }};
+ return fn;
+ }
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_X: {
+ float3 axis = float3(1.0f, 0.0f, 0.0f);
+ if (invert) {
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate X-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
+ }};
+ return fn;
+ }
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate X-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, angle);
+ }};
+ return fn;
+ }
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: {
+ float3 axis = float3(0.0f, 1.0f, 0.0f);
+ if (invert) {
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate Y-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
+ }};
+ return fn;
+ }
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate Y-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, angle);
+ }};
+ return fn;
+ }
+ case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: {
+ float3 axis = float3(0.0f, 0.0f, 1.0f);
+ if (invert) {
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate Z-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
+ }};
+ return fn;
+ }
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ "Rotate Z-Axis", [=](float3 in, float3 center, float angle) {
+ return sh_node_vector_rotate_around_axis(in, center, axis, angle);
+ }};
+ return fn;
+ }
+ case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: {
+ if (invert) {
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
+ "Rotate Euler", [](float3 in, float3 center, float3 rotation) {
+ return sh_node_vector_rotate_euler(in, center, rotation, true);
+ }};
+ return fn;
+ }
+ static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
+ "Rotate Euler", [](float3 in, float3 center, float3 rotation) {
+ return sh_node_vector_rotate_euler(in, center, rotation, false);
+ }};
+ return fn;
+ }
+ default:
+ BLI_assert(false);
+ return builder.get_not_implemented_fn();
+ }
+}
+
+static void sh_node_vector_rotate_expand_in_mf_network(
+ blender::nodes::NodeMFNetworkBuilder &builder)
+{
+ const blender::fn::MultiFunction &fn = get_multi_function(builder);
+ builder.set_matching_fn(fn);
+}
+
+static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation");
+ nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
+ bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis");
+ nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS));
+ bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle");
+ nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
+}
+
+void register_node_type_sh_vector_rotate(void)
+{
+ static bNodeType ntype;
+
+ sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0);
+ node_type_socket_templates(&ntype, sh_node_vector_rotate_in, sh_node_vector_rotate_out);
+ node_type_gpu(&ntype, gpu_shader_vector_rotate);
+ node_type_update(&ntype, node_shader_update_vector_rotate);
+ ntype.expand_in_mf_network = sh_node_vector_rotate_expand_in_mf_network;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index dff4b169f9a..4a2b359bf39 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -96,20 +96,20 @@ static int pygpu_offscreen_valid_check(BPyGPUOffScreen *py_ofs)
typedef struct {
PyObject_HEAD /* required python macro */
- BPyGPUOffScreen *py_offs;
+ BPyGPUOffScreen *py_offscreen;
int level;
bool is_explicitly_bound; /* Bound by "bind" method. */
} OffScreenStackContext;
static void pygpu_offscreen_stack_context__tp_dealloc(OffScreenStackContext *self)
{
- Py_DECREF(self->py_offs);
+ Py_DECREF(self->py_offscreen);
PyObject_DEL(self);
}
static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self)
{
- BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs);
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen);
if (!self->is_explicitly_bound) {
if (self->level != -1) {
@@ -117,7 +117,7 @@ static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self
return NULL;
}
- GPU_offscreen_bind(self->py_offs->ofs, true);
+ GPU_offscreen_bind(self->py_offscreen->ofs, true);
self->level = GPU_framebuffer_stack_level_get();
}
@@ -127,7 +127,7 @@ static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self
static PyObject *pygpu_offscreen_stack_context_exit(OffScreenStackContext *self,
PyObject *UNUSED(args))
{
- BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs);
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen);
if (self->level == -1) {
PyErr_SetString(PyExc_RuntimeError, "Not yet in use\n");
@@ -140,7 +140,7 @@ static PyObject *pygpu_offscreen_stack_context_exit(OffScreenStackContext *self,
PyExc_RuntimeError, "Level of bind mismatch, expected %d, got %d\n", self->level, level);
}
- GPU_offscreen_unbind(self->py_offs->ofs, true);
+ GPU_offscreen_unbind(self->py_offscreen->ofs, true);
Py_RETURN_NONE;
}
@@ -166,7 +166,7 @@ static PyObject *pygpu_offscreen_bind(BPyGPUOffScreen *self)
{
OffScreenStackContext *ret = PyObject_New(OffScreenStackContext,
&PyGPUOffscreenStackContext_Type);
- ret->py_offs = self;
+ ret->py_offscreen = self;
ret->level = -1;
ret->is_explicitly_bound = false;
Py_INCREF(self);
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 352787b4fdb..822ab0bd969 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -75,6 +75,7 @@ set(SRC
bpy_rna_anim.c
bpy_rna_array.c
bpy_rna_callback.c
+ bpy_rna_data.c
bpy_rna_driver.c
bpy_rna_gizmo.c
bpy_rna_id_collection.c
@@ -113,6 +114,7 @@ set(SRC
bpy_rna.h
bpy_rna_anim.h
bpy_rna_callback.h
+ bpy_rna_data.h
bpy_rna_driver.h
bpy_rna_gizmo.h
bpy_rna_id_collection.h
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 74fc8bcfec9..547cf2ad38f 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -44,6 +44,7 @@
#include "bpy_operator.h"
#include "bpy_props.h"
#include "bpy_rna.h"
+#include "bpy_rna_data.h"
#include "bpy_rna_gizmo.h"
#include "bpy_rna_id_collection.h"
#include "bpy_rna_types_capi.h"
@@ -425,6 +426,8 @@ void BPy_init_modules(struct bContext *C)
/* needs to be first so bpy_types can run */
BPY_library_load_type_ready();
+ BPY_rna_data_context_type_ready();
+
BPY_rna_gizmo_module(mod);
bpy_import_test("bpy_types");
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 03771a8c294..1ee14df24cf 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -34,6 +34,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_context.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -67,8 +68,10 @@ typedef struct {
BlendHandle *blo_handle;
int flag;
PyObject *dict;
- /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries. */
+ /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries.
+ * Defaults to #G.main, Otherwise use a temporary #Main when `bmain_is_temp` is true. */
Main *bmain;
+ bool bmain_is_temp;
} BPy_Library;
static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kwds);
@@ -185,6 +188,7 @@ PyDoc_STRVAR(
" :type assets_only: bool\n");
static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kw)
{
+ Main *bmain_base = CTX_data_main(BPY_context_get());
Main *bmain = self->ptr.data; /* Typically #G_MAIN */
BPy_Library *ret;
const char *filename = NULL;
@@ -212,6 +216,7 @@ static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *k
BLI_path_abs(ret->abspath, BKE_main_blendfile_path(bmain));
ret->bmain = bmain;
+ ret->bmain_is_temp = (bmain != bmain_base);
ret->blo_handle = NULL;
ret->flag = ((is_link ? FILE_LINK : 0) | (is_rel ? FILE_RELPATH : 0) |
@@ -344,8 +349,9 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
/* here appending/linking starts */
+ const int id_tag_extra = self->bmain_is_temp ? LIB_TAG_TEMP_MAIN : 0;
struct LibraryLink_Params liblink_params;
- BLO_library_link_params_init(&liblink_params, bmain, self->flag);
+ BLO_library_link_params_init(&liblink_params, bmain, self->flag, id_tag_extra);
mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params);
@@ -372,6 +378,12 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
ID *id = BLO_library_link_named_part(
mainl, &(self->blo_handle), idcode, item_idname, &liblink_params);
if (id) {
+
+ if (self->bmain_is_temp) {
+ /* If this fails, #LibraryLink_Params.id_tag_extra is not being applied. */
+ BLI_assert(id->tag & LIB_TAG_TEMP_MAIN);
+ }
+
#ifdef USE_RNA_DATABLOCKS
/* swap name for pointer to the id */
item_dst = PyCapsule_New((void *)id, NULL, NULL);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index cdf121a6864..7a43c9cb997 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -2061,6 +2061,19 @@ static int pyrna_py_to_prop(
Py_XDECREF(value_new);
return -1;
}
+
+ if (value_owner_id->tag & LIB_TAG_TEMP_MAIN) {
+ /* Allow passing temporary ID's to functions, but not attribute assignment. */
+ if (ptr->type != &RNA_Function) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s %.200s.%.200s ID type assignment is temporary, can't assign",
+ error_prefix,
+ RNA_struct_identifier(ptr->type),
+ RNA_property_identifier(prop));
+ Py_XDECREF(value_new);
+ return -1;
+ }
+ }
}
}
@@ -4598,13 +4611,12 @@ static PyObject *pyrna_prop_collection_getattro(BPy_PropertyRNA *self, PyObject
#else
{
/* Could just do this except for 1 awkward case.
- * PyObject_GenericGetAttr((PyObject *)self, pyname);
- * so as to support 'bpy.data.library.load()'
- * note, this _only_ supports static methods */
+ * `PyObject_GenericGetAttr((PyObject *)self, pyname);`
+ * so as to support `bpy.data.library.load()` */
PyObject *ret = PyObject_GenericGetAttr((PyObject *)self, pyname);
- if (ret == NULL && name[0] != '_') { /* Avoid inheriting __call__ and similar. */
+ if (ret == NULL && name[0] != '_') { /* Avoid inheriting `__call__` and similar. */
/* Since this is least common case, handle it last. */
PointerRNA r_ptr;
if (RNA_property_collection_type_get(&self->ptr, self->prop, &r_ptr)) {
diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c
new file mode 100644
index 00000000000..3771cc05490
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_data.c
@@ -0,0 +1,219 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup pythonintern
+ *
+ * This file defines the API to support temporarily creating #Main data.
+ * The only use case for this is currently to support temporarily loading data-blocks
+ * which can be freed, without them polluting the current #G_MAIN.
+ *
+ * This is exposed via a context manager `bpy.types.BlendData.temp_data(...)`
+ * which returns a new `bpy.types.BlendData` that is freed once the context manager exits.
+ */
+
+#include <Python.h>
+#include <stddef.h>
+
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "RNA_access.h"
+
+#include "bpy_rna.h"
+#include "bpy_rna_data.h"
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ BPy_StructRNA *data_rna;
+ char filepath[1024];
+} BPy_DataContext;
+
+static PyObject *bpy_rna_data_temp_data(PyObject *self, PyObject *args, PyObject *kwds);
+static PyObject *bpy_rna_data_context_enter(BPy_DataContext *self);
+static PyObject *bpy_rna_data_context_exit(BPy_DataContext *self, PyObject *args);
+
+static PyMethodDef bpy_rna_data_context_methods[] = {
+ {"__enter__", (PyCFunction)bpy_rna_data_context_enter, METH_NOARGS},
+ {"__exit__", (PyCFunction)bpy_rna_data_context_exit, METH_VARARGS},
+ {NULL} /* sentinel */
+};
+
+static int bpy_rna_data_context_traverse(BPy_DataContext *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->data_rna);
+ return 0;
+}
+
+static int bpy_rna_data_context_clear(BPy_DataContext *self)
+{
+ Py_CLEAR(self->data_rna);
+ return 0;
+}
+
+static void bpy_rna_data_context_dealloc(BPy_DataContext *self)
+{
+ PyObject_GC_UnTrack(self);
+ Py_CLEAR(self->data_rna);
+ PyObject_GC_Del(self);
+}
+
+static PyTypeObject bpy_rna_data_context_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0) "bpy_rna_data_context", /* tp_name */
+ sizeof(BPy_DataContext), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)bpy_rna_data_context_dealloc, /* tp_dealloc */
+ 0, /* tp_vectorcall_offset */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL,
+ /* tp_compare */ /* DEPRECATED in python 3.0! */
+ NULL, /* tp_repr */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+
+ /* will only use these if this is a subtype of a py class */
+ NULL /*PyObject_GenericGetAttr is assigned later */, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ (traverseproc)bpy_rna_data_context_traverse, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ (inquiry)bpy_rna_data_context_clear, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons (subclassed) ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0,
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ bpy_rna_data_context_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL,
+};
+
+PyDoc_STRVAR(bpy_rna_data_context_load_doc,
+ ".. method:: temp_data(filepath=None)\n"
+ "\n"
+ " A context manager that temporarily creates blender file data.\n"
+ "\n"
+ " :arg filepath: The file path for the newly temporary data. "
+ "When None, the path of the currently open file is used.\n"
+ " :type filepath: str or NoneType\n"
+ "\n"
+ " :return: Blend file data which is freed once the context exists.\n"
+ " :rtype: :class:`bpy.types.BlendData`\n");
+
+static PyObject *bpy_rna_data_temp_data(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ BPy_DataContext *ret;
+ const char *filepath = NULL;
+ static const char *_keywords[] = {"filepath", NULL};
+ static _PyArg_Parser _parser = {"|$z:temp_data", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filepath)) {
+ return NULL;
+ }
+
+ ret = PyObject_GC_New(BPy_DataContext, &bpy_rna_data_context_Type);
+
+ STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->name);
+
+ return (PyObject *)ret;
+}
+
+static PyObject *bpy_rna_data_context_enter(BPy_DataContext *self)
+{
+ Main *bmain_temp = BKE_main_new();
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_BlendData, bmain_temp, &ptr);
+
+ self->data_rna = (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr);
+
+ PyObject_GC_Track(self);
+
+ return (PyObject *)self->data_rna;
+}
+
+static PyObject *bpy_rna_data_context_exit(BPy_DataContext *self, PyObject *UNUSED(args))
+{
+ BKE_main_free(self->data_rna->ptr.data);
+ RNA_POINTER_INVALIDATE(&self->data_rna->ptr);
+ Py_RETURN_NONE;
+}
+
+PyMethodDef BPY_rna_data_context_method_def = {
+ "temp_data",
+ (PyCFunction)bpy_rna_data_temp_data,
+ METH_STATIC | METH_VARARGS | METH_KEYWORDS,
+ bpy_rna_data_context_load_doc,
+};
+
+int BPY_rna_data_context_type_ready(void)
+{
+ if (PyType_Ready(&bpy_rna_data_context_Type) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/source/blender/python/intern/bpy_rna_data.h b/source/blender/python/intern/bpy_rna_data.h
new file mode 100644
index 00000000000..b1d226d9dc4
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_data.h
@@ -0,0 +1,29 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup pythonintern
+ */
+
+#pragma once
+
+int BPY_rna_data_context_type_ready(void);
+
+extern PyMethodDef BPY_rna_data_context_method_def;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c
index 042f7b6fd67..9b15e84663d 100644
--- a/source/blender/python/intern/bpy_rna_types_capi.c
+++ b/source/blender/python/intern/bpy_rna_types_capi.c
@@ -36,6 +36,7 @@
#include "bpy_library.h"
#include "bpy_rna.h"
#include "bpy_rna_callback.h"
+#include "bpy_rna_data.h"
#include "bpy_rna_id_collection.h"
#include "bpy_rna_types_capi.h"
#include "bpy_rna_ui.h"
@@ -56,6 +57,7 @@ static struct PyMethodDef pyrna_blenddata_methods[] = {
{NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_user_map_method_def */
{NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_batch_remove_method_def */
{NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_orphans_purge_method_def */
+ {NULL, NULL, 0, NULL}, /* #BPY_rna_data_context_method_def */
{NULL, NULL, 0, NULL},
};
@@ -207,8 +209,9 @@ void BPY_rna_types_extend_capi(void)
ARRAY_SET_ITEMS(pyrna_blenddata_methods,
BPY_rna_id_collection_user_map_method_def,
BPY_rna_id_collection_batch_remove_method_def,
- BPY_rna_id_collection_orphans_purge_method_def);
- BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 4);
+ BPY_rna_id_collection_orphans_purge_method_def,
+ BPY_rna_data_context_method_def);
+ BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 5);
pyrna_struct_type_extend_capi(&RNA_BlendData, pyrna_blenddata_methods, NULL);
/* BlendDataLibraries */
diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c
index 1859886f563..cba4628b63a 100644
--- a/source/blender/render/intern/multires_bake.c
+++ b/source/blender/render/intern/multires_bake.c
@@ -658,10 +658,10 @@ static void get_ccgdm_data(DerivedMesh *lodm,
/* get the original cage face index */
int cage_face_index = index_mp_to_orig ? index_mp_to_orig[poly_index] : poly_index;
/* local offset in total cage face grids
- * (1 << (2 * lvl)) is number of all polys for one cage face */
- int loc_cage_poly_offs = poly_index % (1 << (2 * lvl));
+ * `(1 << (2 * lvl))` is number of all polys for one cage face */
+ int loc_cage_poly_ofs = poly_index % (1 << (2 * lvl));
/* local offset in the vertex grid itself */
- int cell_index = loc_cage_poly_offs % (polys_per_grid_side * polys_per_grid_side);
+ int cell_index = loc_cage_poly_ofs % (polys_per_grid_side * polys_per_grid_side);
int cell_side = (grid_size - 1) / polys_per_grid_side;
/* row and column based on grid side */
int row = cell_index / polys_per_grid_side;
@@ -1193,7 +1193,7 @@ static void apply_ao_callback(DerivedMesh *lores_dm,
MLoopUV *mloopuv = lores_dm->getLoopDataArray(lores_dm, CD_MLOOPUV);
MAOBakeData *ao_data = (MAOBakeData *)bake_data;
- int i, k, perm_offs;
+ int i, k, perm_ofs;
float pos[3], nrm[3];
float cen[3];
float axisX[3], axisY[3], axisZ[3];
@@ -1236,7 +1236,7 @@ static void apply_ao_callback(DerivedMesh *lores_dm,
build_coordinate_frame(axisX, axisY, axisZ);
/* static noise */
- perm_offs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1);
+ perm_ofs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1);
/* importance sample shadow rays (cosine weighted) */
for (i = 0; i < ao_data->number_of_rays; i++) {
@@ -1246,12 +1246,12 @@ static void apply_ao_callback(DerivedMesh *lores_dm,
* a multi-dimensional domain (2D)
*/
const unsigned short I =
- ao_data->permutation_table_1[(i + perm_offs) % ao_data->number_of_rays];
+ ao_data->permutation_table_1[(i + perm_ofs) % ao_data->number_of_rays];
const unsigned short J = ao_data->permutation_table_2[i];
- const float JitPh = (get_ao_random2(I + perm_offs) & (MAX_NUMBER_OF_AO_RAYS - 1)) /
+ const float JitPh = (get_ao_random2(I + perm_ofs) & (MAX_NUMBER_OF_AO_RAYS - 1)) /
((float)MAX_NUMBER_OF_AO_RAYS);
- const float JitTh = (get_ao_random1(J + perm_offs) & (MAX_NUMBER_OF_AO_RAYS - 1)) /
+ const float JitTh = (get_ao_random1(J + perm_ofs) & (MAX_NUMBER_OF_AO_RAYS - 1)) /
((float)MAX_NUMBER_OF_AO_RAYS);
const float SiSqPhi = (I + JitPh) / ao_data->number_of_rays;
const float Theta = (float)(2 * M_PI) * ((J + JitTh) / ao_data->number_of_rays);
diff --git a/source/blender/render/intern/texture_procedural.c b/source/blender/render/intern/texture_procedural.c
index b0ab20de10d..bea9dfbb0ed 100644
--- a/source/blender/render/intern/texture_procedural.c
+++ b/source/blender/render/intern/texture_procedural.c
@@ -555,10 +555,10 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult
tex->noisebasis);
if (texres->nor != NULL) {
- float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */
+ float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
/* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + offs,
+ texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs,
texvec[1],
texvec[2],
tex->mg_H,
@@ -566,7 +566,7 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult
tex->mg_octaves,
tex->noisebasis);
texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1] + offs,
+ texvec[1] + ofs,
texvec[2],
tex->mg_H,
tex->mg_lacunarity,
@@ -574,7 +574,7 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult
tex->noisebasis);
texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0],
texvec[1],
- texvec[2] + offs,
+ texvec[2] + ofs,
tex->mg_H,
tex->mg_lacunarity,
tex->mg_octaves,
@@ -612,10 +612,10 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu
tex->noisebasis);
if (texres->nor != NULL) {
- float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */
+ float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
/* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + offs,
+ texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs,
texvec[1],
texvec[2],
tex->mg_H,
@@ -625,7 +625,7 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu
tex->mg_gain,
tex->noisebasis);
texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1] + offs,
+ texvec[1] + ofs,
texvec[2],
tex->mg_H,
tex->mg_lacunarity,
@@ -635,7 +635,7 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu
tex->noisebasis);
texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0],
texvec[1],
- texvec[2] + offs,
+ texvec[2] + ofs,
tex->mg_H,
tex->mg_lacunarity,
tex->mg_octaves,
@@ -666,10 +666,10 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr
tex->noisebasis);
if (texres->nor != NULL) {
- float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */
+ float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
/* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0] + offs,
+ texres->nor[0] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0] + ofs,
texvec[1],
texvec[2],
tex->mg_H,
@@ -678,7 +678,7 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr
tex->mg_offset,
tex->noisebasis);
texres->nor[1] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0],
- texvec[1] + offs,
+ texvec[1] + ofs,
texvec[2],
tex->mg_H,
tex->mg_lacunarity,
@@ -687,7 +687,7 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr
tex->noisebasis);
texres->nor[2] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0],
texvec[1],
- texvec[2] + offs,
+ texvec[2] + ofs,
tex->mg_H,
tex->mg_lacunarity,
tex->mg_octaves,
@@ -711,24 +711,24 @@ static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *tex
texvec[0], texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2);
if (texres->nor != NULL) {
- float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */
+ float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
/* calculate bumpnormal */
- texres->nor[0] = BLI_noise_mg_variable_lacunarity(texvec[0] + offs,
+ texres->nor[0] = BLI_noise_mg_variable_lacunarity(texvec[0] + ofs,
texvec[1],
texvec[2],
tex->dist_amount,
tex->noisebasis,
tex->noisebasis2);
texres->nor[1] = BLI_noise_mg_variable_lacunarity(texvec[0],
- texvec[1] + offs,
+ texvec[1] + ofs,
texvec[2],
tex->dist_amount,
tex->noisebasis,
tex->noisebasis2);
texres->nor[2] = BLI_noise_mg_variable_lacunarity(texvec[0],
texvec[1],
- texvec[2] + offs,
+ texvec[2] + ofs,
tex->dist_amount,
tex->noisebasis,
tex->noisebasis2);
@@ -805,14 +805,14 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres)
}
if (texres->nor != NULL) {
- float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */
+ float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
/* calculate bumpnormal */
- BLI_noise_voronoi(texvec[0] + offs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
+ BLI_noise_voronoi(texvec[0] + ofs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
texres->nor[0] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
- BLI_noise_voronoi(texvec[0], texvec[1] + offs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
+ BLI_noise_voronoi(texvec[0], texvec[1] + ofs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
texres->nor[1] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
- BLI_noise_voronoi(texvec[0], texvec[1], texvec[2] + offs, da, pa, tex->vn_mexp, tex->vn_distm);
+ BLI_noise_voronoi(texvec[0], texvec[1], texvec[2] + ofs, da, pa, tex->vn_mexp, tex->vn_distm);
texres->nor[2] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
tex_normal_derivate(tex, texres);
diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c
index 9a86e1e96f5..8a259c6aaff 100644
--- a/source/blender/shader_fx/intern/FX_ui_common.c
+++ b/source/blender/shader_fx/intern/FX_ui_common.c
@@ -241,14 +241,9 @@ static bool shaderfx_ui_poll(const bContext *C, PanelType *UNUSED(pt))
*/
PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw)
{
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- /* Get the name for the effect's panel. */
- char panel_idname[BKE_ST_MAXNAME];
- BKE_shaderfxType_panel_id(type, panel_idname);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
-
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BKE_shaderfxType_panel_id(type, panel_type->idname);
BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "shaderfx", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
@@ -282,13 +277,9 @@ PanelType *shaderfx_subpanel_register(ARegionType *region_type,
PanelDrawFn draw,
PanelType *parent)
{
- /* Create the subpanel's ID name. */
- char panel_idname[BKE_ST_MAXNAME];
- BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
-
- PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
- BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME);
+ BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME);
BLI_strncpy(panel_type->context, "shaderfx", BKE_ST_MAXNAME);
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index f12832faa45..b46a354c7ae 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -427,6 +427,7 @@ typedef struct wmNotifier {
#define ND_SPACE_CHANGED (19 << 16) /*sent to a new editor type after it's replaced an old one*/
#define ND_SPACE_CLIP (20 << 16)
#define ND_SPACE_FILE_PREVIEW (21 << 16)
+#define ND_SPACE_SPREADSHEET (22 << 16)
/* subtype, 256 entries too */
#define NOTE_SUBTYPE 0x0000FF00
@@ -461,6 +462,7 @@ typedef struct wmNotifier {
#define NA_SELECTED 6
#define NA_ACTIVATED 7
#define NA_PAINTING 8
+#define NA_JOB_FINISHED 9
/* ************** Gesture Manager data ************** */
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index e32552063af..d6e4a93f6a6 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -303,7 +303,7 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y)
{
/* note: don't use wmEvent coords because of continuous grab T36409. */
int cx, cy;
- wm_get_cursor_position(win, &cx, &cy);
+ wm_cursor_position_get(win, &cx, &cy);
WM_cursor_warp(win, cx + x, cy + y);
}
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 85611a0be93..e0c4ab8eaf3 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -98,7 +98,7 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
return;
}
- LISTBASE_FOREACH (wmPaintCursor *, pc, &wm->paintcursors) {
+ LISTBASE_FOREACH_MUTABLE (wmPaintCursor *, pc, &wm->paintcursors) {
if ((pc->space_type != SPACE_TYPE_ANY) && (area->spacetype != pc->space_type)) {
continue;
}
@@ -117,7 +117,7 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
int x = 0, y = 0;
- wm_get_cursor_position(win, &x, &y);
+ wm_cursor_position_get(win, &x, &y);
pc->draw(C, x, y, pc->customdata);
}
else {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 18ec8402482..470952956c8 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -2343,7 +2343,7 @@ static int wm_handler_fileselect_do(bContext *C,
wm_window_make_drawable(wm, ctx_win);
/* Ensure correct cursor position, otherwise, popups may close immediately after
* opening (UI_BLOCK_MOVEMOUSE_QUIT). */
- wm_get_cursor_position(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y);
+ wm_cursor_position_get(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y);
wm->winactive = ctx_win; /* Reports use this... */
if (handler->context.win == win) {
handler->context.win = NULL;
@@ -3002,7 +3002,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
* wasn't handled, the KM_RELEASE will become a KM_CLICK */
if (event->val == KM_PRESS) {
- if (event->prevval != KM_PRESS) {
+ if (event->is_repeat == false) {
win->event_queue_check_click = true;
win->event_queue_check_drag = true;
}
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 6a1fc84774c..bf7cf81f0a9 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -229,6 +229,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data,
Library *lib;
const int flag = lapp_data->flag;
+ const int id_tag_extra = 0;
LinkNode *liblink, *itemlink;
int lib_idx, item_idx;
@@ -255,7 +256,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data,
/* here appending/linking starts */
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init_with_context(
- &liblink_params, bmain, flag, scene, view_layer, v3d);
+ &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d);
mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
lib = mainl->curlib;
diff --git a/source/blender/windowmanager/intern/wm_platform_support.c b/source/blender/windowmanager/intern/wm_platform_support.c
index 65e1cd45e02..45618e9d6d3 100644
--- a/source/blender/windowmanager/intern/wm_platform_support.c
+++ b/source/blender/windowmanager/intern/wm_platform_support.c
@@ -43,7 +43,9 @@
#define WM_PLATFORM_SUPPORT_TEXT_SIZE 1024
-/* Check if user has already approved the given platform_support_key. */
+/**
+ * Check if user has already approved the given `platform_support_key`.
+ */
static bool wm_platform_support_check_approval(const char *platform_support_key, bool update)
{
const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
@@ -120,11 +122,11 @@ bool WM_platform_support_perform_checks()
eGPUSupportLevel support_level = GPU_platform_support_level();
const char *platform_key = GPU_platform_support_level_key();
- /* check if previous check matches the current check. Don't update the approval when running in
- * `background`. this could have been triggered by installing addons via installers. */
+ /* Check if previous check matches the current check. Don't update the approval when running in
+ * `background`. this could have been triggered by installing add-ons via installers. */
if (support_level != GPU_SUPPORT_LEVEL_UNSUPPORTED && !G.factory_startup &&
wm_platform_support_check_approval(platform_key, !G.background)) {
- /* if it matches the user has confirmed and whishes to use it */
+ /* If it matches the user has confirmed and wishes to use it. */
return result;
}
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index f09a9aecb1d..2fc941c3d6b 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -520,7 +520,7 @@ void WM_window_set_dpi(const wmWindow *win)
static void wm_window_update_eventstate(wmWindow *win)
{
/* Update mouse position when a window is activated. */
- wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y);
+ wm_cursor_position_get(win, &win->eventstate->x, &win->eventstate->y);
}
static void wm_window_ensure_eventstate(wmWindow *win)
@@ -983,15 +983,15 @@ void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y)
GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y);
}
-void wm_get_cursor_position(wmWindow *win, int *x, int *y)
+void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
{
if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
- *x = win->eventstate->x;
- *y = win->eventstate->y;
+ *r_x = win->eventstate->x;
+ *r_y = win->eventstate->y;
return;
}
- GHOST_GetCursorPosition(g_system, x, y);
- wm_cursor_position_from_ghost(win, x, y);
+ GHOST_GetCursorPosition(g_system, r_x, r_y);
+ wm_cursor_position_from_ghost(win, r_x, r_y);
}
typedef enum {
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index 0ac67b987d7..f205f923ec8 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -69,8 +69,8 @@ void wm_window_swap_buffers(wmWindow *win);
void wm_window_set_swap_interval(wmWindow *win, int interval);
bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
-void wm_get_cursor_position(wmWindow *win, int *x, int *y);
-void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y);
+void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y);
+void wm_cursor_position_from_ghost(wmWindow *win, int *r_x, int *r_y);
void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y);
#ifdef WITH_INPUT_IME