diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index a6609eb80fc..1add04f135c 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -1,762 +1,763 @@ # SPDX-License-Identifier: GPL-2.0-or-later import bpy import nodeitems_utils from nodeitems_utils import ( NodeCategory, NodeItem, NodeItemCustom, ) # Subclasses for standard node types class SortedNodeCategory(NodeCategory): def __init__(self, identifier, name, description="", items=None): # for builtin nodes the convention is to sort by name if isinstance(items, list): items = sorted(items, key=lambda item: item.label.lower()) super().__init__(identifier, name, description=description, items=items) class CompositorNodeCategory(SortedNodeCategory): @classmethod def poll(cls, context): return (context.space_data.type == 'NODE_EDITOR' and context.space_data.tree_type == 'CompositorNodeTree') class ShaderNodeCategory(SortedNodeCategory): @classmethod def poll(cls, context): return (context.space_data.type == 'NODE_EDITOR' and context.space_data.tree_type == 'ShaderNodeTree') class TextureNodeCategory(SortedNodeCategory): @classmethod def poll(cls, context): return (context.space_data.type == 'NODE_EDITOR' and context.space_data.tree_type == 'TextureNodeTree') class GeometryNodeCategory(SortedNodeCategory): @classmethod def poll(cls, context): return (context.space_data.type == 'NODE_EDITOR' and context.space_data.tree_type == 'GeometryNodeTree') # menu entry for node group tools def group_tools_draw(_self, layout, _context): layout.operator("node.group_make") layout.operator("node.group_ungroup") layout.separator() # maps node tree type to group node type node_tree_group_type = { 'CompositorNodeTree': 'CompositorNodeGroup', 'ShaderNodeTree': 'ShaderNodeGroup', 'TextureNodeTree': 'TextureNodeGroup', 'GeometryNodeTree': 'GeometryNodeGroup', } # Custom Menu for Geometry Node Curves. def curve_node_items(context): if context is None: return space = context.space_data if not space: return yield NodeItem("GeometryNodeCurveLength") yield NodeItem("GeometryNodeCurveToMesh") yield NodeItem("GeometryNodeCurveToPoints") yield NodeItem("GeometryNodeDeformCurvesOnSurface") yield NodeItem("GeometryNodeFillCurve") yield NodeItem("GeometryNodeFilletCurve") yield NodeItem("GeometryNodeResampleCurve") yield NodeItem("GeometryNodeReverseCurve") yield NodeItem("GeometryNodeSampleCurve") yield NodeItem("GeometryNodeSubdivideCurve") yield NodeItem("GeometryNodeTrimCurve") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeInputCurveHandlePositions") yield NodeItem("GeometryNodeInputTangent") yield NodeItem("GeometryNodeInputCurveTilt") yield NodeItem("GeometryNodeCurveEndpointSelection") yield NodeItem("GeometryNodeCurveHandleTypeSelection") yield NodeItem("GeometryNodeInputSplineCyclic") yield NodeItem("GeometryNodeSplineLength") yield NodeItem("GeometryNodeSplineParameter") yield NodeItem("GeometryNodeInputSplineResolution") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeSetCurveRadius") yield NodeItem("GeometryNodeSetCurveTilt") yield NodeItem("GeometryNodeSetCurveHandlePositions") yield NodeItem("GeometryNodeCurveSetHandles") yield NodeItem("GeometryNodeSetSplineCyclic") yield NodeItem("GeometryNodeSetSplineResolution") yield NodeItem("GeometryNodeCurveSplineType") # Custom Menu for Geometry Node Mesh. def mesh_node_items(context): if context is None: return space = context.space_data if not space: return yield NodeItem("GeometryNodeDualMesh") yield NodeItem("GeometryNodeEdgePathsToCurves") yield NodeItem("GeometryNodeEdgePathsToSelection") yield NodeItem("GeometryNodeExtrudeMesh") yield NodeItem("GeometryNodeFlipFaces") yield NodeItem("GeometryNodeMeshBoolean") yield NodeItem("GeometryNodeMeshToCurve") yield NodeItem("GeometryNodeMeshToPoints") yield NodeItem("GeometryNodeMeshToVolume") yield NodeItem("GeometryNodeScaleElements") yield NodeItem("GeometryNodeSplitEdges") yield NodeItem("GeometryNodeSubdivideMesh") yield NodeItem("GeometryNodeSubdivisionSurface") yield NodeItem("GeometryNodeTriangulate") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeInputMeshEdgeAngle") yield NodeItem("GeometryNodeInputMeshEdgeNeighbors") yield NodeItem("GeometryNodeInputMeshEdgeVertices") yield NodeItem("GeometryNodeInputMeshFaceArea") yield NodeItem("GeometryNodeInputMeshFaceNeighbors") yield NodeItem("GeometryNodeInputMeshFaceIsPlanar") yield NodeItem("GeometryNodeInputShadeSmooth") yield NodeItem("GeometryNodeInputMeshIsland") yield NodeItem("GeometryNodeInputShortestEdgePaths") yield NodeItem("GeometryNodeInputMeshVertexNeighbors") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeSetShadeSmooth") # Custom Menu for Geometry Nodes "Geometry" category. def geometry_node_items(context): if context is None: return space = context.space_data if not space: return yield NodeItem("GeometryNodeBoundBox") yield NodeItem("GeometryNodeConvexHull") yield NodeItem("GeometryNodeDeleteGeometry") yield NodeItem("GeometryNodeDuplicateElements") yield NodeItem("GeometryNodeProximity") yield NodeItem("GeometryNodeGeometryToInstance") yield NodeItem("GeometryNodeJoinGeometry") yield NodeItem("GeometryNodeMergeByDistance") yield NodeItem("GeometryNodeRaycast") yield NodeItem("GeometryNodeSeparateComponents") yield NodeItem("GeometryNodeSeparateGeometry") yield NodeItem("GeometryNodeTransform") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeSetID") yield NodeItem("GeometryNodeSetPosition") # Custom Menu for UV Nodes. def uv_node_items(context): if context is None: return space = context.space_data if not space: return yield NodeItem("GeometryNodeUVPackIslands") yield NodeItem("GeometryNodeUVUnwrap") # Custom Menu for Geometry Node Input Nodes. def geometry_input_node_items(context): if context is None: return space = context.space_data if not space: return yield NodeItem("FunctionNodeInputBool") yield NodeItem("GeometryNodeCollectionInfo") yield NodeItem("FunctionNodeInputColor") yield NodeItem("FunctionNodeInputInt") yield NodeItem("GeometryNodeIsViewport") yield NodeItem("GeometryNodeInputMaterial") yield NodeItem("GeometryNodeObjectInfo") yield NodeItem("FunctionNodeInputString") yield NodeItem("ShaderNodeValue") yield NodeItem("FunctionNodeInputVector") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeInputID") yield NodeItem("GeometryNodeInputIndex") yield NodeItem("GeometryNodeInputNamedAttribute") yield NodeItem("GeometryNodeInputNormal") yield NodeItem("GeometryNodeInputPosition") yield NodeItem("GeometryNodeInputRadius") yield NodeItem("GeometryNodeInputSceneTime") # Custom Menu for Geometry Node Instance Nodes. def geometry_instance_node_items(context): if context is None: return space = context.space_data if not space: return yield NodeItem("GeometryNodeInstanceOnPoints") yield NodeItem("GeometryNodeInstancesToPoints") yield NodeItem("GeometryNodeRealizeInstances") yield NodeItem("GeometryNodeRotateInstances") yield NodeItem("GeometryNodeScaleInstances") yield NodeItem("GeometryNodeTranslateInstances") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeInputInstanceRotation") yield NodeItem("GeometryNodeInputInstanceScale") # Custom Menu for Material Nodes. def geometry_material_node_items(context): if context is None: return space = context.space_data if not space: return yield NodeItem("GeometryNodeReplaceMaterial") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeInputMaterialIndex") yield NodeItem("GeometryNodeMaterialSelection") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeSetMaterial") yield NodeItem("GeometryNodeSetMaterialIndex") # Custom Menu for Geometry Node Points. def point_node_items(context): if context is None: return space = context.space_data if not space: return yield NodeItem("GeometryNodeDistributePointsOnFaces") yield NodeItem("GeometryNodePoints") yield NodeItem("GeometryNodePointsToVertices") yield NodeItem("GeometryNodePointsToVolume") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) yield NodeItem("GeometryNodeSetPointRadius") # Generic node group items generator for shader, compositor, geometry and texture node groups. def node_group_items(context): if context is None: return space = context.space_data if not space: return yield NodeItemCustom(draw=group_tools_draw) yield NodeItem("NodeGroupInput", poll=group_input_output_item_poll) yield NodeItem("NodeGroupOutput", poll=group_input_output_item_poll) ntree = space.edit_tree if not ntree: return yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) def contains_group(nodetree, group): if nodetree == group: return True else: for node in nodetree.nodes: if node.bl_idname in node_tree_group_type.values() and node.node_tree is not None: if contains_group(node.node_tree, group): return True return False for group in context.blend_data.node_groups: if group.bl_idname != ntree.bl_idname: continue # filter out recursive groups if contains_group(group, ntree): continue # filter out hidden nodetrees if group.name.startswith('.'): continue yield NodeItem(node_tree_group_type[group.bl_idname], label=group.name, settings={"node_tree": "bpy.data.node_groups[%r]" % group.name}) # only show input/output nodes inside node groups def group_input_output_item_poll(context): space = context.space_data if space.edit_tree in bpy.data.node_groups.values(): return True return False # only show input/output nodes when editing line style node trees def line_style_shader_nodes_poll(context): snode = context.space_data return (snode.tree_type == 'ShaderNodeTree' and snode.shader_type == 'LINESTYLE') # only show nodes working in world node trees def world_shader_nodes_poll(context): snode = context.space_data return (snode.tree_type == 'ShaderNodeTree' and snode.shader_type == 'WORLD') # only show nodes working in object node trees def object_shader_nodes_poll(context): snode = context.space_data return (snode.tree_type == 'ShaderNodeTree' and snode.shader_type == 'OBJECT') def cycles_shader_nodes_poll(context): return context.engine == 'CYCLES' def eevee_shader_nodes_poll(context): return context.engine == 'BLENDER_EEVEE' def eevee_cycles_shader_nodes_poll(context): return (cycles_shader_nodes_poll(context) or eevee_shader_nodes_poll(context)) def object_cycles_shader_nodes_poll(context): return (object_shader_nodes_poll(context) and cycles_shader_nodes_poll(context)) def object_eevee_shader_nodes_poll(context): return (object_shader_nodes_poll(context) and eevee_shader_nodes_poll(context)) def object_eevee_cycles_shader_nodes_poll(context): return (object_shader_nodes_poll(context) and eevee_cycles_shader_nodes_poll(context)) # All standard node categories currently used in nodes. shader_node_categories = [ # Shader Nodes (Cycles and Eevee) ShaderNodeCategory("SH_NEW_INPUT", "Input", items=[ NodeItem("ShaderNodeTexCoord"), NodeItem("ShaderNodeAttribute"), NodeItem("ShaderNodeLightPath"), NodeItem("ShaderNodeFresnel"), NodeItem("ShaderNodeLayerWeight"), NodeItem("ShaderNodeRGB"), NodeItem("ShaderNodeValue"), NodeItem("ShaderNodeTangent"), NodeItem("ShaderNodeNewGeometry"), NodeItem("ShaderNodeWireframe"), NodeItem("ShaderNodeBevel"), NodeItem("ShaderNodeAmbientOcclusion"), NodeItem("ShaderNodeObjectInfo"), NodeItem("ShaderNodeHairInfo"), NodeItem("ShaderNodePointInfo"), NodeItem("ShaderNodeVolumeInfo"), NodeItem("ShaderNodeParticleInfo"), NodeItem("ShaderNodeCameraData"), NodeItem("ShaderNodeUVMap"), NodeItem("ShaderNodeVertexColor"), NodeItem("ShaderNodeUVAlongStroke", poll=line_style_shader_nodes_poll), ]), ShaderNodeCategory("SH_NEW_OUTPUT", "Output", items=[ NodeItem("ShaderNodeOutputMaterial", poll=object_eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeOutputLight", poll=object_cycles_shader_nodes_poll), NodeItem("ShaderNodeOutputAOV"), NodeItem("ShaderNodeOutputWorld", poll=world_shader_nodes_poll), NodeItem("ShaderNodeOutputLineStyle", poll=line_style_shader_nodes_poll), ]), ShaderNodeCategory("SH_NEW_SHADER", "Shader", items=[ NodeItem("ShaderNodeMixShader", poll=eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeAddShader", poll=eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeBsdfDiffuse", poll=object_eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeBsdfPrincipled", poll=object_eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeBsdfGlossy", poll=object_eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeBsdfTransparent", poll=object_eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeBsdfRefraction", poll=object_eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeBsdfGlass", poll=object_eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeBsdfTranslucent", poll=object_eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeBsdfAnisotropic", poll=object_cycles_shader_nodes_poll), NodeItem("ShaderNodeBsdfVelvet", poll=object_cycles_shader_nodes_poll), NodeItem("ShaderNodeBsdfToon", poll=object_cycles_shader_nodes_poll), NodeItem("ShaderNodeSubsurfaceScattering", poll=object_eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeEmission", poll=eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeBsdfHair", poll=object_cycles_shader_nodes_poll), NodeItem("ShaderNodeBackground", poll=world_shader_nodes_poll), NodeItem("ShaderNodeHoldout", poll=object_eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeVolumeAbsorption", poll=eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeVolumeScatter", poll=eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeVolumePrincipled"), NodeItem("ShaderNodeEeveeSpecular", poll=object_eevee_shader_nodes_poll), NodeItem("ShaderNodeBsdfHairPrincipled", poll=object_cycles_shader_nodes_poll) ]), ShaderNodeCategory("SH_NEW_TEXTURE", "Texture", items=[ NodeItem("ShaderNodeTexImage"), NodeItem("ShaderNodeTexEnvironment"), NodeItem("ShaderNodeTexSky"), NodeItem("ShaderNodeTexNoise"), NodeItem("ShaderNodeTexWave"), NodeItem("ShaderNodeTexVoronoi"), NodeItem("ShaderNodeTexMusgrave"), NodeItem("ShaderNodeTexGradient"), NodeItem("ShaderNodeTexMagic"), NodeItem("ShaderNodeTexChecker"), NodeItem("ShaderNodeTexBrick"), NodeItem("ShaderNodeTexPointDensity"), NodeItem("ShaderNodeTexIES"), NodeItem("ShaderNodeTexWhiteNoise"), ]), ShaderNodeCategory("SH_NEW_OP_COLOR", "Color", items=[ NodeItem("ShaderNodeRGBCurve"), NodeItem("ShaderNodeInvert"), NodeItem("ShaderNodeLightFalloff"), NodeItem("ShaderNodeHueSaturation"), NodeItem("ShaderNodeGamma"), NodeItem("ShaderNodeBrightContrast"), ]), ShaderNodeCategory("SH_NEW_OP_VECTOR", "Vector", items=[ NodeItem("ShaderNodeMapping"), NodeItem("ShaderNodeBump"), NodeItem("ShaderNodeDisplacement"), NodeItem("ShaderNodeVectorDisplacement"), NodeItem("ShaderNodeNormalMap"), NodeItem("ShaderNodeNormal"), NodeItem("ShaderNodeVectorCurve"), NodeItem("ShaderNodeVectorRotate"), NodeItem("ShaderNodeVectorTransform"), ]), ShaderNodeCategory("SH_NEW_CONVERTOR", "Converter", items=[ NodeItem("ShaderNodeMapRange"), NodeItem("ShaderNodeFloatCurve"), NodeItem("ShaderNodeClamp"), NodeItem("ShaderNodeMath"), NodeItem("ShaderNodeMix"), NodeItem("ShaderNodeValToRGB"), NodeItem("ShaderNodeRGBToBW"), NodeItem("ShaderNodeShaderToRGB", poll=object_eevee_shader_nodes_poll), NodeItem("ShaderNodeVectorMath"), NodeItem("ShaderNodeSeparateColor"), NodeItem("ShaderNodeCombineColor"), NodeItem("ShaderNodeSeparateXYZ"), NodeItem("ShaderNodeCombineXYZ"), NodeItem("ShaderNodeWavelength"), NodeItem("ShaderNodeBlackbody"), ]), ShaderNodeCategory("SH_NEW_SCRIPT", "Script", items=[ NodeItem("ShaderNodeScript"), ]), ShaderNodeCategory("SH_NEW_GROUP", "Group", items=node_group_items), ShaderNodeCategory("SH_NEW_LAYOUT", "Layout", items=[ NodeItem("NodeFrame"), NodeItem("NodeReroute"), ]), ] compositor_node_categories = [ # Compositor Nodes CompositorNodeCategory("CMP_INPUT", "Input", items=[ NodeItem("CompositorNodeRLayers"), NodeItem("CompositorNodeImage"), NodeItem("CompositorNodeMovieClip"), NodeItem("CompositorNodeMask"), NodeItem("CompositorNodeRGB"), NodeItem("CompositorNodeValue"), NodeItem("CompositorNodeTexture"), NodeItem("CompositorNodeBokehImage"), NodeItem("CompositorNodeTime"), NodeItem("CompositorNodeSceneTime"), NodeItem("CompositorNodeTrackPos"), ]), CompositorNodeCategory("CMP_OUTPUT", "Output", items=[ NodeItem("CompositorNodeComposite"), NodeItem("CompositorNodeViewer"), NodeItem("CompositorNodeSplitViewer"), NodeItem("CompositorNodeOutputFile"), NodeItem("CompositorNodeLevels"), ]), CompositorNodeCategory("CMP_OP_COLOR", "Color", items=[ NodeItem("CompositorNodeMixRGB"), NodeItem("CompositorNodeAlphaOver"), NodeItem("CompositorNodeInvert"), NodeItem("CompositorNodeCurveRGB"), NodeItem("CompositorNodeHueSat"), NodeItem("CompositorNodeColorBalance"), NodeItem("CompositorNodeHueCorrect"), NodeItem("CompositorNodeBrightContrast"), NodeItem("CompositorNodeGamma"), NodeItem("CompositorNodeExposure"), NodeItem("CompositorNodeColorCorrection"), NodeItem("CompositorNodePosterize"), NodeItem("CompositorNodeTonemap"), NodeItem("CompositorNodeZcombine"), ]), CompositorNodeCategory("CMP_CONVERTOR", "Converter", items=[ NodeItem("CompositorNodeMath"), NodeItem("CompositorNodeValToRGB"), NodeItem("CompositorNodeSetAlpha"), NodeItem("CompositorNodePremulKey"), NodeItem("CompositorNodeIDMask"), NodeItem("CompositorNodeRGBToBW"), NodeItem("CompositorNodeSeparateColor"), NodeItem("CompositorNodeCombineColor"), NodeItem("CompositorNodeSeparateXYZ"), NodeItem("CompositorNodeCombineXYZ"), NodeItem("CompositorNodeSwitchView"), NodeItem("CompositorNodeConvertColorSpace"), ]), CompositorNodeCategory("CMP_OP_FILTER", "Filter", items=[ NodeItem("CompositorNodeBlur"), NodeItem("CompositorNodeBilateralblur"), NodeItem("CompositorNodeDilateErode"), NodeItem("CompositorNodeDespeckle"), NodeItem("CompositorNodeFilter"), NodeItem("CompositorNodeBokehBlur"), NodeItem("CompositorNodeVecBlur"), NodeItem("CompositorNodeDefocus"), NodeItem("CompositorNodeGlare"), NodeItem("CompositorNodeInpaint"), NodeItem("CompositorNodeDBlur"), NodeItem("CompositorNodePixelate"), NodeItem("CompositorNodeSunBeams"), NodeItem("CompositorNodeDenoise"), NodeItem("CompositorNodeAntiAliasing"), ]), CompositorNodeCategory("CMP_OP_VECTOR", "Vector", items=[ NodeItem("CompositorNodeNormal"), NodeItem("CompositorNodeMapValue"), NodeItem("CompositorNodeMapRange"), NodeItem("CompositorNodeNormalize"), NodeItem("CompositorNodeCurveVec"), ]), CompositorNodeCategory("CMP_MATTE", "Matte", items=[ NodeItem("CompositorNodeKeying"), NodeItem("CompositorNodeKeyingScreen"), NodeItem("CompositorNodeChannelMatte"), NodeItem("CompositorNodeColorSpill"), NodeItem("CompositorNodeBoxMask"), NodeItem("CompositorNodeEllipseMask"), NodeItem("CompositorNodeLumaMatte"), NodeItem("CompositorNodeDiffMatte"), NodeItem("CompositorNodeDistanceMatte"), NodeItem("CompositorNodeChromaMatte"), NodeItem("CompositorNodeColorMatte"), NodeItem("CompositorNodeDoubleEdgeMask"), NodeItem("CompositorNodeCryptomatte"), NodeItem("CompositorNodeCryptomatteV2"), ]), CompositorNodeCategory("CMP_DISTORT", "Distort", items=[ NodeItem("CompositorNodeScale"), NodeItem("CompositorNodeLensdist"), NodeItem("CompositorNodeMovieDistortion"), NodeItem("CompositorNodeTranslate"), NodeItem("CompositorNodeRotate"), NodeItem("CompositorNodeFlip"), NodeItem("CompositorNodeCrop"), NodeItem("CompositorNodeDisplace"), NodeItem("CompositorNodeMapUV"), NodeItem("CompositorNodeTransform"), NodeItem("CompositorNodeStabilize"), NodeItem("CompositorNodePlaneTrackDeform"), NodeItem("CompositorNodeCornerPin"), ]), CompositorNodeCategory("CMP_GROUP", "Group", items=node_group_items), CompositorNodeCategory("CMP_LAYOUT", "Layout", items=[ NodeItem("NodeFrame"), NodeItem("NodeReroute"), NodeItem("CompositorNodeSwitch"), ]), ] texture_node_categories = [ # Texture Nodes TextureNodeCategory("TEX_INPUT", "Input", items=[ NodeItem("TextureNodeCurveTime"), NodeItem("TextureNodeCoordinates"), NodeItem("TextureNodeTexture"), NodeItem("TextureNodeImage"), ]), TextureNodeCategory("TEX_OUTPUT", "Output", items=[ NodeItem("TextureNodeOutput"), NodeItem("TextureNodeViewer"), ]), TextureNodeCategory("TEX_OP_COLOR", "Color", items=[ NodeItem("TextureNodeMixRGB"), NodeItem("TextureNodeCurveRGB"), NodeItem("TextureNodeInvert"), NodeItem("TextureNodeHueSaturation"), NodeItem("TextureNodeCombineColor"), NodeItem("TextureNodeSeparateColor"), ]), TextureNodeCategory("TEX_PATTERN", "Pattern", items=[ NodeItem("TextureNodeChecker"), NodeItem("TextureNodeBricks"), ]), TextureNodeCategory("TEX_TEXTURE", "Textures", items=[ NodeItem("TextureNodeTexNoise"), NodeItem("TextureNodeTexDistNoise"), NodeItem("TextureNodeTexClouds"), NodeItem("TextureNodeTexBlend"), NodeItem("TextureNodeTexVoronoi"), NodeItem("TextureNodeTexMagic"), NodeItem("TextureNodeTexMarble"), NodeItem("TextureNodeTexWood"), NodeItem("TextureNodeTexMusgrave"), NodeItem("TextureNodeTexStucci"), ]), TextureNodeCategory("TEX_CONVERTOR", "Converter", items=[ NodeItem("TextureNodeMath"), NodeItem("TextureNodeValToRGB"), NodeItem("TextureNodeRGBToBW"), NodeItem("TextureNodeValToNor"), NodeItem("TextureNodeDistance"), ]), TextureNodeCategory("TEX_DISTORT", "Distort", items=[ NodeItem("TextureNodeScale"), NodeItem("TextureNodeTranslate"), NodeItem("TextureNodeRotate"), NodeItem("TextureNodeAt"), ]), TextureNodeCategory("TEX_GROUP", "Group", items=node_group_items), TextureNodeCategory("TEX_LAYOUT", "Layout", items=[ NodeItem("NodeFrame"), NodeItem("NodeReroute"), ]), ] geometry_node_categories = [ # Geometry Nodes GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[ NodeItem("GeometryNodeCaptureAttribute"), NodeItem("GeometryNodeAttributeDomainSize"), NodeItem("GeometryNodeAttributeStatistic"), NodeItem("GeometryNodeAttributeTransfer"), NodeItem("GeometryNodeRemoveAttribute"), + NodeItem("GeometryNodeSmoothAttribute"), NodeItem("GeometryNodeStoreNamedAttribute"), ]), GeometryNodeCategory("GEO_COLOR", "Color", items=[ NodeItem("ShaderNodeRGBCurve"), NodeItem("ShaderNodeValToRGB"), NodeItem("FunctionNodeSeparateColor"), NodeItem("FunctionNodeCombineColor"), ]), GeometryNodeCategory("GEO_CURVE", "Curve", items=curve_node_items), GeometryNodeCategory("GEO_PRIMITIVES_CURVE", "Curve Primitives", items=[ NodeItem("GeometryNodeCurvePrimitiveLine"), NodeItem("GeometryNodeCurvePrimitiveCircle"), NodeItem("GeometryNodeCurveStar"), NodeItem("GeometryNodeCurveSpiral"), NodeItem("GeometryNodeCurveArc"), NodeItem("GeometryNodeCurveQuadraticBezier"), NodeItem("GeometryNodeCurvePrimitiveQuadrilateral"), NodeItem("GeometryNodeCurvePrimitiveBezierSegment"), ]), GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=geometry_node_items), GeometryNodeCategory("GEO_INPUT", "Input", items=geometry_input_node_items), GeometryNodeCategory("GEO_INSTANCE", "Instances", items=geometry_instance_node_items), GeometryNodeCategory("GEO_MATERIAL", "Material", items=geometry_material_node_items), GeometryNodeCategory("GEO_MESH", "Mesh", items=mesh_node_items), GeometryNodeCategory("GEO_PRIMITIVES_MESH", "Mesh Primitives", items=[ NodeItem("GeometryNodeMeshCircle"), NodeItem("GeometryNodeMeshCone"), NodeItem("GeometryNodeMeshCube"), NodeItem("GeometryNodeMeshCylinder"), NodeItem("GeometryNodeMeshGrid"), NodeItem("GeometryNodeMeshIcoSphere"), NodeItem("GeometryNodeMeshLine"), NodeItem("GeometryNodeMeshUVSphere"), ]), GeometryNodeCategory("GEO_OUTPUT", "Output", items=[ NodeItem("GeometryNodeViewer"), ]), GeometryNodeCategory("GEO_POINT", "Point", items=point_node_items), GeometryNodeCategory("GEO_TEXT", "Text", items=[ NodeItem("FunctionNodeStringLength"), NodeItem("FunctionNodeSliceString"), NodeItem("FunctionNodeValueToString"), NodeItem("GeometryNodeStringJoin"), NodeItem("FunctionNodeInputSpecialCharacters"), NodeItem("GeometryNodeStringToCurves"), NodeItem("FunctionNodeReplaceString"), ]), GeometryNodeCategory("GEO_TEXTURE", "Texture", items=[ NodeItem("ShaderNodeTexBrick"), NodeItem("ShaderNodeTexChecker"), NodeItem("ShaderNodeTexGradient"), NodeItem("ShaderNodeTexMagic"), NodeItem("ShaderNodeTexMusgrave"), NodeItem("ShaderNodeTexNoise"), NodeItem("ShaderNodeTexVoronoi"), NodeItem("ShaderNodeTexWave"), NodeItem("ShaderNodeTexWhiteNoise"), NodeItem("GeometryNodeImageTexture"), ]), GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[ NodeItem("GeometryNodeAccumulateField"), NodeItem("GeometryNodeFieldAtIndex"), NodeItem("GeometryNodeFieldOnDomain"), NodeItem("ShaderNodeMapRange"), NodeItem("ShaderNodeFloatCurve"), NodeItem("ShaderNodeClamp"), NodeItem("ShaderNodeMath"), NodeItem("FunctionNodeBooleanMath"), NodeItem("FunctionNodeRotateEuler"), NodeItem("FunctionNodeCompare"), NodeItem("ShaderNodeMix"), NodeItem("FunctionNodeFloatToInt"), NodeItem("GeometryNodeSwitch"), NodeItem("FunctionNodeRandomValue"), NodeItem("FunctionNodeAlignEulerToVector"), ]), GeometryNodeCategory("GEO_UV", "UV", items=uv_node_items), GeometryNodeCategory("GEO_VECTOR", "Vector", items=[ NodeItem("ShaderNodeVectorCurve"), NodeItem("ShaderNodeSeparateXYZ"), NodeItem("ShaderNodeCombineXYZ"), NodeItem("ShaderNodeVectorMath"), NodeItem("ShaderNodeVectorRotate"), ]), GeometryNodeCategory("GEO_VOLUME", "Volume", items=[ NodeItem("GeometryNodeVolumeCube"), NodeItem("GeometryNodeVolumeToMesh"), ]), GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items), GeometryNodeCategory("GEO_LAYOUT", "Layout", items=[ NodeItem("NodeFrame"), NodeItem("NodeReroute"), ]), ] def register(): nodeitems_utils.register_node_categories('SHADER', shader_node_categories) nodeitems_utils.register_node_categories('COMPOSITING', compositor_node_categories) nodeitems_utils.register_node_categories('TEXTURE', texture_node_categories) nodeitems_utils.register_node_categories('GEOMETRY', geometry_node_categories) def unregister(): nodeitems_utils.unregister_node_categories('SHADER') nodeitems_utils.unregister_node_categories('COMPOSITING') nodeitems_utils.unregister_node_categories('TEXTURE') nodeitems_utils.unregister_node_categories('GEOMETRY') if __name__ == "__main__": register() diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 55bf24f943e..c40c6ae5547 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1,1587 +1,1588 @@ /* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2005 Blender Foundation. All rights reserved. */ #pragma once /** \file * \ingroup bke */ #include "BLI_compiler_compat.h" #include "BLI_ghash.h" #include "DNA_listBase.h" /* for FOREACH_NODETREE_BEGIN */ #include "DNA_node_types.h" #include "RNA_types.h" #ifdef __cplusplus # include "BLI_map.hh" # include "BLI_string_ref.hh" #endif #ifdef __cplusplus extern "C" { #endif /* not very important, but the stack solver likes to know a maximum */ #define MAX_SOCKET 512 struct ARegion; struct BlendDataReader; struct BlendExpander; struct BlendLibReader; struct BlendWriter; struct ColorManagedDisplaySettings; struct ColorManagedViewSettings; struct CryptomatteSession; struct FreestyleLineStyle; struct GPUMaterial; struct GPUNodeStack; struct ID; struct ImBuf; struct ImageFormatData; struct Light; struct ListBase; struct MTex; struct Main; struct Material; struct PointerRNA; struct RenderData; struct Scene; struct SpaceNode; struct Tex; struct World; struct bContext; struct bNode; struct bNodeExecContext; struct bNodeExecData; struct bNodeInstanceHash; struct bNodeLink; struct bNodeSocket; struct bNodeStack; struct bNodeTree; struct bNodeTreeExec; struct bNodeTreeType; struct uiLayout; /* -------------------------------------------------------------------- */ /** \name Node Type Definitions * \{ */ /** * \brief Compact definition of a node socket. * * Can be used to quickly define a list of static sockets for a node, * which are added to each new node of that type. * * \deprecated This struct is used by C nodes to define templates as simple * static struct lists. These are converted to the new template collections * in RNA types automatically. */ typedef struct bNodeSocketTemplate { int type; char name[64]; /* MAX_NAME */ float val1, val2, val3, val4; /* default alloc value for inputs */ float min, max; int subtype; /* would use PropertySubType but this is a bad level include to use RNA */ int flag; /* after this line is used internal only */ struct bNodeSocket *sock; /* used to hold verified socket */ char identifier[64]; /* generated from name */ } bNodeSocketTemplate; /* Use `void *` for callbacks that require C++. This is rather ugly, but works well for now. This * would not be necessary if we would use bNodeSocketType and bNodeType only in C++ code. * However, achieving this requires quite a few changes currently. */ #ifdef __cplusplus namespace blender { class CPPType; namespace nodes { class DNode; class NodeMultiFunctionBuilder; class GeoNodeExecParams; class NodeDeclarationBuilder; class GatherLinkSearchOpParams; } // namespace nodes namespace fn { class MFDataType; } // namespace fn namespace realtime_compositor { class Context; class NodeOperation; class ShaderNode; } // namespace realtime_compositor } // namespace blender using CPPTypeHandle = blender::CPPType; using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder); using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params); using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder); using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value); using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value); /* Adds socket link operations that are specific to this node type. */ using NodeGatherSocketLinkOperationsFunction = void (*)(blender::nodes::GatherLinkSearchOpParams ¶ms); using NodeGetCompositorOperationFunction = blender::realtime_compositor::NodeOperation *(*)(blender::realtime_compositor::Context &context, blender::nodes::DNode node); using NodeGetCompositorShaderNodeFunction = blender::realtime_compositor::ShaderNode *(*)(blender::nodes::DNode node); #else typedef void *NodeGetCompositorOperationFunction; typedef void *NodeGetCompositorShaderNodeFunction; typedef void *NodeMultiFunctionBuildFunction; typedef void *NodeGeometryExecFunction; typedef void *NodeDeclareFunction; typedef void *NodeGatherSocketLinkOperationsFunction; typedef void *SocketGetCPPTypeFunction; typedef void *SocketGetGeometryNodesCPPTypeFunction; typedef void *SocketGetGeometryNodesCPPValueFunction; typedef void *SocketGetCPPValueFunction; typedef struct CPPTypeHandle CPPTypeHandle; #endif /** * \brief Defines a socket type. * * Defines the appearance and behavior of a socket in the UI. */ typedef struct bNodeSocketType { /* Identifier name */ char idname[64]; /* Type label */ char label[64]; void (*draw)(struct bContext *C, struct uiLayout *layout, struct PointerRNA *ptr, struct PointerRNA *node_ptr, const char *text); void (*draw_color)(struct bContext *C, struct PointerRNA *ptr, struct PointerRNA *node_ptr, float *r_color); void (*interface_draw)(struct bContext *C, struct uiLayout *layout, struct PointerRNA *ptr); void (*interface_draw_color)(struct bContext *C, struct PointerRNA *ptr, float *r_color); void (*interface_register_properties)(struct bNodeTree *ntree, struct bNodeSocket *interface_socket, struct StructRNA *data_srna); void (*interface_init_socket)(struct bNodeTree *ntree, const struct bNodeSocket *interface_socket, struct bNode *node, struct bNodeSocket *sock, const char *data_path); void (*interface_verify_socket)(struct bNodeTree *ntree, const struct bNodeSocket *interface_socket, struct bNode *node, struct bNodeSocket *sock, const char *data_path); void (*interface_from_socket)(struct bNodeTree *ntree, struct bNodeSocket *interface_socket, struct bNode *node, struct bNodeSocket *sock); /* RNA integration */ ExtensionRNA ext_socket; ExtensionRNA ext_interface; /* for standard socket types in C */ int type, subtype; /* When set, bNodeSocket->limit does not have any effect anymore. */ bool use_link_limits_of_type; int input_link_limit; int output_link_limit; /* Callback to free the socket type. */ void (*free_self)(struct bNodeSocketType *stype); /* Return the CPPType of this socket. */ const CPPTypeHandle *base_cpp_type; /* Get the value of this socket in a generic way. */ SocketGetCPPValueFunction get_base_cpp_value; /* Get geometry nodes cpp type. */ const CPPTypeHandle *geometry_nodes_cpp_type; /* Get geometry nodes cpp value. */ SocketGetGeometryNodesCPPValueFunction get_geometry_nodes_cpp_value; } bNodeSocketType; typedef void *(*NodeInitExecFunction)(struct bNodeExecContext *context, struct bNode *node, bNodeInstanceKey key); typedef void (*NodeFreeExecFunction)(void *nodedata); typedef void (*NodeExecFunction)(void *data, int thread, struct bNode *, struct bNodeExecData *execdata, struct bNodeStack **in, struct bNodeStack **out); typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat, struct bNode *node, struct bNodeExecData *execdata, struct GPUNodeStack *in, struct GPUNodeStack *out); /** * \brief Defines a node type. * * Initial attributes and constants for a node as well as callback functions * implementing the node behavior. */ typedef struct bNodeType { char idname[64]; /* identifier name */ int type; char ui_name[64]; /* MAX_NAME */ char ui_description[256]; int ui_icon; float width, minwidth, maxwidth; float height, minheight, maxheight; short nclass, flag; /* templates for static sockets */ bNodeSocketTemplate *inputs, *outputs; char storagename[64]; /* struct name for DNA */ /* Draw the option buttons on the node */ void (*draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr); /* Additional parameters in the side panel */ void (*draw_buttons_ex)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr); /* Additional drawing on backdrop */ void (*draw_backdrop)( struct SpaceNode *snode, struct ImBuf *backdrop, struct bNode *node, int x, int y); /** * Optional custom label function for the node header. * \note Used as a fallback when #bNode.label isn't set. */ void (*labelfunc)(const struct bNodeTree *ntree, const struct bNode *node, char *label, int maxlen); /** Optional override for node class, used for drawing node header. */ int (*ui_class)(const struct bNode *node); /** Called when the node is updated in the editor. */ void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node); /** Check and update if internal ID data has changed. */ void (*group_update_func)(struct bNodeTree *ntree, struct bNode *node); /** Initialize a new node instance of this type after creation. */ void (*initfunc)(struct bNodeTree *ntree, struct bNode *node); /** Free the node instance. */ void (*freefunc)(struct bNode *node); /** Make a copy of the node instance. */ void (*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node); /* Registerable API callback versions, called in addition to C callbacks */ void (*initfunc_api)(const struct bContext *C, struct PointerRNA *ptr); void (*freefunc_api)(struct PointerRNA *ptr); void (*copyfunc_api)(struct PointerRNA *ptr, const struct bNode *src_node); /** * Can this node type be added to a node tree? * \param r_disabled_hint: Hint to display in the UI when the poll fails. * The callback can set this to a static string without having to * null-check it (or without setting it to null if it's not used). * The caller must pass a valid `const char **` and null-initialize it * when it's not just a dummy, that is, if it actually wants to access * the returned disabled-hint (null-check needed!). */ bool (*poll)(struct bNodeType *ntype, struct bNodeTree *nodetree, const char **r_disabled_hint); /** Can this node be added to a node tree? * \param r_disabled_hint: See `poll()`. */ bool (*poll_instance)(struct bNode *node, struct bNodeTree *nodetree, const char **r_disabled_hint); /* optional handling of link insertion */ void (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); void (*free_self)(struct bNodeType *ntype); /* **** execution callbacks **** */ NodeInitExecFunction init_exec_fn; NodeFreeExecFunction free_exec_fn; NodeExecFunction exec_fn; /* gpu */ NodeGPUExecFunction gpu_fn; /* Get an instance of this node's compositor operation. Freeing the instance is the * responsibility of the caller. */ NodeGetCompositorOperationFunction get_compositor_operation; /* Get an instance of this node's compositor shader node. Freeing the instance is the * responsibility of the caller. */ NodeGetCompositorShaderNodeFunction get_compositor_shader_node; /* Build a multi-function for this node. */ NodeMultiFunctionBuildFunction build_multi_function; /* Execute a geometry node. */ NodeGeometryExecFunction geometry_node_execute; /** * If true, the geometry nodes evaluator can call the execute function multiple times to improve * performance by specifying required data in one call and using it for calculations in another. */ bool geometry_node_execute_supports_laziness; /* Declares which sockets the node has. */ NodeDeclareFunction declare; /* Different nodes of this type can have different declarations. */ bool declaration_is_dynamic; /* Declaration to be used when it is not dynamic. */ NodeDeclarationHandle *fixed_declaration; /** * Add to the list of search names and operations gathered by node link drag searching. * Usually it isn't necessary to override the default behavior here, but a node type can have * custom behavior here like adding custom search items. */ NodeGatherSocketLinkOperationsFunction gather_link_search_ops; /** True when the node cannot be muted. */ bool no_muting; /* RNA integration */ ExtensionRNA rna_ext; } bNodeType; /* nodetype->nclass, for add-menu and themes */ #define NODE_CLASS_INPUT 0 #define NODE_CLASS_OUTPUT 1 #define NODE_CLASS_OP_COLOR 3 #define NODE_CLASS_OP_VECTOR 4 #define NODE_CLASS_OP_FILTER 5 #define NODE_CLASS_GROUP 6 #define NODE_CLASS_CONVERTER 8 #define NODE_CLASS_MATTE 9 #define NODE_CLASS_DISTORT 10 #define NODE_CLASS_PATTERN 12 #define NODE_CLASS_TEXTURE 13 #define NODE_CLASS_SCRIPT 32 #define NODE_CLASS_INTERFACE 33 #define NODE_CLASS_SHADER 40 #define NODE_CLASS_GEOMETRY 41 #define NODE_CLASS_ATTRIBUTE 42 #define NODE_CLASS_LAYOUT 100 typedef enum eNodeSizePreset { NODE_SIZE_DEFAULT, NODE_SIZE_SMALL, NODE_SIZE_MIDDLE, NODE_SIZE_LARGE, } eNodeSizePreset; struct bNodeTreeExec; typedef void (*bNodeClassCallback)(void *calldata, int nclass, const char *name); typedef struct bNodeTreeType { int type; /* type identifier */ char idname[64]; /* identifier name */ /* The ID name of group nodes for this type. */ char group_idname[64]; char ui_name[64]; char ui_description[256]; int ui_icon; /* callbacks */ void (*free_cache)(struct bNodeTree *ntree); void (*free_node_cache)(struct bNodeTree *ntree, struct bNode *node); /* Iteration over all node classes. */ void (*foreach_nodeclass)(struct Scene *scene, void *calldata, bNodeClassCallback func); /* Check visibility in the node editor */ bool (*poll)(const struct bContext *C, struct bNodeTreeType *ntreetype); /* Select a node tree from the context */ void (*get_from_context)(const struct bContext *C, struct bNodeTreeType *ntreetype, struct bNodeTree **r_ntree, struct ID **r_id, struct ID **r_from); /* calls allowing threaded composite */ void (*localize)(struct bNodeTree *localtree, struct bNodeTree *ntree); void (*local_merge)(struct Main *bmain, struct bNodeTree *localtree, struct bNodeTree *ntree); /* Tree update. Overrides `nodetype->updatetreefunc` ! */ void (*update)(struct bNodeTree *ntree); bool (*validate_link)(eNodeSocketDatatype from, eNodeSocketDatatype to); void (*node_add_init)(struct bNodeTree *ntree, struct bNode *bnode); /* Check if the socket type is valid for this tree type. */ bool (*valid_socket_type)(struct bNodeTreeType *ntreetype, struct bNodeSocketType *socket_type); /* RNA integration */ ExtensionRNA rna_ext; } bNodeTreeType; /** \} */ /* -------------------------------------------------------------------- */ /** \name Generic API, Trees * \{ */ struct bNodeTreeType *ntreeTypeFind(const char *idname); void ntreeTypeAdd(struct bNodeTreeType *nt); void ntreeTypeFreeLink(const struct bNodeTreeType *nt); bool ntreeIsRegistered(struct bNodeTree *ntree); struct GHashIterator *ntreeTypeGetIterator(void); /* Helper macros for iterating over tree types. */ #define NODE_TREE_TYPES_BEGIN(ntype) \ { \ GHashIterator *__node_tree_type_iter__ = ntreeTypeGetIterator(); \ for (; !BLI_ghashIterator_done(__node_tree_type_iter__); \ BLI_ghashIterator_step(__node_tree_type_iter__)) { \ bNodeTreeType *ntype = (bNodeTreeType *)BLI_ghashIterator_getValue(__node_tree_type_iter__); #define NODE_TREE_TYPES_END \ } \ BLI_ghashIterator_free(__node_tree_type_iter__); \ } \ (void)0 /** * Try to initialize all type-info in a node tree. * * \note In general undefined type-info is a perfectly valid case, * the type may just be registered later. * In that case the update_typeinfo function will set type-info on registration * and do necessary updates. */ void ntreeSetTypes(const struct bContext *C, struct bNodeTree *ntree); struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname); struct bNodeTree *ntreeAddTreeEmbedded(struct Main *bmain, struct ID *owner_id, const char *name, const char *idname); /* copy/free funcs, need to manage ID users */ /** * Free (or release) any data used by this node-tree. * Does not free the node-tree itself and does no ID user counting. */ void ntreeFreeTree(struct bNodeTree *ntree); /** * Free tree which is embedded into another data-block. */ void ntreeFreeEmbeddedTree(struct bNodeTree *ntree); struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree, struct Main *bmain, bool do_id_user); struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree); /** * Get address of potential node-tree pointer of given ID. * * \warning Using this function directly is potentially dangerous, if you don't know or are not * sure, please use `ntreeFromID()` instead. */ struct bNodeTree **BKE_ntree_ptr_from_id(struct ID *id); /** * Returns the private NodeTree object of the data-block, if it has one. */ struct bNodeTree *ntreeFromID(struct ID *id); void ntreeFreeLocalNode(struct bNodeTree *ntree, struct bNode *node); void ntreeFreeLocalTree(struct bNodeTree *ntree); struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type); bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup); void ntreeUpdateAllNew(struct Main *main); void ntreeUpdateAllUsers(struct Main *main, struct ID *id); void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***r_deplist, int *r_deplist_len); void ntreeUpdateNodeLevels(struct bNodeTree *ntree); /** * XXX: old trees handle output flags automatically based on special output * node types and last active selection. * New tree types have a per-output socket flag to indicate the final output to use explicitly. */ void ntreeSetOutput(struct bNodeTree *ntree); void ntreeFreeCache(struct bNodeTree *ntree); void ntreeNodeFlagSet(const bNodeTree *ntree, int flag, bool enable); /** * Returns localized tree for execution in threads. */ struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree); /** * Merge local tree results back, and free local tree. * * We have to assume the editor already changed completely. */ void ntreeLocalMerge(struct Main *bmain, struct bNodeTree *localtree, struct bNodeTree *ntree); /** * This is only direct data, tree itself should have been written. */ void ntreeBlendWrite(struct BlendWriter *writer, struct bNodeTree *ntree); /** * \note `ntree` itself has been read! */ void ntreeBlendReadData(struct BlendDataReader *reader, struct ID *owner_id, struct bNodeTree *ntree); void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree); void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntree); /** \} */ /* -------------------------------------------------------------------- */ /** \name Node Tree Interface * \{ */ struct bNodeSocket *ntreeFindSocketInterface(struct bNodeTree *ntree, eNodeSocketInOut in_out, const char *identifier); struct bNodeSocket *ntreeAddSocketInterface(struct bNodeTree *ntree, eNodeSocketInOut in_out, const char *idname, const char *name); struct bNodeSocket *ntreeInsertSocketInterface(struct bNodeTree *ntree, eNodeSocketInOut in_out, const char *idname, struct bNodeSocket *next_sock, const char *name); struct bNodeSocket *ntreeAddSocketInterfaceFromSocket(struct bNodeTree *ntree, struct bNode *from_node, struct bNodeSocket *from_sock); struct bNodeSocket *ntreeInsertSocketInterfaceFromSocket(struct bNodeTree *ntree, struct bNodeSocket *next_sock, struct bNode *from_node, struct bNodeSocket *from_sock); void ntreeRemoveSocketInterface(struct bNodeTree *ntree, struct bNodeSocket *sock); struct StructRNA *ntreeInterfaceTypeGet(struct bNodeTree *ntree, bool create); void ntreeInterfaceTypeFree(struct bNodeTree *ntree); void ntreeInterfaceTypeUpdate(struct bNodeTree *ntree); /** \} */ /* -------------------------------------------------------------------- */ /** \name Generic API, Nodes * \{ */ struct bNodeType *nodeTypeFind(const char *idname); void nodeRegisterType(struct bNodeType *ntype); void nodeUnregisterType(struct bNodeType *ntype); bool nodeTypeUndefined(const struct bNode *node); struct GHashIterator *nodeTypeGetIterator(void); /* Helper macros for iterating over node types. */ #define NODE_TYPES_BEGIN(ntype) \ { \ GHashIterator *__node_type_iter__ = nodeTypeGetIterator(); \ for (; !BLI_ghashIterator_done(__node_type_iter__); \ BLI_ghashIterator_step(__node_type_iter__)) { \ bNodeType *ntype = (bNodeType *)BLI_ghashIterator_getValue(__node_type_iter__); #define NODE_TYPES_END \ } \ BLI_ghashIterator_free(__node_type_iter__); \ } \ ((void)0) struct bNodeSocketType *nodeSocketTypeFind(const char *idname); void nodeRegisterSocketType(struct bNodeSocketType *stype); void nodeUnregisterSocketType(struct bNodeSocketType *stype); bool nodeSocketIsRegistered(struct bNodeSocket *sock); struct GHashIterator *nodeSocketTypeGetIterator(void); const char *nodeSocketTypeLabel(const bNodeSocketType *stype); bool nodeIsStaticSocketType(const struct bNodeSocketType *stype); const char *nodeStaticSocketType(int type, int subtype); const char *nodeStaticSocketInterfaceType(int type, int subtype); const char *nodeStaticSocketLabel(int type, int subtype); /* Helper macros for iterating over node types. */ #define NODE_SOCKET_TYPES_BEGIN(stype) \ { \ GHashIterator *__node_socket_type_iter__ = nodeSocketTypeGetIterator(); \ for (; !BLI_ghashIterator_done(__node_socket_type_iter__); \ BLI_ghashIterator_step(__node_socket_type_iter__)) { \ bNodeSocketType *stype = (bNodeSocketType *)BLI_ghashIterator_getValue( \ __node_socket_type_iter__); #define NODE_SOCKET_TYPES_END \ } \ BLI_ghashIterator_free(__node_socket_type_iter__); \ } \ ((void)0) struct bNodeSocket *nodeFindSocket(const struct bNode *node, eNodeSocketInOut in_out, const char *identifier); struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree, struct bNode *node, eNodeSocketInOut in_out, const char *idname, const char *identifier, const char *name); struct bNodeSocket *nodeAddStaticSocket(struct bNodeTree *ntree, struct bNode *node, eNodeSocketInOut in_out, int type, int subtype, const char *identifier, const char *name); void nodeRemoveSocket(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock); void nodeRemoveSocketEx(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock, bool do_id_user); void nodeRemoveAllSockets(struct bNodeTree *ntree, struct bNode *node); void nodeModifySocketType(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock, const char *idname); void nodeModifySocketTypeStatic( struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock, int type, int subtype); struct bNode *nodeAddNode(const struct bContext *C, struct bNodeTree *ntree, const char *idname); struct bNode *nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type); /** * \note Goes over entire tree. */ void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node); /** * Find the first available, non-duplicate name for a given node. */ void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node); /** * Delete node, associated animation data and ID user count. */ void nodeRemoveNode(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node, bool do_id_user); #ifdef __cplusplus namespace blender::bke { /** * \note keeps socket list order identical, for copying links. * \note `unique_name` should usually be true, unless the \a dst_tree is temporary, * or the names can already be assumed valid. */ bNode *node_copy_with_mapping(bNodeTree *dst_tree, const bNode &node_src, int flag, bool unique_name, Map &new_socket_map); bNode *node_copy(bNodeTree *dst_tree, const bNode &src_node, int flag, bool unique_name); } // namespace blender::bke #endif /** * Also used via RNA API, so we check for proper input output direction. */ struct bNodeLink *nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock); void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link); void nodeRemSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock); /** * Set the mute status of a single link. */ void nodeLinkSetMute(struct bNodeTree *ntree, struct bNodeLink *link, const bool muted); bool nodeLinkIsHidden(const struct bNodeLink *link); bool nodeLinkIsSelected(const struct bNodeLink *link); void nodeInternalRelink(struct bNodeTree *ntree, struct bNode *node); void nodeToView(const struct bNode *node, float x, float y, float *rx, float *ry); void nodeFromView(const struct bNode *node, float x, float y, float *rx, float *ry); bool nodeAttachNodeCheck(const struct bNode *node, const struct bNode *parent); void nodeAttachNode(struct bNode *node, struct bNode *parent); void nodeDetachNode(struct bNode *node); void nodePositionRelative(struct bNode *from_node, struct bNode *to_node, struct bNodeSocket *from_sock, struct bNodeSocket *to_sock); void nodePositionPropagate(struct bNode *node); /** * Finds a node based on its name. */ struct bNode *nodeFindNodebyName(struct bNodeTree *ntree, const char *name); /** * Finds a node based on given socket and returns true on success. */ bool nodeFindNode(struct bNodeTree *ntree, struct bNodeSocket *sock, struct bNode **r_node, int *r_sockindex); /** * \note Recursive. */ struct bNode *nodeFindRootParent(bNode *node); /** * \returns true if \a child has \a parent as a parent/grandparent/... etc. * \note Recursive */ bool nodeIsChildOf(const bNode *parent, const bNode *child); /** * Iterate over a chain of nodes, starting with \a node_start, executing * \a callback for each node (which can return false to end iterator). * * \param reversed: for backwards iteration * \note Recursive */ void nodeChainIter(const bNodeTree *ntree, const bNode *node_start, bool (*callback)(bNode *, bNode *, void *, const bool), void *userdata, bool reversed); /** * Iterate over a chain of nodes, starting with \a node_start, executing * \a callback for each node (which can return false to end iterator). * * Faster than nodeChainIter. Iter only once per node. * Can be called recursively (using another nodeChainIterBackwards) by * setting the recursion_lvl accordingly. * * \note Needs updated socket links (ntreeUpdateTree). * \note Recursive */ void nodeChainIterBackwards(const bNodeTree *ntree, const bNode *node_start, bool (*callback)(bNode *, bNode *, void *), void *userdata, int recursion_lvl); /** * Iterate over all parents of \a node, executing \a callback for each parent * (which can return false to end iterator) * * \note Recursive */ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata); struct bNodeLink *nodeFindLink(struct bNodeTree *ntree, const struct bNodeSocket *from, const struct bNodeSocket *to); int nodeCountSocketLinks(const struct bNodeTree *ntree, const struct bNodeSocket *sock); void nodeSetSelected(struct bNode *node, bool select); /** * Two active flags, ID nodes have special flag for buttons display. */ void nodeSetActive(struct bNodeTree *ntree, struct bNode *node); struct bNode *nodeGetActive(struct bNodeTree *ntree); void nodeClearActive(struct bNodeTree *ntree); /** * Two active flags, ID nodes have special flag for buttons display. */ struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree); struct bNode *nodeGetActivePaintCanvas(struct bNodeTree *ntree); /** * \brief Does the given node supports the sub active flag. * * \param sub_active: The active flag to check. #NODE_ACTIVE_TEXTURE / #NODE_ACTIVE_PAINT_CANVAS. */ bool nodeSupportsActiveFlag(const struct bNode *node, int sub_active); int nodeSocketIsHidden(const struct bNodeSocket *sock); void nodeSetSocketAvailability(struct bNodeTree *ntree, struct bNodeSocket *sock, bool is_available); int nodeSocketLinkLimit(const struct bNodeSocket *sock); /** * If the node implements a `declare` function, this function makes sure that `node->declaration` * is up to date. It is expected that the sockets of the node are up to date already. */ bool nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node); /** * Just update `node->declaration` if necessary. This can also be called on nodes that may not be * up to date (e.g. because the need versioning or are dynamic). */ bool nodeDeclarationEnsureOnOutdatedNode(struct bNodeTree *ntree, struct bNode *node); /** * Update `socket->declaration` for all sockets in the node. This assumes that the node declaration * and sockets are up to date already. */ void nodeSocketDeclarationsUpdate(struct bNode *node); /** * Node Clipboard. */ void BKE_node_clipboard_init(const struct bNodeTree *ntree); void BKE_node_clipboard_clear(void); void BKE_node_clipboard_free(void); /** * Return false when one or more ID's are lost. */ bool BKE_node_clipboard_validate(void); void BKE_node_clipboard_add_node(struct bNode *node); void BKE_node_clipboard_add_link(struct bNodeLink *link); const struct ListBase *BKE_node_clipboard_get_nodes(void); const struct ListBase *BKE_node_clipboard_get_links(void); int BKE_node_clipboard_get_type(void); /** * Node Instance Hash. */ typedef struct bNodeInstanceHash { /** XXX should be made a direct member, #GHash allocation needs to support it */ GHash *ghash; } bNodeInstanceHash; typedef void (*bNodeInstanceValueFP)(void *value); /** * Magic number for initial hash key. */ extern const bNodeInstanceKey NODE_INSTANCE_KEY_BASE; extern const bNodeInstanceKey NODE_INSTANCE_KEY_NONE; bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, const struct bNodeTree *ntree, const struct bNode *node); bNodeInstanceHash *BKE_node_instance_hash_new(const char *info); void BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp); void BKE_node_instance_hash_insert(bNodeInstanceHash *hash, bNodeInstanceKey key, void *value); void *BKE_node_instance_hash_lookup(bNodeInstanceHash *hash, bNodeInstanceKey key); int BKE_node_instance_hash_remove(bNodeInstanceHash *hash, bNodeInstanceKey key, bNodeInstanceValueFP valfreefp); void BKE_node_instance_hash_clear(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp); void *BKE_node_instance_hash_pop(bNodeInstanceHash *hash, bNodeInstanceKey key); int BKE_node_instance_hash_haskey(bNodeInstanceHash *hash, bNodeInstanceKey key); int BKE_node_instance_hash_size(bNodeInstanceHash *hash); void BKE_node_instance_hash_clear_tags(bNodeInstanceHash *hash); void BKE_node_instance_hash_tag(bNodeInstanceHash *hash, void *value); bool BKE_node_instance_hash_tag_key(bNodeInstanceHash *hash, bNodeInstanceKey key); void BKE_node_instance_hash_remove_untagged(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp); typedef GHashIterator bNodeInstanceHashIterator; BLI_INLINE bNodeInstanceHashIterator *BKE_node_instance_hash_iterator_new(bNodeInstanceHash *hash) { return BLI_ghashIterator_new(hash->ghash); } BLI_INLINE void BKE_node_instance_hash_iterator_init(bNodeInstanceHashIterator *iter, bNodeInstanceHash *hash) { BLI_ghashIterator_init(iter, hash->ghash); } BLI_INLINE void BKE_node_instance_hash_iterator_free(bNodeInstanceHashIterator *iter) { BLI_ghashIterator_free(iter); } BLI_INLINE bNodeInstanceKey BKE_node_instance_hash_iterator_get_key(bNodeInstanceHashIterator *iter) { return *(bNodeInstanceKey *)BLI_ghashIterator_getKey(iter); } BLI_INLINE void *BKE_node_instance_hash_iterator_get_value(bNodeInstanceHashIterator *iter) { return BLI_ghashIterator_getValue(iter); } BLI_INLINE void BKE_node_instance_hash_iterator_step(bNodeInstanceHashIterator *iter) { BLI_ghashIterator_step(iter); } BLI_INLINE bool BKE_node_instance_hash_iterator_done(bNodeInstanceHashIterator *iter) { return BLI_ghashIterator_done(iter); } #define NODE_INSTANCE_HASH_ITER(iter_, hash_) \ for (BKE_node_instance_hash_iterator_init(&iter_, hash_); \ BKE_node_instance_hash_iterator_done(&iter_) == false; \ BKE_node_instance_hash_iterator_step(&iter_)) /* Node Previews */ bool BKE_node_preview_used(const struct bNode *node); bNodePreview *BKE_node_preview_verify( struct bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create); bNodePreview *BKE_node_preview_copy(struct bNodePreview *preview); void BKE_node_preview_free(struct bNodePreview *preview); void BKE_node_preview_init_tree(struct bNodeTree *ntree, int xsize, int ysize); void BKE_node_preview_remove_unused(struct bNodeTree *ntree); void BKE_node_preview_clear(struct bNodePreview *preview); void BKE_node_preview_clear_tree(struct bNodeTree *ntree); void BKE_node_preview_merge_tree(struct bNodeTree *to_ntree, struct bNodeTree *from_ntree, bool remove_old); /** \} */ /* -------------------------------------------------------------------- */ /** \name Node Type Access * \{ */ void nodeLabel(const struct bNodeTree *ntree, const struct bNode *node, char *label, int maxlen); /** * Get node socket label if it is set. */ const char *nodeSocketLabel(const struct bNodeSocket *sock); bool nodeGroupPoll(struct bNodeTree *nodetree, struct bNodeTree *grouptree, const char **r_disabled_hint); /** * Initialize a new node type struct with default values and callbacks. */ void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); void node_type_base_custom(struct bNodeType *ntype, const char *idname, const char *name, short nclass); void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs); void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth); void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size); void node_type_init(struct bNodeType *ntype, void (*initfunc)(struct bNodeTree *ntree, struct bNode *node)); /** * \warning Nodes defining a storage type _must_ allocate this for new nodes. * Otherwise nodes will reload as undefined (T46619). */ void node_type_storage(struct bNodeType *ntype, const char *storagename, void (*freefunc)(struct bNode *node), void (*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node)); void node_type_update(struct bNodeType *ntype, void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node)); void node_type_group_update(struct bNodeType *ntype, void (*group_update_func)(struct bNodeTree *ntree, struct bNode *node)); void node_type_exec(struct bNodeType *ntype, NodeInitExecFunction init_exec_fn, NodeFreeExecFunction free_exec_fn, NodeExecFunction exec_fn); void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn); /** \} */ /* -------------------------------------------------------------------- */ /** \name Node Generic Functions * \{ */ bool BKE_node_is_connected_to_output(struct bNodeTree *ntree, struct bNode *node); /* ************** COMMON NODES *************** */ #define NODE_UNDEFINED -2 /* node type is not registered */ #define NODE_CUSTOM -1 /* for dynamically registered custom types */ #define NODE_GROUP 2 // #define NODE_FORLOOP 3 /* deprecated */ // #define NODE_WHILELOOP 4 /* deprecated */ #define NODE_FRAME 5 #define NODE_REROUTE 6 #define NODE_GROUP_INPUT 7 #define NODE_GROUP_OUTPUT 8 #define NODE_CUSTOM_GROUP 9 void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree); /** \} */ /* -------------------------------------------------------------------- */ /** \name Node Tree Iterator * * Utility macro for visiting every node tree in the library data, * including local bNodeTree blocks in other IDs. * This avoids the need for callback functions and allows executing code * in a single inner code block. * * Variables: * * - nodetree: * The actual bNodeTree data block. * Check nodetree->idname or nodetree->typeinfo to use only specific types. * * - id: * The owner of the bNodeTree data block. * Same as nodetree if it's a linkable node tree from the library. * * Examples: * * \code{.c} * FOREACH_NODETREE_BEGIN(bmain, nodetree, id) { * if (id == nodetree) * printf("This is a linkable node tree"); * } FOREACH_NODETREE_END; * * FOREACH_NODETREE_BEGIN(bmain, nodetree, id) { * if (nodetree->idname == "ShaderNodeTree") * printf("This is a shader node tree); * if (GS(id) == ID_MA) * printf(" and it's owned by a material"); * } FOREACH_NODETREE_END; * \endcode * * \{ */ /* should be an opaque type, only for internal use by BKE_node_tree_iter_*** */ struct NodeTreeIterStore { bNodeTree *ngroup; Scene *scene; struct Material *mat; Tex *tex; struct Light *light; struct World *world; struct FreestyleLineStyle *linestyle; struct Simulation *simulation; }; void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain); bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, struct bNodeTree **r_nodetree, struct ID **r_id); #define FOREACH_NODETREE_BEGIN(bmain, _nodetree, _id) \ { \ struct NodeTreeIterStore _nstore; \ bNodeTree *_nodetree; \ ID *_id; \ /* avoid compiler warning about unused variables */ \ BKE_node_tree_iter_init(&_nstore, bmain); \ while (BKE_node_tree_iter_step(&_nstore, &_nodetree, &_id) == true) { \ if (_nodetree) { #define FOREACH_NODETREE_END \ } \ } \ } \ ((void)0) /** \} */ /* -------------------------------------------------------------------- */ /** \name Node Tree */ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, int layer_index); /* -------------------------------------------------------------------- */ /** \name Shader Nodes * \{ */ /* NOTE: types are needed to restore callbacks, don't change values. */ //#define SH_NODE_MATERIAL 100 #define SH_NODE_RGB 101 #define SH_NODE_VALUE 102 #define SH_NODE_MIX_RGB_LEGACY 103 #define SH_NODE_VALTORGB 104 #define SH_NODE_RGBTOBW 105 #define SH_NODE_SHADERTORGB 106 //#define SH_NODE_TEXTURE 106 #define SH_NODE_NORMAL 107 //#define SH_NODE_GEOMETRY 108 #define SH_NODE_MAPPING 109 #define SH_NODE_CURVE_VEC 110 #define SH_NODE_CURVE_RGB 111 #define SH_NODE_CAMERA 114 #define SH_NODE_MATH 115 #define SH_NODE_VECTOR_MATH 116 #define SH_NODE_SQUEEZE 117 //#define SH_NODE_MATERIAL_EXT 118 #define SH_NODE_INVERT 119 #define SH_NODE_SEPRGB_LEGACY 120 #define SH_NODE_COMBRGB_LEGACY 121 #define SH_NODE_HUE_SAT 122 #define SH_NODE_OUTPUT_MATERIAL 124 #define SH_NODE_OUTPUT_WORLD 125 #define SH_NODE_OUTPUT_LIGHT 126 #define SH_NODE_FRESNEL 127 #define SH_NODE_MIX_SHADER 128 #define SH_NODE_ATTRIBUTE 129 #define SH_NODE_BACKGROUND 130 #define SH_NODE_BSDF_ANISOTROPIC 131 #define SH_NODE_BSDF_DIFFUSE 132 #define SH_NODE_BSDF_GLOSSY 133 #define SH_NODE_BSDF_GLASS 134 #define SH_NODE_BSDF_TRANSLUCENT 137 #define SH_NODE_BSDF_TRANSPARENT 138 #define SH_NODE_BSDF_VELVET 139 #define SH_NODE_EMISSION 140 #define SH_NODE_NEW_GEOMETRY 141 #define SH_NODE_LIGHT_PATH 142 #define SH_NODE_TEX_IMAGE 143 #define SH_NODE_TEX_SKY 145 #define SH_NODE_TEX_GRADIENT 146 #define SH_NODE_TEX_VORONOI 147 #define SH_NODE_TEX_MAGIC 148 #define SH_NODE_TEX_WAVE 149 #define SH_NODE_TEX_NOISE 150 #define SH_NODE_TEX_MUSGRAVE 152 #define SH_NODE_TEX_COORD 155 #define SH_NODE_ADD_SHADER 156 #define SH_NODE_TEX_ENVIRONMENT 157 // #define SH_NODE_OUTPUT_TEXTURE 158 #define SH_NODE_HOLDOUT 159 #define SH_NODE_LAYER_WEIGHT 160 #define SH_NODE_VOLUME_ABSORPTION 161 #define SH_NODE_VOLUME_SCATTER 162 #define SH_NODE_GAMMA 163 #define SH_NODE_TEX_CHECKER 164 #define SH_NODE_BRIGHTCONTRAST 165 #define SH_NODE_LIGHT_FALLOFF 166 #define SH_NODE_OBJECT_INFO 167 #define SH_NODE_PARTICLE_INFO 168 #define SH_NODE_TEX_BRICK 169 #define SH_NODE_BUMP 170 #define SH_NODE_SCRIPT 171 #define SH_NODE_AMBIENT_OCCLUSION 172 #define SH_NODE_BSDF_REFRACTION 173 #define SH_NODE_TANGENT 174 #define SH_NODE_NORMAL_MAP 175 #define SH_NODE_HAIR_INFO 176 #define SH_NODE_SUBSURFACE_SCATTERING 177 #define SH_NODE_WIREFRAME 178 #define SH_NODE_BSDF_TOON 179 #define SH_NODE_WAVELENGTH 180 #define SH_NODE_BLACKBODY 181 #define SH_NODE_VECT_TRANSFORM 182 #define SH_NODE_SEPHSV_LEGACY 183 #define SH_NODE_COMBHSV_LEGACY 184 #define SH_NODE_BSDF_HAIR 185 // #define SH_NODE_LAMP 186 #define SH_NODE_UVMAP 187 #define SH_NODE_SEPXYZ 188 #define SH_NODE_COMBXYZ 189 #define SH_NODE_OUTPUT_LINESTYLE 190 #define SH_NODE_UVALONGSTROKE 191 #define SH_NODE_TEX_POINTDENSITY 192 #define SH_NODE_BSDF_PRINCIPLED 193 #define SH_NODE_TEX_IES 194 #define SH_NODE_EEVEE_SPECULAR 195 #define SH_NODE_BEVEL 197 #define SH_NODE_DISPLACEMENT 198 #define SH_NODE_VECTOR_DISPLACEMENT 199 #define SH_NODE_VOLUME_PRINCIPLED 200 /* 201..700 occupied by other node types, continue from 701 */ #define SH_NODE_BSDF_HAIR_PRINCIPLED 701 #define SH_NODE_MAP_RANGE 702 #define SH_NODE_CLAMP 703 #define SH_NODE_TEX_WHITE_NOISE 704 #define SH_NODE_VOLUME_INFO 705 #define SH_NODE_VERTEX_COLOR 706 #define SH_NODE_OUTPUT_AOV 707 #define SH_NODE_VECTOR_ROTATE 708 #define SH_NODE_CURVE_FLOAT 709 #define SH_NODE_POINT_INFO 710 #define SH_NODE_COMBINE_COLOR 711 #define SH_NODE_SEPARATE_COLOR 712 #define SH_NODE_MIX 713 /** \} */ /* -------------------------------------------------------------------- */ /** \name Composite Nodes * \{ */ /* output socket defines */ #define RRES_OUT_IMAGE 0 #define RRES_OUT_ALPHA 1 /* NOTE: types are needed to restore callbacks, don't change values. */ #define CMP_NODE_VIEWER 201 #define CMP_NODE_RGB 202 #define CMP_NODE_VALUE 203 #define CMP_NODE_MIX_RGB 204 #define CMP_NODE_VALTORGB 205 #define CMP_NODE_RGBTOBW 206 #define CMP_NODE_NORMAL 207 #define CMP_NODE_CURVE_VEC 208 #define CMP_NODE_CURVE_RGB 209 #define CMP_NODE_ALPHAOVER 210 #define CMP_NODE_BLUR 211 #define CMP_NODE_FILTER 212 #define CMP_NODE_MAP_VALUE 213 #define CMP_NODE_TIME 214 #define CMP_NODE_VECBLUR 215 #define CMP_NODE_SEPRGBA_LEGACY 216 #define CMP_NODE_SEPHSVA_LEGACY 217 #define CMP_NODE_SETALPHA 218 #define CMP_NODE_HUE_SAT 219 #define CMP_NODE_IMAGE 220 #define CMP_NODE_R_LAYERS 221 #define CMP_NODE_COMPOSITE 222 #define CMP_NODE_OUTPUT_FILE 223 #define CMP_NODE_TEXTURE 224 #define CMP_NODE_TRANSLATE 225 #define CMP_NODE_ZCOMBINE 226 #define CMP_NODE_COMBRGBA_LEGACY 227 #define CMP_NODE_DILATEERODE 228 #define CMP_NODE_ROTATE 229 #define CMP_NODE_SCALE 230 #define CMP_NODE_SEPYCCA_LEGACY 231 #define CMP_NODE_COMBYCCA_LEGACY 232 #define CMP_NODE_SEPYUVA_LEGACY 233 #define CMP_NODE_COMBYUVA_LEGACY 234 #define CMP_NODE_DIFF_MATTE 235 #define CMP_NODE_COLOR_SPILL 236 #define CMP_NODE_CHROMA_MATTE 237 #define CMP_NODE_CHANNEL_MATTE 238 #define CMP_NODE_FLIP 239 #define CMP_NODE_SPLITVIEWER 240 // #define CMP_NODE_INDEX_MASK 241 #define CMP_NODE_MAP_UV 242 #define CMP_NODE_ID_MASK 243 #define CMP_NODE_DEFOCUS 244 #define CMP_NODE_DISPLACE 245 #define CMP_NODE_COMBHSVA_LEGACY 246 #define CMP_NODE_MATH 247 #define CMP_NODE_LUMA_MATTE 248 #define CMP_NODE_BRIGHTCONTRAST 249 #define CMP_NODE_GAMMA 250 #define CMP_NODE_INVERT 251 #define CMP_NODE_NORMALIZE 252 #define CMP_NODE_CROP 253 #define CMP_NODE_DBLUR 254 #define CMP_NODE_BILATERALBLUR 255 #define CMP_NODE_PREMULKEY 256 #define CMP_NODE_DIST_MATTE 257 #define CMP_NODE_VIEW_LEVELS 258 #define CMP_NODE_COLOR_MATTE 259 #define CMP_NODE_COLORBALANCE 260 #define CMP_NODE_HUECORRECT 261 #define CMP_NODE_MOVIECLIP 262 #define CMP_NODE_STABILIZE2D 263 #define CMP_NODE_TRANSFORM 264 #define CMP_NODE_MOVIEDISTORTION 265 #define CMP_NODE_DOUBLEEDGEMASK 266 #define CMP_NODE_OUTPUT_MULTI_FILE__DEPRECATED \ 267 /* DEPRECATED multi file node has been merged into regular CMP_NODE_OUTPUT_FILE */ #define CMP_NODE_MASK 268 #define CMP_NODE_KEYINGSCREEN 269 #define CMP_NODE_KEYING 270 #define CMP_NODE_TRACKPOS 271 #define CMP_NODE_INPAINT 272 #define CMP_NODE_DESPECKLE 273 #define CMP_NODE_ANTIALIASING 274 #define CMP_NODE_GLARE 301 #define CMP_NODE_TONEMAP 302 #define CMP_NODE_LENSDIST 303 #define CMP_NODE_SUNBEAMS 304 #define CMP_NODE_COLORCORRECTION 312 #define CMP_NODE_MASK_BOX 313 #define CMP_NODE_MASK_ELLIPSE 314 #define CMP_NODE_BOKEHIMAGE 315 #define CMP_NODE_BOKEHBLUR 316 #define CMP_NODE_SWITCH 317 #define CMP_NODE_PIXELATE 318 #define CMP_NODE_MAP_RANGE 319 #define CMP_NODE_PLANETRACKDEFORM 320 #define CMP_NODE_CORNERPIN 321 #define CMP_NODE_SWITCH_VIEW 322 #define CMP_NODE_CRYPTOMATTE_LEGACY 323 #define CMP_NODE_DENOISE 324 #define CMP_NODE_EXPOSURE 325 #define CMP_NODE_CRYPTOMATTE 326 #define CMP_NODE_POSTERIZE 327 #define CMP_NODE_CONVERT_COLOR_SPACE 328 #define CMP_NODE_SCENE_TIME 329 #define CMP_NODE_SEPARATE_XYZ 330 #define CMP_NODE_COMBINE_XYZ 331 #define CMP_NODE_COMBINE_COLOR 332 #define CMP_NODE_SEPARATE_COLOR 333 /* channel toggles */ #define CMP_CHAN_RGB 1 #define CMP_CHAN_A 2 /* track position node, in custom1 */ #define CMP_TRACKPOS_ABSOLUTE 0 #define CMP_TRACKPOS_RELATIVE_START 1 #define CMP_TRACKPOS_RELATIVE_FRAME 2 #define CMP_TRACKPOS_ABSOLUTE_FRAME 3 /* Cryptomatte source. */ #define CMP_CRYPTOMATTE_SRC_RENDER 0 #define CMP_CRYPTOMATTE_SRC_IMAGE 1 /* Default SMAA configuration values. */ #define CMP_DEFAULT_SMAA_THRESHOLD 1.0f #define CMP_DEFAULT_SMAA_CONTRAST_LIMIT 0.2f #define CMP_DEFAULT_SMAA_CORNER_ROUNDING 0.25f /** \} */ /* -------------------------------------------------------------------- */ /** \name Texture Nodes * \{ */ struct TexResult; #define TEX_NODE_OUTPUT 401 #define TEX_NODE_CHECKER 402 #define TEX_NODE_TEXTURE 403 #define TEX_NODE_BRICKS 404 #define TEX_NODE_MATH 405 #define TEX_NODE_MIX_RGB 406 #define TEX_NODE_RGBTOBW 407 #define TEX_NODE_VALTORGB 408 #define TEX_NODE_IMAGE 409 #define TEX_NODE_CURVE_RGB 410 #define TEX_NODE_INVERT 411 #define TEX_NODE_HUE_SAT 412 #define TEX_NODE_CURVE_TIME 413 #define TEX_NODE_ROTATE 414 #define TEX_NODE_VIEWER 415 #define TEX_NODE_TRANSLATE 416 #define TEX_NODE_COORD 417 #define TEX_NODE_DISTANCE 418 #define TEX_NODE_COMPOSE_LEGACY 419 #define TEX_NODE_DECOMPOSE_LEGACY 420 #define TEX_NODE_VALTONOR 421 #define TEX_NODE_SCALE 422 #define TEX_NODE_AT 423 #define TEX_NODE_COMBINE_COLOR 424 #define TEX_NODE_SEPARATE_COLOR 425 /* 501-599 reserved. Use like this: TEX_NODE_PROC + TEX_CLOUDS, etc */ #define TEX_NODE_PROC 500 #define TEX_NODE_PROC_MAX 600 /** \} */ /* -------------------------------------------------------------------- */ /** \name Geometry Nodes * \{ */ #define GEO_NODE_TRIANGULATE 1000 #define GEO_NODE_TRANSFORM 1002 #define GEO_NODE_MESH_BOOLEAN 1003 #define GEO_NODE_OBJECT_INFO 1007 #define GEO_NODE_JOIN_GEOMETRY 1010 #define GEO_NODE_COLLECTION_INFO 1023 #define GEO_NODE_IS_VIEWPORT 1024 #define GEO_NODE_SUBDIVIDE_MESH 1029 #define GEO_NODE_MESH_PRIMITIVE_CUBE 1032 #define GEO_NODE_MESH_PRIMITIVE_CIRCLE 1033 #define GEO_NODE_MESH_PRIMITIVE_UV_SPHERE 1034 #define GEO_NODE_MESH_PRIMITIVE_CYLINDER 1035 #define GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE 1036 #define GEO_NODE_MESH_PRIMITIVE_CONE 1037 #define GEO_NODE_MESH_PRIMITIVE_LINE 1038 #define GEO_NODE_MESH_PRIMITIVE_GRID 1039 #define GEO_NODE_BOUNDING_BOX 1042 #define GEO_NODE_SWITCH 1043 #define GEO_NODE_CURVE_TO_MESH 1045 #define GEO_NODE_RESAMPLE_CURVE 1047 #define GEO_NODE_INPUT_MATERIAL 1050 #define GEO_NODE_REPLACE_MATERIAL 1051 #define GEO_NODE_CURVE_LENGTH 1054 #define GEO_NODE_CONVEX_HULL 1056 #define GEO_NODE_SEPARATE_COMPONENTS 1059 #define GEO_NODE_CURVE_PRIMITIVE_STAR 1062 #define GEO_NODE_CURVE_PRIMITIVE_SPIRAL 1063 #define GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER 1064 #define GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT 1065 #define GEO_NODE_CURVE_PRIMITIVE_CIRCLE 1066 #define GEO_NODE_VIEWER 1067 #define GEO_NODE_CURVE_PRIMITIVE_LINE 1068 #define GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL 1070 #define GEO_NODE_TRIM_CURVE 1071 #define GEO_NODE_FILL_CURVE 1075 #define GEO_NODE_INPUT_POSITION 1076 #define GEO_NODE_SET_POSITION 1077 #define GEO_NODE_INPUT_INDEX 1078 #define GEO_NODE_INPUT_NORMAL 1079 #define GEO_NODE_CAPTURE_ATTRIBUTE 1080 #define GEO_NODE_MATERIAL_SELECTION 1081 #define GEO_NODE_SET_MATERIAL 1082 #define GEO_NODE_REALIZE_INSTANCES 1083 #define GEO_NODE_ATTRIBUTE_STATISTIC 1084 #define GEO_NODE_SAMPLE_CURVE 1085 #define GEO_NODE_INPUT_TANGENT 1086 #define GEO_NODE_STRING_JOIN 1087 #define GEO_NODE_CURVE_SPLINE_PARAMETER 1088 #define GEO_NODE_FILLET_CURVE 1089 #define GEO_NODE_DISTRIBUTE_POINTS_ON_FACES 1090 #define GEO_NODE_STRING_TO_CURVES 1091 #define GEO_NODE_INSTANCE_ON_POINTS 1092 #define GEO_NODE_MESH_TO_POINTS 1093 #define GEO_NODE_POINTS_TO_VERTICES 1094 #define GEO_NODE_REVERSE_CURVE 1095 #define GEO_NODE_PROXIMITY 1096 #define GEO_NODE_SUBDIVIDE_CURVE 1097 #define GEO_NODE_INPUT_SPLINE_LENGTH 1098 #define GEO_NODE_CURVE_SPLINE_TYPE 1099 #define GEO_NODE_CURVE_SET_HANDLE_TYPE 1100 #define GEO_NODE_POINTS_TO_VOLUME 1101 #define GEO_NODE_CURVE_HANDLE_TYPE_SELECTION 1102 #define GEO_NODE_DELETE_GEOMETRY 1103 #define GEO_NODE_SEPARATE_GEOMETRY 1104 #define GEO_NODE_INPUT_RADIUS 1105 #define GEO_NODE_INPUT_CURVE_TILT 1106 #define GEO_NODE_INPUT_CURVE_HANDLES 1107 #define GEO_NODE_INPUT_SHADE_SMOOTH 1108 #define GEO_NODE_INPUT_SPLINE_RESOLUTION 1109 #define GEO_NODE_INPUT_SPLINE_CYCLIC 1110 #define GEO_NODE_SET_CURVE_RADIUS 1111 #define GEO_NODE_SET_CURVE_TILT 1112 #define GEO_NODE_SET_CURVE_HANDLES 1113 #define GEO_NODE_SET_SHADE_SMOOTH 1114 #define GEO_NODE_SET_SPLINE_RESOLUTION 1115 #define GEO_NODE_SET_SPLINE_CYCLIC 1116 #define GEO_NODE_SET_POINT_RADIUS 1117 #define GEO_NODE_INPUT_MATERIAL_INDEX 1118 #define GEO_NODE_SET_MATERIAL_INDEX 1119 #define GEO_NODE_TRANSLATE_INSTANCES 1120 #define GEO_NODE_SCALE_INSTANCES 1121 #define GEO_NODE_ROTATE_INSTANCES 1122 #define GEO_NODE_SPLIT_EDGES 1123 #define GEO_NODE_MESH_TO_CURVE 1124 #define GEO_NODE_TRANSFER_ATTRIBUTE 1125 #define GEO_NODE_SUBDIVISION_SURFACE 1126 #define GEO_NODE_CURVE_ENDPOINT_SELECTION 1127 #define GEO_NODE_RAYCAST 1128 #define GEO_NODE_CURVE_TO_POINTS 1130 #define GEO_NODE_INSTANCES_TO_POINTS 1131 #define GEO_NODE_IMAGE_TEXTURE 1132 #define GEO_NODE_VOLUME_TO_MESH 1133 #define GEO_NODE_INPUT_ID 1134 #define GEO_NODE_SET_ID 1135 #define GEO_NODE_ATTRIBUTE_DOMAIN_SIZE 1136 #define GEO_NODE_DUAL_MESH 1137 #define GEO_NODE_INPUT_MESH_EDGE_VERTICES 1138 #define GEO_NODE_INPUT_MESH_FACE_AREA 1139 #define GEO_NODE_INPUT_MESH_FACE_NEIGHBORS 1140 #define GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS 1141 #define GEO_NODE_GEOMETRY_TO_INSTANCE 1142 #define GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS 1143 #define GEO_NODE_INPUT_MESH_ISLAND 1144 #define GEO_NODE_INPUT_SCENE_TIME 1145 #define GEO_NODE_ACCUMULATE_FIELD 1146 #define GEO_NODE_INPUT_MESH_EDGE_ANGLE 1147 #define GEO_NODE_FIELD_AT_INDEX 1148 #define GEO_NODE_CURVE_PRIMITIVE_ARC 1149 #define GEO_NODE_FLIP_FACES 1150 #define GEO_NODE_SCALE_ELEMENTS 1151 #define GEO_NODE_EXTRUDE_MESH 1152 #define GEO_NODE_MERGE_BY_DISTANCE 1153 #define GEO_NODE_DUPLICATE_ELEMENTS 1154 #define GEO_NODE_INPUT_MESH_FACE_IS_PLANAR 1155 #define GEO_NODE_STORE_NAMED_ATTRIBUTE 1156 #define GEO_NODE_INPUT_NAMED_ATTRIBUTE 1157 #define GEO_NODE_REMOVE_ATTRIBUTE 1158 #define GEO_NODE_INPUT_INSTANCE_ROTATION 1159 #define GEO_NODE_INPUT_INSTANCE_SCALE 1160 #define GEO_NODE_VOLUME_CUBE 1161 #define GEO_NODE_POINTS 1162 #define GEO_NODE_INTERPOLATE_DOMAIN 1163 #define GEO_NODE_MESH_TO_VOLUME 1164 #define GEO_NODE_UV_UNWRAP 1165 #define GEO_NODE_UV_PACK_ISLANDS 1166 #define GEO_NODE_DEFORM_CURVES_ON_SURFACE 1167 #define GEO_NODE_INPUT_SHORTEST_EDGE_PATHS 1168 #define GEO_NODE_EDGE_PATHS_TO_CURVES 1169 #define GEO_NODE_EDGE_PATHS_TO_SELECTION 1170 +#define GEO_NODE_SMOOTH_ATTRIBUTE 1171 /** \} */ /* -------------------------------------------------------------------- */ /** \name Function Nodes * \{ */ #define FN_NODE_BOOLEAN_MATH 1200 #define FN_NODE_COMPARE 1202 #define FN_NODE_LEGACY_RANDOM_FLOAT 1206 #define FN_NODE_INPUT_VECTOR 1207 #define FN_NODE_INPUT_STRING 1208 #define FN_NODE_FLOAT_TO_INT 1209 #define FN_NODE_VALUE_TO_STRING 1210 #define FN_NODE_STRING_LENGTH 1211 #define FN_NODE_SLICE_STRING 1212 #define FN_NODE_INPUT_SPECIAL_CHARACTERS 1213 #define FN_NODE_RANDOM_VALUE 1214 #define FN_NODE_ROTATE_EULER 1215 #define FN_NODE_ALIGN_EULER_TO_VECTOR 1216 #define FN_NODE_INPUT_COLOR 1217 #define FN_NODE_REPLACE_STRING 1218 #define FN_NODE_INPUT_BOOL 1219 #define FN_NODE_INPUT_INT 1220 #define FN_NODE_SEPARATE_COLOR 1221 #define FN_NODE_COMBINE_COLOR 1222 /** \} */ void BKE_node_system_init(void); void BKE_node_system_exit(void); extern struct bNodeType NodeTypeUndefined; extern struct bNodeSocketType NodeSocketTypeUndefined; #ifdef __cplusplus } #endif #ifdef __cplusplus namespace blender::bke { bNodeSocket *node_find_enabled_socket(bNode &node, eNodeSocketInOut in_out, StringRef name); bNodeSocket *node_find_enabled_input_socket(bNode &node, StringRef name); bNodeSocket *node_find_enabled_output_socket(bNode &node, StringRef name); } // namespace blender::bke #endif #define NODE_STORAGE_FUNCS(StorageT) \ [[maybe_unused]] static StorageT &node_storage(bNode &node) \ { \ return *static_cast(node.storage); \ } \ [[maybe_unused]] static const StorageT &node_storage(const bNode &node) \ { \ return *static_cast(node.storage); \ } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index b82cf30416a..6f92128b163 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -1,4975 +1,4976 @@ /* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2005 Blender Foundation. All rights reserved. */ /** \file * \ingroup bke */ #include "CLG_log.h" #include "MEM_guardedalloc.h" #include #include #include #include /* Allow using deprecated functionality for .blend file I/O. */ #define DNA_DEPRECATED_ALLOW #include "DNA_action_types.h" #include "DNA_anim_types.h" #include "DNA_collection_types.h" #include "DNA_gpencil_types.h" #include "DNA_light_types.h" #include "DNA_linestyle_types.h" #include "DNA_material_types.h" #include "DNA_modifier_types.h" #include "DNA_node_types.h" #include "DNA_scene_types.h" #include "DNA_simulation_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" #include "BLI_color.hh" #include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_map.hh" #include "BLI_path_util.h" #include "BLI_set.hh" #include "BLI_stack.hh" #include "BLI_string.h" #include "BLI_string_utils.h" #include "BLI_threads.h" #include "BLI_utildefines.h" #include "BLI_vector_set.hh" #include "BLT_translation.h" #include "BKE_anim_data.h" #include "BKE_animsys.h" #include "BKE_bpath.h" #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_cryptomatte.h" #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_image_format.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" #include "RNA_access.h" #include "RNA_define.h" #include "RNA_prototypes.h" #include "NOD_common.h" #include "NOD_composite.h" #include "NOD_function.h" #include "NOD_geometry.h" #include "NOD_geometry_nodes_lazy_function.hh" #include "NOD_node_declaration.hh" #include "NOD_shader.h" #include "NOD_socket.h" #include "NOD_texture.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" #include "BLO_read_write.h" #include "MOD_nodes.h" #define NODE_DEFAULT_MAX_WIDTH 700 using blender::Array; using blender::Map; using blender::MutableSpan; using blender::Set; using blender::Span; using blender::Stack; using blender::StringRef; using blender::Vector; using blender::VectorSet; using blender::bke::bNodeRuntime; using blender::bke::bNodeSocketRuntime; using blender::bke::bNodeTreeRuntime; using blender::nodes::FieldInferencingInterface; using blender::nodes::InputSocketFieldType; using blender::nodes::NodeDeclaration; using blender::nodes::OutputFieldDependency; using blender::nodes::OutputSocketFieldType; using blender::nodes::SocketDeclaration; /* Fallback types for undefined tree, nodes, sockets */ static bNodeTreeType NodeTreeTypeUndefined; bNodeType NodeTypeUndefined; bNodeSocketType NodeSocketTypeUndefined; static CLG_LogRef LOG = {"bke.node"}; static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo); static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag); static void free_localized_node_groups(bNodeTree *ntree); static void node_free_node(bNodeTree *ntree, bNode *node); static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool do_id_user); static void ntree_init_data(ID *id) { bNodeTree *ntree = (bNodeTree *)id; ntree->runtime = MEM_new(__func__); ntree_set_typeinfo(ntree, nullptr); } static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) { bNodeTree *ntree_dst = (bNodeTree *)id_dst; const bNodeTree *ntree_src = (const bNodeTree *)id_src; /* We never handle usercount here for own data. */ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; ntree_dst->runtime = MEM_new(__func__); /* in case a running nodetree is copied */ ntree_dst->execdata = nullptr; BLI_listbase_clear(&ntree_dst->nodes); BLI_listbase_clear(&ntree_dst->links); Map node_map; Map socket_map; BLI_listbase_clear(&ntree_dst->nodes); LISTBASE_FOREACH (const bNode *, src_node, &ntree_src->nodes) { /* Don't find a unique name for every node, since they should have valid names already. */ bNode *new_node = blender::bke::node_copy_with_mapping( ntree_dst, *src_node, flag_subdata, false, socket_map); node_map.add(src_node, new_node); } /* copy links */ BLI_listbase_clear(&ntree_dst->links); LISTBASE_FOREACH (const bNodeLink *, src_link, &ntree_src->links) { bNodeLink *dst_link = (bNodeLink *)MEM_dupallocN(src_link); dst_link->fromnode = node_map.lookup(src_link->fromnode); dst_link->fromsock = socket_map.lookup(src_link->fromsock); dst_link->tonode = node_map.lookup(src_link->tonode); dst_link->tosock = socket_map.lookup(src_link->tosock); BLI_assert(dst_link->tosock); dst_link->tosock->link = dst_link; BLI_addtail(&ntree_dst->links, dst_link); } /* copy interface sockets */ BLI_listbase_clear(&ntree_dst->inputs); LISTBASE_FOREACH (const bNodeSocket *, src_socket, &ntree_src->inputs) { bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket); node_socket_copy(dst_socket, src_socket, flag_subdata); BLI_addtail(&ntree_dst->inputs, dst_socket); } BLI_listbase_clear(&ntree_dst->outputs); LISTBASE_FOREACH (const bNodeSocket *, src_socket, &ntree_src->outputs) { bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket); node_socket_copy(dst_socket, src_socket, flag_subdata); BLI_addtail(&ntree_dst->outputs, dst_socket); } /* copy preview hash */ if (ntree_src->previews && (flag & LIB_ID_COPY_NO_PREVIEW) == 0) { bNodeInstanceHashIterator iter; ntree_dst->previews = BKE_node_instance_hash_new("node previews"); NODE_INSTANCE_HASH_ITER (iter, ntree_src->previews) { bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); BKE_node_instance_hash_insert(ntree_dst->previews, key, BKE_node_preview_copy(preview)); } } else { ntree_dst->previews = nullptr; } /* update node->parent pointers */ LISTBASE_FOREACH (bNode *, new_node, &ntree_dst->nodes) { if (new_node->parent) { new_node->parent = node_map.lookup(new_node->parent); } } /* node tree will generate its own interface type */ ntree_dst->interface_type = nullptr; if (ntree_src->runtime->field_inferencing_interface) { ntree_dst->runtime->field_inferencing_interface = std::make_unique( *ntree_src->runtime->field_inferencing_interface); } if (flag & LIB_ID_COPY_NO_PREVIEW) { ntree_dst->preview = nullptr; } else { BKE_previewimg_id_copy(&ntree_dst->id, &ntree_src->id); } } static void ntree_free_data(ID *id) { bNodeTree *ntree = (bNodeTree *)id; /* XXX hack! node trees should not store execution graphs at all. * This should be removed when old tree types no longer require it. * Currently the execution data for texture nodes remains in the tree * after execution, until the node tree is updated or freed. */ if (ntree->execdata) { switch (ntree->type) { case NTREE_SHADER: ntreeShaderEndExecTree(ntree->execdata); break; case NTREE_TEXTURE: ntreeTexEndExecTree(ntree->execdata); ntree->execdata = nullptr; break; } } /* XXX not nice, but needed to free localized node groups properly */ free_localized_node_groups(ntree); /* Unregister associated RNA types. */ ntreeInterfaceTypeFree(ntree); BLI_freelistN(&ntree->links); LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) { node_free_node(ntree, node); } /* free interface sockets */ LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &ntree->inputs) { node_socket_interface_free(ntree, sock, false); MEM_freeN(sock); } LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &ntree->outputs) { node_socket_interface_free(ntree, sock, false); MEM_freeN(sock); } /* free preview hash */ if (ntree->previews) { BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); } if (ntree->id.tag & LIB_TAG_LOCALIZED) { BKE_libblock_free_data(&ntree->id, true); } BKE_previewimg_free(&ntree->preview); MEM_delete(ntree->runtime); } static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock) { BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( data, IDP_foreach_property( sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data)); switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER); break; } case SOCK_IMAGE: { bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER); break; } case SOCK_COLLECTION: { bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) sock->default_value; BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER); break; } case SOCK_TEXTURE: { bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value; BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER); break; } case SOCK_MATERIAL: { bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value; BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value->value, IDWALK_CB_USER); break; } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: case SOCK_BOOLEAN: case SOCK_INT: case SOCK_STRING: case __SOCK_MESH: case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: break; } } static void node_foreach_id(ID *id, LibraryForeachIDData *data) { bNodeTree *ntree = (bNodeTree *)id; BKE_LIB_FOREACHID_PROCESS_ID(data, ntree->owner_id, IDWALK_CB_LOOPBACK); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, ntree->gpd, IDWALK_CB_USER); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { BKE_LIB_FOREACHID_PROCESS_ID(data, node->id, IDWALK_CB_USER); BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( data, IDP_foreach_property(node->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data)); LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } } static void node_foreach_cache(ID *id, IDTypeForeachCacheFunctionCallback function_callback, void *user_data) { bNodeTree *nodetree = (bNodeTree *)id; IDCacheKey key = {0}; key.id_session_uuid = id->session_uuid; key.offset_in_ID = offsetof(bNodeTree, previews); /* TODO: see also `direct_link_nodetree()` in readfile.c. */ #if 0 function_callback(id, &key, (void **)&nodetree->previews, 0, user_data); #endif if (nodetree->type == NTREE_COMPOSIT) { LISTBASE_FOREACH (bNode *, node, &nodetree->nodes) { if (node->type == CMP_NODE_MOVIEDISTORTION) { key.offset_in_ID = (size_t)BLI_ghashutil_strhash_p(node->name); function_callback(id, &key, (void **)&node->storage, 0, user_data); } } } } static void node_foreach_path(ID *id, BPathForeachPathData *bpath_data) { bNodeTree *ntree = reinterpret_cast(id); switch (ntree->type) { case NTREE_SHADER: { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == SH_NODE_SCRIPT) { NodeShaderScript *nss = reinterpret_cast(node->storage); BKE_bpath_foreach_path_fixed_process(bpath_data, nss->filepath); } else if (node->type == SH_NODE_TEX_IES) { NodeShaderTexIES *ies = reinterpret_cast(node->storage); BKE_bpath_foreach_path_fixed_process(bpath_data, ies->filepath); } } break; } default: break; } } static ID **node_owner_pointer_get(ID *id) { if ((id->flag & LIB_EMBEDDED_DATA) == 0) { return NULL; } /* TODO: Sort this NO_MAIN or not for embedded node trees. See T86119. */ // BLI_assert((id->tag & LIB_TAG_NO_MAIN) == 0); bNodeTree *ntree = reinterpret_cast(id); BLI_assert(ntree->owner_id != NULL); BLI_assert(ntreeFromID(ntree->owner_id) == ntree); return &ntree->owner_id; } static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *sock) { if (sock->default_value == nullptr) { return; } switch ((eNodeSocketDatatype)sock->type) { case SOCK_FLOAT: BLO_write_struct(writer, bNodeSocketValueFloat, sock->default_value); break; case SOCK_VECTOR: BLO_write_struct(writer, bNodeSocketValueVector, sock->default_value); break; case SOCK_RGBA: BLO_write_struct(writer, bNodeSocketValueRGBA, sock->default_value); break; case SOCK_BOOLEAN: BLO_write_struct(writer, bNodeSocketValueBoolean, sock->default_value); break; case SOCK_INT: BLO_write_struct(writer, bNodeSocketValueInt, sock->default_value); break; case SOCK_STRING: BLO_write_struct(writer, bNodeSocketValueString, sock->default_value); break; case SOCK_OBJECT: BLO_write_struct(writer, bNodeSocketValueObject, sock->default_value); break; case SOCK_IMAGE: BLO_write_struct(writer, bNodeSocketValueImage, sock->default_value); break; case SOCK_COLLECTION: BLO_write_struct(writer, bNodeSocketValueCollection, sock->default_value); break; case SOCK_TEXTURE: BLO_write_struct(writer, bNodeSocketValueTexture, sock->default_value); break; case SOCK_MATERIAL: BLO_write_struct(writer, bNodeSocketValueMaterial, sock->default_value); break; case SOCK_CUSTOM: /* Custom node sockets where default_value is defined uses custom properties for storage. */ break; case __SOCK_MESH: case SOCK_SHADER: case SOCK_GEOMETRY: BLI_assert_unreachable(); break; } } static void write_node_socket(BlendWriter *writer, bNodeSocket *sock) { BLO_write_struct(writer, bNodeSocket, sock); if (sock->prop) { IDP_BlendWrite(writer, sock->prop); } /* This property should only be used for group node "interface" sockets. */ BLI_assert(sock->default_attribute_name == nullptr); write_node_socket_default_value(writer, sock); } static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock) { BLO_write_struct(writer, bNodeSocket, sock); if (sock->prop) { IDP_BlendWrite(writer, sock->prop); } BLO_write_string(writer, sock->default_attribute_name); write_node_socket_default_value(writer, sock); } void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) { BKE_id_blend_write(writer, &ntree->id); if (ntree->adt) { BKE_animdata_blend_write(writer, ntree->adt); } LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { BLO_write_struct(writer, bNode, node); if (node->prop) { IDP_BlendWrite(writer, node->prop); } LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { write_node_socket(writer, sock); } LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { write_node_socket(writer, sock); } LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { BLO_write_struct(writer, bNodeLink, link); } if (node->storage) { if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) && ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) { BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage); } else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) { NodeShaderScript *nss = (NodeShaderScript *)node->storage; if (nss->bytecode) { BLO_write_string(writer, nss->bytecode); } BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); } else if ((ntree->type == NTREE_COMPOSIT) && ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) { BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage); } else if ((ntree->type == NTREE_TEXTURE) && ELEM(node->type, TEX_NODE_CURVE_RGB, TEX_NODE_CURVE_TIME)) { BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage); } else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_MOVIEDISTORTION)) { /* pass */ } else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_GLARE)) { /* Simple forward compatibility for fix for T50736. * Not ideal (there is no ideal solution here), but should do for now. */ NodeGlare *ndg = (NodeGlare *)node->storage; /* Not in undo case. */ if (!BLO_write_is_undo(writer)) { switch (ndg->type) { case 2: /* Grrrr! magic numbers :( */ ndg->angle = ndg->streaks; break; case 0: ndg->angle = ndg->star_45; break; default: break; } } BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); } else if ((ntree->type == NTREE_COMPOSIT) && ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY)) { NodeCryptomatte *nc = (NodeCryptomatte *)node->storage; 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); } else if (node->type == FN_NODE_INPUT_STRING) { NodeInputString *storage = (NodeInputString *)node->storage; if (storage->string) { BLO_write_string(writer, storage->string); } BLO_write_struct_by_name(writer, node->typeinfo->storagename, storage); } else if (node->typeinfo != &NodeTypeUndefined) { BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); } } if (node->type == CMP_NODE_OUTPUT_FILE) { /* Inputs have their own storage data. */ NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage; BKE_image_format_blend_write(writer, &nimf->format); LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage; BLO_write_struct(writer, NodeImageMultiFileSocket, sockdata); BKE_image_format_blend_write(writer, &sockdata->format); } } if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) { /* Write extra socket info. */ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { BLO_write_struct(writer, NodeImageLayer, sock->storage); } } } LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { BLO_write_struct(writer, bNodeLink, link); } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { write_node_socket_interface(writer, sock); } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { write_node_socket_interface(writer, sock); } BKE_previewimg_blend_write(writer, ntree->preview); } static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_address) { bNodeTree *ntree = (bNodeTree *)id; /* Clean up, important in undo case to reduce false detection of changed datablocks. */ ntree->is_updating = false; ntree->typeinfo = nullptr; ntree->interface_type = nullptr; ntree->progress = nullptr; ntree->execdata = nullptr; BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id); ntreeBlendWrite(writer, ntree); } static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) { BLO_read_data_address(reader, &sock->prop); IDP_BlendDataRead(reader, &sock->prop); BLO_read_data_address(reader, &sock->link); sock->typeinfo = nullptr; BLO_read_data_address(reader, &sock->storage); BLO_read_data_address(reader, &sock->default_value); BLO_read_data_address(reader, &sock->default_attribute_name); sock->total_inputs = 0; /* Clear runtime data set before drawing. */ sock->cache = nullptr; sock->runtime = MEM_new(__func__); } void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree) { /* Special case for this pointer, do not rely on regular `lib_link` process here. Avoids needs * for do_versioning, and ensures coherence of data in any case. * * NOTE: Old versions are very often 'broken' here, just fix it silently in these cases. */ if (BLO_read_fileversion_get(reader) > 300) { BLI_assert((ntree->id.flag & LIB_EMBEDDED_DATA) != 0 || owner_id == nullptr); } BLI_assert(owner_id == NULL || owner_id->lib == ntree->id.lib); if (owner_id != nullptr && (ntree->id.flag & LIB_EMBEDDED_DATA) == 0) { /* This is unfortunate, but currently a lot of existing files (including startup ones) have * missing `LIB_EMBEDDED_DATA` flag. * * NOTE: Using do_version is not a solution here, since this code will be called before any * do_version takes place. Keeping it here also ensures future (or unknown existing) similar * bugs won't go easily unnoticed. */ if (BLO_read_fileversion_get(reader) > 300) { CLOG_WARN(&LOG, "Fixing root node tree '%s' owned by '%s' missing EMBEDDED tag, please consider " "re-saving your (startup) file", ntree->id.name, owner_id->name); } ntree->id.flag |= LIB_EMBEDDED_DATA; } ntree->owner_id = owner_id; /* NOTE: writing and reading goes in sync, for speed. */ ntree->is_updating = false; ntree->typeinfo = nullptr; ntree->interface_type = nullptr; ntree->progress = nullptr; ntree->execdata = nullptr; ntree->runtime = MEM_new(__func__); BKE_ntree_update_tag_missing_runtime_data(ntree); BLO_read_data_address(reader, &ntree->adt); BKE_animdata_blend_read_data(reader, ntree->adt); BLO_read_list(reader, &ntree->nodes); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { node->runtime = MEM_new(__func__); node->typeinfo = nullptr; BLO_read_list(reader, &node->inputs); BLO_read_list(reader, &node->outputs); BLO_read_data_address(reader, &node->prop); IDP_BlendDataRead(reader, &node->prop); BLO_read_list(reader, &node->internal_links); LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { BLO_read_data_address(reader, &link->fromnode); BLO_read_data_address(reader, &link->fromsock); BLO_read_data_address(reader, &link->tonode); BLO_read_data_address(reader, &link->tosock); } if (node->type == CMP_NODE_MOVIEDISTORTION) { /* Do nothing, this is runtime cache and hence handled by generic code using * `IDTypeInfo.foreach_cache` callback. */ } else { BLO_read_data_address(reader, &node->storage); } if (node->storage) { switch (node->type) { case SH_NODE_CURVE_VEC: case SH_NODE_CURVE_RGB: case SH_NODE_CURVE_FLOAT: case CMP_NODE_TIME: case CMP_NODE_CURVE_VEC: case CMP_NODE_CURVE_RGB: case CMP_NODE_HUECORRECT: case TEX_NODE_CURVE_RGB: case TEX_NODE_CURVE_TIME: { BKE_curvemapping_blend_read(reader, (CurveMapping *)node->storage); break; } case SH_NODE_SCRIPT: { NodeShaderScript *nss = (NodeShaderScript *)node->storage; BLO_read_data_address(reader, &nss->bytecode); break; } case SH_NODE_TEX_POINTDENSITY: { NodeShaderTexPointDensity *npd = (NodeShaderTexPointDensity *)node->storage; npd->pd = blender::dna::shallow_zero_initialize(); break; } case SH_NODE_TEX_IMAGE: { NodeTexImage *tex = (NodeTexImage *)node->storage; tex->iuser.scene = nullptr; break; } case SH_NODE_TEX_ENVIRONMENT: { NodeTexEnvironment *tex = (NodeTexEnvironment *)node->storage; tex->iuser.scene = nullptr; break; } case CMP_NODE_IMAGE: case CMP_NODE_R_LAYERS: case CMP_NODE_VIEWER: case CMP_NODE_SPLITVIEWER: { ImageUser *iuser = (ImageUser *)node->storage; iuser->scene = nullptr; break; } case CMP_NODE_CRYPTOMATTE_LEGACY: case CMP_NODE_CRYPTOMATTE: { NodeCryptomatte *nc = (NodeCryptomatte *)node->storage; BLO_read_data_address(reader, &nc->matte_id); BLO_read_list(reader, &nc->entries); BLI_listbase_clear(&nc->runtime.layers); break; } case TEX_NODE_IMAGE: { ImageUser *iuser = (ImageUser *)node->storage; iuser->scene = nullptr; break; } case CMP_NODE_OUTPUT_FILE: { NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage; BKE_image_format_blend_read_data(reader, &nimf->format); break; } case FN_NODE_INPUT_STRING: { NodeInputString *storage = (NodeInputString *)node->storage; BLO_read_data_address(reader, &storage->string); break; } default: break; } } } BLO_read_list(reader, &ntree->links); /* and we connect the rest */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { BLO_read_data_address(reader, &node->parent); LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { direct_link_node_socket(reader, sock); } LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { direct_link_node_socket(reader, sock); } /* Socket storage. */ if (node->type == CMP_NODE_OUTPUT_FILE) { LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage; BKE_image_format_blend_read_data(reader, &sockdata->format); } } } /* interface socket lists */ BLO_read_list(reader, &ntree->inputs); BLO_read_list(reader, &ntree->outputs); LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { direct_link_node_socket(reader, sock); } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { direct_link_node_socket(reader, sock); } LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { BLO_read_data_address(reader, &link->fromnode); BLO_read_data_address(reader, &link->tonode); BLO_read_data_address(reader, &link->fromsock); BLO_read_data_address(reader, &link->tosock); } /* TODO: should be dealt by new generic cache handling of IDs... */ ntree->previews = nullptr; BLO_read_data_address(reader, &ntree->preview); BKE_previewimg_blend_read(reader, ntree->preview); /* type verification is in lib-link */ } static void ntree_blend_read_data(BlendDataReader *reader, ID *id) { bNodeTree *ntree = (bNodeTree *)id; ntreeBlendReadData(reader, nullptr, ntree); } static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSocket *sock) { IDP_BlendReadLib(reader, lib, sock->prop); /* This can happen for all socket types when a file is saved in an older version of Blender than * it was originally created in (T86298). Some socket types still require a default value. The * default value of those sockets will be created in `ntreeSetTypes`. */ if (sock->default_value == nullptr) { return; } switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; BLO_read_id_address(reader, lib, &default_value->value); break; } case SOCK_IMAGE: { bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; BLO_read_id_address(reader, lib, &default_value->value); break; } case SOCK_COLLECTION: { bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) sock->default_value; BLO_read_id_address(reader, lib, &default_value->value); break; } case SOCK_TEXTURE: { bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value; BLO_read_id_address(reader, lib, &default_value->value); break; } case SOCK_MATERIAL: { bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value; BLO_read_id_address(reader, lib, &default_value->value); break; } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: case SOCK_BOOLEAN: case SOCK_INT: case SOCK_STRING: case __SOCK_MESH: case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: break; } } static void lib_link_node_sockets(BlendLibReader *reader, Library *lib, ListBase *sockets) { LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { lib_link_node_socket(reader, lib, sock); } } void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree) { Library *lib = ntree->id.lib; BLO_read_id_address(reader, lib, &ntree->gpd); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this. */ IDP_BlendReadLib(reader, lib, node->prop); BLO_read_id_address(reader, lib, &node->id); lib_link_node_sockets(reader, lib, &node->inputs); lib_link_node_sockets(reader, lib, &node->outputs); } lib_link_node_sockets(reader, lib, &ntree->inputs); lib_link_node_sockets(reader, lib, &ntree->outputs); /* Set `node->typeinfo` pointers. This is done in lib linking, after the * first versioning that can change types still without functions that * update the `typeinfo` pointers. Versioning after lib linking needs * these top be valid. */ ntreeSetTypes(nullptr, ntree); /* For nodes with static socket layout, add/remove sockets as needed * to match the static layout. */ if (!BLO_read_lib_is_undo(reader)) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { node_verify_sockets(ntree, node, false); } } } static void ntree_blend_read_lib(BlendLibReader *reader, ID *id) { bNodeTree *ntree = (bNodeTree *)id; ntreeBlendReadLib(reader, ntree); } static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock) { IDP_BlendReadExpand(expander, sock->prop); if (sock->default_value != nullptr) { switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; BLO_expand(expander, default_value->value); break; } case SOCK_IMAGE: { bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; BLO_expand(expander, default_value->value); break; } case SOCK_COLLECTION: { bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) sock->default_value; BLO_expand(expander, default_value->value); break; } case SOCK_TEXTURE: { bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value; BLO_expand(expander, default_value->value); break; } case SOCK_MATERIAL: { bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value; BLO_expand(expander, default_value->value); break; } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: case SOCK_BOOLEAN: case SOCK_INT: case SOCK_STRING: case __SOCK_MESH: case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: break; } } } static void expand_node_sockets(BlendExpander *expander, ListBase *sockets) { LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { expand_node_socket(expander, sock); } } void ntreeBlendReadExpand(BlendExpander *expander, bNodeTree *ntree) { if (ntree->gpd) { BLO_expand(expander, ntree->gpd); } LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->id && !(node->type == CMP_NODE_R_LAYERS) && !(node->type == CMP_NODE_CRYPTOMATTE && node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER)) { BLO_expand(expander, node->id); } IDP_BlendReadExpand(expander, node->prop); expand_node_sockets(expander, &node->inputs); expand_node_sockets(expander, &node->outputs); } expand_node_sockets(expander, &ntree->inputs); expand_node_sockets(expander, &ntree->outputs); } static void ntree_blend_read_expand(BlendExpander *expander, ID *id) { bNodeTree *ntree = (bNodeTree *)id; ntreeBlendReadExpand(expander, ntree); } IDTypeInfo IDType_ID_NT = { /* id_code */ ID_NT, /* id_filter */ FILTER_ID_NT, /* main_listbase_index */ INDEX_ID_NT, /* struct_size */ sizeof(bNodeTree), /* name */ "NodeTree", /* name_plural */ "node_groups", /* translation_context */ BLT_I18NCONTEXT_ID_NODETREE, /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, /* asset_type_info */ nullptr, /* init_data */ ntree_init_data, /* copy_data */ ntree_copy_data, /* free_data */ ntree_free_data, /* make_local */ nullptr, /* foreach_id */ node_foreach_id, /* foreach_cache */ node_foreach_cache, /* foreach_path */ node_foreach_path, /* owner_pointer_get */ node_owner_pointer_get, /* blend_write */ ntree_blend_write, /* blend_read_data */ ntree_blend_read_data, /* blend_read_lib */ ntree_blend_read_lib, /* blend_read_expand */ ntree_blend_read_expand, /* blend_read_undo_preserve */ nullptr, /* lib_override_apply_post */ nullptr, }; static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype) { if (ntype->declare != nullptr) { node_verify_sockets(ntree, node, true); return; } bNodeSocketTemplate *sockdef; if (ntype->inputs) { sockdef = ntype->inputs; while (sockdef->type != -1) { node_add_socket_from_template(ntree, node, sockdef, SOCK_IN); sockdef++; } } if (ntype->outputs) { sockdef = ntype->outputs; while (sockdef->type != -1) { node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT); sockdef++; } } } /* NOTE: This function is called to initialize node data based on the type. * The #bNodeType may not be registered at creation time of the node, * so this can be delayed until the node type gets registered. */ static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node) { bNodeType *ntype = node->typeinfo; if (ntype == &NodeTypeUndefined) { return; } /* only do this once */ if (node->flag & NODE_INIT) { return; } node->flag = NODE_SELECT | NODE_OPTIONS | ntype->flag; node->width = ntype->width; node->miniwidth = 42.0f; node->height = ntype->height; node->color[0] = node->color[1] = node->color[2] = 0.608; /* default theme color */ /* initialize the node name with the node label. * NOTE: do this after the initfunc so nodes get their data set which may be used in naming * (node groups for example) */ /* XXX Do not use nodeLabel() here, it returns translated content for UI, * which should *only* be used in UI, *never* in data... * Data have their own translation option! * This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler * than adding "do_translate" flags to this func (and labelfunc() as well). */ BLI_strncpy(node->name, DATA_(ntype->ui_name), NODE_MAXSTR); nodeUniqueName(ntree, node); node_add_sockets_from_type(ntree, node, ntype); if (ntype->initfunc != nullptr) { ntype->initfunc(ntree, node); } if (ntree->typeinfo->node_add_init != nullptr) { ntree->typeinfo->node_add_init(ntree, node); } if (node->id) { id_us_plus(node->id); } /* extra init callback */ if (ntype->initfunc_api) { PointerRNA ptr; RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); /* XXX WARNING: context can be nullptr in case nodes are added in do_versions. * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment. */ BLI_assert(C != nullptr); ntype->initfunc_api(C, &ptr); } node->flag |= NODE_INIT; } static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo) { if (typeinfo) { ntree->typeinfo = typeinfo; } else { ntree->typeinfo = &NodeTreeTypeUndefined; } /* Deprecated integer type. */ ntree->type = ntree->typeinfo->type; BKE_ntree_update_tag_all(ntree); } static void node_set_typeinfo(const struct bContext *C, bNodeTree *ntree, bNode *node, bNodeType *typeinfo) { /* for nodes saved in older versions storage can get lost, make undefined then */ if (node->flag & NODE_INIT) { if (typeinfo && typeinfo->storagename[0] && !node->storage) { typeinfo = nullptr; } } if (typeinfo) { node->typeinfo = typeinfo; /* deprecated integer type */ node->type = typeinfo->type; /* initialize the node if necessary */ node_init(C, ntree, node); } else { node->typeinfo = &NodeTypeUndefined; } } /* WARNING: default_value must either be null or match the typeinfo at this point. * This function is called both for initializing new sockets and after loading files. */ static void node_socket_set_typeinfo(bNodeTree *ntree, bNodeSocket *sock, bNodeSocketType *typeinfo) { if (typeinfo) { sock->typeinfo = typeinfo; /* deprecated integer type */ sock->type = typeinfo->type; if (sock->default_value == nullptr) { /* initialize the default_value pointer used by standard socket types */ node_socket_init_default_value(sock); } } else { sock->typeinfo = &NodeSocketTypeUndefined; } BKE_ntree_update_tag_socket_type(ntree, sock); } /* Set specific typeinfo pointers in all node trees on register/unregister */ static void update_typeinfo(Main *bmain, const struct bContext *C, bNodeTreeType *treetype, bNodeType *nodetype, bNodeSocketType *socktype, bool unregister) { if (!bmain) { return; } FOREACH_NODETREE_BEGIN (bmain, ntree, id) { if (treetype && STREQ(ntree->idname, treetype->idname)) { ntree_set_typeinfo(ntree, unregister ? nullptr : treetype); } /* initialize nodes */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (nodetype && STREQ(node->idname, nodetype->idname)) { node_set_typeinfo(C, ntree, node, unregister ? nullptr : nodetype); } /* initialize node sockets */ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (socktype && STREQ(sock->idname, socktype->idname)) { node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); } } LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { if (socktype && STREQ(sock->idname, socktype->idname)) { node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); } } } /* initialize tree sockets */ LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { if (socktype && STREQ(sock->idname, socktype->idname)) { node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); } } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { if (socktype && STREQ(sock->idname, socktype->idname)) { node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype); } } } FOREACH_NODETREE_END; } void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree) { ntree_set_typeinfo(ntree, ntreeTypeFind(ntree->idname)); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { node_set_typeinfo(C, ntree, node, nodeTypeFind(node->idname)); LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); } LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); } } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname)); } } static GHash *nodetreetypes_hash = nullptr; static GHash *nodetypes_hash = nullptr; static GHash *nodesockettypes_hash = nullptr; bNodeTreeType *ntreeTypeFind(const char *idname) { if (idname[0]) { bNodeTreeType *nt = (bNodeTreeType *)BLI_ghash_lookup(nodetreetypes_hash, idname); if (nt) { return nt; } } return nullptr; } void ntreeTypeAdd(bNodeTreeType *nt) { BLI_ghash_insert(nodetreetypes_hash, nt->idname, nt); /* XXX pass Main to register function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ update_typeinfo(G_MAIN, nullptr, nt, nullptr, nullptr, false); } /* callback for hash value free function */ static void ntree_free_type(void *treetype_v) { bNodeTreeType *treetype = (bNodeTreeType *)treetype_v; /* XXX pass Main to unregister function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ update_typeinfo(G_MAIN, nullptr, treetype, nullptr, nullptr, true); MEM_freeN(treetype); } void ntreeTypeFreeLink(const bNodeTreeType *nt) { BLI_ghash_remove(nodetreetypes_hash, nt->idname, nullptr, ntree_free_type); } bool ntreeIsRegistered(bNodeTree *ntree) { return (ntree->typeinfo != &NodeTreeTypeUndefined); } GHashIterator *ntreeTypeGetIterator() { return BLI_ghashIterator_new(nodetreetypes_hash); } bNodeType *nodeTypeFind(const char *idname) { if (idname[0]) { bNodeType *nt = (bNodeType *)BLI_ghash_lookup(nodetypes_hash, idname); if (nt) { return nt; } } return nullptr; } /* callback for hash value free function */ static void node_free_type(void *nodetype_v) { bNodeType *nodetype = (bNodeType *)nodetype_v; /* XXX pass Main to unregister function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ update_typeinfo(G_MAIN, nullptr, nullptr, nodetype, nullptr, true); delete nodetype->fixed_declaration; nodetype->fixed_declaration = nullptr; /* Can be null when the type is not dynamically allocated. */ if (nodetype->free_self) { nodetype->free_self(nodetype); } } void nodeRegisterType(bNodeType *nt) { /* debug only: basic verification of registered types */ BLI_assert(nt->idname[0] != '\0'); BLI_assert(nt->poll != nullptr); if (nt->declare && !nt->declaration_is_dynamic) { if (nt->fixed_declaration == nullptr) { nt->fixed_declaration = new blender::nodes::NodeDeclaration(); blender::nodes::NodeDeclarationBuilder builder{*nt->fixed_declaration}; nt->declare(builder); } } BLI_ghash_insert(nodetypes_hash, nt->idname, nt); /* XXX pass Main to register function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ update_typeinfo(G_MAIN, nullptr, nullptr, nt, nullptr, false); } void nodeUnregisterType(bNodeType *nt) { BLI_ghash_remove(nodetypes_hash, nt->idname, nullptr, node_free_type); } bool nodeTypeUndefined(const bNode *node) { return (node->typeinfo == &NodeTypeUndefined) || ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id && ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING)); } GHashIterator *nodeTypeGetIterator() { return BLI_ghashIterator_new(nodetypes_hash); } bNodeSocketType *nodeSocketTypeFind(const char *idname) { if (idname[0]) { bNodeSocketType *st = (bNodeSocketType *)BLI_ghash_lookup(nodesockettypes_hash, idname); if (st) { return st; } } return nullptr; } /* callback for hash value free function */ static void node_free_socket_type(void *socktype_v) { bNodeSocketType *socktype = (bNodeSocketType *)socktype_v; /* XXX pass Main to unregister function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ update_typeinfo(G_MAIN, nullptr, nullptr, nullptr, socktype, true); socktype->free_self(socktype); } void nodeRegisterSocketType(bNodeSocketType *st) { BLI_ghash_insert(nodesockettypes_hash, (void *)st->idname, st); /* XXX pass Main to register function? */ /* Probably not. It is pretty much expected we want to update G_MAIN here I think - * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ update_typeinfo(G_MAIN, nullptr, nullptr, nullptr, st, false); } void nodeUnregisterSocketType(bNodeSocketType *st) { BLI_ghash_remove(nodesockettypes_hash, st->idname, nullptr, node_free_socket_type); } bool nodeSocketIsRegistered(bNodeSocket *sock) { return (sock->typeinfo != &NodeSocketTypeUndefined); } GHashIterator *nodeSocketTypeGetIterator() { return BLI_ghashIterator_new(nodesockettypes_hash); } const char *nodeSocketTypeLabel(const bNodeSocketType *stype) { /* Use socket type name as a fallback if label is undefined. */ return stype->label[0] != '\0' ? stype->label : RNA_struct_ui_name(stype->ext_socket.srna); } struct bNodeSocket *nodeFindSocket(const bNode *node, eNodeSocketInOut in_out, const char *identifier) { const ListBase *sockets = (in_out == SOCK_IN) ? &node->inputs : &node->outputs; LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { if (STREQ(sock->identifier, identifier)) { return sock; } } return nullptr; } namespace blender::bke { bNodeSocket *node_find_enabled_socket(bNode &node, const eNodeSocketInOut in_out, const StringRef name) { ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs; LISTBASE_FOREACH (bNodeSocket *, socket, sockets) { if (!(socket->flag & SOCK_UNAVAIL) && socket->name == name) { return socket; } } return nullptr; } bNodeSocket *node_find_enabled_input_socket(bNode &node, StringRef name) { return node_find_enabled_socket(node, SOCK_IN, name); } bNodeSocket *node_find_enabled_output_socket(bNode &node, StringRef name) { return node_find_enabled_socket(node, SOCK_OUT, name); } } // namespace blender::bke /* find unique socket identifier */ static bool unique_identifier_check(void *arg, const char *identifier) { const ListBase *lb = (const ListBase *)arg; LISTBASE_FOREACH (bNodeSocket *, sock, lb) { if (STREQ(sock->identifier, identifier)) { return true; } } return false; } static bNodeSocket *make_socket(bNodeTree *ntree, bNode *UNUSED(node), int in_out, ListBase *lb, const char *idname, const char *identifier, const char *name) { char auto_identifier[MAX_NAME]; if (identifier && identifier[0] != '\0') { /* use explicit identifier */ BLI_strncpy(auto_identifier, identifier, sizeof(auto_identifier)); } else { /* if no explicit identifier is given, assign a unique identifier based on the name */ BLI_strncpy(auto_identifier, name, sizeof(auto_identifier)); } /* Make the identifier unique. */ BLI_uniquename_cb( unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier)); bNodeSocket *sock = MEM_cnew("sock"); sock->runtime = MEM_new(__func__); sock->in_out = in_out; BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR); sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); BLI_strncpy(sock->name, name, NODE_MAXSTR); sock->storage = nullptr; sock->flag |= SOCK_COLLAPSED; sock->type = SOCK_CUSTOM; /* int type undefined by default */ BLI_strncpy(sock->idname, idname, sizeof(sock->idname)); node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname)); return sock; } static void socket_id_user_increment(bNodeSocket *sock) { switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; id_us_plus((ID *)default_value->value); break; } case SOCK_IMAGE: { bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; id_us_plus((ID *)default_value->value); break; } case SOCK_COLLECTION: { bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) sock->default_value; id_us_plus((ID *)default_value->value); break; } case SOCK_TEXTURE: { bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value; id_us_plus((ID *)default_value->value); break; } case SOCK_MATERIAL: { bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value; id_us_plus((ID *)default_value->value); break; } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: case SOCK_BOOLEAN: case SOCK_INT: case SOCK_STRING: case __SOCK_MESH: case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: break; } } /** \return True if the socket had an ID default value. */ static bool socket_id_user_decrement(bNodeSocket *sock) { switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; if (default_value->value != nullptr) { id_us_min(&default_value->value->id); return true; } break; } case SOCK_IMAGE: { bNodeSocketValueImage *default_value = (bNodeSocketValueImage *)sock->default_value; if (default_value->value != nullptr) { id_us_min(&default_value->value->id); return true; } break; } case SOCK_COLLECTION: { bNodeSocketValueCollection *default_value = (bNodeSocketValueCollection *) sock->default_value; if (default_value->value != nullptr) { id_us_min(&default_value->value->id); return true; } break; } case SOCK_TEXTURE: { bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value; if (default_value->value != nullptr) { id_us_min(&default_value->value->id); return true; } break; } case SOCK_MATERIAL: { bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value; if (default_value->value != nullptr) { id_us_min(&default_value->value->id); return true; } break; } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: case SOCK_BOOLEAN: case SOCK_INT: case SOCK_STRING: case __SOCK_MESH: case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: break; } return false; } void nodeModifySocketType(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, const char *idname) { bNodeSocketType *socktype = nodeSocketTypeFind(idname); if (!socktype) { CLOG_ERROR(&LOG, "node socket type %s undefined", idname); return; } if (sock->default_value) { socket_id_user_decrement(sock); MEM_freeN(sock->default_value); sock->default_value = nullptr; } BLI_strncpy(sock->idname, idname, sizeof(sock->idname)); node_socket_set_typeinfo(ntree, sock, socktype); } void nodeModifySocketTypeStatic( bNodeTree *ntree, bNode *node, bNodeSocket *sock, int type, int subtype) { const char *idname = nodeStaticSocketType(type, subtype); if (!idname) { CLOG_ERROR(&LOG, "static node socket type %d undefined", type); return; } nodeModifySocketType(ntree, node, sock, idname); } bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, eNodeSocketInOut in_out, const char *idname, const char *identifier, const char *name) { BLI_assert(node->type != NODE_FRAME); BLI_assert(!(in_out == SOCK_IN && node->type == NODE_GROUP_INPUT)); BLI_assert(!(in_out == SOCK_OUT && node->type == NODE_GROUP_OUTPUT)); ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs); bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name); BLI_remlink(lb, sock); /* does nothing for new socket */ BLI_addtail(lb, sock); BKE_ntree_update_tag_socket_new(ntree, sock); return sock; } bool nodeIsStaticSocketType(const struct bNodeSocketType *stype) { /* * Cannot rely on type==SOCK_CUSTOM here, because type is 0 by default * and can be changed on custom sockets. */ return RNA_struct_is_a(stype->ext_socket.srna, &RNA_NodeSocketStandard); } const char *nodeStaticSocketType(int type, int subtype) { switch (type) { case SOCK_FLOAT: switch (subtype) { case PROP_UNSIGNED: return "NodeSocketFloatUnsigned"; case PROP_PERCENTAGE: return "NodeSocketFloatPercentage"; case PROP_FACTOR: return "NodeSocketFloatFactor"; case PROP_ANGLE: return "NodeSocketFloatAngle"; case PROP_TIME: return "NodeSocketFloatTime"; case PROP_TIME_ABSOLUTE: return "NodeSocketFloatTimeAbsolute"; case PROP_DISTANCE: return "NodeSocketFloatDistance"; case PROP_NONE: default: return "NodeSocketFloat"; } case SOCK_INT: switch (subtype) { case PROP_UNSIGNED: return "NodeSocketIntUnsigned"; case PROP_PERCENTAGE: return "NodeSocketIntPercentage"; case PROP_FACTOR: return "NodeSocketIntFactor"; case PROP_NONE: default: return "NodeSocketInt"; } case SOCK_BOOLEAN: return "NodeSocketBool"; case SOCK_VECTOR: switch (subtype) { case PROP_TRANSLATION: return "NodeSocketVectorTranslation"; case PROP_DIRECTION: return "NodeSocketVectorDirection"; case PROP_VELOCITY: return "NodeSocketVectorVelocity"; case PROP_ACCELERATION: return "NodeSocketVectorAcceleration"; case PROP_EULER: return "NodeSocketVectorEuler"; case PROP_XYZ: return "NodeSocketVectorXYZ"; case PROP_NONE: default: return "NodeSocketVector"; } case SOCK_RGBA: return "NodeSocketColor"; case SOCK_STRING: return "NodeSocketString"; case SOCK_SHADER: return "NodeSocketShader"; case SOCK_OBJECT: return "NodeSocketObject"; case SOCK_IMAGE: return "NodeSocketImage"; case SOCK_GEOMETRY: return "NodeSocketGeometry"; case SOCK_COLLECTION: return "NodeSocketCollection"; case SOCK_TEXTURE: return "NodeSocketTexture"; case SOCK_MATERIAL: return "NodeSocketMaterial"; } return nullptr; } const char *nodeStaticSocketInterfaceType(int type, int subtype) { switch (type) { case SOCK_FLOAT: switch (subtype) { case PROP_UNSIGNED: return "NodeSocketInterfaceFloatUnsigned"; case PROP_PERCENTAGE: return "NodeSocketInterfaceFloatPercentage"; case PROP_FACTOR: return "NodeSocketInterfaceFloatFactor"; case PROP_ANGLE: return "NodeSocketInterfaceFloatAngle"; case PROP_TIME: return "NodeSocketInterfaceFloatTime"; case PROP_TIME_ABSOLUTE: return "NodeSocketInterfaceFloatTimeAbsolute"; case PROP_DISTANCE: return "NodeSocketInterfaceFloatDistance"; case PROP_NONE: default: return "NodeSocketInterfaceFloat"; } case SOCK_INT: switch (subtype) { case PROP_UNSIGNED: return "NodeSocketInterfaceIntUnsigned"; case PROP_PERCENTAGE: return "NodeSocketInterfaceIntPercentage"; case PROP_FACTOR: return "NodeSocketInterfaceIntFactor"; case PROP_NONE: default: return "NodeSocketInterfaceInt"; } case SOCK_BOOLEAN: return "NodeSocketInterfaceBool"; case SOCK_VECTOR: switch (subtype) { case PROP_TRANSLATION: return "NodeSocketInterfaceVectorTranslation"; case PROP_DIRECTION: return "NodeSocketInterfaceVectorDirection"; case PROP_VELOCITY: return "NodeSocketInterfaceVectorVelocity"; case PROP_ACCELERATION: return "NodeSocketInterfaceVectorAcceleration"; case PROP_EULER: return "NodeSocketInterfaceVectorEuler"; case PROP_XYZ: return "NodeSocketInterfaceVectorXYZ"; case PROP_NONE: default: return "NodeSocketInterfaceVector"; } case SOCK_RGBA: return "NodeSocketInterfaceColor"; case SOCK_STRING: return "NodeSocketInterfaceString"; case SOCK_SHADER: return "NodeSocketInterfaceShader"; case SOCK_OBJECT: return "NodeSocketInterfaceObject"; case SOCK_IMAGE: return "NodeSocketInterfaceImage"; case SOCK_GEOMETRY: return "NodeSocketInterfaceGeometry"; case SOCK_COLLECTION: return "NodeSocketInterfaceCollection"; case SOCK_TEXTURE: return "NodeSocketInterfaceTexture"; case SOCK_MATERIAL: return "NodeSocketInterfaceMaterial"; } return nullptr; } const char *nodeStaticSocketLabel(int type, int UNUSED(subtype)) { switch (type) { case SOCK_FLOAT: return "Float"; case SOCK_INT: return "Integer"; case SOCK_BOOLEAN: return "Boolean"; case SOCK_VECTOR: return "Vector"; case SOCK_RGBA: return "Color"; case SOCK_STRING: return "String"; case SOCK_SHADER: return "Shader"; case SOCK_OBJECT: return "Object"; case SOCK_IMAGE: return "Image"; case SOCK_GEOMETRY: return "Geometry"; case SOCK_COLLECTION: return "Collection"; case SOCK_TEXTURE: return "Texture"; case SOCK_MATERIAL: return "Material"; } return nullptr; } bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree, bNode *node, eNodeSocketInOut in_out, int type, int subtype, const char *identifier, const char *name) { const char *idname = nodeStaticSocketType(type, subtype); if (!idname) { CLOG_ERROR(&LOG, "static node socket type %d undefined", type); return nullptr; } bNodeSocket *sock = nodeAddSocket(ntree, node, in_out, idname, identifier, name); sock->type = type; return sock; } static void node_socket_free(bNodeSocket *sock, const bool do_id_user) { if (sock->prop) { IDP_FreePropertyContent_ex(sock->prop, do_id_user); MEM_freeN(sock->prop); } if (sock->default_value) { if (do_id_user) { socket_id_user_decrement(sock); } MEM_freeN(sock->default_value); } if (sock->default_attribute_name) { MEM_freeN(sock->default_attribute_name); } MEM_delete(sock->runtime); } void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock) { nodeRemoveSocketEx(ntree, node, sock, true); } void nodeRemoveSocketEx(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock, bool do_id_user) { LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { if (link->fromsock == sock || link->tosock == sock) { nodeRemLink(ntree, link); } } LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node->internal_links) { if (link->fromsock == sock || link->tosock == sock) { BLI_remlink(&node->internal_links, link); MEM_freeN(link); BKE_ntree_update_tag_node_internal_link(ntree, node); } } /* this is fast, this way we don't need an in_out argument */ BLI_remlink(&node->inputs, sock); BLI_remlink(&node->outputs, sock); node_socket_free(sock, do_id_user); MEM_freeN(sock); BKE_ntree_update_tag_socket_removed(ntree); } void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node) { LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { if (link->fromnode == node || link->tonode == node) { nodeRemLink(ntree, link); } } BLI_freelistN(&node->internal_links); LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) { node_socket_free(sock, true); MEM_freeN(sock); } BLI_listbase_clear(&node->inputs); LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) { node_socket_free(sock, true); MEM_freeN(sock); } BLI_listbase_clear(&node->outputs); BKE_ntree_update_tag_socket_removed(ntree); } bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name) { return (bNode *)BLI_findstring(&ntree->nodes, name, offsetof(bNode, name)); } bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex) { *r_node = nullptr; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; int index = 0; LISTBASE_FOREACH (bNodeSocket *, tsock, sockets) { if (sock == tsock) { if (r_node != nullptr) { *r_node = node; } if (r_sockindex != nullptr) { *r_sockindex = index; } return true; } index++; } } return false; } bNode *nodeFindRootParent(bNode *node) { if (node->parent) { return nodeFindRootParent(node->parent); } return node->type == NODE_FRAME ? node : nullptr; } bool nodeIsChildOf(const bNode *parent, const bNode *child) { if (parent == child) { return true; } if (child->parent) { return nodeIsChildOf(parent, child->parent); } return false; } void nodeChainIter(const bNodeTree *ntree, const bNode *node_start, bool (*callback)(bNode *, bNode *, void *, const bool), void *userdata, const bool reversed) { LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { if ((link->flag & NODE_LINK_VALID) == 0) { /* Skip links marked as cyclic. */ continue; } if (link->tonode && link->fromnode) { /* Is the link part of the chain meaning node_start == fromnode * (or tonode for reversed case)? */ if ((reversed && (link->tonode == node_start)) || (!reversed && link->fromnode == node_start)) { if (!callback(link->fromnode, link->tonode, userdata, reversed)) { return; } nodeChainIter( ntree, reversed ? link->fromnode : link->tonode, callback, userdata, reversed); } } } } static void iter_backwards_ex(const bNodeTree *ntree, const bNode *node_start, bool (*callback)(bNode *, bNode *, void *), void *userdata, char recursion_mask) { LISTBASE_FOREACH (bNodeSocket *, sock, &node_start->inputs) { bNodeLink *link = sock->link; if (link == nullptr) { continue; } if ((link->flag & NODE_LINK_VALID) == 0) { /* Skip links marked as cyclic. */ continue; } if (link->fromnode->iter_flag & recursion_mask) { continue; } link->fromnode->iter_flag |= recursion_mask; if (!callback(link->fromnode, link->tonode, userdata)) { return; } iter_backwards_ex(ntree, link->fromnode, callback, userdata, recursion_mask); } } void nodeChainIterBackwards(const bNodeTree *ntree, const bNode *node_start, bool (*callback)(bNode *, bNode *, void *), void *userdata, int recursion_lvl) { if (!node_start) { return; } /* Limited by iter_flag type. */ BLI_assert(recursion_lvl < 8); char recursion_mask = (1 << recursion_lvl); /* Reset flag. */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { node->iter_flag &= ~recursion_mask; } iter_backwards_ex(ntree, node_start, callback, userdata, recursion_mask); } void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata) { if (node->parent) { if (!callback(node->parent, userdata)) { return; } nodeParentsIter(node->parent, callback, userdata); } } /* ************** Add stuff ********** */ void nodeUniqueName(bNodeTree *ntree, bNode *node) { BLI_uniquename( &ntree->nodes, node, DATA_("Node"), '.', offsetof(bNode, name), sizeof(node->name)); } bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname) { bNode *node = MEM_cnew("new node"); node->runtime = MEM_new(__func__); BLI_addtail(&ntree->nodes, node); BLI_strncpy(node->idname, idname, sizeof(node->idname)); node_set_typeinfo(C, ntree, node, nodeTypeFind(idname)); BKE_ntree_update_tag_node_new(ntree, node); if (node->type == GEO_NODE_INPUT_SCENE_TIME) { DEG_relations_tag_update(CTX_data_main(C)); } return node; } bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) { const char *idname = nullptr; NODE_TYPES_BEGIN (ntype) { /* Do an extra poll here, because some int types are used * for multiple node types, this helps find the desired type. */ const char *disabled_hint; if (ntype->type == type && (!ntype->poll || ntype->poll(ntype, ntree, &disabled_hint))) { idname = ntype->idname; break; } } NODE_TYPES_END; if (!idname) { CLOG_ERROR(&LOG, "static node type %d undefined", type); return nullptr; } return nodeAddNode(C, ntree, idname); } static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag) { sock_dst->runtime = MEM_new(__func__); if (sock_src->prop) { sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag); } if (sock_src->default_value) { sock_dst->default_value = MEM_dupallocN(sock_src->default_value); if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { socket_id_user_increment(sock_dst); } } sock_dst->default_attribute_name = static_cast( MEM_dupallocN(sock_src->default_attribute_name)); sock_dst->stack_index = 0; /* XXX some compositor nodes (e.g. image, render layers) still store * some persistent buffer data here, need to clear this to avoid dangling pointers. */ sock_dst->cache = nullptr; } namespace blender::bke { bNode *node_copy_with_mapping(bNodeTree *dst_tree, const bNode &node_src, const int flag, const bool unique_name, Map &socket_map) { bNode *node_dst = (bNode *)MEM_mallocN(sizeof(bNode), __func__); *node_dst = node_src; node_dst->runtime = MEM_new(__func__); /* Can be called for nodes outside a node tree (e.g. clipboard). */ if (dst_tree) { if (unique_name) { nodeUniqueName(dst_tree, node_dst); } BLI_addtail(&dst_tree->nodes, node_dst); } BLI_listbase_clear(&node_dst->inputs); LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.inputs) { bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket); node_socket_copy(dst_socket, src_socket, flag); BLI_addtail(&node_dst->inputs, dst_socket); socket_map.add_new(src_socket, dst_socket); } BLI_listbase_clear(&node_dst->outputs); LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.outputs) { bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket); node_socket_copy(dst_socket, src_socket, flag); BLI_addtail(&node_dst->outputs, dst_socket); socket_map.add_new(src_socket, dst_socket); } if (node_src.prop) { node_dst->prop = IDP_CopyProperty_ex(node_src.prop, flag); } BLI_listbase_clear(&node_dst->internal_links); LISTBASE_FOREACH (const bNodeLink *, src_link, &node_src.internal_links) { bNodeLink *dst_link = (bNodeLink *)MEM_dupallocN(src_link); dst_link->fromnode = node_dst; dst_link->tonode = node_dst; dst_link->fromsock = socket_map.lookup(src_link->fromsock); dst_link->tosock = socket_map.lookup(src_link->tosock); BLI_addtail(&node_dst->internal_links, dst_link); } if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { id_us_plus(node_dst->id); } if (node_src.typeinfo->copyfunc) { node_src.typeinfo->copyfunc(dst_tree, node_dst, &node_src); } /* Only call copy function when a copy is made for the main database, not * for cases like the dependency graph and localization. */ if (node_dst->typeinfo->copyfunc_api && !(flag & LIB_ID_CREATE_NO_MAIN)) { PointerRNA ptr; RNA_pointer_create((ID *)dst_tree, &RNA_Node, node_dst, &ptr); node_dst->typeinfo->copyfunc_api(&ptr, &node_src); } if (dst_tree) { BKE_ntree_update_tag_node_new(dst_tree, node_dst); } /* Reset the declaration of the new node. */ nodeDeclarationEnsure(dst_tree, node_dst); return node_dst; } bNode *node_copy(bNodeTree *dst_tree, const bNode &src_node, const int flag, const bool unique_name) { Map socket_map; return node_copy_with_mapping(dst_tree, src_node, flag, unique_name, socket_map); } } // namespace blender::bke static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket) { int count = 0; LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { if (ELEM(socket, link->fromsock, link->tosock)) { count++; } } return count; } bNodeLink *nodeAddLink( bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock) { bNodeLink *link = nullptr; /* Test valid input. */ BLI_assert(fromnode); BLI_assert(tonode); if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) { link = MEM_cnew("link"); if (ntree) { BLI_addtail(&ntree->links, link); } link->fromnode = fromnode; link->fromsock = fromsock; link->tonode = tonode; link->tosock = tosock; } else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) { /* OK but flip */ link = MEM_cnew("link"); if (ntree) { BLI_addtail(&ntree->links, link); } link->fromnode = tonode; link->fromsock = tosock; link->tonode = fromnode; link->tosock = fromsock; } if (ntree) { BKE_ntree_update_tag_link_added(ntree, link); } if (link != nullptr && link->tosock->flag & SOCK_MULTI_INPUT) { link->multi_input_socket_index = node_count_links(ntree, link->tosock) - 1; } return link; } void nodeRemLink(bNodeTree *ntree, bNodeLink *link) { /* Can be called for links outside a node tree (e.g. clipboard). */ if (ntree) { BLI_remlink(&ntree->links, link); } if (link->tosock) { link->tosock->link = nullptr; } MEM_freeN(link); if (ntree) { BKE_ntree_update_tag_link_removed(ntree); } } void nodeLinkSetMute(bNodeTree *ntree, bNodeLink *link, const bool muted) { const bool was_muted = link->flag & NODE_LINK_MUTED; SET_FLAG_FROM_TEST(link->flag, muted, NODE_LINK_MUTED); if (muted != was_muted) { BKE_ntree_update_tag_link_mute(ntree, link); } } void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock) { LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { if (link->fromsock == sock || link->tosock == sock) { nodeRemLink(ntree, link); } } } bool nodeLinkIsHidden(const bNodeLink *link) { return nodeSocketIsHidden(link->fromsock) || nodeSocketIsHidden(link->tosock); } bool nodeLinkIsSelected(const bNodeLink *link) { return (link->fromnode->flag & NODE_SELECT) || (link->tonode->flag & NODE_SELECT); } /* Adjust the indices of links connected to the given multi input socket after deleting the link at * `deleted_index`. This function also works if the link has not yet been deleted. */ static void adjust_multi_input_indices_after_removed_link(bNodeTree *ntree, bNodeSocket *sock, int deleted_index) { LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { /* We only need to adjust those with a greater index, because the others will have the same * index. */ if (link->tosock != sock || link->multi_input_socket_index <= deleted_index) { continue; } link->multi_input_socket_index -= 1; } } void nodeInternalRelink(bNodeTree *ntree, bNode *node) { /* store link pointers in output sockets, for efficient lookup */ LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { link->tosock->link = link; } /* redirect downstream links */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { /* do we have internal link? */ if (link->fromnode == node) { if (link->fromsock->link) { /* get the upstream input link */ bNodeLink *fromlink = link->fromsock->link->fromsock->link; /* skip the node */ if (fromlink) { if (link->tosock->flag & SOCK_MULTI_INPUT) { /* remove the link that would be the same as the relinked one */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link_to_compare, &ntree->links) { if (link_to_compare->fromsock == fromlink->fromsock && link_to_compare->tosock == link->tosock) { adjust_multi_input_indices_after_removed_link( ntree, link_to_compare->tosock, link_to_compare->multi_input_socket_index); nodeRemLink(ntree, link_to_compare); } } } link->fromnode = fromlink->fromnode; link->fromsock = fromlink->fromsock; /* if the up- or downstream link is invalid, * the replacement link will be invalid too. */ if (!(fromlink->flag & NODE_LINK_VALID)) { link->flag &= ~NODE_LINK_VALID; } if (fromlink->flag & NODE_LINK_MUTED) { link->flag |= NODE_LINK_MUTED; } BKE_ntree_update_tag_link_changed(ntree); } else { if (link->tosock->flag & SOCK_MULTI_INPUT) { adjust_multi_input_indices_after_removed_link( ntree, link->tosock, link->multi_input_socket_index); } nodeRemLink(ntree, link); } } else { if (link->tosock->flag & SOCK_MULTI_INPUT) { adjust_multi_input_indices_after_removed_link( ntree, link->tosock, link->multi_input_socket_index); }; nodeRemLink(ntree, link); } } } /* remove remaining upstream links */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { if (link->tonode == node) { nodeRemLink(ntree, link); } } } void nodeToView(const bNode *node, float x, float y, float *rx, float *ry) { if (node->parent) { nodeToView(node->parent, x + node->locx, y + node->locy, rx, ry); } else { *rx = x + node->locx; *ry = y + node->locy; } } void nodeFromView(const bNode *node, float x, float y, float *rx, float *ry) { if (node->parent) { nodeFromView(node->parent, x, y, rx, ry); *rx -= node->locx; *ry -= node->locy; } else { *rx = x - node->locx; *ry = y - node->locy; } } bool nodeAttachNodeCheck(const bNode *node, const bNode *parent) { for (const bNode *parent_iter = node; parent_iter; parent_iter = parent_iter->parent) { if (parent_iter == parent) { return true; } } return false; } void nodeAttachNode(bNode *node, bNode *parent) { BLI_assert(parent->type == NODE_FRAME); BLI_assert(nodeAttachNodeCheck(parent, node) == false); float locx, locy; nodeToView(node, 0.0f, 0.0f, &locx, &locy); node->parent = parent; /* transform to parent space */ nodeFromView(parent, locx, locy, &node->locx, &node->locy); } void nodeDetachNode(struct bNode *node) { if (node->parent) { BLI_assert(node->parent->type == NODE_FRAME); /* transform to view space */ float locx, locy; nodeToView(node, 0.0f, 0.0f, &locx, &locy); node->locx = locx; node->locy = locy; node->parent = nullptr; } } void nodePositionRelative(bNode *from_node, bNode *to_node, bNodeSocket *from_sock, bNodeSocket *to_sock) { float offset_x; int tot_sock_idx; /* Socket to plug into. */ if (SOCK_IN == to_sock->in_out) { offset_x = -(from_node->typeinfo->width + 50); tot_sock_idx = BLI_listbase_count(&to_node->outputs); tot_sock_idx += BLI_findindex(&to_node->inputs, to_sock); } else { offset_x = to_node->typeinfo->width + 50; tot_sock_idx = BLI_findindex(&to_node->outputs, to_sock); } BLI_assert(tot_sock_idx != -1); float offset_y = U.widget_unit * tot_sock_idx; /* Output socket. */ if (from_sock) { if (SOCK_IN == from_sock->in_out) { tot_sock_idx = BLI_listbase_count(&from_node->outputs); tot_sock_idx += BLI_findindex(&from_node->inputs, from_sock); } else { tot_sock_idx = BLI_findindex(&from_node->outputs, from_sock); } } BLI_assert(tot_sock_idx != -1); offset_y -= U.widget_unit * tot_sock_idx; from_node->locx = to_node->locx + offset_x; from_node->locy = to_node->locy - offset_y; } void nodePositionPropagate(bNode *node) { LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { if (socket->link != nullptr) { bNodeLink *link = socket->link; nodePositionRelative(link->fromnode, link->tonode, link->fromsock, link->tosock); nodePositionPropagate(link->fromnode); } } } static bNodeTree *ntreeAddTree_do( Main *bmain, ID *owner_id, const bool is_embedded, const char *name, const char *idname) { /* trees are created as local trees for compositor, material or texture nodes, * node groups and other tree types are created as library data. */ int flag = 0; if (is_embedded || bmain == nullptr) { flag |= LIB_ID_CREATE_NO_MAIN; } bNodeTree *ntree = (bNodeTree *)BKE_libblock_alloc(bmain, ID_NT, name, flag); BKE_libblock_init_empty(&ntree->id); if (is_embedded) { BLI_assert(owner_id != NULL); ntree->id.flag |= LIB_EMBEDDED_DATA; ntree->owner_id = owner_id; bNodeTree **ntree_owner_ptr = BKE_ntree_ptr_from_id(owner_id); BLI_assert(ntree_owner_ptr != NULL); *ntree_owner_ptr = ntree; } else { BLI_assert(owner_id == NULL); } BLI_strncpy(ntree->idname, idname, sizeof(ntree->idname)); ntree_set_typeinfo(ntree, ntreeTypeFind(idname)); return ntree; } bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) { return ntreeAddTree_do(bmain, nullptr, false, name, idname); } bNodeTree *ntreeAddTreeEmbedded(Main *UNUSED(bmain), ID *owner_id, const char *name, const char *idname) { return ntreeAddTree_do(nullptr, owner_id, true, name, idname); } bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_id_user) { const int flag = do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN; bNodeTree *ntree_copy = (bNodeTree *)BKE_id_copy_ex(bmain, (ID *)ntree, nullptr, flag); return ntree_copy; } bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree) { return ntreeCopyTree_ex(ntree, bmain, true); } /* *************** Node Preview *********** */ /* XXX this should be removed eventually ... * Currently BKE functions are modeled closely on previous code, * using BKE_node_preview_init_tree to set up previews for a whole node tree in advance. * This should be left more to the individual node tree implementations. */ bool BKE_node_preview_used(const bNode *node) { /* XXX check for closed nodes? */ return (node->typeinfo->flag & NODE_PREVIEW) != 0; } bNodePreview *BKE_node_preview_verify(bNodeInstanceHash *previews, bNodeInstanceKey key, const int xsize, const int ysize, const bool create) { bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key); if (!preview) { if (create) { preview = MEM_cnew("node preview"); BKE_node_instance_hash_insert(previews, key, preview); } else { return nullptr; } } /* node previews can get added with variable size this way */ if (xsize == 0 || ysize == 0) { return preview; } /* sanity checks & initialize */ if (preview->rect) { if (preview->xsize != xsize || preview->ysize != ysize) { MEM_freeN(preview->rect); preview->rect = nullptr; } } if (preview->rect == nullptr) { preview->rect = (unsigned char *)MEM_callocN(4 * xsize + xsize * ysize * sizeof(char[4]), "node preview rect"); preview->xsize = xsize; preview->ysize = ysize; } /* no clear, makes nicer previews */ return preview; } bNodePreview *BKE_node_preview_copy(bNodePreview *preview) { bNodePreview *new_preview = (bNodePreview *)MEM_dupallocN(preview); if (preview->rect) { new_preview->rect = (unsigned char *)MEM_dupallocN(preview->rect); } return new_preview; } void BKE_node_preview_free(bNodePreview *preview) { if (preview->rect) { MEM_freeN(preview->rect); } MEM_freeN(preview); } static void node_preview_init_tree_recursive(bNodeInstanceHash *previews, bNodeTree *ntree, bNodeInstanceKey parent_key, const int xsize, const int ysize) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); if (BKE_node_preview_used(node)) { node->preview_xsize = xsize; node->preview_ysize = ysize; BKE_node_preview_verify(previews, key, xsize, ysize, false); } if (node->type == NODE_GROUP && node->id) { node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize); } } } void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize) { if (!ntree) { return; } if (!ntree->previews) { ntree->previews = BKE_node_instance_hash_new("node previews"); } node_preview_init_tree_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize); } static void node_preview_tag_used_recursive(bNodeInstanceHash *previews, bNodeTree *ntree, bNodeInstanceKey parent_key) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); if (BKE_node_preview_used(node)) { BKE_node_instance_hash_tag_key(previews, key); } if (node->type == NODE_GROUP && node->id) { node_preview_tag_used_recursive(previews, (bNodeTree *)node->id, key); } } } void BKE_node_preview_remove_unused(bNodeTree *ntree) { if (!ntree || !ntree->previews) { return; } /* use the instance hash functions for tagging and removing unused previews */ BKE_node_instance_hash_clear_tags(ntree->previews); node_preview_tag_used_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE); BKE_node_instance_hash_remove_untagged(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); } void BKE_node_preview_clear(bNodePreview *preview) { if (preview && preview->rect) { memset(preview->rect, 0, MEM_allocN_len(preview->rect)); } } void BKE_node_preview_clear_tree(bNodeTree *ntree) { if (!ntree || !ntree->previews) { return; } bNodeInstanceHashIterator iter; NODE_INSTANCE_HASH_ITER (iter, ntree->previews) { bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); BKE_node_preview_clear(preview); } } void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, bool remove_old) { if (remove_old || !to_ntree->previews) { /* free old previews */ if (to_ntree->previews) { BKE_node_instance_hash_free(to_ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free); } /* transfer previews */ to_ntree->previews = from_ntree->previews; from_ntree->previews = nullptr; /* clean up, in case any to_ntree nodes have been removed */ BKE_node_preview_remove_unused(to_ntree); } else { if (from_ntree->previews) { bNodeInstanceHashIterator iter; NODE_INSTANCE_HASH_ITER (iter, from_ntree->previews) { bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); /* replace existing previews */ BKE_node_instance_hash_remove( to_ntree->previews, key, (bNodeInstanceValueFP)BKE_node_preview_free); BKE_node_instance_hash_insert(to_ntree->previews, key, preview); } /* NOTE: null free function here, * because pointers have already been moved over to to_ntree->previews! */ BKE_node_instance_hash_free(from_ntree->previews, nullptr); from_ntree->previews = nullptr; } } } /* ************** Free stuff ********** */ void nodeUnlinkNode(bNodeTree *ntree, bNode *node) { LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { ListBase *lb; if (link->fromnode == node) { lb = &node->outputs; } else if (link->tonode == node) { lb = &node->inputs; } else { lb = nullptr; } if (lb) { /* Only bother adjusting if the socket is not on the node we're deleting. */ if (link->tonode != node && link->tosock->flag & SOCK_MULTI_INPUT) { adjust_multi_input_indices_after_removed_link( ntree, link->tosock, link->multi_input_socket_index); } LISTBASE_FOREACH (bNodeSocket *, sock, lb) { if (link->fromsock == sock || link->tosock == sock) { nodeRemLink(ntree, link); break; } } } } } static void node_unlink_attached(bNodeTree *ntree, bNode *parent) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->parent == parent) { nodeDetachNode(node); } } } /* Free the node itself. ID user refcounting is up the caller, * that does not happen here. */ static void node_free_node(bNodeTree *ntree, bNode *node) { /* since it is called while free database, node->id is undefined */ /* can be called for nodes outside a node tree (e.g. clipboard) */ if (ntree) { BLI_remlink(&ntree->nodes, node); if (ntree->typeinfo->free_node_cache) { ntree->typeinfo->free_node_cache(ntree, node); } /* texture node has bad habit of keeping exec data around */ if (ntree->type == NTREE_TEXTURE && ntree->execdata) { ntreeTexEndExecTree(ntree->execdata); ntree->execdata = nullptr; } } if (node->typeinfo->freefunc) { node->typeinfo->freefunc(node); } LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) { /* Remember, no ID user refcount management here! */ node_socket_free(sock, false); MEM_freeN(sock); } LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) { /* Remember, no ID user refcount management here! */ node_socket_free(sock, false); MEM_freeN(sock); } BLI_freelistN(&node->internal_links); if (node->prop) { /* Remember, no ID user refcount management here! */ IDP_FreePropertyContent_ex(node->prop, false); MEM_freeN(node->prop); } if (node->typeinfo->declaration_is_dynamic) { delete node->runtime->declaration; } MEM_delete(node->runtime); MEM_freeN(node); if (ntree) { BKE_ntree_update_tag_node_removed(ntree); } } void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node) { /* For removing nodes while editing localized node trees. */ BLI_assert((ntree->id.tag & LIB_TAG_LOCALIZED) != 0); /* These two lines assume the caller might want to free a single node and maintain * a valid state in the node tree. */ nodeUnlinkNode(ntree, node); node_unlink_attached(ntree, node); node_free_node(ntree, node); } void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user) { /* This function is not for localized node trees, we do not want * do to ID user refcounting and removal of animdation data then. */ BLI_assert((ntree->id.tag & LIB_TAG_LOCALIZED) == 0); bool node_has_id = false; if (do_id_user) { /* Free callback for NodeCustomGroup. */ if (node->typeinfo->freefunc_api) { PointerRNA ptr; RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); node->typeinfo->freefunc_api(&ptr); } /* Do user counting. */ if (node->id) { id_us_min(node->id); node_has_id = true; } LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { node_has_id |= socket_id_user_decrement(sock); } LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { node_has_id |= socket_id_user_decrement(sock); } } /* Remove animation data. */ char propname_esc[MAX_IDPROP_NAME * 2]; char prefix[MAX_IDPROP_NAME * 2]; BLI_str_escape(propname_esc, node->name, sizeof(propname_esc)); BLI_snprintf(prefix, sizeof(prefix), "nodes[\"%s\"]", propname_esc); if (BKE_animdata_fix_paths_remove((ID *)ntree, prefix)) { if (bmain != nullptr) { DEG_relations_tag_update(bmain); } } /* Also update relations for the scene time node, which causes a dependency * on time that users expect to be removed when the node is removed. */ if (node_has_id || node->type == GEO_NODE_INPUT_SCENE_TIME) { if (bmain != nullptr) { DEG_relations_tag_update(bmain); } } nodeUnlinkNode(ntree, node); node_unlink_attached(ntree, node); /* Free node itself. */ node_free_node(ntree, node); } static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool do_id_user) { if (sock->prop) { IDP_FreeProperty_ex(sock->prop, do_id_user); } if (sock->default_value) { if (do_id_user) { socket_id_user_decrement(sock); } MEM_freeN(sock->default_value); } if (sock->default_attribute_name) { MEM_freeN(sock->default_attribute_name); } MEM_delete(sock->runtime); } static void free_localized_node_groups(bNodeTree *ntree) { /* Only localized node trees store a copy for each node group tree. * Each node group tree in a localized node tree can be freed, * since it is a localized copy itself (no risk of accessing free'd * data in main, see T37939). */ if (!(ntree->id.tag & LIB_TAG_LOCALIZED)) { return; } LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) { bNodeTree *ngroup = (bNodeTree *)node->id; ntreeFreeTree(ngroup); MEM_freeN(ngroup); } } } void ntreeFreeTree(bNodeTree *ntree) { ntree_free_data(&ntree->id); BKE_animdata_free(&ntree->id, false); } void ntreeFreeEmbeddedTree(bNodeTree *ntree) { ntreeFreeTree(ntree); BKE_libblock_free_data(&ntree->id, true); BKE_libblock_free_data_py(&ntree->id); } void ntreeFreeLocalTree(bNodeTree *ntree) { if (ntree->id.tag & LIB_TAG_LOCALIZED) { ntreeFreeTree(ntree); } else { ntreeFreeTree(ntree); BKE_libblock_free_data(&ntree->id, true); } } void ntreeFreeCache(bNodeTree *ntree) { if (ntree == nullptr) { return; } if (ntree->typeinfo->free_cache) { ntree->typeinfo->free_cache(ntree); } } void ntreeSetOutput(bNodeTree *ntree) { /* find the active outputs, might become tree type dependent handler */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) { /* we need a check for which output node should be tagged like this, below an exception */ if (node->type == CMP_NODE_OUTPUT_FILE) { continue; } int output = 0; /* there is more types having output class, each one is checked */ LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) { if (tnode->typeinfo->nclass == NODE_CLASS_OUTPUT) { if (ntree->type == NTREE_COMPOSIT) { /* same type, exception for viewer */ if (tnode->type == node->type || (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER) && ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER))) { if (tnode->flag & NODE_DO_OUTPUT) { output++; if (output > 1) { tnode->flag &= ~NODE_DO_OUTPUT; } } } } else { /* same type */ if (tnode->type == node->type) { if (tnode->flag & NODE_DO_OUTPUT) { output++; if (output > 1) { tnode->flag &= ~NODE_DO_OUTPUT; } } } } } } if (output == 0) { node->flag |= NODE_DO_OUTPUT; } } /* group node outputs use this flag too */ if (node->type == NODE_GROUP_OUTPUT) { int output = 0; LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) { if (tnode->type == NODE_GROUP_OUTPUT) { if (tnode->flag & NODE_DO_OUTPUT) { output++; if (output > 1) { tnode->flag &= ~NODE_DO_OUTPUT; } } } } if (output == 0) { node->flag |= NODE_DO_OUTPUT; } } } /* here we could recursively set which nodes have to be done, * might be different for editor or for "real" use... */ } bNodeTree **BKE_ntree_ptr_from_id(ID *id) { switch (GS(id->name)) { case ID_MA: return &((Material *)id)->nodetree; case ID_LA: return &((Light *)id)->nodetree; case ID_WO: return &((World *)id)->nodetree; case ID_TE: return &((Tex *)id)->nodetree; case ID_SCE: return &((Scene *)id)->nodetree; case ID_LS: return &((FreestyleLineStyle *)id)->nodetree; case ID_SIM: return &((Simulation *)id)->nodetree; default: return nullptr; } } bNodeTree *ntreeFromID(ID *id) { bNodeTree **nodetree = BKE_ntree_ptr_from_id(id); return (nodetree != nullptr) ? *nodetree : nullptr; } void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (enable) { node->flag |= flag; } else { node->flag &= ~flag; } } } bNodeTree *ntreeLocalize(bNodeTree *ntree) { if (ntree == nullptr) { return nullptr; } /* Make full copy outside of Main database. * NOTE: previews are not copied here. */ bNodeTree *ltree = (bNodeTree *)BKE_id_copy_ex( nullptr, &ntree->id, nullptr, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA)); ltree->id.tag |= LIB_TAG_LOCALIZED; LISTBASE_FOREACH (bNode *, node, <ree->nodes) { if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) { node->id = (ID *)ntreeLocalize((bNodeTree *)node->id); } } /* Ensures only a single output node is enabled. */ ntreeSetOutput(ntree); bNode *node_src = (bNode *)ntree->nodes.first; bNode *node_local = (bNode *)ltree->nodes.first; while (node_src != nullptr) { node_local->original = node_src; node_src = node_src->next; node_local = node_local->next; } if (ntree->typeinfo->localize) { ntree->typeinfo->localize(ltree, ntree); } return ltree; } void ntreeLocalMerge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree) { if (ntree && localtree) { if (ntree->typeinfo->local_merge) { ntree->typeinfo->local_merge(bmain, localtree, ntree); } ntreeFreeTree(localtree); MEM_freeN(localtree); } } /* ************ NODE TREE INTERFACE *************** */ static bNodeSocket *make_socket_interface(bNodeTree *ntree, eNodeSocketInOut in_out, const char *idname, const char *name) { bNodeSocketType *stype = nodeSocketTypeFind(idname); if (stype == nullptr) { return nullptr; } bNodeSocket *sock = MEM_cnew("socket template"); sock->runtime = MEM_new(__func__); BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname)); sock->in_out = in_out; sock->type = SOCK_CUSTOM; /* int type undefined by default */ node_socket_set_typeinfo(ntree, sock, stype); /* assign new unique index */ const int own_index = ntree->cur_index++; /* use the own_index as socket identifier */ if (in_out == SOCK_IN) { BLI_snprintf(sock->identifier, MAX_NAME, "Input_%d", own_index); } else { BLI_snprintf(sock->identifier, MAX_NAME, "Output_%d", own_index); } sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); BLI_strncpy(sock->name, name, NODE_MAXSTR); sock->storage = nullptr; sock->flag |= SOCK_COLLAPSED; return sock; } bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, eNodeSocketInOut in_out, const char *identifier) { ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs; LISTBASE_FOREACH (bNodeSocket *, iosock, sockets) { if (STREQ(iosock->identifier, identifier)) { return iosock; } } return nullptr; } bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree, eNodeSocketInOut in_out, const char *idname, const char *name) { bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name); if (in_out == SOCK_IN) { BLI_addtail(&ntree->inputs, iosock); } else if (in_out == SOCK_OUT) { BLI_addtail(&ntree->outputs, iosock); } BKE_ntree_update_tag_interface(ntree); return iosock; } bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree, eNodeSocketInOut in_out, const char *idname, bNodeSocket *next_sock, const char *name) { bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name); if (in_out == SOCK_IN) { BLI_insertlinkbefore(&ntree->inputs, next_sock, iosock); } else if (in_out == SOCK_OUT) { BLI_insertlinkbefore(&ntree->outputs, next_sock, iosock); } BKE_ntree_update_tag_interface(ntree); return iosock; } struct bNodeSocket *ntreeAddSocketInterfaceFromSocket(bNodeTree *ntree, bNode *from_node, bNodeSocket *from_sock) { bNodeSocket *iosock = ntreeAddSocketInterface(ntree, static_cast(from_sock->in_out), from_sock->idname, DATA_(from_sock->name)); if (iosock) { if (iosock->typeinfo->interface_from_socket) { iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); } } return iosock; } struct bNodeSocket *ntreeInsertSocketInterfaceFromSocket(bNodeTree *ntree, bNodeSocket *next_sock, bNode *from_node, bNodeSocket *from_sock) { bNodeSocket *iosock = ntreeInsertSocketInterface( ntree, static_cast(from_sock->in_out), from_sock->idname, next_sock, from_sock->name); if (iosock) { if (iosock->typeinfo->interface_from_socket) { iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); } } return iosock; } void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock) { /* this is fast, this way we don't need an in_out argument */ BLI_remlink(&ntree->inputs, sock); BLI_remlink(&ntree->outputs, sock); node_socket_interface_free(ntree, sock, true); MEM_freeN(sock); BKE_ntree_update_tag_interface(ntree); } /* generates a valid RNA identifier from the node tree name */ static void ntree_interface_identifier_base(bNodeTree *ntree, char *base) { /* generate a valid RNA identifier */ sprintf(base, "NodeTreeInterface_%s", ntree->id.name + 2); RNA_identifier_sanitize(base, false); } /* check if the identifier is already in use */ static bool ntree_interface_unique_identifier_check(void *UNUSED(data), const char *identifier) { return (RNA_struct_find(identifier) != nullptr); } /* generates the actual unique identifier and ui name and description */ static void ntree_interface_identifier(bNodeTree *ntree, const char *base, char *identifier, int maxlen, char *name, char *description) { /* There is a possibility that different node tree names get mapped to the same identifier * after sanitation (e.g. "SomeGroup_A", "SomeGroup.A" both get sanitized to "SomeGroup_A"). * On top of the sanitized id string add a number suffix if necessary to avoid duplicates. */ identifier[0] = '\0'; BLI_uniquename_cb( ntree_interface_unique_identifier_check, nullptr, base, '_', identifier, maxlen); sprintf(name, "Node Tree %s Interface", ntree->id.name + 2); sprintf(description, "Interface properties of node group %s", ntree->id.name + 2); } static void ntree_interface_type_create(bNodeTree *ntree) { /* strings are generated from base string + ID name, sizes are sufficient */ char base[MAX_ID_NAME + 64], identifier[MAX_ID_NAME + 64], name[MAX_ID_NAME + 64], description[MAX_ID_NAME + 64]; /* generate a valid RNA identifier */ ntree_interface_identifier_base(ntree, base); ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description); /* register a subtype of PropertyGroup */ StructRNA *srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_PropertyGroup); RNA_def_struct_ui_text(srna, name, description); RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna); /* associate the RNA type with the node tree */ ntree->interface_type = srna; RNA_struct_blender_type_set(srna, ntree); /* add socket properties */ LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { bNodeSocketType *stype = sock->typeinfo; if (stype && stype->interface_register_properties) { stype->interface_register_properties(ntree, sock, srna); } } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { bNodeSocketType *stype = sock->typeinfo; if (stype && stype->interface_register_properties) { stype->interface_register_properties(ntree, sock, srna); } } } StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, bool create) { if (ntree->interface_type) { /* strings are generated from base string + ID name, sizes are sufficient */ char base[MAX_ID_NAME + 64], identifier[MAX_ID_NAME + 64], name[MAX_ID_NAME + 64], description[MAX_ID_NAME + 64]; /* A bit of a hack: when changing the ID name, update the RNA type identifier too, * so that the names match. This is not strictly necessary to keep it working, * but better for identifying associated NodeTree blocks and RNA types. */ StructRNA *srna = ntree->interface_type; ntree_interface_identifier_base(ntree, base); /* RNA identifier may have a number suffix, but should start with the idbase string */ if (!STREQLEN(RNA_struct_identifier(srna), base, sizeof(base))) { /* generate new unique RNA identifier from the ID name */ ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description); /* rename the RNA type */ RNA_def_struct_free_pointers(&BLENDER_RNA, srna); RNA_def_struct_identifier(&BLENDER_RNA, srna, identifier); RNA_def_struct_ui_text(srna, name, description); RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna); } } else if (create) { ntree_interface_type_create(ntree); } return ntree->interface_type; } void ntreeInterfaceTypeFree(bNodeTree *ntree) { if (ntree->interface_type) { RNA_struct_free(&BLENDER_RNA, ntree->interface_type); ntree->interface_type = nullptr; } } void ntreeInterfaceTypeUpdate(bNodeTree *ntree) { /* XXX it would be sufficient to just recreate all properties * instead of re-registering the whole struct type, * but there is currently no good way to do this in the RNA functions. * Overhead should be negligible. */ ntreeInterfaceTypeFree(ntree); ntree_interface_type_create(ntree); } /* ************ find stuff *************** */ bNode *ntreeFindType(const bNodeTree *ntree, int type) { if (ntree) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == type) { return node; } } } return nullptr; } bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup) { if (ntree == lookup) { return true; } LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) { if (ntreeHasTree((bNodeTree *)node->id, lookup)) { return true; } } } return false; } bNodeLink *nodeFindLink(bNodeTree *ntree, const bNodeSocket *from, const bNodeSocket *to) { LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { if (link->fromsock == from && link->tosock == to) { return link; } if (link->fromsock == to && link->tosock == from) { /* hrms? */ return link; } } return nullptr; } int nodeCountSocketLinks(const bNodeTree *ntree, const bNodeSocket *sock) { int tot = 0; LISTBASE_FOREACH (const bNodeLink *, link, &ntree->links) { if (link->fromsock == sock || link->tosock == sock) { tot++; } } return tot; } bNode *nodeGetActive(bNodeTree *ntree) { if (ntree == nullptr) { return nullptr; } LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & NODE_ACTIVE) { return node; } } return nullptr; } void nodeSetSelected(bNode *node, bool select) { if (select) { node->flag |= NODE_SELECT; } else { node->flag &= ~NODE_SELECT; /* deselect sockets too */ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { sock->flag &= ~NODE_SELECT; } LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { sock->flag &= ~NODE_SELECT; } } } void nodeClearActive(bNodeTree *ntree) { if (ntree == nullptr) { return; } LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { node->flag &= ~NODE_ACTIVE; } } void nodeSetActive(bNodeTree *ntree, bNode *node) { const bool is_paint_canvas = nodeSupportsActiveFlag(node, NODE_ACTIVE_PAINT_CANVAS); const bool is_texture_class = nodeSupportsActiveFlag(node, NODE_ACTIVE_TEXTURE); int flags_to_set = NODE_ACTIVE; SET_FLAG_FROM_TEST(flags_to_set, is_paint_canvas, NODE_ACTIVE_PAINT_CANVAS); SET_FLAG_FROM_TEST(flags_to_set, is_texture_class, NODE_ACTIVE_TEXTURE); /* Make sure only one node is active per node tree. */ LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) { tnode->flag &= ~flags_to_set; } node->flag |= flags_to_set; } int nodeSocketIsHidden(const bNodeSocket *sock) { return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0); } void nodeSetSocketAvailability(bNodeTree *ntree, bNodeSocket *sock, bool is_available) { const bool was_available = (sock->flag & SOCK_UNAVAIL) == 0; if (is_available != was_available) { BKE_ntree_update_tag_socket_availability(ntree, sock); } if (is_available) { sock->flag &= ~SOCK_UNAVAIL; } else { sock->flag |= SOCK_UNAVAIL; } } int nodeSocketLinkLimit(const bNodeSocket *sock) { bNodeSocketType *stype = sock->typeinfo; if (sock->flag & SOCK_MULTI_INPUT) { return 4095; } if (stype != nullptr && stype->use_link_limits_of_type) { int limit = (sock->in_out == SOCK_IN) ? stype->input_link_limit : stype->output_link_limit; return limit; } return sock->limit; } static void update_socket_declarations(ListBase *sockets, Span declarations) { int index; LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) { const SocketDeclaration &socket_decl = *declarations[index]; socket->runtime->declaration = &socket_decl; } } void nodeSocketDeclarationsUpdate(bNode *node) { BLI_assert(node->runtime->declaration != nullptr); update_socket_declarations(&node->inputs, node->runtime->declaration->inputs()); update_socket_declarations(&node->outputs, node->runtime->declaration->outputs()); } bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node) { if (node->runtime->declaration != nullptr) { return false; } if (node->typeinfo->declare == nullptr) { return false; } if (node->typeinfo->declaration_is_dynamic) { node->runtime->declaration = new blender::nodes::NodeDeclaration(); blender::nodes::NodeDeclarationBuilder builder{*node->runtime->declaration}; node->typeinfo->declare(builder); } else { /* Declaration should have been created in #nodeRegisterType. */ BLI_assert(node->typeinfo->fixed_declaration != nullptr); node->runtime->declaration = node->typeinfo->fixed_declaration; } return true; } bool nodeDeclarationEnsure(bNodeTree *ntree, bNode *node) { if (nodeDeclarationEnsureOnOutdatedNode(ntree, node)) { nodeSocketDeclarationsUpdate(node); return true; } return false; } /* ************** Node Clipboard *********** */ #define USE_NODE_CB_VALIDATE #ifdef USE_NODE_CB_VALIDATE /** * This data structure is to validate the node on creation, * otherwise we may reference missing data. * * Currently its only used for ID's, but nodes may one day * reference other pointers which need validation. */ struct bNodeClipboardExtraInfo { struct bNodeClipboardExtraInfo *next, *prev; ID *id; char id_name[MAX_ID_NAME]; char library_name[FILE_MAX]; }; #endif /* USE_NODE_CB_VALIDATE */ struct bNodeClipboard { ListBase nodes; #ifdef USE_NODE_CB_VALIDATE ListBase nodes_extra_info; #endif ListBase links; int type; }; static bNodeClipboard node_clipboard = {{nullptr}}; void BKE_node_clipboard_init(const struct bNodeTree *ntree) { node_clipboard.type = ntree->type; } void BKE_node_clipboard_clear() { LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node_clipboard.links) { nodeRemLink(nullptr, link); } BLI_listbase_clear(&node_clipboard.links); LISTBASE_FOREACH_MUTABLE (bNode *, node, &node_clipboard.nodes) { node_free_node(nullptr, node); } BLI_listbase_clear(&node_clipboard.nodes); #ifdef USE_NODE_CB_VALIDATE BLI_freelistN(&node_clipboard.nodes_extra_info); #endif } bool BKE_node_clipboard_validate() { bool ok = true; #ifdef USE_NODE_CB_VALIDATE bNodeClipboardExtraInfo *node_info; bNode *node; /* lists must be aligned */ BLI_assert(BLI_listbase_count(&node_clipboard.nodes) == BLI_listbase_count(&node_clipboard.nodes_extra_info)); for (node = (bNode *)node_clipboard.nodes.first, node_info = (bNodeClipboardExtraInfo *)node_clipboard.nodes_extra_info.first; node; node = (bNode *)node->next, node_info = (bNodeClipboardExtraInfo *)node_info->next) { /* validate the node against the stored node info */ /* re-assign each loop since we may clear, * open a new file where the ID is valid, and paste again */ node->id = node_info->id; /* currently only validate the ID */ if (node->id) { /* We want to search into current blend file, so using G_MAIN is valid here too. */ ListBase *lb = which_libbase(G_MAIN, GS(node_info->id_name)); BLI_assert(lb != nullptr); if (BLI_findindex(lb, node_info->id) == -1) { /* May assign null. */ node->id = (ID *)BLI_findstring(lb, node_info->id_name + 2, offsetof(ID, name) + 2); if (node->id == nullptr) { ok = false; } } } } #endif /* USE_NODE_CB_VALIDATE */ return ok; } void BKE_node_clipboard_add_node(bNode *node) { #ifdef USE_NODE_CB_VALIDATE /* add extra info */ bNodeClipboardExtraInfo *node_info = (bNodeClipboardExtraInfo *)MEM_mallocN( sizeof(bNodeClipboardExtraInfo), __func__); node_info->id = node->id; if (node->id) { BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name)); if (ID_IS_LINKED(node->id)) { BLI_strncpy( node_info->library_name, node->id->lib->filepath_abs, sizeof(node_info->library_name)); } else { node_info->library_name[0] = '\0'; } } else { node_info->id_name[0] = '\0'; node_info->library_name[0] = '\0'; } BLI_addtail(&node_clipboard.nodes_extra_info, node_info); /* end extra info */ #endif /* USE_NODE_CB_VALIDATE */ /* add node */ BLI_addtail(&node_clipboard.nodes, node); } void BKE_node_clipboard_add_link(bNodeLink *link) { BLI_addtail(&node_clipboard.links, link); } const ListBase *BKE_node_clipboard_get_nodes() { return &node_clipboard.nodes; } const ListBase *BKE_node_clipboard_get_links() { return &node_clipboard.links; } int BKE_node_clipboard_get_type() { return node_clipboard.type; } void BKE_node_clipboard_free() { BKE_node_clipboard_validate(); BKE_node_clipboard_clear(); } /* Node Instance Hash */ const bNodeInstanceKey NODE_INSTANCE_KEY_BASE = {5381}; const bNodeInstanceKey NODE_INSTANCE_KEY_NONE = {0}; /* Generate a hash key from ntree and node names * Uses the djb2 algorithm with xor by Bernstein: * http://www.cse.yorku.ca/~oz/hash.html */ static bNodeInstanceKey node_hash_int_str(bNodeInstanceKey hash, const char *str) { char c; while ((c = *str++)) { hash.value = ((hash.value << 5) + hash.value) ^ c; /* (hash * 33) ^ c */ } /* separator '\0' character, to avoid ambiguity from concatenated strings */ hash.value = (hash.value << 5) + hash.value; /* hash * 33 */ return hash; } bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, const bNodeTree *ntree, const bNode *node) { bNodeInstanceKey key = node_hash_int_str(parent_key, ntree->id.name + 2); if (node) { key = node_hash_int_str(key, node->name); } return key; } static unsigned int node_instance_hash_key(const void *key) { return ((const bNodeInstanceKey *)key)->value; } static bool node_instance_hash_key_cmp(const void *a, const void *b) { unsigned int value_a = ((const bNodeInstanceKey *)a)->value; unsigned int value_b = ((const bNodeInstanceKey *)b)->value; return (value_a != value_b); } bNodeInstanceHash *BKE_node_instance_hash_new(const char *info) { bNodeInstanceHash *hash = (bNodeInstanceHash *)MEM_mallocN(sizeof(bNodeInstanceHash), info); hash->ghash = BLI_ghash_new( node_instance_hash_key, node_instance_hash_key_cmp, "node instance hash ghash"); return hash; } void BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) { BLI_ghash_free(hash->ghash, nullptr, (GHashValFreeFP)valfreefp); MEM_freeN(hash); } void BKE_node_instance_hash_insert(bNodeInstanceHash *hash, bNodeInstanceKey key, void *value) { bNodeInstanceHashEntry *entry = (bNodeInstanceHashEntry *)value; entry->key = key; entry->tag = 0; BLI_ghash_insert(hash->ghash, &entry->key, value); } void *BKE_node_instance_hash_lookup(bNodeInstanceHash *hash, bNodeInstanceKey key) { return BLI_ghash_lookup(hash->ghash, &key); } int BKE_node_instance_hash_remove(bNodeInstanceHash *hash, bNodeInstanceKey key, bNodeInstanceValueFP valfreefp) { return BLI_ghash_remove(hash->ghash, &key, nullptr, (GHashValFreeFP)valfreefp); } void BKE_node_instance_hash_clear(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) { BLI_ghash_clear(hash->ghash, nullptr, (GHashValFreeFP)valfreefp); } void *BKE_node_instance_hash_pop(bNodeInstanceHash *hash, bNodeInstanceKey key) { return BLI_ghash_popkey(hash->ghash, &key, nullptr); } int BKE_node_instance_hash_haskey(bNodeInstanceHash *hash, bNodeInstanceKey key) { return BLI_ghash_haskey(hash->ghash, &key); } int BKE_node_instance_hash_size(bNodeInstanceHash *hash) { return BLI_ghash_len(hash->ghash); } void BKE_node_instance_hash_clear_tags(bNodeInstanceHash *hash) { bNodeInstanceHashIterator iter; NODE_INSTANCE_HASH_ITER (iter, hash) { bNodeInstanceHashEntry *value = (bNodeInstanceHashEntry *) BKE_node_instance_hash_iterator_get_value(&iter); value->tag = 0; } } void BKE_node_instance_hash_tag(bNodeInstanceHash *UNUSED(hash), void *value) { bNodeInstanceHashEntry *entry = (bNodeInstanceHashEntry *)value; entry->tag = 1; } bool BKE_node_instance_hash_tag_key(bNodeInstanceHash *hash, bNodeInstanceKey key) { bNodeInstanceHashEntry *entry = (bNodeInstanceHashEntry *)BKE_node_instance_hash_lookup(hash, key); if (entry) { entry->tag = 1; return true; } return false; } void BKE_node_instance_hash_remove_untagged(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp) { /* NOTE: Hash must not be mutated during iterating! * Store tagged entries in a separate list and remove items afterward. */ bNodeInstanceKey *untagged = (bNodeInstanceKey *)MEM_mallocN( sizeof(bNodeInstanceKey) * BKE_node_instance_hash_size(hash), "temporary node instance key list"); bNodeInstanceHashIterator iter; int num_untagged = 0; NODE_INSTANCE_HASH_ITER (iter, hash) { bNodeInstanceHashEntry *value = (bNodeInstanceHashEntry *) BKE_node_instance_hash_iterator_get_value(&iter); if (!value->tag) { untagged[num_untagged++] = BKE_node_instance_hash_iterator_get_key(&iter); } } for (int i = 0; i < num_untagged; i++) { BKE_node_instance_hash_remove(hash, untagged[i], valfreefp); } MEM_freeN(untagged); } /* ************** dependency stuff *********** */ /* node is guaranteed to be not checked before */ static int node_get_deplist_recurs(bNodeTree *ntree, bNode *node, bNode ***nsort) { int level = 0xFFF; node->done = true; /* check linked nodes */ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { if (link->tonode == node) { bNode *fromnode = link->fromnode; if (fromnode->done == 0) { fromnode->level = node_get_deplist_recurs(ntree, fromnode, nsort); } if (fromnode->level <= level) { level = fromnode->level - 1; } } } /* check parent node */ if (node->parent) { if (node->parent->done == 0) { node->parent->level = node_get_deplist_recurs(ntree, node->parent, nsort); } if (node->parent->level <= level) { level = node->parent->level - 1; } } if (nsort) { **nsort = node; (*nsort)++; } return level; } void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***r_deplist, int *r_deplist_len) { *r_deplist_len = 0; /* first clear data */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { node->done = false; (*r_deplist_len)++; } if (*r_deplist_len == 0) { *r_deplist = nullptr; return; } bNode **nsort; nsort = *r_deplist = (bNode **)MEM_callocN((*r_deplist_len) * sizeof(bNode *), "sorted node array"); /* recursive check */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->done == 0) { node->level = node_get_deplist_recurs(ntree, node, &nsort); } } } /* only updates node->level for detecting cycles links */ void ntreeUpdateNodeLevels(bNodeTree *ntree) { /* first clear tag */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { node->done = false; } /* recursive check */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->done == 0) { node->level = node_get_deplist_recurs(ntree, node, nullptr); } } } void ntreeUpdateAllNew(Main *main) { Vector new_ntrees; /* Update all new node trees on file read or append, to add/remove sockets * in groups nodes if the group changed, and handle any update flags that * might have been set in file reading or versioning. */ FOREACH_NODETREE_BEGIN (main, ntree, owner_id) { if (owner_id->tag & LIB_TAG_NEW) { BKE_ntree_update_tag_all(ntree); } } FOREACH_NODETREE_END; BKE_ntree_update_main(main, nullptr); } void ntreeUpdateAllUsers(Main *main, ID *id) { if (id == nullptr) { return; } bool need_update = false; /* Update all users of ngroup, to add/remove sockets as needed. */ FOREACH_NODETREE_BEGIN (main, ntree, owner_id) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->id == id) { BKE_ntree_update_tag_node_property(ntree, node); need_update = true; } } } FOREACH_NODETREE_END; if (need_update) { BKE_ntree_update_main(main, nullptr); } } /* ************* node type access ********** */ void nodeLabel(const bNodeTree *ntree, const bNode *node, char *label, int maxlen) { label[0] = '\0'; if (node->label[0] != '\0') { BLI_strncpy(label, node->label, maxlen); } else if (node->typeinfo->labelfunc) { node->typeinfo->labelfunc(ntree, node, label, maxlen); } /* The previous methods (labelfunc) could not provide an adequate label for the node. */ if (label[0] == '\0') { /* Kind of hacky and weak... Ideally would be better to use RNA here. :| */ const char *tmp = CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, node->typeinfo->ui_name); if (tmp == node->typeinfo->ui_name) { tmp = IFACE_(node->typeinfo->ui_name); } BLI_strncpy(label, tmp, maxlen); } } const char *nodeSocketLabel(const bNodeSocket *sock) { return (sock->label[0] != '\0') ? sock->label : sock->name; } static void node_type_base_defaults(bNodeType *ntype) { /* default size values */ node_type_size_preset(ntype, NODE_SIZE_DEFAULT); ntype->height = 100; ntype->minheight = 30; ntype->maxheight = FLT_MAX; } /* allow this node for any tree type */ static bool node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *UNUSED(ntree), const char **UNUSED(disabled_hint)) { return true; } /* use the basic poll function */ static bool node_poll_instance_default(bNode *node, bNodeTree *ntree, const char **disabled_hint) { return node->typeinfo->poll(node->typeinfo, ntree, disabled_hint); } void node_type_base(bNodeType *ntype, int type, const char *name, short nclass) { /* Use static type info header to map static int type to identifier string and RNA struct type. * Associate the RNA struct type with the bNodeType. * Dynamically registered nodes will create an RNA type at runtime * and call RNA_struct_blender_type_set, so this only needs to be done for old RNA types * created in makesrna, which can not be associated to a bNodeType immediately, * since bNodeTypes are registered afterward ... */ #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ case ID: \ BLI_strncpy(ntype->idname, #Category #StructName, sizeof(ntype->idname)); \ ntype->rna_ext.srna = RNA_struct_find(#Category #StructName); \ BLI_assert(ntype->rna_ext.srna != nullptr); \ RNA_struct_blender_type_set(ntype->rna_ext.srna, ntype); \ break; switch (type) { #include "NOD_static_types.h" } /* make sure we have a valid type (everything registered) */ BLI_assert(ntype->idname[0] != '\0'); ntype->type = type; BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name)); ntype->nclass = nclass; node_type_base_defaults(ntype); ntype->poll = node_poll_default; ntype->poll_instance = node_poll_instance_default; } void node_type_base_custom(bNodeType *ntype, const char *idname, const char *name, short nclass) { BLI_strncpy(ntype->idname, idname, sizeof(ntype->idname)); ntype->type = NODE_CUSTOM; BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name)); ntype->nclass = nclass; node_type_base_defaults(ntype); } struct SocketTemplateIdentifierCallbackData { bNodeSocketTemplate *list; bNodeSocketTemplate *ntemp; }; static bool unique_socket_template_identifier_check(void *arg, const char *name) { SocketTemplateIdentifierCallbackData *data = (SocketTemplateIdentifierCallbackData *)arg; for (bNodeSocketTemplate *ntemp = data->list; ntemp->type >= 0; ntemp++) { if (ntemp != data->ntemp) { if (STREQ(ntemp->identifier, name)) { return true; } } } return false; } static void unique_socket_template_identifier(bNodeSocketTemplate *list, bNodeSocketTemplate *ntemp, const char defname[], char delim) { SocketTemplateIdentifierCallbackData data; data.list = list; data.ntemp = ntemp; BLI_uniquename_cb(unique_socket_template_identifier_check, &data, defname, delim, ntemp->identifier, sizeof(ntemp->identifier)); } void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs) { ntype->inputs = inputs; ntype->outputs = outputs; /* automatically generate unique identifiers */ if (inputs) { /* clear identifier strings (uninitialized memory) */ for (bNodeSocketTemplate *ntemp = inputs; ntemp->type >= 0; ntemp++) { ntemp->identifier[0] = '\0'; } for (bNodeSocketTemplate *ntemp = inputs; ntemp->type >= 0; ntemp++) { BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier)); unique_socket_template_identifier(inputs, ntemp, ntemp->identifier, '_'); } } if (outputs) { /* clear identifier strings (uninitialized memory) */ for (bNodeSocketTemplate *ntemp = outputs; ntemp->type >= 0; ntemp++) { ntemp->identifier[0] = '\0'; } for (bNodeSocketTemplate *ntemp = outputs; ntemp->type >= 0; ntemp++) { BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier)); unique_socket_template_identifier(outputs, ntemp, ntemp->identifier, '_'); } } } void node_type_init(struct bNodeType *ntype, void (*initfunc)(struct bNodeTree *ntree, struct bNode *node)) { ntype->initfunc = initfunc; } void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth) { ntype->width = width; ntype->minwidth = minwidth; if (maxwidth <= minwidth) { ntype->maxwidth = FLT_MAX; } else { ntype->maxwidth = maxwidth; } } void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size) { switch (size) { case NODE_SIZE_DEFAULT: node_type_size(ntype, 140, 100, NODE_DEFAULT_MAX_WIDTH); break; case NODE_SIZE_SMALL: node_type_size(ntype, 100, 80, NODE_DEFAULT_MAX_WIDTH); break; case NODE_SIZE_MIDDLE: node_type_size(ntype, 150, 120, NODE_DEFAULT_MAX_WIDTH); break; case NODE_SIZE_LARGE: node_type_size(ntype, 240, 140, NODE_DEFAULT_MAX_WIDTH); break; } } void node_type_storage(bNodeType *ntype, const char *storagename, void (*freefunc)(struct bNode *node), void (*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node)) { if (storagename) { BLI_strncpy(ntype->storagename, storagename, sizeof(ntype->storagename)); } else { ntype->storagename[0] = '\0'; } ntype->copyfunc = copyfunc; ntype->freefunc = freefunc; } void node_type_update(struct bNodeType *ntype, void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node)) { ntype->updatefunc = updatefunc; } void node_type_group_update(struct bNodeType *ntype, void (*group_update_func)(struct bNodeTree *ntree, struct bNode *node)) { ntype->group_update_func = group_update_func; } void node_type_exec(struct bNodeType *ntype, NodeInitExecFunction init_exec_fn, NodeFreeExecFunction free_exec_fn, NodeExecFunction exec_fn) { 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 gpu_fn) { ntype->gpu_fn = gpu_fn; } /* callbacks for undefined types */ static bool node_undefined_poll(bNodeType *UNUSED(ntype), bNodeTree *UNUSED(nodetree), const char **UNUSED(r_disabled_hint)) { /* this type can not be added deliberately, it's just a placeholder */ return false; } /* register fallback types used for undefined tree, nodes, sockets */ static void register_undefined_types() { /* NOTE: these types are not registered in the type hashes, * they are just used as placeholders in case the actual types are not registered. */ NodeTreeTypeUndefined.type = NTREE_UNDEFINED; strcpy(NodeTreeTypeUndefined.idname, "NodeTreeUndefined"); strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined")); strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type")); node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0); NodeTypeUndefined.poll = node_undefined_poll; BLI_strncpy(NodeSocketTypeUndefined.idname, "NodeSocketUndefined", sizeof(NodeSocketTypeUndefined.idname)); /* extra type info for standard socket types */ NodeSocketTypeUndefined.type = SOCK_CUSTOM; NodeSocketTypeUndefined.subtype = PROP_NONE; NodeSocketTypeUndefined.use_link_limits_of_type = true; NodeSocketTypeUndefined.input_link_limit = 0xFFF; NodeSocketTypeUndefined.output_link_limit = 0xFFF; } static void registerCompositNodes() { register_node_type_cmp_group(); register_node_type_cmp_rlayers(); register_node_type_cmp_image(); register_node_type_cmp_texture(); register_node_type_cmp_value(); register_node_type_cmp_rgb(); register_node_type_cmp_curve_time(); register_node_type_cmp_scene_time(); register_node_type_cmp_movieclip(); register_node_type_cmp_composite(); register_node_type_cmp_viewer(); register_node_type_cmp_splitviewer(); register_node_type_cmp_output_file(); register_node_type_cmp_view_levels(); register_node_type_cmp_curve_rgb(); register_node_type_cmp_mix_rgb(); register_node_type_cmp_hue_sat(); register_node_type_cmp_brightcontrast(); register_node_type_cmp_gamma(); register_node_type_cmp_exposure(); register_node_type_cmp_invert(); register_node_type_cmp_alphaover(); register_node_type_cmp_zcombine(); register_node_type_cmp_colorbalance(); register_node_type_cmp_huecorrect(); register_node_type_cmp_normal(); register_node_type_cmp_curve_vec(); register_node_type_cmp_map_value(); register_node_type_cmp_map_range(); register_node_type_cmp_normalize(); register_node_type_cmp_filter(); register_node_type_cmp_blur(); register_node_type_cmp_dblur(); register_node_type_cmp_bilateralblur(); register_node_type_cmp_vecblur(); register_node_type_cmp_dilateerode(); register_node_type_cmp_inpaint(); register_node_type_cmp_despeckle(); register_node_type_cmp_defocus(); register_node_type_cmp_posterize(); register_node_type_cmp_sunbeams(); register_node_type_cmp_denoise(); register_node_type_cmp_antialiasing(); register_node_type_cmp_convert_color_space(); register_node_type_cmp_valtorgb(); register_node_type_cmp_rgbtobw(); register_node_type_cmp_setalpha(); register_node_type_cmp_idmask(); register_node_type_cmp_math(); register_node_type_cmp_seprgba(); register_node_type_cmp_combrgba(); register_node_type_cmp_sephsva(); register_node_type_cmp_combhsva(); register_node_type_cmp_sepyuva(); register_node_type_cmp_combyuva(); register_node_type_cmp_sepycca(); register_node_type_cmp_combycca(); register_node_type_cmp_premulkey(); register_node_type_cmp_separate_xyz(); register_node_type_cmp_combine_xyz(); register_node_type_cmp_separate_color(); register_node_type_cmp_combine_color(); register_node_type_cmp_diff_matte(); register_node_type_cmp_distance_matte(); register_node_type_cmp_chroma_matte(); register_node_type_cmp_color_matte(); register_node_type_cmp_channel_matte(); register_node_type_cmp_color_spill(); register_node_type_cmp_luma_matte(); register_node_type_cmp_doubleedgemask(); register_node_type_cmp_keyingscreen(); register_node_type_cmp_keying(); register_node_type_cmp_cryptomatte(); register_node_type_cmp_cryptomatte_legacy(); register_node_type_cmp_translate(); register_node_type_cmp_rotate(); register_node_type_cmp_scale(); register_node_type_cmp_flip(); register_node_type_cmp_crop(); register_node_type_cmp_displace(); register_node_type_cmp_mapuv(); register_node_type_cmp_glare(); register_node_type_cmp_tonemap(); register_node_type_cmp_lensdist(); register_node_type_cmp_transform(); register_node_type_cmp_stabilize2d(); register_node_type_cmp_moviedistortion(); register_node_type_cmp_colorcorrection(); register_node_type_cmp_boxmask(); register_node_type_cmp_ellipsemask(); register_node_type_cmp_bokehimage(); register_node_type_cmp_bokehblur(); register_node_type_cmp_switch(); register_node_type_cmp_switch_view(); register_node_type_cmp_pixelate(); register_node_type_cmp_mask(); register_node_type_cmp_trackpos(); register_node_type_cmp_planetrackdeform(); register_node_type_cmp_cornerpin(); } static void registerShaderNodes() { register_node_type_sh_group(); register_node_type_sh_camera(); register_node_type_sh_gamma(); register_node_type_sh_brightcontrast(); register_node_type_sh_value(); register_node_type_sh_rgb(); register_node_type_sh_wireframe(); register_node_type_sh_wavelength(); register_node_type_sh_blackbody(); register_node_type_sh_mix_rgb(); register_node_type_sh_mix(); register_node_type_sh_valtorgb(); register_node_type_sh_rgbtobw(); register_node_type_sh_shadertorgb(); register_node_type_sh_normal(); register_node_type_sh_mapping(); register_node_type_sh_curve_float(); register_node_type_sh_curve_vec(); register_node_type_sh_curve_rgb(); register_node_type_sh_map_range(); register_node_type_sh_clamp(); register_node_type_sh_math(); register_node_type_sh_vect_math(); register_node_type_sh_vector_rotate(); register_node_type_sh_vect_transform(); register_node_type_sh_squeeze(); register_node_type_sh_invert(); register_node_type_sh_sepcolor(); register_node_type_sh_combcolor(); register_node_type_sh_seprgb(); register_node_type_sh_combrgb(); register_node_type_sh_sephsv(); register_node_type_sh_combhsv(); register_node_type_sh_sepxyz(); register_node_type_sh_combxyz(); register_node_type_sh_hue_sat(); register_node_type_sh_attribute(); register_node_type_sh_bevel(); register_node_type_sh_displacement(); register_node_type_sh_vector_displacement(); register_node_type_sh_geometry(); register_node_type_sh_light_path(); register_node_type_sh_light_falloff(); register_node_type_sh_object_info(); register_node_type_sh_fresnel(); register_node_type_sh_layer_weight(); register_node_type_sh_tex_coord(); register_node_type_sh_particle_info(); register_node_type_sh_bump(); register_node_type_sh_vertex_color(); register_node_type_sh_background(); register_node_type_sh_bsdf_anisotropic(); register_node_type_sh_bsdf_diffuse(); register_node_type_sh_bsdf_principled(); register_node_type_sh_bsdf_glossy(); register_node_type_sh_bsdf_glass(); register_node_type_sh_bsdf_translucent(); register_node_type_sh_bsdf_transparent(); register_node_type_sh_bsdf_velvet(); register_node_type_sh_bsdf_toon(); register_node_type_sh_bsdf_hair(); register_node_type_sh_bsdf_hair_principled(); register_node_type_sh_emission(); register_node_type_sh_holdout(); register_node_type_sh_volume_absorption(); register_node_type_sh_volume_scatter(); register_node_type_sh_volume_principled(); register_node_type_sh_subsurface_scattering(); register_node_type_sh_mix_shader(); register_node_type_sh_add_shader(); register_node_type_sh_uvmap(); register_node_type_sh_uvalongstroke(); register_node_type_sh_eevee_specular(); register_node_type_sh_output_light(); register_node_type_sh_output_material(); register_node_type_sh_output_world(); register_node_type_sh_output_linestyle(); register_node_type_sh_output_aov(); register_node_type_sh_tex_image(); register_node_type_sh_tex_environment(); register_node_type_sh_tex_sky(); register_node_type_sh_tex_noise(); register_node_type_sh_tex_wave(); register_node_type_sh_tex_voronoi(); register_node_type_sh_tex_musgrave(); register_node_type_sh_tex_gradient(); register_node_type_sh_tex_magic(); register_node_type_sh_tex_checker(); register_node_type_sh_tex_brick(); register_node_type_sh_tex_pointdensity(); register_node_type_sh_tex_ies(); register_node_type_sh_tex_white_noise(); } static void registerTextureNodes() { register_node_type_tex_group(); register_node_type_tex_math(); register_node_type_tex_mix_rgb(); register_node_type_tex_valtorgb(); register_node_type_tex_rgbtobw(); register_node_type_tex_valtonor(); register_node_type_tex_curve_rgb(); register_node_type_tex_curve_time(); register_node_type_tex_invert(); register_node_type_tex_hue_sat(); register_node_type_tex_coord(); register_node_type_tex_distance(); register_node_type_tex_compose(); register_node_type_tex_decompose(); register_node_type_tex_combine_color(); register_node_type_tex_separate_color(); register_node_type_tex_output(); register_node_type_tex_viewer(); register_node_type_sh_script(); register_node_type_sh_tangent(); register_node_type_sh_normal_map(); register_node_type_sh_hair_info(); register_node_type_sh_point_info(); register_node_type_sh_volume_info(); register_node_type_tex_checker(); register_node_type_tex_texture(); register_node_type_tex_bricks(); register_node_type_tex_image(); register_node_type_sh_bsdf_refraction(); register_node_type_sh_ambient_occlusion(); register_node_type_tex_rotate(); register_node_type_tex_translate(); register_node_type_tex_scale(); register_node_type_tex_at(); register_node_type_tex_proc_voronoi(); register_node_type_tex_proc_blend(); register_node_type_tex_proc_magic(); register_node_type_tex_proc_marble(); register_node_type_tex_proc_clouds(); register_node_type_tex_proc_wood(); register_node_type_tex_proc_musgrave(); register_node_type_tex_proc_noise(); register_node_type_tex_proc_stucci(); register_node_type_tex_proc_distnoise(); } static void registerGeometryNodes() { register_node_type_geo_group(); register_node_type_geo_accumulate_field(); register_node_type_geo_attribute_capture(); register_node_type_geo_attribute_domain_size(); register_node_type_geo_attribute_statistic(); register_node_type_geo_boolean(); register_node_type_geo_bounding_box(); register_node_type_geo_collection_info(); register_node_type_geo_convex_hull(); register_node_type_geo_curve_endpoint_selection(); register_node_type_geo_curve_fill(); register_node_type_geo_curve_fillet(); register_node_type_geo_curve_handle_type_selection(); register_node_type_geo_curve_length(); register_node_type_geo_curve_primitive_arc(); register_node_type_geo_curve_primitive_bezier_segment(); register_node_type_geo_curve_primitive_circle(); register_node_type_geo_curve_primitive_line(); register_node_type_geo_curve_primitive_quadratic_bezier(); register_node_type_geo_curve_primitive_quadrilateral(); register_node_type_geo_curve_primitive_spiral(); register_node_type_geo_curve_primitive_star(); register_node_type_geo_curve_resample(); register_node_type_geo_curve_reverse(); register_node_type_geo_curve_sample(); register_node_type_geo_curve_set_handle_type(); register_node_type_geo_curve_spline_parameter(); register_node_type_geo_curve_spline_type(); register_node_type_geo_curve_subdivide(); register_node_type_geo_curve_to_mesh(); register_node_type_geo_curve_to_points(); register_node_type_geo_curve_trim(); register_node_type_geo_deform_curves_on_surface(); register_node_type_geo_delete_geometry(); register_node_type_geo_distribute_points_on_faces(); register_node_type_geo_dual_mesh(); register_node_type_geo_duplicate_elements(); register_node_type_geo_edge_paths_to_curves(); register_node_type_geo_edge_paths_to_selection(); register_node_type_geo_edge_split(); register_node_type_geo_extrude_mesh(); register_node_type_geo_field_at_index(); register_node_type_geo_flip_faces(); register_node_type_geo_geometry_to_instance(); register_node_type_geo_image_texture(); register_node_type_geo_input_curve_handles(); register_node_type_geo_input_curve_tilt(); register_node_type_geo_input_id(); register_node_type_geo_input_index(); register_node_type_geo_input_instance_rotation(); register_node_type_geo_input_instance_scale(); register_node_type_geo_input_material_index(); register_node_type_geo_input_material(); register_node_type_geo_input_mesh_edge_angle(); register_node_type_geo_input_mesh_edge_neighbors(); register_node_type_geo_input_mesh_edge_vertices(); register_node_type_geo_input_mesh_face_area(); register_node_type_geo_input_mesh_face_is_planar(); register_node_type_geo_input_mesh_face_neighbors(); register_node_type_geo_input_mesh_island(); register_node_type_geo_input_mesh_vertex_neighbors(); register_node_type_geo_input_named_attribute(); register_node_type_geo_input_normal(); register_node_type_geo_input_position(); register_node_type_geo_input_radius(); register_node_type_geo_input_scene_time(); register_node_type_geo_input_shade_smooth(); register_node_type_geo_input_shortest_edge_paths(); register_node_type_geo_input_spline_cyclic(); register_node_type_geo_input_spline_length(); register_node_type_geo_input_spline_resolution(); register_node_type_geo_input_tangent(); register_node_type_geo_instance_on_points(); register_node_type_geo_instances_to_points(); register_node_type_geo_interpolate_domain(); register_node_type_geo_is_viewport(); register_node_type_geo_join_geometry(); register_node_type_geo_material_replace(); register_node_type_geo_material_selection(); register_node_type_geo_merge_by_distance(); register_node_type_geo_mesh_primitive_circle(); register_node_type_geo_mesh_primitive_cone(); register_node_type_geo_mesh_primitive_cube(); register_node_type_geo_mesh_primitive_cylinder(); register_node_type_geo_mesh_primitive_grid(); register_node_type_geo_mesh_primitive_ico_sphere(); register_node_type_geo_mesh_primitive_line(); register_node_type_geo_mesh_primitive_uv_sphere(); register_node_type_geo_mesh_subdivide(); register_node_type_geo_mesh_to_curve(); register_node_type_geo_mesh_to_points(); register_node_type_geo_mesh_to_volume(); register_node_type_geo_object_info(); register_node_type_geo_points_to_vertices(); register_node_type_geo_points_to_volume(); register_node_type_geo_points(); register_node_type_geo_proximity(); register_node_type_geo_raycast(); register_node_type_geo_realize_instances(); register_node_type_geo_remove_attribute(); register_node_type_geo_rotate_instances(); register_node_type_geo_scale_elements(); register_node_type_geo_scale_instances(); register_node_type_geo_separate_components(); register_node_type_geo_separate_geometry(); register_node_type_geo_set_curve_handles(); register_node_type_geo_set_curve_radius(); register_node_type_geo_set_curve_tilt(); register_node_type_geo_set_id(); register_node_type_geo_set_material_index(); register_node_type_geo_set_material(); register_node_type_geo_set_point_radius(); register_node_type_geo_set_position(); register_node_type_geo_set_shade_smooth(); register_node_type_geo_set_spline_cyclic(); register_node_type_geo_set_spline_resolution(); + register_node_type_geo_smooth_attribute(); register_node_type_geo_store_named_attribute(); register_node_type_geo_string_join(); register_node_type_geo_string_to_curves(); register_node_type_geo_subdivision_surface(); register_node_type_geo_switch(); register_node_type_geo_transfer_attribute(); register_node_type_geo_transform(); register_node_type_geo_translate_instances(); register_node_type_geo_triangulate(); register_node_type_geo_uv_pack_islands(); register_node_type_geo_uv_unwrap(); register_node_type_geo_viewer(); register_node_type_geo_volume_cube(); register_node_type_geo_volume_to_mesh(); } static void registerFunctionNodes() { register_node_type_fn_align_euler_to_vector(); register_node_type_fn_boolean_math(); register_node_type_fn_combine_color(); register_node_type_fn_compare(); register_node_type_fn_float_to_int(); register_node_type_fn_input_bool(); register_node_type_fn_input_color(); register_node_type_fn_input_int(); register_node_type_fn_input_special_characters(); register_node_type_fn_input_string(); register_node_type_fn_input_vector(); register_node_type_fn_random_value(); register_node_type_fn_replace_string(); register_node_type_fn_rotate_euler(); register_node_type_fn_separate_color(); register_node_type_fn_slice_string(); register_node_type_fn_string_length(); register_node_type_fn_value_to_string(); } void BKE_node_system_init() { nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh"); nodetypes_hash = BLI_ghash_str_new("nodetypes_hash gh"); nodesockettypes_hash = BLI_ghash_str_new("nodesockettypes_hash gh"); register_undefined_types(); register_standard_node_socket_types(); register_node_tree_type_cmp(); register_node_tree_type_sh(); register_node_tree_type_tex(); register_node_tree_type_geo(); register_node_type_frame(); register_node_type_reroute(); register_node_type_group_input(); register_node_type_group_output(); registerCompositNodes(); registerShaderNodes(); registerTextureNodes(); registerGeometryNodes(); registerFunctionNodes(); } void BKE_node_system_exit() { if (nodetypes_hash) { NODE_TYPES_BEGIN (nt) { if (nt->rna_ext.free) { nt->rna_ext.free(nt->rna_ext.data); } } NODE_TYPES_END; BLI_ghash_free(nodetypes_hash, nullptr, node_free_type); nodetypes_hash = nullptr; } if (nodesockettypes_hash) { NODE_SOCKET_TYPES_BEGIN (st) { if (st->ext_socket.free) { st->ext_socket.free(st->ext_socket.data); } if (st->ext_interface.free) { st->ext_interface.free(st->ext_interface.data); } } NODE_SOCKET_TYPES_END; BLI_ghash_free(nodesockettypes_hash, nullptr, node_free_socket_type); nodesockettypes_hash = nullptr; } if (nodetreetypes_hash) { NODE_TREE_TYPES_BEGIN (nt) { if (nt->rna_ext.free) { nt->rna_ext.free(nt->rna_ext.data); } } NODE_TREE_TYPES_END; BLI_ghash_free(nodetreetypes_hash, nullptr, ntree_free_type); nodetreetypes_hash = nullptr; } } /* -------------------------------------------------------------------- */ /* NodeTree Iterator Helpers (FOREACH_NODETREE_BEGIN) */ void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain) { ntreeiter->ngroup = (bNodeTree *)bmain->nodetrees.first; ntreeiter->scene = (Scene *)bmain->scenes.first; ntreeiter->mat = (Material *)bmain->materials.first; ntreeiter->tex = (Tex *)bmain->textures.first; ntreeiter->light = (Light *)bmain->lights.first; ntreeiter->world = (World *)bmain->worlds.first; ntreeiter->linestyle = (FreestyleLineStyle *)bmain->linestyles.first; ntreeiter->simulation = (Simulation *)bmain->simulations.first; } bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, bNodeTree **r_nodetree, struct ID **r_id) { if (ntreeiter->ngroup) { *r_nodetree = (bNodeTree *)ntreeiter->ngroup; *r_id = (ID *)ntreeiter->ngroup; ntreeiter->ngroup = (bNodeTree *)ntreeiter->ngroup->id.next; } else if (ntreeiter->scene) { *r_nodetree = (bNodeTree *)ntreeiter->scene->nodetree; *r_id = (ID *)ntreeiter->scene; ntreeiter->scene = (Scene *)ntreeiter->scene->id.next; } else if (ntreeiter->mat) { *r_nodetree = (bNodeTree *)ntreeiter->mat->nodetree; *r_id = (ID *)ntreeiter->mat; ntreeiter->mat = (Material *)ntreeiter->mat->id.next; } else if (ntreeiter->tex) { *r_nodetree = (bNodeTree *)ntreeiter->tex->nodetree; *r_id = (ID *)ntreeiter->tex; ntreeiter->tex = (Tex *)ntreeiter->tex->id.next; } else if (ntreeiter->light) { *r_nodetree = (bNodeTree *)ntreeiter->light->nodetree; *r_id = (ID *)ntreeiter->light; ntreeiter->light = (Light *)ntreeiter->light->id.next; } else if (ntreeiter->world) { *r_nodetree = (bNodeTree *)ntreeiter->world->nodetree; *r_id = (ID *)ntreeiter->world; ntreeiter->world = (World *)ntreeiter->world->id.next; } else if (ntreeiter->linestyle) { *r_nodetree = (bNodeTree *)ntreeiter->linestyle->nodetree; *r_id = (ID *)ntreeiter->linestyle; ntreeiter->linestyle = (FreestyleLineStyle *)ntreeiter->linestyle->id.next; } else if (ntreeiter->simulation) { *r_nodetree = (bNodeTree *)ntreeiter->simulation->nodetree; *r_id = (ID *)ntreeiter->simulation; ntreeiter->simulation = (Simulation *)ntreeiter->simulation->id.next; } else { return false; } return true; } /* -------------------------------------------------------------------- */ /* NodeTree kernel functions */ void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index) { BLI_assert(layer_index != -1); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) { if (node->custom1 == layer_index) { node->custom1 = 0; } else if (node->custom1 > layer_index) { node->custom1--; } } } } diff --git a/source/blender/blenlib/BLI_task.hh b/source/blender/blenlib/BLI_task.hh index 33a781d3749..25d83f156fc 100644 --- a/source/blender/blenlib/BLI_task.hh +++ b/source/blender/blenlib/BLI_task.hh @@ -1,134 +1,157 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once /** \file * \ingroup bli */ #ifdef WITH_TBB /* Quiet top level deprecation message, unrelated to API usage here. */ # if defined(WIN32) && !defined(NOMINMAX) /* TBB includes Windows.h which will define min/max macros causing issues * when we try to use std::min and std::max later on. */ # define NOMINMAX # define TBB_MIN_MAX_CLEANUP # endif # include # include # include # include # include # include # ifdef WIN32 /* We cannot keep this defined, since other parts of the code deal with this on their own, leading * to multiple define warnings unless we un-define this, however we can only undefine this if we * were the ones that made the definition earlier. */ # ifdef TBB_MIN_MAX_CLEANUP # undef NOMINMAX # endif # endif #endif #include "BLI_index_range.hh" #include "BLI_utildefines.h" namespace blender::threading { template void parallel_for_each(Range &range, const Function &function) { #ifdef WITH_TBB tbb::parallel_for_each(range, function); #else for (auto &value : range) { function(value); } #endif } template void parallel_for(IndexRange range, int64_t grain_size, const Function &function) { if (range.size() == 0) { return; } #ifdef WITH_TBB /* Invoking tbb for small workloads has a large overhead. */ if (range.size() >= grain_size) { tbb::parallel_for( tbb::blocked_range(range.first(), range.one_after_last(), grain_size), [&](const tbb::blocked_range &subrange) { function(IndexRange(subrange.begin(), subrange.size())); }); return; } #else UNUSED_VARS(grain_size); #endif function(range); } template Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction) { #ifdef WITH_TBB if (range.size() >= grain_size) { return tbb::parallel_reduce( tbb::blocked_range(range.first(), range.one_after_last(), grain_size), identity, [&](const tbb::blocked_range &subrange, const Value &ident) { return function(IndexRange(subrange.begin(), subrange.size()), ident); }, reduction); } #else UNUSED_VARS(grain_size, reduction); #endif return function(range, identity); } /** * Execute all of the provided functions. The functions might be executed in parallel or in serial * or some combination of both. */ template void parallel_invoke(Functions &&...functions) { #ifdef WITH_TBB tbb::parallel_invoke(std::forward(functions)...); #else (functions(), ...); #endif } /** * Same #parallel_invoke, but allows disabling threading dynamically. This is useful because when * the individual functions do very little work, there is a lot of overhead from starting parallel * tasks. */ template void parallel_invoke(const bool use_threading, Functions &&...functions) { if (use_threading) { parallel_invoke(std::forward(functions)...); } else { (functions(), ...); } } /** See #BLI_task_isolate for a description of what isolating a task means. */ template void isolate_task(const Function &function) { #ifdef WITH_TBB tbb::this_task_arena::isolate(function); #else function(); #endif } +/* + * The task granulation size must be a power of two. + * If the complexity is dynamic, the calculation may require a fast conversion to a power of two. + */ +inline int prepair_grain_size(const int crude_grain) { +#ifdef WITH_TBB + if (crude_grain <= 0) { + return 1; + } + int power = 0; + int grain = crude_grain; + while (grain != 1) { + grain >>= 1; + power++; + } + const int grain_size = 1 << power; + return grain_size != crude_grain ? grain_size << 1 : grain_size; +#else + /* Any processing of excess. If another addiction appears, the preparation for it should be individual. */ + return crude_grain; +#endif +} + } // namespace blender::threading diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index caeee35a80a..793039f0871 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1,12989 +1,13003 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup RNA */ #include #include #include #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLT_translation.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_particle_types.h" #include "DNA_text_types.h" #include "DNA_texture_types.h" #include "BKE_animsys.h" #include "BKE_attribute.h" #include "BKE_cryptomatte.h" #include "BKE_geometry_set.h" #include "BKE_image.h" #include "BKE_node.h" #include "BKE_node_tree_update.h" #include "BKE_texture.h" #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" #include "rna_internal.h" #include "rna_internal_types.h" #include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "WM_types.h" #include "MEM_guardedalloc.h" #include "RE_texture.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" const EnumPropertyItem rna_enum_node_socket_in_out_items[] = { {SOCK_IN, "IN", 0, "Input", ""}, {SOCK_OUT, "OUT", 0, "Output", ""}, {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem node_socket_data_type_items[] = { {SOCK_FLOAT, "FLOAT", 0, "Float", ""}, {SOCK_INT, "INT", 0, "Integer", ""}, {SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""}, {SOCK_VECTOR, "VECTOR", 0, "Vector", ""}, {SOCK_STRING, "STRING", 0, "String", ""}, {SOCK_RGBA, "RGBA", 0, "Color", ""}, {SOCK_OBJECT, "OBJECT", 0, "Object", ""}, {SOCK_IMAGE, "IMAGE", 0, "Image", ""}, {SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""}, {SOCK_COLLECTION, "COLLECTION", 0, "Collection", ""}, {SOCK_TEXTURE, "TEXTURE", 0, "Texture", ""}, {SOCK_MATERIAL, "MATERIAL", 0, "Material", ""}, {0, NULL, 0, NULL, NULL}, }; #ifndef RNA_RUNTIME static const EnumPropertyItem rna_enum_node_socket_display_shape_items[] = { {SOCK_DISPLAY_SHAPE_CIRCLE, "CIRCLE", 0, "Circle", ""}, {SOCK_DISPLAY_SHAPE_SQUARE, "SQUARE", 0, "Square", ""}, {SOCK_DISPLAY_SHAPE_DIAMOND, "DIAMOND", 0, "Diamond", ""}, {SOCK_DISPLAY_SHAPE_CIRCLE_DOT, "CIRCLE_DOT", 0, "Circle with inner dot", ""}, {SOCK_DISPLAY_SHAPE_SQUARE_DOT, "SQUARE_DOT", 0, "Square with inner dot", ""}, {SOCK_DISPLAY_SHAPE_DIAMOND_DOT, "DIAMOND_DOT", 0, "Diamond with inner dot", ""}, {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem node_socket_type_items[] = { {SOCK_CUSTOM, "CUSTOM", 0, "Custom", ""}, {SOCK_FLOAT, "VALUE", 0, "Value", ""}, {SOCK_INT, "INT", 0, "Integer", ""}, {SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""}, {SOCK_VECTOR, "VECTOR", 0, "Vector", ""}, {SOCK_STRING, "STRING", 0, "String", ""}, {SOCK_RGBA, "RGBA", 0, "RGBA", ""}, {SOCK_SHADER, "SHADER", 0, "Shader", ""}, {SOCK_OBJECT, "OBJECT", 0, "Object", ""}, {SOCK_IMAGE, "IMAGE", 0, "Image", ""}, {SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""}, {SOCK_COLLECTION, "COLLECTION", 0, "Collection", ""}, {SOCK_TEXTURE, "TEXTURE", 0, "Texture", ""}, {SOCK_MATERIAL, "MATERIAL", 0, "Material", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_quality_items[] = { {NTREE_QUALITY_HIGH, "HIGH", 0, "High", "High quality"}, {NTREE_QUALITY_MEDIUM, "MEDIUM", 0, "Medium", "Medium quality"}, {NTREE_QUALITY_LOW, "LOW", 0, "Low", "Low quality"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_chunksize_items[] = { {NTREE_CHUNKSIZE_32, "32", 0, "32x32", "Chunksize of 32x32"}, {NTREE_CHUNKSIZE_64, "64", 0, "64x64", "Chunksize of 64x64"}, {NTREE_CHUNKSIZE_128, "128", 0, "128x128", "Chunksize of 128x128"}, {NTREE_CHUNKSIZE_256, "256", 0, "256x256", "Chunksize of 256x256"}, {NTREE_CHUNKSIZE_512, "512", 0, "512x512", "Chunksize of 512x512"}, {NTREE_CHUNKSIZE_1024, "1024", 0, "1024x1024", "Chunksize of 1024x1024"}, {0, NULL, 0, NULL, NULL}, }; #endif static const EnumPropertyItem rna_enum_execution_mode_items[] = { {NTREE_EXECUTION_MODE_TILED, "TILED", 0, "Tiled", "Compositing is tiled, having as priority to display first tiles as fast as possible"}, {NTREE_EXECUTION_MODE_FULL_FRAME, "FULL_FRAME", 0, "Full Frame", "Composites full image result as fast as possible"}, {0, NULL, 0, NULL, NULL}, }; const EnumPropertyItem rna_enum_mapping_type_items[] = { {NODE_MAPPING_TYPE_POINT, "POINT", 0, "Point", "Transform a point"}, {NODE_MAPPING_TYPE_TEXTURE, "TEXTURE", 0, "Texture", "Transform a texture by inverse mapping the texture coordinate"}, {NODE_MAPPING_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector. Location is ignored"}, {NODE_MAPPING_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a unit normal vector. Location is ignored"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem rna_enum_vector_rotate_type_items[] = { {NODE_VECTOR_ROTATE_TYPE_AXIS, "AXIS_ANGLE", 0, "Axis Angle", "Rotate a point using axis angle"}, {NODE_VECTOR_ROTATE_TYPE_AXIS_X, "X_AXIS", 0, "X Axis", "Rotate a point using X axis"}, {NODE_VECTOR_ROTATE_TYPE_AXIS_Y, "Y_AXIS", 0, "Y Axis", "Rotate a point using Y axis"}, {NODE_VECTOR_ROTATE_TYPE_AXIS_Z, "Z_AXIS", 0, "Z Axis", "Rotate a point using Z axis"}, {NODE_VECTOR_ROTATE_TYPE_EULER_XYZ, "EULER_XYZ", 0, "Euler", "Rotate a point using XYZ order"}, {0, NULL, 0, NULL, NULL}, }; const EnumPropertyItem rna_enum_node_math_items[] = { RNA_ENUM_ITEM_HEADING(N_("Functions"), NULL), {NODE_MATH_ADD, "ADD", 0, "Add", "A + B"}, {NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"}, {NODE_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "A * B"}, {NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", "A / B"}, {NODE_MATH_MULTIPLY_ADD, "MULTIPLY_ADD", 0, "Multiply Add", "A * B + C"}, RNA_ENUM_ITEM_SEPR, {NODE_MATH_POWER, "POWER", 0, "Power", "A power B"}, {NODE_MATH_LOGARITHM, "LOGARITHM", 0, "Logarithm", "Logarithm A base B"}, {NODE_MATH_SQRT, "SQRT", 0, "Square Root", "Square root of A"}, {NODE_MATH_INV_SQRT, "INVERSE_SQRT", 0, "Inverse Square Root", "1 / Square root of A"}, {NODE_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Magnitude of A"}, {NODE_MATH_EXPONENT, "EXPONENT", 0, "Exponent", "exp(A)"}, RNA_ENUM_ITEM_HEADING(N_("Comparison"), NULL), {NODE_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "The minimum from A and B"}, {NODE_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "The maximum from A and B"}, {NODE_MATH_LESS_THAN, "LESS_THAN", 0, "Less Than", "1 if A < B else 0"}, {NODE_MATH_GREATER_THAN, "GREATER_THAN", 0, "Greater Than", "1 if A > B else 0"}, {NODE_MATH_SIGN, "SIGN", 0, "Sign", "Returns the sign of A"}, {NODE_MATH_COMPARE, "COMPARE", 0, "Compare", "1 if (A == B) within tolerance C else 0"}, {NODE_MATH_SMOOTH_MIN, "SMOOTH_MIN", 0, "Smooth Minimum", "The minimum from A and B with smoothing C"}, {NODE_MATH_SMOOTH_MAX, "SMOOTH_MAX", 0, "Smooth Maximum", "The maximum from A and B with smoothing C"}, RNA_ENUM_ITEM_HEADING(N_("Rounding"), NULL), {NODE_MATH_ROUND, "ROUND", 0, "Round", "Round A to the nearest integer. Round upward if the fraction part is 0.5"}, {NODE_MATH_FLOOR, "FLOOR", 0, "Floor", "The largest integer smaller than or equal A"}, {NODE_MATH_CEIL, "CEIL", 0, "Ceil", "The smallest integer greater than or equal A"}, {NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "The integer part of A, removing fractional digits"}, RNA_ENUM_ITEM_SEPR, {NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"}, {NODE_MATH_MODULO, "MODULO", 0, "Modulo", "Modulo using fmod(A,B)"}, {NODE_MATH_WRAP, "WRAP", 0, "Wrap", "Wrap value to range, wrap(A,B)"}, {NODE_MATH_SNAP, "SNAP", 0, "Snap", "Snap to increment, snap(A,B)"}, {NODE_MATH_PINGPONG, "PINGPONG", 0, "Ping-Pong", "Wraps a value and reverses every other cycle (A,B)"}, RNA_ENUM_ITEM_HEADING(N_("Trigonometric"), NULL), {NODE_MATH_SINE, "SINE", 0, "Sine", "sin(A)"}, {NODE_MATH_COSINE, "COSINE", 0, "Cosine", "cos(A)"}, {NODE_MATH_TANGENT, "TANGENT", 0, "Tangent", "tan(A)"}, RNA_ENUM_ITEM_SEPR, {NODE_MATH_ARCSINE, "ARCSINE", 0, "Arcsine", "arcsin(A)"}, {NODE_MATH_ARCCOSINE, "ARCCOSINE", 0, "Arccosine", "arccos(A)"}, {NODE_MATH_ARCTANGENT, "ARCTANGENT", 0, "Arctangent", "arctan(A)"}, {NODE_MATH_ARCTAN2, "ARCTAN2", 0, "Arctan2", "The signed angle arctan(A / B)"}, RNA_ENUM_ITEM_SEPR, {NODE_MATH_SINH, "SINH", 0, "Hyperbolic Sine", "sinh(A)"}, {NODE_MATH_COSH, "COSH", 0, "Hyperbolic Cosine", "cosh(A)"}, {NODE_MATH_TANH, "TANH", 0, "Hyperbolic Tangent", "tanh(A)"}, RNA_ENUM_ITEM_HEADING(N_("Conversion"), NULL), {NODE_MATH_RADIANS, "RADIANS", 0, "To Radians", "Convert from degrees to radians"}, {NODE_MATH_DEGREES, "DEGREES", 0, "To Degrees", "Convert from radians to degrees"}, {0, NULL, 0, NULL, NULL}, }; const EnumPropertyItem rna_enum_node_vec_math_items[] = { {NODE_VECTOR_MATH_ADD, "ADD", 0, "Add", "A + B"}, {NODE_VECTOR_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"}, {NODE_VECTOR_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "Entry-wise multiply"}, {NODE_VECTOR_MATH_DIVIDE, "DIVIDE", 0, "Divide", "Entry-wise divide"}, {NODE_VECTOR_MATH_MULTIPLY_ADD, "MULTIPLY_ADD", 0, "Multiply Add", "A * B + C"}, RNA_ENUM_ITEM_SEPR, {NODE_VECTOR_MATH_CROSS_PRODUCT, "CROSS_PRODUCT", 0, "Cross Product", "A cross B"}, {NODE_VECTOR_MATH_PROJECT, "PROJECT", 0, "Project", "Project A onto B"}, {NODE_VECTOR_MATH_REFLECT, "REFLECT", 0, "Reflect", "Reflect A around the normal B. B doesn't need to be normalized"}, {NODE_VECTOR_MATH_REFRACT, "REFRACT", 0, "Refract", "For a given incident vector A, surface normal B and ratio of indices of refraction, Ior, " "refract returns the refraction vector, R"}, {NODE_VECTOR_MATH_FACEFORWARD, "FACEFORWARD", 0, "Faceforward", "Orients a vector A to point away from a surface B as defined by its normal C. " "Returns (dot(B, C) < 0) ? A : -A"}, {NODE_VECTOR_MATH_DOT_PRODUCT, "DOT_PRODUCT", 0, "Dot Product", "A dot B"}, RNA_ENUM_ITEM_SEPR, {NODE_VECTOR_MATH_DISTANCE, "DISTANCE", 0, "Distance", "Distance between A and B"}, {NODE_VECTOR_MATH_LENGTH, "LENGTH", 0, "Length", "Length of A"}, {NODE_VECTOR_MATH_SCALE, "SCALE", 0, "Scale", "A multiplied by Scale"}, {NODE_VECTOR_MATH_NORMALIZE, "NORMALIZE", 0, "Normalize", "Normalize A"}, RNA_ENUM_ITEM_SEPR, {NODE_VECTOR_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Entry-wise absolute"}, {NODE_VECTOR_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "Entry-wise minimum"}, {NODE_VECTOR_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "Entry-wise maximum"}, {NODE_VECTOR_MATH_FLOOR, "FLOOR", 0, "Floor", "Entry-wise floor"}, {NODE_VECTOR_MATH_CEIL, "CEIL", 0, "Ceil", "Entry-wise ceil"}, {NODE_VECTOR_MATH_FRACTION, "FRACTION", 0, "Fraction", "The fraction part of A entry-wise"}, {NODE_VECTOR_MATH_MODULO, "MODULO", 0, "Modulo", "Entry-wise modulo using fmod(A,B)"}, {NODE_VECTOR_MATH_WRAP, "WRAP", 0, "Wrap", "Entry-wise wrap(A,B)"}, {NODE_VECTOR_MATH_SNAP, "SNAP", 0, "Snap", "Round A to the largest integer multiple of B less than or equal A"}, RNA_ENUM_ITEM_SEPR, {NODE_VECTOR_MATH_SINE, "SINE", 0, "Sine", "Entry-wise sin(A)"}, {NODE_VECTOR_MATH_COSINE, "COSINE", 0, "Cosine", "Entry-wise cos(A)"}, {NODE_VECTOR_MATH_TANGENT, "TANGENT", 0, "Tangent", "Entry-wise tan(A)"}, {0, NULL, 0, NULL, NULL}, }; const EnumPropertyItem rna_enum_node_boolean_math_items[] = { {NODE_BOOLEAN_MATH_AND, "AND", 0, "And", "True when both inputs are true"}, {NODE_BOOLEAN_MATH_OR, "OR", 0, "Or", "True when at least one input is true"}, {NODE_BOOLEAN_MATH_NOT, "NOT", 0, "Not", "Opposite of the input"}, RNA_ENUM_ITEM_SEPR, {NODE_BOOLEAN_MATH_NAND, "NAND", 0, "Not And", "True when at least one input is false"}, {NODE_BOOLEAN_MATH_NOR, "NOR", 0, "Nor", "True when both inputs are false"}, {NODE_BOOLEAN_MATH_XNOR, "XNOR", 0, "Equal", "True when both inputs are equal (exclusive nor)"}, {NODE_BOOLEAN_MATH_XOR, "XOR", 0, "Not Equal", "True when both inputs are different (exclusive or)"}, RNA_ENUM_ITEM_SEPR, {NODE_BOOLEAN_MATH_IMPLY, "IMPLY", 0, "Imply", "True unless the first input is true and the second is false"}, {NODE_BOOLEAN_MATH_NIMPLY, "NIMPLY", 0, "Subtract", "True when the first input is true and the second is false (not imply)"}, {0, NULL, 0, NULL, NULL}, }; const EnumPropertyItem rna_enum_node_float_compare_items[] = { {NODE_COMPARE_LESS_THAN, "LESS_THAN", 0, "Less Than", "True when the first input is smaller than second input"}, {NODE_COMPARE_LESS_EQUAL, "LESS_EQUAL", 0, "Less Than or Equal", "True when the first input is smaller than the second input or equal"}, {NODE_COMPARE_GREATER_THAN, "GREATER_THAN", 0, "Greater Than", "True when the first input is greater than the second input"}, {NODE_COMPARE_GREATER_EQUAL, "GREATER_EQUAL", 0, "Greater Than or Equal", "True when the first input is greater than the second input or equal"}, {NODE_COMPARE_EQUAL, "EQUAL", 0, "Equal", "True when both inputs are approximately equal"}, {NODE_COMPARE_NOT_EQUAL, "NOT_EQUAL", 0, "Not Equal", "True when both inputs are not approximately equal"}, {0, NULL, 0, NULL, NULL}, }; const EnumPropertyItem rna_enum_node_compare_operation_items[] = { {NODE_COMPARE_LESS_THAN, "LESS_THAN", 0, "Less Than", "True when the first input is smaller than second input"}, {NODE_COMPARE_LESS_EQUAL, "LESS_EQUAL", 0, "Less Than or Equal", "True when the first input is smaller than the second input or equal"}, {NODE_COMPARE_GREATER_THAN, "GREATER_THAN", 0, "Greater Than", "True when the first input is greater than the second input"}, {NODE_COMPARE_GREATER_EQUAL, "GREATER_EQUAL", 0, "Greater Than or Equal", "True when the first input is greater than the second input or equal"}, {NODE_COMPARE_EQUAL, "EQUAL", 0, "Equal", "True when both inputs are approximately equal"}, {NODE_COMPARE_NOT_EQUAL, "NOT_EQUAL", 0, "Not Equal", "True when both inputs are not approximately equal"}, {NODE_COMPARE_COLOR_BRIGHTER, "BRIGHTER", 0, "Brighter", "True when the first input is brighter"}, {NODE_COMPARE_COLOR_DARKER, "DARKER", 0, "Darker", "True when the first input is darker"}, {0, NULL, 0, NULL, NULL}, }; const EnumPropertyItem rna_enum_node_float_to_int_items[] = { {FN_NODE_FLOAT_TO_INT_ROUND, "ROUND", 0, "Round", "Round the float up or down to the nearest integer"}, {FN_NODE_FLOAT_TO_INT_FLOOR, "FLOOR", 0, "Floor", "Round the float down to the next smallest integer"}, {FN_NODE_FLOAT_TO_INT_CEIL, "CEILING", 0, "Ceiling", "Round the float up to the next largest integer"}, {FN_NODE_FLOAT_TO_INT_TRUNCATE, "TRUNCATE", 0, "Truncate", "Round the float to the closest integer in the direction of zero (floor if positive; ceiling " "if negative)"}, {0, NULL, 0, NULL, NULL}, }; const EnumPropertyItem rna_enum_node_map_range_items[] = { {NODE_MAP_RANGE_LINEAR, "LINEAR", 0, "Linear", "Linear interpolation between From Min and From Max values"}, {NODE_MAP_RANGE_STEPPED, "STEPPED", 0, "Stepped Linear", "Stepped linear interpolation between From Min and From Max values"}, {NODE_MAP_RANGE_SMOOTHSTEP, "SMOOTHSTEP", 0, "Smooth Step", "Smooth Hermite edge interpolation between From Min and From Max values"}, {NODE_MAP_RANGE_SMOOTHERSTEP, "SMOOTHERSTEP", 0, "Smoother Step", "Smoother Hermite edge interpolation between From Min and From Max values"}, {0, NULL, 0, NULL, NULL}, }; const EnumPropertyItem rna_enum_node_clamp_items[] = { {NODE_CLAMP_MINMAX, "MINMAX", 0, "Min Max", "Constrain value between min and max"}, {NODE_CLAMP_RANGE, "RANGE", 0, "Range", "Constrain value between min and max, swapping arguments when min > max"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem rna_enum_node_tex_dimensions_items[] = { {1, "1D", 0, "1D", "Use the scalar value W as input"}, {2, "2D", 0, "2D", "Use the 2D vector (X, Y) as input. The Z component is ignored"}, {3, "3D", 0, "3D", "Use the 3D vector (X, Y, Z) as input"}, {4, "4D", 0, "4D", "Use the 4D vector (X, Y, Z, W) as input"}, {0, NULL, 0, NULL, NULL}, }; const EnumPropertyItem rna_enum_node_filter_items[] = { {0, "SOFTEN", 0, "Soften", ""}, {1, "SHARPEN", 0, "Box Sharpen", "An aggressive sharpening filter"}, {7, "SHARPEN_DIAMOND", 0, "Diamond Sharpen", "A moderate sharpening filter"}, {2, "LAPLACE", 0, "Laplace", ""}, {3, "SOBEL", 0, "Sobel", ""}, {4, "PREWITT", 0, "Prewitt", ""}, {5, "KIRSCH", 0, "Kirsch", ""}, {6, "SHADOW", 0, "Shadow", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem rna_node_geometry_curve_handle_type_items[] = { {GEO_NODE_CURVE_HANDLE_FREE, "FREE", ICON_HANDLE_FREE, "Free", "The handle can be moved anywhere, and doesn't influence the point's other handle"}, {GEO_NODE_CURVE_HANDLE_AUTO, "AUTO", ICON_HANDLE_AUTO, "Auto", "The location is automatically calculated to be smooth"}, {GEO_NODE_CURVE_HANDLE_VECTOR, "VECTOR", ICON_HANDLE_VECTOR, "Vector", "The location is calculated to point to the next/previous control point"}, {GEO_NODE_CURVE_HANDLE_ALIGN, "ALIGN", ICON_HANDLE_ALIGNED, "Align", "The location is constrained to point in the opposite direction as the other handle"}, {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem rna_node_geometry_curve_handle_side_items[] = { {GEO_NODE_CURVE_HANDLE_LEFT, "LEFT", ICON_NONE, "Left", "Use the left handles"}, {GEO_NODE_CURVE_HANDLE_RIGHT, "RIGHT", ICON_NONE, "Right", "Use the right handles"}, {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem rna_node_combsep_color_items[] = { {NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"}, {NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"}, {NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"}, {0, NULL, 0, NULL, NULL}, }; #ifndef RNA_RUNTIME static const EnumPropertyItem node_sampler_type_items[] = { {0, "NEAREST", 0, "Nearest", ""}, {1, "BILINEAR", 0, "Bilinear", ""}, {2, "BICUBIC", 0, "Bicubic", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_shader_output_target_items[] = { {SHD_OUTPUT_ALL, "ALL", 0, "All", "Use shaders for all renderers and viewports, unless there exists a more specific output"}, {SHD_OUTPUT_EEVEE, "EEVEE", 0, "Eevee", "Use shaders for Eevee renderer"}, {SHD_OUTPUT_CYCLES, "CYCLES", 0, "Cycles", "Use shaders for Cycles renderer"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_cryptomatte_layer_name_items[] = { {0, "CryptoObject", 0, "Object", "Use Object layer"}, {1, "CryptoMaterial", 0, "Material", "Use Material layer"}, {2, "CryptoAsset", 0, "Asset", "Use Asset layer"}, {0, NULL, 0, NULL, NULL}, }; static EnumPropertyItem rna_node_geometry_mesh_circle_fill_type_items[] = { {GEO_NODE_MESH_CIRCLE_FILL_NONE, "NONE", 0, "None", ""}, {GEO_NODE_MESH_CIRCLE_FILL_NGON, "NGON", 0, "N-Gon", ""}, {GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN, "TRIANGLE_FAN", 0, "Triangles", ""}, {0, NULL, 0, NULL, NULL}, }; #endif #ifndef RNA_RUNTIME #endif #undef ITEM_ATTRIBUTE #undef ITEM_FLOAT #undef ITEM_VECTOR #undef ITEM_COLOR #undef ITEM_BOOLEAN #ifdef RNA_RUNTIME # include "BLI_linklist.h" # include "BLI_string.h" # include "BKE_context.h" # include "BKE_idprop.h" # include "BKE_global.h" # include "ED_node.h" # include "ED_render.h" # include "GPU_material.h" # include "NOD_common.h" # include "NOD_composite.h" # include "NOD_geometry.h" # include "NOD_shader.h" # include "NOD_socket.h" # include "NOD_texture.h" # include "RE_engine.h" # include "RE_pipeline.h" # include "DNA_scene_types.h" # include "WM_api.h" static void rna_Node_socket_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr); int rna_node_tree_type_to_enum(bNodeTreeType *typeinfo) { int i = 0, result = -1; NODE_TREE_TYPES_BEGIN (nt) { if (nt == typeinfo) { result = i; break; } i++; } NODE_TREE_TYPES_END; return result; } int rna_node_tree_idname_to_enum(const char *idname) { int i = 0, result = -1; NODE_TREE_TYPES_BEGIN (nt) { if (STREQ(nt->idname, idname)) { result = i; break; } i++; } NODE_TREE_TYPES_END; return result; } bNodeTreeType *rna_node_tree_type_from_enum(int value) { int i = 0; bNodeTreeType *result = NULL; NODE_TREE_TYPES_BEGIN (nt) { if (i == value) { result = nt; break; } i++; } NODE_TREE_TYPES_END; return result; } const EnumPropertyItem *rna_node_tree_type_itemf(void *data, bool (*poll)(void *data, bNodeTreeType *), bool *r_free) { EnumPropertyItem tmp = {0}; EnumPropertyItem *item = NULL; int totitem = 0, i = 0; NODE_TREE_TYPES_BEGIN (nt) { if (poll && !poll(data, nt)) { i++; continue; } tmp.value = i; tmp.identifier = nt->idname; tmp.icon = nt->ui_icon; tmp.name = nt->ui_name; tmp.description = nt->ui_description; RNA_enum_item_add(&item, &totitem, &tmp); i++; } NODE_TREE_TYPES_END; if (totitem == 0) { *r_free = false; return DummyRNA_NULL_items; } RNA_enum_item_end(&item, &totitem); *r_free = true; return item; } int rna_node_type_to_enum(bNodeType *typeinfo) { int i = 0, result = -1; NODE_TYPES_BEGIN (ntype) { if (ntype == typeinfo) { result = i; break; } i++; } NODE_TYPES_END; return result; } int rna_node_idname_to_enum(const char *idname) { int i = 0, result = -1; NODE_TYPES_BEGIN (ntype) { if (STREQ(ntype->idname, idname)) { result = i; break; } i++; } NODE_TYPES_END; return result; } bNodeType *rna_node_type_from_enum(int value) { int i = 0; bNodeType *result = NULL; NODE_TYPES_BEGIN (ntype) { if (i == value) { result = ntype; break; } i++; } NODE_TYPES_END; return result; } const EnumPropertyItem *rna_node_type_itemf(void *data, bool (*poll)(void *data, bNodeType *), bool *r_free) { EnumPropertyItem *item = NULL; EnumPropertyItem tmp = {0}; int totitem = 0, i = 0; NODE_TYPES_BEGIN (ntype) { if (poll && !poll(data, ntype)) { i++; continue; } tmp.value = i; tmp.identifier = ntype->idname; tmp.icon = ntype->ui_icon; tmp.name = ntype->ui_name; tmp.description = ntype->ui_description; RNA_enum_item_add(&item, &totitem, &tmp); i++; } NODE_TYPES_END; if (totitem == 0) { *r_free = false; return DummyRNA_NULL_items; } RNA_enum_item_end(&item, &totitem); *r_free = true; return item; } int rna_node_socket_type_to_enum(bNodeSocketType *typeinfo) { int i = 0, result = -1; NODE_SOCKET_TYPES_BEGIN (stype) { if (stype == typeinfo) { result = i; break; } i++; } NODE_SOCKET_TYPES_END; return result; } int rna_node_socket_idname_to_enum(const char *idname) { int i = 0, result = -1; NODE_SOCKET_TYPES_BEGIN (stype) { if (STREQ(stype->idname, idname)) { result = i; break; } i++; } NODE_SOCKET_TYPES_END; return result; } bNodeSocketType *rna_node_socket_type_from_enum(int value) { int i = 0; bNodeSocketType *result = NULL; NODE_SOCKET_TYPES_BEGIN (stype) { if (i == value) { result = stype; break; } i++; } NODE_SOCKET_TYPES_END; return result; } const EnumPropertyItem *rna_node_socket_type_itemf(void *data, bool (*poll)(void *data, bNodeSocketType *), bool *r_free) { EnumPropertyItem *item = NULL; EnumPropertyItem tmp = {0}; int totitem = 0, i = 0; StructRNA *srna; NODE_SOCKET_TYPES_BEGIN (stype) { if (poll && !poll(data, stype)) { i++; continue; } srna = stype->ext_socket.srna; tmp.value = i; tmp.identifier = stype->idname; tmp.icon = RNA_struct_ui_icon(srna); tmp.name = nodeSocketTypeLabel(stype); tmp.description = RNA_struct_ui_description(srna); RNA_enum_item_add(&item, &totitem, &tmp); i++; } NODE_SOCKET_TYPES_END; if (totitem == 0) { *r_free = false; return DummyRNA_NULL_items; } RNA_enum_item_end(&item, &totitem); *r_free = true; return item; } static const EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { EnumPropertyItem *item = NULL; EnumPropertyItem tmp; int totitem = 0; /* hack, don't want to add include path to RNA just for this, since in the future RNA types * for nodes should be defined locally at runtime anyway ... */ tmp.value = NODE_CUSTOM; tmp.identifier = "CUSTOM"; tmp.name = "Custom"; tmp.description = "Custom Node"; tmp.icon = ICON_NONE; RNA_enum_item_add(&item, &totitem, &tmp); tmp.value = NODE_CUSTOM_GROUP; tmp.identifier = "CUSTOM GROUP"; tmp.name = "CustomGroup"; tmp.description = "Custom Group Node"; tmp.icon = ICON_NONE; RNA_enum_item_add(&item, &totitem, &tmp); tmp.value = NODE_UNDEFINED; tmp.identifier = "UNDEFINED"; tmp.name = "UNDEFINED"; tmp.description = ""; tmp.icon = ICON_NONE; RNA_enum_item_add(&item, &totitem, &tmp); # define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "Node")) { \ tmp.value = ID; \ tmp.identifier = EnumName; \ tmp.name = UIName; \ tmp.description = UIDesc; \ tmp.icon = ICON_NONE; \ RNA_enum_item_add(&item, &totitem, &tmp); \ } # include "../../nodes/NOD_static_types.h" # undef DefNode if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) { # define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "ShaderNode")) { \ tmp.value = ID; \ tmp.identifier = EnumName; \ tmp.name = UIName; \ tmp.description = UIDesc; \ tmp.icon = ICON_NONE; \ RNA_enum_item_add(&item, &totitem, &tmp); \ } # include "../../nodes/NOD_static_types.h" # undef DefNode } if (RNA_struct_is_a(ptr->type, &RNA_CompositorNode)) { # define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "CompositorNode")) { \ tmp.value = ID; \ tmp.identifier = EnumName; \ tmp.name = UIName; \ tmp.description = UIDesc; \ tmp.icon = ICON_NONE; \ RNA_enum_item_add(&item, &totitem, &tmp); \ } # include "../../nodes/NOD_static_types.h" # undef DefNode } if (RNA_struct_is_a(ptr->type, &RNA_TextureNode)) { # define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "TextureNode")) { \ tmp.value = ID; \ tmp.identifier = EnumName; \ tmp.name = UIName; \ tmp.description = UIDesc; \ tmp.icon = ICON_NONE; \ RNA_enum_item_add(&item, &totitem, &tmp); \ } # include "../../nodes/NOD_static_types.h" # undef DefNode } if (RNA_struct_is_a(ptr->type, &RNA_GeometryNode)) { # define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "GeometryNode")) { \ tmp.value = ID; \ tmp.identifier = EnumName; \ tmp.name = UIName; \ tmp.description = UIDesc; \ tmp.icon = ICON_NONE; \ RNA_enum_item_add(&item, &totitem, &tmp); \ } # include "../../nodes/NOD_static_types.h" # undef DefNode } if (RNA_struct_is_a(ptr->type, &RNA_FunctionNode)) { # define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ if (STREQ(#Category, "FunctionNode")) { \ tmp.value = ID; \ tmp.identifier = EnumName; \ tmp.name = UIName; \ tmp.description = UIDesc; \ tmp.icon = ICON_NONE; \ RNA_enum_item_add(&item, &totitem, &tmp); \ } # include "../../nodes/NOD_static_types.h" # undef DefNode } RNA_enum_item_end(&item, &totitem); *r_free = true; return item; } /* ******** Node Tree ******** */ static StructRNA *rna_NodeTree_refine(struct PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->data; if (ntree->typeinfo->rna_ext.srna) { return ntree->typeinfo->rna_ext.srna; } else { return &RNA_NodeTree; } } static bool rna_NodeTree_poll(const bContext *C, bNodeTreeType *ntreetype) { extern FunctionRNA rna_NodeTree_poll_func; PointerRNA ptr; ParameterList list; FunctionRNA *func; void *ret; bool visible; RNA_pointer_create(NULL, ntreetype->rna_ext.srna, NULL, &ptr); /* dummy */ func = &rna_NodeTree_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */ RNA_parameter_list_create(&list, &ptr, func); RNA_parameter_set_lookup(&list, "context", &C); ntreetype->rna_ext.call((bContext *)C, &ptr, func, &list); RNA_parameter_get_lookup(&list, "visible", &ret); visible = *(bool *)ret; RNA_parameter_list_free(&list); return visible; } static void rna_NodeTree_update_reg(bNodeTree *ntree) { extern FunctionRNA rna_NodeTree_update_func; PointerRNA ptr; ParameterList list; FunctionRNA *func; RNA_id_pointer_create(&ntree->id, &ptr); func = &rna_NodeTree_update_func; /* RNA_struct_find_function(&ptr, "update"); */ RNA_parameter_list_create(&list, &ptr, func); ntree->typeinfo->rna_ext.call(NULL, &ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_NodeTree_get_from_context( const bContext *C, bNodeTreeType *ntreetype, bNodeTree **r_ntree, ID **r_id, ID **r_from) { extern FunctionRNA rna_NodeTree_get_from_context_func; PointerRNA ptr; ParameterList list; FunctionRNA *func; void *ret1, *ret2, *ret3; RNA_pointer_create(NULL, ntreetype->rna_ext.srna, NULL, &ptr); /* dummy */ // RNA_struct_find_function(&ptr, "get_from_context"); func = &rna_NodeTree_get_from_context_func; RNA_parameter_list_create(&list, &ptr, func); RNA_parameter_set_lookup(&list, "context", &C); ntreetype->rna_ext.call((bContext *)C, &ptr, func, &list); RNA_parameter_get_lookup(&list, "result_1", &ret1); RNA_parameter_get_lookup(&list, "result_2", &ret2); RNA_parameter_get_lookup(&list, "result_3", &ret3); *r_ntree = *(bNodeTree **)ret1; *r_id = *(ID **)ret2; *r_from = *(ID **)ret3; RNA_parameter_list_free(&list); } static bool rna_NodeTree_valid_socket_type(bNodeTreeType *ntreetype, bNodeSocketType *socket_type) { extern FunctionRNA rna_NodeTree_valid_socket_type_func; PointerRNA ptr; ParameterList list; FunctionRNA *func; void *ret; bool valid; RNA_pointer_create(NULL, ntreetype->rna_ext.srna, NULL, &ptr); /* dummy */ func = &rna_NodeTree_valid_socket_type_func; RNA_parameter_list_create(&list, &ptr, func); RNA_parameter_set_lookup(&list, "idname", &socket_type->idname); ntreetype->rna_ext.call(NULL, &ptr, func, &list); RNA_parameter_get_lookup(&list, "valid", &ret); valid = *(bool *)ret; RNA_parameter_list_free(&list); return valid; } static void rna_NodeTree_unregister(Main *UNUSED(bmain), StructRNA *type) { bNodeTreeType *nt = RNA_struct_blender_type_get(type); if (!nt) { return; } RNA_struct_free_extension(type, &nt->rna_ext); RNA_struct_free(&BLENDER_RNA, type); ntreeTypeFreeLink(nt); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); } static StructRNA *rna_NodeTree_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeTreeType *nt, dummynt; bNodeTree dummyntree; PointerRNA dummyptr; int have_function[4]; /* setup dummy tree & tree type to store static properties in */ memset(&dummynt, 0, sizeof(bNodeTreeType)); memset(&dummyntree, 0, sizeof(bNodeTree)); dummyntree.typeinfo = &dummynt; RNA_pointer_create(NULL, &RNA_NodeTree, &dummyntree, &dummyptr); /* validate the python class */ if (validate(&dummyptr, data, have_function) != 0) { return NULL; } if (strlen(identifier) >= sizeof(dummynt.idname)) { BKE_reportf(reports, RPT_ERROR, "Registering node tree class: '%s' is too long, maximum length is %d", identifier, (int)sizeof(dummynt.idname)); return NULL; } /* check if we have registered this tree type before, and remove it */ nt = ntreeTypeFind(dummynt.idname); if (nt) { rna_NodeTree_unregister(bmain, nt->rna_ext.srna); } /* create a new node tree type */ nt = MEM_mallocN(sizeof(bNodeTreeType), "node tree type"); memcpy(nt, &dummynt, sizeof(dummynt)); nt->type = NTREE_CUSTOM; nt->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, nt->idname, &RNA_NodeTree); nt->rna_ext.data = data; nt->rna_ext.call = call; nt->rna_ext.free = free; RNA_struct_blender_type_set(nt->rna_ext.srna, nt); RNA_def_struct_ui_text(nt->rna_ext.srna, nt->ui_name, nt->ui_description); RNA_def_struct_ui_icon(nt->rna_ext.srna, nt->ui_icon); nt->poll = (have_function[0]) ? rna_NodeTree_poll : NULL; nt->update = (have_function[1]) ? rna_NodeTree_update_reg : NULL; nt->get_from_context = (have_function[2]) ? rna_NodeTree_get_from_context : NULL; nt->valid_socket_type = (have_function[3]) ? rna_NodeTree_valid_socket_type : NULL; ntreeTypeAdd(nt); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return nt->rna_ext.srna; } static bool rna_NodeTree_check(bNodeTree *ntree, ReportList *reports) { if (!ntreeIsRegistered(ntree)) { if (reports) { BKE_reportf(reports, RPT_ERROR, "Node tree '%s' has undefined type %s", ntree->id.name + 2, ntree->idname); } return false; } else { return true; } } static void rna_NodeTree_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); WM_main_add_notifier(NC_SCENE | ND_NODES, &ntree->id); ED_node_tree_propagate_change(NULL, bmain, ntree); } static bNode *rna_NodeTree_node_new(bNodeTree *ntree, bContext *C, ReportList *reports, const char *type) { bNodeType *ntype; bNode *node; if (!rna_NodeTree_check(ntree, reports)) { return NULL; } ntype = nodeTypeFind(type); if (!ntype) { BKE_reportf(reports, RPT_ERROR, "Node type %s undefined", type); return NULL; } const char *disabled_hint = NULL; if (ntype->poll && !ntype->poll(ntype, ntree, &disabled_hint)) { if (disabled_hint) { BKE_reportf(reports, RPT_ERROR, "Cannot add node of type %s to node tree '%s'\n %s", type, ntree->id.name + 2, disabled_hint); return NULL; } else { BKE_reportf(reports, RPT_ERROR, "Cannot add node of type %s to node tree '%s'", type, ntree->id.name + 2); return NULL; } } node = nodeAddNode(C, ntree, type); BLI_assert(node && node->typeinfo); if (ntree->type == NTREE_TEXTURE) { ntreeTexCheckCyclics(ntree); } Main *bmain = CTX_data_main(C); ED_node_tree_propagate_change(C, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); return node; } static void rna_NodeTree_node_remove(bNodeTree *ntree, Main *bmain, ReportList *reports, PointerRNA *node_ptr) { bNode *node = node_ptr->data; if (!rna_NodeTree_check(ntree, reports)) { return; } if (BLI_findindex(&ntree->nodes, node) == -1) { BKE_reportf(reports, RPT_ERROR, "Unable to locate node '%s' in node tree", node->name); return; } nodeRemoveNode(bmain, ntree, node, true); RNA_POINTER_INVALIDATE(node_ptr); ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static void rna_NodeTree_node_clear(bNodeTree *ntree, Main *bmain, ReportList *reports) { bNode *node = ntree->nodes.first; if (!rna_NodeTree_check(ntree, reports)) { return; } while (node) { bNode *next_node = node->next; nodeRemoveNode(bmain, ntree, node, true); node = next_node; } ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static PointerRNA rna_NodeTree_active_node_get(PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->data; bNode *node = nodeGetActive(ntree); return rna_pointer_inherit_refine(ptr, &RNA_Node, node); } static void rna_NodeTree_active_node_set(PointerRNA *ptr, const PointerRNA value, struct ReportList *UNUSED(reports)) { bNodeTree *ntree = (bNodeTree *)ptr->data; bNode *node = (bNode *)value.data; if (node && BLI_findindex(&ntree->nodes, node) != -1) { nodeSetActive(ntree, node); /* Handle NODE_DO_OUTPUT as well. */ if (node->typeinfo->nclass == NODE_CLASS_OUTPUT && node->type != CMP_NODE_OUTPUT_FILE) { /* If this node becomes the active output, the others of the same type can't be the active * output anymore. */ LISTBASE_FOREACH (bNode *, other_node, &ntree->nodes) { if (other_node->type == node->type) { other_node->flag &= ~NODE_DO_OUTPUT; } } node->flag |= NODE_DO_OUTPUT; ntreeSetOutput(ntree); BKE_ntree_update_tag_active_output_changed(ntree); } } else { nodeClearActive(ntree); } } static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree, Main *bmain, ReportList *reports, bNodeSocket *fromsock, bNodeSocket *tosock, bool verify_limits) { bNodeLink *ret; bNode *fromnode = NULL, *tonode = NULL; if (!rna_NodeTree_check(ntree, reports)) { return NULL; } nodeFindNode(ntree, fromsock, &fromnode, NULL); nodeFindNode(ntree, tosock, &tonode, NULL); /* check validity of the sockets: * if sockets from different trees are passed in this will fail! */ if (!fromnode || !tonode) { return NULL; } if (&fromsock->in_out == &tosock->in_out) { BKE_report(reports, RPT_ERROR, "Same input/output direction of sockets"); return NULL; } if (verify_limits) { /* remove other socket links if limit is exceeded */ if (nodeCountSocketLinks(ntree, fromsock) + 1 > nodeSocketLinkLimit(fromsock)) { nodeRemSocketLinks(ntree, fromsock); } if (nodeCountSocketLinks(ntree, tosock) + 1 > nodeSocketLinkLimit(tosock)) { nodeRemSocketLinks(ntree, tosock); } if (tosock->flag & SOCK_MULTI_INPUT) { LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { if (link->fromsock == fromsock && link->tosock == tosock) { nodeRemLink(ntree, link); } } } } ret = nodeAddLink(ntree, fromnode, fromsock, tonode, tosock); if (ret) { /* not an issue from the UI, clear hidden from API to keep valid state. */ fromsock->flag &= ~SOCK_HIDDEN; tosock->flag &= ~SOCK_HIDDEN; ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } return ret; } static void rna_NodeTree_link_remove(bNodeTree *ntree, Main *bmain, ReportList *reports, PointerRNA *link_ptr) { bNodeLink *link = link_ptr->data; if (!rna_NodeTree_check(ntree, reports)) { return; } if (BLI_findindex(&ntree->links, link) == -1) { BKE_report(reports, RPT_ERROR, "Unable to locate link in node tree"); return; } nodeRemLink(ntree, link); RNA_POINTER_INVALIDATE(link_ptr); ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static void rna_NodeTree_link_clear(bNodeTree *ntree, Main *bmain, ReportList *reports) { bNodeLink *link = ntree->links.first; if (!rna_NodeTree_check(ntree, reports)) { return; } while (link) { bNodeLink *next_link = link->next; nodeRemLink(ntree, link); link = next_link; } ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static int rna_NodeTree_active_input_get(PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->data; int index = 0; LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &ntree->inputs, index) { if (socket->flag & SELECT) { return index; } } return -1; } static void rna_NodeTree_active_input_set(PointerRNA *ptr, int value) { bNodeTree *ntree = (bNodeTree *)ptr->data; int index = 0; LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &ntree->inputs, index) { SET_FLAG_FROM_TEST(socket->flag, index == value, SELECT); } } static int rna_NodeTree_active_output_get(PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->data; int index = 0; LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &ntree->outputs, index) { if (socket->flag & SELECT) { return index; } } return -1; } static void rna_NodeTree_active_output_set(PointerRNA *ptr, int value) { bNodeTree *ntree = (bNodeTree *)ptr->data; int index = 0; LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &ntree->outputs, index) { SET_FLAG_FROM_TEST(socket->flag, index == value, SELECT); } } static bNodeSocket *rna_NodeTree_inputs_new( bNodeTree *ntree, Main *bmain, ReportList *reports, const char *type, const char *name) { if (!rna_NodeTree_check(ntree, reports)) { return NULL; } bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_IN, type, name); if (sock == NULL) { BKE_report(reports, RPT_ERROR, "Unable to create socket"); } else { ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } return sock; } static bNodeSocket *rna_NodeTree_outputs_new( bNodeTree *ntree, Main *bmain, ReportList *reports, const char *type, const char *name) { if (!rna_NodeTree_check(ntree, reports)) { return NULL; } bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_OUT, type, name); if (sock == NULL) { BKE_report(reports, RPT_ERROR, "Unable to create socket"); } else { ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } return sock; } static void rna_NodeTree_socket_remove(bNodeTree *ntree, Main *bmain, ReportList *reports, bNodeSocket *sock) { if (!rna_NodeTree_check(ntree, reports)) { return; } if (BLI_findindex(&ntree->inputs, sock) == -1 && BLI_findindex(&ntree->outputs, sock) == -1) { BKE_reportf(reports, RPT_ERROR, "Unable to locate socket '%s' in node", sock->identifier); } else { ntreeRemoveSocketInterface(ntree, sock); ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } } static void rna_NodeTree_inputs_clear(bNodeTree *ntree, Main *bmain, ReportList *reports) { if (!rna_NodeTree_check(ntree, reports)) { return; } LISTBASE_FOREACH_MUTABLE (bNodeSocket *, socket, &ntree->inputs) { ntreeRemoveSocketInterface(ntree, socket); } ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static void rna_NodeTree_outputs_clear(bNodeTree *ntree, Main *bmain, ReportList *reports) { if (!rna_NodeTree_check(ntree, reports)) { return; } LISTBASE_FOREACH_MUTABLE (bNodeSocket *, socket, &ntree->outputs) { ntreeRemoveSocketInterface(ntree, socket); } ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static void rna_NodeTree_inputs_move(bNodeTree *ntree, Main *bmain, int from_index, int to_index) { if (from_index == to_index) { return; } if (from_index < 0 || to_index < 0) { return; } bNodeSocket *sock = BLI_findlink(&ntree->inputs, from_index); if (to_index < from_index) { bNodeSocket *nextsock = BLI_findlink(&ntree->inputs, to_index); if (nextsock) { BLI_remlink(&ntree->inputs, sock); BLI_insertlinkbefore(&ntree->inputs, nextsock, sock); } } else { bNodeSocket *prevsock = BLI_findlink(&ntree->inputs, to_index); if (prevsock) { BLI_remlink(&ntree->inputs, sock); BLI_insertlinkafter(&ntree->inputs, prevsock, sock); } } BKE_ntree_update_tag_interface(ntree); ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static void rna_NodeTree_outputs_move(bNodeTree *ntree, Main *bmain, int from_index, int to_index) { if (from_index == to_index) { return; } if (from_index < 0 || to_index < 0) { return; } bNodeSocket *sock = BLI_findlink(&ntree->outputs, from_index); if (to_index < from_index) { bNodeSocket *nextsock = BLI_findlink(&ntree->outputs, to_index); if (nextsock) { BLI_remlink(&ntree->outputs, sock); BLI_insertlinkbefore(&ntree->outputs, nextsock, sock); } } else { bNodeSocket *prevsock = BLI_findlink(&ntree->outputs, to_index); if (prevsock) { BLI_remlink(&ntree->outputs, sock); BLI_insertlinkafter(&ntree->outputs, prevsock, sock); } } BKE_ntree_update_tag_interface(ntree); ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static void rna_NodeTree_interface_update(bNodeTree *ntree, bContext *C) { Main *bmain = CTX_data_main(C); BKE_ntree_update_tag_interface(ntree); ED_node_tree_propagate_change(NULL, bmain, ntree); } /* ******** NodeLink ******** */ static bool rna_NodeLink_is_hidden_get(PointerRNA *ptr) { bNodeLink *link = ptr->data; return nodeLinkIsHidden(link); } /* ******** Node ******** */ static StructRNA *rna_Node_refine(struct PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; if (node->typeinfo->rna_ext.srna) { return node->typeinfo->rna_ext.srna; } else { return ptr->type; } } static char *rna_Node_path(const PointerRNA *ptr) { const bNode *node = (bNode *)ptr->data; char name_esc[sizeof(node->name) * 2]; BLI_str_escape(name_esc, node->name, sizeof(name_esc)); return BLI_sprintfN("nodes[\"%s\"]", name_esc); } char *rna_Node_ImageUser_path(const PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; if (!ELEM(ntree->type, NTREE_SHADER, NTREE_CUSTOM)) { return NULL; } for (bNode *node = ntree->nodes.first; node; node = node->next) { switch (node->type) { case SH_NODE_TEX_ENVIRONMENT: { NodeTexEnvironment *data = node->storage; if (&data->iuser != ptr->data) { continue; } break; } case SH_NODE_TEX_IMAGE: { NodeTexImage *data = node->storage; if (&data->iuser != ptr->data) { continue; } break; } default: continue; } char name_esc[sizeof(node->name) * 2]; BLI_str_escape(name_esc, node->name, sizeof(name_esc)); return BLI_sprintfN("nodes[\"%s\"].image_user", name_esc); } return NULL; } static bool rna_Node_poll(bNodeType *ntype, bNodeTree *ntree, const char **UNUSED(r_disabled_hint)) { extern FunctionRNA rna_Node_poll_func; PointerRNA ptr; ParameterList list; FunctionRNA *func; void *ret; bool visible; RNA_pointer_create(NULL, ntype->rna_ext.srna, NULL, &ptr); /* dummy */ func = &rna_Node_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */ RNA_parameter_list_create(&list, &ptr, func); RNA_parameter_set_lookup(&list, "node_tree", &ntree); ntype->rna_ext.call(NULL, &ptr, func, &list); RNA_parameter_get_lookup(&list, "visible", &ret); visible = *(bool *)ret; RNA_parameter_list_free(&list); return visible; } static bool rna_Node_poll_instance(bNode *node, bNodeTree *ntree, const char **UNUSED(disabled_info)) { extern FunctionRNA rna_Node_poll_instance_func; PointerRNA ptr; ParameterList list; FunctionRNA *func; void *ret; bool visible; RNA_pointer_create(NULL, node->typeinfo->rna_ext.srna, node, &ptr); /* dummy */ func = &rna_Node_poll_instance_func; /* RNA_struct_find_function(&ptr, "poll_instance"); */ RNA_parameter_list_create(&list, &ptr, func); RNA_parameter_set_lookup(&list, "node_tree", &ntree); node->typeinfo->rna_ext.call(NULL, &ptr, func, &list); RNA_parameter_get_lookup(&list, "visible", &ret); visible = *(bool *)ret; RNA_parameter_list_free(&list); return visible; } static bool rna_Node_poll_instance_default(bNode *node, bNodeTree *ntree, const char **disabled_info) { /* use the basic poll function */ return rna_Node_poll(node->typeinfo, ntree, disabled_info); } static void rna_Node_update_reg(bNodeTree *ntree, bNode *node) { extern FunctionRNA rna_Node_update_func; PointerRNA ptr; ParameterList list; FunctionRNA *func; RNA_pointer_create((ID *)ntree, node->typeinfo->rna_ext.srna, node, &ptr); func = &rna_Node_update_func; /* RNA_struct_find_function(&ptr, "update"); */ RNA_parameter_list_create(&list, &ptr, func); node->typeinfo->rna_ext.call(NULL, &ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_Node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link) { extern FunctionRNA rna_Node_insert_link_func; PointerRNA ptr; ParameterList list; FunctionRNA *func; RNA_pointer_create((ID *)ntree, node->typeinfo->rna_ext.srna, node, &ptr); func = &rna_Node_insert_link_func; RNA_parameter_list_create(&list, &ptr, func); RNA_parameter_set_lookup(&list, "link", &link); node->typeinfo->rna_ext.call(NULL, &ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_Node_init(const bContext *C, PointerRNA *ptr) { extern FunctionRNA rna_Node_init_func; bNode *node = (bNode *)ptr->data; ParameterList list; FunctionRNA *func; func = &rna_Node_init_func; /* RNA_struct_find_function(&ptr, "init"); */ RNA_parameter_list_create(&list, ptr, func); node->typeinfo->rna_ext.call((bContext *)C, ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_Node_copy(PointerRNA *ptr, const struct bNode *copynode) { extern FunctionRNA rna_Node_copy_func; bNode *node = (bNode *)ptr->data; ParameterList list; FunctionRNA *func; func = &rna_Node_copy_func; /* RNA_struct_find_function(&ptr, "copy"); */ RNA_parameter_list_create(&list, ptr, func); RNA_parameter_set_lookup(&list, "node", ©node); node->typeinfo->rna_ext.call(NULL, ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_Node_free(PointerRNA *ptr) { extern FunctionRNA rna_Node_free_func; bNode *node = (bNode *)ptr->data; ParameterList list; FunctionRNA *func; func = &rna_Node_free_func; /* RNA_struct_find_function(&ptr, "free"); */ RNA_parameter_list_create(&list, ptr, func); node->typeinfo->rna_ext.call(NULL, ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_Node_draw_buttons(struct uiLayout *layout, bContext *C, PointerRNA *ptr) { extern FunctionRNA rna_Node_draw_buttons_func; bNode *node = (bNode *)ptr->data; ParameterList list; FunctionRNA *func; func = &rna_Node_draw_buttons_func; /* RNA_struct_find_function(&ptr, "draw_buttons"); */ RNA_parameter_list_create(&list, ptr, func); RNA_parameter_set_lookup(&list, "context", &C); RNA_parameter_set_lookup(&list, "layout", &layout); node->typeinfo->rna_ext.call(C, ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_Node_draw_buttons_ext(struct uiLayout *layout, bContext *C, PointerRNA *ptr) { extern FunctionRNA rna_Node_draw_buttons_ext_func; bNode *node = (bNode *)ptr->data; ParameterList list; FunctionRNA *func; func = &rna_Node_draw_buttons_ext_func; /* RNA_struct_find_function(&ptr, "draw_buttons_ext"); */ RNA_parameter_list_create(&list, ptr, func); RNA_parameter_set_lookup(&list, "context", &C); RNA_parameter_set_lookup(&list, "layout", &layout); node->typeinfo->rna_ext.call(C, ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_Node_draw_label(const bNodeTree *ntree, const bNode *node, char *label, int maxlen) { extern FunctionRNA rna_Node_draw_label_func; PointerRNA ptr; ParameterList list; FunctionRNA *func; void *ret; char *rlabel; func = &rna_Node_draw_label_func; /* RNA_struct_find_function(&ptr, "draw_label"); */ RNA_pointer_create((ID *)&ntree->id, &RNA_Node, (bNode *)node, &ptr); RNA_parameter_list_create(&list, &ptr, func); node->typeinfo->rna_ext.call(NULL, &ptr, func, &list); RNA_parameter_get_lookup(&list, "label", &ret); rlabel = (char *)ret; BLI_strncpy(label, rlabel != NULL ? rlabel : "", maxlen); RNA_parameter_list_free(&list); } static bool rna_Node_is_registered_node_type(StructRNA *type) { return (RNA_struct_blender_type_get(type) != NULL); } static void rna_Node_is_registered_node_type_runtime(bContext *UNUSED(C), ReportList *UNUSED(reports), PointerRNA *ptr, ParameterList *parms) { int result = (RNA_struct_blender_type_get(ptr->type) != NULL); RNA_parameter_set_lookup(parms, "result", &result); } static void rna_Node_unregister(Main *UNUSED(bmain), StructRNA *type) { bNodeType *nt = RNA_struct_blender_type_get(type); if (!nt) { return; } RNA_struct_free_extension(type, &nt->rna_ext); RNA_struct_free(&BLENDER_RNA, type); /* this also frees the allocated nt pointer, no MEM_free call needed! */ nodeUnregisterType(nt); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); } /* Generic internal registration function. * Can be used to implement callbacks for registerable RNA node subtypes. */ static bNodeType *rna_Node_register_base(Main *bmain, ReportList *reports, StructRNA *basetype, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt, dummynt; bNode dummynode; PointerRNA dummyptr; FunctionRNA *func; PropertyRNA *parm; int have_function[10]; /* setup dummy node & node type to store static properties in */ memset(&dummynt, 0, sizeof(bNodeType)); /* this does some additional initialization of default values */ node_type_base_custom(&dummynt, identifier, "", 0); memset(&dummynode, 0, sizeof(bNode)); dummynode.typeinfo = &dummynt; RNA_pointer_create(NULL, basetype, &dummynode, &dummyptr); /* validate the python class */ if (validate(&dummyptr, data, have_function) != 0) { return NULL; } if (strlen(identifier) >= sizeof(dummynt.idname)) { BKE_reportf(reports, RPT_ERROR, "Registering node class: '%s' is too long, maximum length is %d", identifier, (int)sizeof(dummynt.idname)); return NULL; } /* check if we have registered this node type before, and remove it */ nt = nodeTypeFind(dummynt.idname); if (nt) { rna_Node_unregister(bmain, nt->rna_ext.srna); } /* create a new node type */ nt = MEM_mallocN(sizeof(bNodeType), "node type"); memcpy(nt, &dummynt, sizeof(dummynt)); nt->free_self = (void (*)(bNodeType *))MEM_freeN; nt->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, nt->idname, basetype); nt->rna_ext.data = data; nt->rna_ext.call = call; nt->rna_ext.free = free; RNA_struct_blender_type_set(nt->rna_ext.srna, nt); RNA_def_struct_ui_text(nt->rna_ext.srna, nt->ui_name, nt->ui_description); RNA_def_struct_ui_icon(nt->rna_ext.srna, nt->ui_icon); func = RNA_def_function_runtime( nt->rna_ext.srna, "is_registered_node_type", rna_Node_is_registered_node_type_runtime); RNA_def_function_ui_description(func, "True if a registered node type"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE); parm = RNA_def_boolean(func, "result", false, "Result", ""); RNA_def_function_return(func, parm); /* XXX bad level call! needed to initialize the basic draw functions ... */ ED_init_custom_node_type(nt); nt->poll = (have_function[0]) ? rna_Node_poll : NULL; nt->poll_instance = (have_function[1]) ? rna_Node_poll_instance : rna_Node_poll_instance_default; nt->updatefunc = (have_function[2]) ? rna_Node_update_reg : NULL; nt->insert_link = (have_function[3]) ? rna_Node_insert_link : NULL; nt->initfunc_api = (have_function[4]) ? rna_Node_init : NULL; nt->copyfunc_api = (have_function[5]) ? rna_Node_copy : NULL; nt->freefunc_api = (have_function[6]) ? rna_Node_free : NULL; nt->draw_buttons = (have_function[7]) ? rna_Node_draw_buttons : NULL; nt->draw_buttons_ex = (have_function[8]) ? rna_Node_draw_buttons_ext : NULL; nt->labelfunc = (have_function[9]) ? rna_Node_draw_label : NULL; /* sanitize size values in case not all have been registered */ if (nt->maxwidth < nt->minwidth) { nt->maxwidth = nt->minwidth; } if (nt->maxheight < nt->minheight) { nt->maxheight = nt->minheight; } CLAMP(nt->width, nt->minwidth, nt->maxwidth); CLAMP(nt->height, nt->minheight, nt->maxheight); return nt; } static StructRNA *rna_Node_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base( bmain, reports, &RNA_Node, data, identifier, validate, call, free); if (!nt) { return NULL; } nodeRegisterType(nt); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return nt->rna_ext.srna; } static const EnumPropertyItem *itemf_function_check( const EnumPropertyItem *original_item_array, bool (*value_supported)(const EnumPropertyItem *item)) { EnumPropertyItem *item_array = NULL; int items_len = 0; for (const EnumPropertyItem *item = original_item_array; item->identifier != NULL; item++) { if (value_supported(item)) { RNA_enum_item_add(&item_array, &items_len, item); } } RNA_enum_item_end(&item_array, &items_len); return item_array; } static bool switch_type_supported(const EnumPropertyItem *item) { return ELEM(item->value, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_STRING, SOCK_RGBA, SOCK_GEOMETRY, SOCK_OBJECT, SOCK_COLLECTION, SOCK_TEXTURE, SOCK_MATERIAL, SOCK_IMAGE); } static const EnumPropertyItem *rna_GeometryNodeSwitch_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { *r_free = true; return itemf_function_check(node_socket_data_type_items, switch_type_supported); } static bool compare_type_supported(const EnumPropertyItem *item) { return ELEM(item->value, SOCK_FLOAT, SOCK_INT, SOCK_VECTOR, SOCK_STRING, SOCK_RGBA); } static bool compare_main_operation_supported(const EnumPropertyItem *item) { return !ELEM(item->value, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER); } static bool compare_rgba_operation_supported(const EnumPropertyItem *item) { return ELEM(item->value, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER); } static bool compare_string_operation_supported(const EnumPropertyItem *item) { return ELEM(item->value, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL); } static bool compare_other_operation_supported(const EnumPropertyItem *UNUSED(item)) { return false; } static const EnumPropertyItem *rna_FunctionNodeCompare_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { *r_free = true; return itemf_function_check(node_socket_data_type_items, compare_type_supported); } static const EnumPropertyItem *rna_FunctionNodeCompare_operation_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { *r_free = true; bNode *node = ptr->data; NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage; if (ELEM(data->data_type, SOCK_FLOAT, SOCK_INT, SOCK_VECTOR)) { return itemf_function_check(rna_enum_node_compare_operation_items, compare_main_operation_supported); } else if (data->data_type == SOCK_STRING) { return itemf_function_check(rna_enum_node_compare_operation_items, compare_string_operation_supported); } else if (data->data_type == SOCK_RGBA) { return itemf_function_check(rna_enum_node_compare_operation_items, compare_rgba_operation_supported); } else { return itemf_function_check(rna_enum_node_compare_operation_items, compare_other_operation_supported); } } static bool random_value_type_supported(const EnumPropertyItem *item) { return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_BOOL, CD_PROP_INT32); } static const EnumPropertyItem *rna_FunctionNodeRandomValue_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { *r_free = true; return itemf_function_check(rna_enum_attribute_type_items, random_value_type_supported); } static bool accumulate_field_type_supported(const EnumPropertyItem *item) { return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_INT32); } static const EnumPropertyItem *rna_GeoNodeAccumulateField_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { *r_free = true; return itemf_function_check(rna_enum_attribute_type_items, accumulate_field_type_supported); } static void rna_GeometryNodeCompare_data_type_update(Main *bmain, Scene *scene, PointerRNA *ptr) { bNode *node = ptr->data; NodeFunctionCompare *node_storage = (NodeFunctionCompare *)node->storage; if (node_storage->data_type == SOCK_RGBA && !ELEM(node_storage->operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER)) { node_storage->operation = NODE_COMPARE_EQUAL; } else if (node_storage->data_type == SOCK_STRING && !ELEM(node_storage->operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL)) { node_storage->operation = NODE_COMPARE_EQUAL; } else if (node_storage->data_type != SOCK_RGBA && ELEM(node_storage->operation, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER)) { node_storage->operation = NODE_COMPARE_EQUAL; } rna_Node_socket_update(bmain, scene, ptr); } static bool generic_attribute_type_supported(const EnumPropertyItem *item) { return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR, CD_PROP_BOOL, CD_PROP_INT32, CD_PROP_BYTE_COLOR); } static const EnumPropertyItem *rna_GeometryNodeAttributeType_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { *r_free = true; return itemf_function_check(rna_enum_attribute_type_items, generic_attribute_type_supported); } static bool generic_attribute_type_supported_with_socket(const EnumPropertyItem *item) { return generic_attribute_type_supported(item) && !ELEM(item->value, CD_PROP_BYTE_COLOR); } static const EnumPropertyItem *rna_GeometryNodeAttributeType_type_with_socket_itemf( bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { *r_free = true; return itemf_function_check(rna_enum_attribute_type_items, generic_attribute_type_supported_with_socket); } static bool transfer_attribute_type_supported(const EnumPropertyItem *item) { return ELEM( item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR, CD_PROP_BOOL, CD_PROP_INT32); } static const EnumPropertyItem *rna_NodeGeometryTransferAttribute_type_itemf( bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { *r_free = true; return itemf_function_check(rna_enum_attribute_type_items, transfer_attribute_type_supported); } static bool attribute_statistic_type_supported(const EnumPropertyItem *item) { return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3); } static const EnumPropertyItem *rna_GeometryNodeAttributeStatistic_type_itemf( bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { *r_free = true; return itemf_function_check(rna_enum_attribute_type_items, attribute_statistic_type_supported); } static StructRNA *rna_ShaderNode_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base( bmain, reports, &RNA_ShaderNode, data, identifier, validate, call, free); if (!nt) { return NULL; } nodeRegisterType(nt); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return nt->rna_ext.srna; } static StructRNA *rna_CompositorNode_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base( bmain, reports, &RNA_CompositorNode, data, identifier, validate, call, free); if (!nt) { return NULL; } nodeRegisterType(nt); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return nt->rna_ext.srna; } static StructRNA *rna_TextureNode_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base( bmain, reports, &RNA_TextureNode, data, identifier, validate, call, free); if (!nt) { return NULL; } nodeRegisterType(nt); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return nt->rna_ext.srna; } static StructRNA *rna_GeometryNode_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base( bmain, reports, &RNA_GeometryNode, data, identifier, validate, call, free); if (!nt) { return NULL; } nodeRegisterType(nt); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return nt->rna_ext.srna; } static StructRNA *rna_FunctionNode_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base( bmain, reports, &RNA_FunctionNode, data, identifier, validate, call, free); if (!nt) { return NULL; } nodeRegisterType(nt); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return nt->rna_ext.srna; } static IDProperty **rna_Node_idprops(PointerRNA *ptr) { bNode *node = ptr->data; return &node->prop; } static void rna_Node_parent_set(PointerRNA *ptr, PointerRNA value, struct ReportList *UNUSED(reports)) { bNode *node = ptr->data; bNode *parent = value.data; if (parent) { /* XXX only Frame node allowed for now, * in the future should have a poll function or so to test possible attachment. */ if (parent->type != NODE_FRAME) { return; } /* make sure parent is not attached to the node */ if (nodeAttachNodeCheck(parent, node)) { return; } } nodeDetachNode(node); if (parent) { nodeAttachNode(node, parent); } } static bool rna_Node_parent_poll(PointerRNA *ptr, PointerRNA value) { bNode *node = ptr->data; bNode *parent = value.data; /* XXX only Frame node allowed for now, * in the future should have a poll function or so to test possible attachment. */ if (parent->type != NODE_FRAME) { return false; } /* make sure parent is not attached to the node */ if (nodeAttachNodeCheck(parent, node)) { return false; } return true; } static void rna_Node_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; BKE_ntree_update_tag_node_property(ntree, node); ED_node_tree_propagate_change(NULL, bmain, ntree); } static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr) { rna_Node_update(bmain, scene, ptr); DEG_relations_tag_update(bmain); } static void rna_Node_socket_value_update(ID *id, bNode *UNUSED(node), bContext *C) { BKE_ntree_update_tag_all((bNodeTree *)id); ED_node_tree_propagate_change(C, CTX_data_main(C), (bNodeTree *)id); } static void rna_Node_select_set(PointerRNA *ptr, bool value) { bNode *node = (bNode *)ptr->data; nodeSetSelected(node, value); } static void rna_Node_name_set(PointerRNA *ptr, const char *value) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; char oldname[sizeof(node->name)]; /* make a copy of the old name first */ BLI_strncpy(oldname, node->name, sizeof(node->name)); /* set new name */ BLI_strncpy_utf8(node->name, value, sizeof(node->name)); nodeUniqueName(ntree, node); /* fix all the animation data which may link to this */ BKE_animdata_fix_paths_rename_all(NULL, "nodes", oldname, node->name); } static bNodeSocket *rna_Node_inputs_new(ID *id, bNode *node, Main *bmain, ReportList *reports, const char *type, const char *name, const char *identifier) { if (ELEM(node->type, NODE_GROUP_INPUT, NODE_FRAME)) { BKE_report(reports, RPT_ERROR, "Unable to create socket"); return NULL; } /* Adding an input to a group node is not working, * simpler to add it to its underlying nodetree. */ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) { return rna_NodeTree_inputs_new((bNodeTree *)node->id, bmain, reports, type, name); } bNodeTree *ntree = (bNodeTree *)id; bNodeSocket *sock; sock = nodeAddSocket(ntree, node, SOCK_IN, type, identifier, name); if (sock == NULL) { BKE_report(reports, RPT_ERROR, "Unable to create socket"); } else { ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } return sock; } static bNodeSocket *rna_Node_outputs_new(ID *id, bNode *node, Main *bmain, ReportList *reports, const char *type, const char *name, const char *identifier) { if (ELEM(node->type, NODE_GROUP_OUTPUT, NODE_FRAME)) { BKE_report(reports, RPT_ERROR, "Unable to create socket"); return NULL; } /* Adding an output to a group node is not working, * simpler to add it to its underlying nodetree. */ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) { return rna_NodeTree_outputs_new((bNodeTree *)node->id, bmain, reports, type, name); } bNodeTree *ntree = (bNodeTree *)id; bNodeSocket *sock; sock = nodeAddSocket(ntree, node, SOCK_OUT, type, identifier, name); if (sock == NULL) { BKE_report(reports, RPT_ERROR, "Unable to create socket"); } else { ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } return sock; } static void rna_Node_socket_remove( ID *id, bNode *node, Main *bmain, ReportList *reports, bNodeSocket *sock) { bNodeTree *ntree = (bNodeTree *)id; if (BLI_findindex(&node->inputs, sock) == -1 && BLI_findindex(&node->outputs, sock) == -1) { BKE_reportf(reports, RPT_ERROR, "Unable to locate socket '%s' in node", sock->identifier); } else { nodeRemoveSocket(ntree, node, sock); ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } } static void rna_Node_inputs_clear(ID *id, bNode *node, Main *bmain) { bNodeTree *ntree = (bNodeTree *)id; bNodeSocket *sock, *nextsock; for (sock = node->inputs.first; sock; sock = nextsock) { nextsock = sock->next; nodeRemoveSocket(ntree, node, sock); } ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static void rna_Node_outputs_clear(ID *id, bNode *node, Main *bmain) { bNodeTree *ntree = (bNodeTree *)id; bNodeSocket *sock, *nextsock; for (sock = node->outputs.first; sock; sock = nextsock) { nextsock = sock->next; nodeRemoveSocket(ntree, node, sock); } ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static void rna_Node_inputs_move(ID *id, bNode *node, Main *bmain, int from_index, int to_index) { bNodeTree *ntree = (bNodeTree *)id; bNodeSocket *sock; if (from_index == to_index) { return; } if (from_index < 0 || to_index < 0) { return; } sock = BLI_findlink(&node->inputs, from_index); if (to_index < from_index) { bNodeSocket *nextsock = BLI_findlink(&node->inputs, to_index); if (nextsock) { BLI_remlink(&node->inputs, sock); BLI_insertlinkbefore(&node->inputs, nextsock, sock); } } else { bNodeSocket *prevsock = BLI_findlink(&node->inputs, to_index); if (prevsock) { BLI_remlink(&node->inputs, sock); BLI_insertlinkafter(&node->inputs, prevsock, sock); } } ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static void rna_Node_outputs_move(ID *id, bNode *node, Main *bmain, int from_index, int to_index) { bNodeTree *ntree = (bNodeTree *)id; bNodeSocket *sock; if (from_index == to_index) { return; } if (from_index < 0 || to_index < 0) { return; } sock = BLI_findlink(&node->outputs, from_index); if (to_index < from_index) { bNodeSocket *nextsock = BLI_findlink(&node->outputs, to_index); if (nextsock) { BLI_remlink(&node->outputs, sock); BLI_insertlinkbefore(&node->outputs, nextsock, sock); } } else { bNodeSocket *prevsock = BLI_findlink(&node->outputs, to_index); if (prevsock) { BLI_remlink(&node->outputs, sock); BLI_insertlinkafter(&node->outputs, prevsock, sock); } } ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } static void rna_Node_width_range( PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) { bNode *node = ptr->data; *min = *softmin = node->typeinfo->minwidth; *max = *softmax = node->typeinfo->maxwidth; } static void rna_Node_height_range( PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) { bNode *node = ptr->data; *min = *softmin = node->typeinfo->minheight; *max = *softmax = node->typeinfo->maxheight; } static void rna_Node_dimensions_get(PointerRNA *ptr, float *value) { bNode *node = ptr->data; value[0] = node->totr.xmax - node->totr.xmin; value[1] = node->totr.ymax - node->totr.ymin; } /* ******** Node Socket ******** */ static void rna_NodeSocket_draw( bContext *C, struct uiLayout *layout, PointerRNA *ptr, PointerRNA *node_ptr, const char *text) { extern FunctionRNA rna_NodeSocket_draw_func; bNodeSocket *sock = (bNodeSocket *)ptr->data; ParameterList list; FunctionRNA *func; func = &rna_NodeSocket_draw_func; /* RNA_struct_find_function(&ptr, "draw"); */ RNA_parameter_list_create(&list, ptr, func); RNA_parameter_set_lookup(&list, "context", &C); RNA_parameter_set_lookup(&list, "layout", &layout); RNA_parameter_set_lookup(&list, "node", node_ptr); RNA_parameter_set_lookup(&list, "text", &text); sock->typeinfo->ext_socket.call(C, ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_NodeSocket_draw_color(bContext *C, PointerRNA *ptr, PointerRNA *node_ptr, float *r_color) { extern FunctionRNA rna_NodeSocket_draw_color_func; bNodeSocket *sock = (bNodeSocket *)ptr->data; ParameterList list; FunctionRNA *func; void *ret; func = &rna_NodeSocket_draw_color_func; /* RNA_struct_find_function(&ptr, "draw_color"); */ RNA_parameter_list_create(&list, ptr, func); RNA_parameter_set_lookup(&list, "context", &C); RNA_parameter_set_lookup(&list, "node", node_ptr); sock->typeinfo->ext_socket.call(C, ptr, func, &list); RNA_parameter_get_lookup(&list, "color", &ret); copy_v4_v4(r_color, (float *)ret); RNA_parameter_list_free(&list); } static void rna_NodeSocket_unregister(Main *UNUSED(bmain), StructRNA *type) { bNodeSocketType *st = RNA_struct_blender_type_get(type); if (!st) { return; } RNA_struct_free_extension(type, &st->ext_socket); RNA_struct_free(&BLENDER_RNA, type); nodeUnregisterSocketType(st); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); } static StructRNA *rna_NodeSocket_register(Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeSocketType *st, dummyst; bNodeSocket dummysock; PointerRNA dummyptr; int have_function[2]; /* setup dummy socket & socket type to store static properties in */ memset(&dummyst, 0, sizeof(bNodeSocketType)); dummyst.type = SOCK_CUSTOM; memset(&dummysock, 0, sizeof(bNodeSocket)); dummysock.typeinfo = &dummyst; RNA_pointer_create(NULL, &RNA_NodeSocket, &dummysock, &dummyptr); /* validate the python class */ if (validate(&dummyptr, data, have_function) != 0) { return NULL; } if (strlen(identifier) >= sizeof(dummyst.idname)) { BKE_reportf(reports, RPT_ERROR, "Registering node socket class: '%s' is too long, maximum length is %d", identifier, (int)sizeof(dummyst.idname)); return NULL; } /* check if we have registered this socket type before */ st = nodeSocketTypeFind(dummyst.idname); if (!st) { /* create a new node socket type */ st = MEM_mallocN(sizeof(bNodeSocketType), "node socket type"); memcpy(st, &dummyst, sizeof(dummyst)); nodeRegisterSocketType(st); } st->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN; /* if RNA type is already registered, unregister first */ if (st->ext_socket.srna) { StructRNA *srna = st->ext_socket.srna; RNA_struct_free_extension(srna, &st->ext_socket); RNA_struct_free(&BLENDER_RNA, srna); } st->ext_socket.srna = RNA_def_struct_ptr(&BLENDER_RNA, st->idname, &RNA_NodeSocket); st->ext_socket.data = data; st->ext_socket.call = call; st->ext_socket.free = free; RNA_struct_blender_type_set(st->ext_socket.srna, st); /* XXX bad level call! needed to initialize the basic draw functions ... */ ED_init_custom_node_socket_type(st); st->draw = (have_function[0]) ? rna_NodeSocket_draw : NULL; st->draw_color = (have_function[1]) ? rna_NodeSocket_draw_color : NULL; /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return st->ext_socket.srna; } static StructRNA *rna_NodeSocket_refine(PointerRNA *ptr) { bNodeSocket *sock = (bNodeSocket *)ptr->data; if (sock->typeinfo->ext_socket.srna) { return sock->typeinfo->ext_socket.srna; } else { return &RNA_NodeSocket; } } static char *rna_NodeSocket_path(const PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNodeSocket *sock = (bNodeSocket *)ptr->data; bNode *node; int socketindex; char name_esc[sizeof(node->name) * 2]; if (!nodeFindNode(ntree, sock, &node, &socketindex)) { return NULL; } BLI_str_escape(name_esc, node->name, sizeof(name_esc)); if (sock->in_out == SOCK_IN) { return BLI_sprintfN("nodes[\"%s\"].inputs[%d]", name_esc, socketindex); } else { return BLI_sprintfN("nodes[\"%s\"].outputs[%d]", name_esc, socketindex); } } static IDProperty **rna_NodeSocket_idprops(PointerRNA *ptr) { bNodeSocket *sock = ptr->data; return &sock->prop; } static PointerRNA rna_NodeSocket_node_get(PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNodeSocket *sock = (bNodeSocket *)ptr->data; bNode *node; PointerRNA r_ptr; nodeFindNode(ntree, sock, &node, NULL); RNA_pointer_create((ID *)ntree, &RNA_Node, node, &r_ptr); return r_ptr; } static void rna_NodeSocket_type_set(PointerRNA *ptr, int value) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNodeSocket *sock = (bNodeSocket *)ptr->data; bNode *node; nodeFindNode(ntree, sock, &node, NULL); nodeModifySocketTypeStatic(ntree, node, sock, value, 0); } static void rna_NodeSocket_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNodeSocket *sock = (bNodeSocket *)ptr->data; BKE_ntree_update_tag_socket_property(ntree, sock); ED_node_tree_propagate_change(NULL, bmain, ntree); } static bool rna_NodeSocket_is_output_get(PointerRNA *ptr) { bNodeSocket *sock = ptr->data; return sock->in_out == SOCK_OUT; } static void rna_NodeSocket_link_limit_set(PointerRNA *ptr, int value) { bNodeSocket *sock = ptr->data; sock->limit = (value == 0 ? 0xFFF : value); } static void rna_NodeSocket_hide_set(PointerRNA *ptr, bool value) { bNodeSocket *sock = (bNodeSocket *)ptr->data; /* don't hide linked sockets */ if (sock->flag & SOCK_IN_USE) { return; } if (value) { sock->flag |= SOCK_HIDDEN; } else { sock->flag &= ~SOCK_HIDDEN; } } static void rna_NodeSocketInterface_draw(bContext *C, struct uiLayout *layout, PointerRNA *ptr) { extern FunctionRNA rna_NodeSocketInterface_draw_func; bNodeSocket *stemp = (bNodeSocket *)ptr->data; ParameterList list; FunctionRNA *func; if (!stemp->typeinfo) { return; } func = &rna_NodeSocketInterface_draw_func; /* RNA_struct_find_function(&ptr, "draw"); */ RNA_parameter_list_create(&list, ptr, func); RNA_parameter_set_lookup(&list, "context", &C); RNA_parameter_set_lookup(&list, "layout", &layout); stemp->typeinfo->ext_interface.call(C, ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_NodeSocketInterface_draw_color(bContext *C, PointerRNA *ptr, float *r_color) { extern FunctionRNA rna_NodeSocketInterface_draw_color_func; bNodeSocket *sock = (bNodeSocket *)ptr->data; ParameterList list; FunctionRNA *func; void *ret; if (!sock->typeinfo) { return; } func = &rna_NodeSocketInterface_draw_color_func; /* RNA_struct_find_function(&ptr, "draw_color"); */ RNA_parameter_list_create(&list, ptr, func); RNA_parameter_set_lookup(&list, "context", &C); sock->typeinfo->ext_interface.call(C, ptr, func, &list); RNA_parameter_get_lookup(&list, "color", &ret); copy_v4_v4(r_color, (float *)ret); RNA_parameter_list_free(&list); } static void rna_NodeSocketInterface_register_properties(bNodeTree *ntree, bNodeSocket *stemp, StructRNA *data_srna) { extern FunctionRNA rna_NodeSocketInterface_register_properties_func; PointerRNA ptr; ParameterList list; FunctionRNA *func; if (!stemp->typeinfo) { return; } RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, stemp, &ptr); // RNA_struct_find_function(&ptr, "register_properties"); func = &rna_NodeSocketInterface_register_properties_func; RNA_parameter_list_create(&list, &ptr, func); RNA_parameter_set_lookup(&list, "data_rna_type", &data_srna); stemp->typeinfo->ext_interface.call(NULL, &ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_NodeSocketInterface_init_socket(bNodeTree *ntree, const bNodeSocket *interface_socket, bNode *node, bNodeSocket *sock, const char *data_path) { extern FunctionRNA rna_NodeSocketInterface_init_socket_func; PointerRNA ptr, node_ptr, sock_ptr; ParameterList list; FunctionRNA *func; if (!interface_socket->typeinfo) { return; } RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, (bNodeSocket *)interface_socket, &ptr); RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sock_ptr); // RNA_struct_find_function(&ptr, "init_socket"); func = &rna_NodeSocketInterface_init_socket_func; RNA_parameter_list_create(&list, &ptr, func); RNA_parameter_set_lookup(&list, "node", &node_ptr); RNA_parameter_set_lookup(&list, "socket", &sock_ptr); RNA_parameter_set_lookup(&list, "data_path", &data_path); interface_socket->typeinfo->ext_interface.call(NULL, &ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_NodeSocketInterface_from_socket(bNodeTree *ntree, bNodeSocket *interface_socket, bNode *node, bNodeSocket *sock) { extern FunctionRNA rna_NodeSocketInterface_from_socket_func; PointerRNA ptr, node_ptr, sock_ptr; ParameterList list; FunctionRNA *func; if (!interface_socket->typeinfo) { return; } RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, interface_socket, &ptr); RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sock_ptr); // RNA_struct_find_function(&ptr, "from_socket"); func = &rna_NodeSocketInterface_from_socket_func; RNA_parameter_list_create(&list, &ptr, func); RNA_parameter_set_lookup(&list, "node", &node_ptr); RNA_parameter_set_lookup(&list, "socket", &sock_ptr); interface_socket->typeinfo->ext_interface.call(NULL, &ptr, func, &list); RNA_parameter_list_free(&list); } static void rna_NodeSocketInterface_unregister(Main *UNUSED(bmain), StructRNA *type) { bNodeSocketType *st = RNA_struct_blender_type_get(type); if (!st) { return; } RNA_struct_free_extension(type, &st->ext_interface); RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); } static StructRNA *rna_NodeSocketInterface_register(Main *UNUSED(bmain), ReportList *UNUSED(reports), void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeSocketType *st, dummyst; bNodeSocket dummysock; PointerRNA dummyptr; int have_function[5]; /* setup dummy socket & socket type to store static properties in */ memset(&dummyst, 0, sizeof(bNodeSocketType)); memset(&dummysock, 0, sizeof(bNodeSocket)); dummysock.typeinfo = &dummyst; RNA_pointer_create(NULL, &RNA_NodeSocketInterface, &dummysock, &dummyptr); /* validate the python class */ if (validate(&dummyptr, data, have_function) != 0) { return NULL; } /* check if we have registered this socket type before */ st = nodeSocketTypeFind(dummyst.idname); if (st) { /* basic socket type registered by a socket class before. */ } else { /* create a new node socket type */ st = MEM_mallocN(sizeof(bNodeSocketType), "node socket type"); memcpy(st, &dummyst, sizeof(dummyst)); nodeRegisterSocketType(st); } st->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN; /* if RNA type is already registered, unregister first */ if (st->ext_interface.srna) { StructRNA *srna = st->ext_interface.srna; RNA_struct_free_extension(srna, &st->ext_interface); RNA_struct_free(&BLENDER_RNA, srna); } st->ext_interface.srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_NodeSocketInterface); st->ext_interface.data = data; st->ext_interface.call = call; st->ext_interface.free = free; RNA_struct_blender_type_set(st->ext_interface.srna, st); st->interface_draw = (have_function[0]) ? rna_NodeSocketInterface_draw : NULL; st->interface_draw_color = (have_function[1]) ? rna_NodeSocketInterface_draw_color : NULL; st->interface_register_properties = (have_function[2]) ? rna_NodeSocketInterface_register_properties : NULL; st->interface_init_socket = (have_function[3]) ? rna_NodeSocketInterface_init_socket : NULL; st->interface_from_socket = (have_function[4]) ? rna_NodeSocketInterface_from_socket : NULL; /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return st->ext_interface.srna; } static StructRNA *rna_NodeSocketInterface_refine(PointerRNA *ptr) { bNodeSocket *sock = (bNodeSocket *)ptr->data; if (sock->typeinfo && sock->typeinfo->ext_interface.srna) { return sock->typeinfo->ext_interface.srna; } else { return &RNA_NodeSocketInterface; } } static char *rna_NodeSocketInterface_path(const PointerRNA *ptr) { const bNodeTree *ntree = (bNodeTree *)ptr->owner_id; const bNodeSocket *sock = (bNodeSocket *)ptr->data; int socketindex; socketindex = BLI_findindex(&ntree->inputs, sock); if (socketindex != -1) { return BLI_sprintfN("inputs[%d]", socketindex); } socketindex = BLI_findindex(&ntree->outputs, sock); if (socketindex != -1) { return BLI_sprintfN("outputs[%d]", socketindex); } return NULL; } static IDProperty **rna_NodeSocketInterface_idprops(PointerRNA *ptr) { bNodeSocket *sock = ptr->data; return &sock->prop; } static void rna_NodeSocketInterface_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNodeSocket *stemp = ptr->data; if (!stemp->typeinfo) { return; } BKE_ntree_update_tag_interface(ntree); ED_node_tree_propagate_change(NULL, bmain, ntree); } /* ******** Standard Node Socket Base Types ******** */ static void rna_NodeSocketStandard_draw(ID *id, bNodeSocket *sock, struct bContext *C, struct uiLayout *layout, PointerRNA *nodeptr, const char *text) { PointerRNA ptr; RNA_pointer_create(id, &RNA_NodeSocket, sock, &ptr); sock->typeinfo->draw(C, layout, &ptr, nodeptr, text); } static void rna_NodeSocketStandard_draw_color( ID *id, bNodeSocket *sock, struct bContext *C, PointerRNA *nodeptr, float r_color[4]) { PointerRNA ptr; RNA_pointer_create(id, &RNA_NodeSocket, sock, &ptr); sock->typeinfo->draw_color(C, &ptr, nodeptr, r_color); } static void rna_NodeSocketInterfaceStandard_draw(ID *id, bNodeSocket *sock, struct bContext *C, struct uiLayout *layout) { PointerRNA ptr; RNA_pointer_create(id, &RNA_NodeSocketInterface, sock, &ptr); sock->typeinfo->interface_draw(C, layout, &ptr); } static void rna_NodeSocketInterfaceStandard_draw_color(ID *id, bNodeSocket *sock, struct bContext *C, float r_color[4]) { PointerRNA ptr; RNA_pointer_create(id, &RNA_NodeSocketInterface, sock, &ptr); sock->typeinfo->interface_draw_color(C, &ptr, r_color); } static void rna_NodeSocketStandard_float_range( PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) { bNodeSocket *sock = ptr->data; bNodeSocketValueFloat *dval = sock->default_value; int subtype = sock->typeinfo->subtype; if (dval->max < dval->min) { dval->max = dval->min; } *min = (subtype == PROP_UNSIGNED ? 0.0f : -FLT_MAX); *max = FLT_MAX; *softmin = dval->min; *softmax = dval->max; } static void rna_NodeSocketStandard_int_range( PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) { bNodeSocket *sock = ptr->data; bNodeSocketValueInt *dval = sock->default_value; int subtype = sock->typeinfo->subtype; if (dval->max < dval->min) { dval->max = dval->min; } *min = (subtype == PROP_UNSIGNED ? 0 : INT_MIN); *max = INT_MAX; *softmin = dval->min; *softmax = dval->max; } static void rna_NodeSocketStandard_vector_range( PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) { bNodeSocket *sock = ptr->data; bNodeSocketValueVector *dval = sock->default_value; if (dval->max < dval->min) { dval->max = dval->min; } *min = -FLT_MAX; *max = FLT_MAX; *softmin = dval->min; *softmax = dval->max; } /* using a context update function here, to avoid searching the node if possible */ static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *ptr) { /* default update */ rna_NodeSocket_update(CTX_data_main(C), CTX_data_scene(C), ptr); } static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C, PointerRNA *ptr) { rna_NodeSocketStandard_value_update(C, ptr); Main *bmain = CTX_data_main(C); DEG_relations_tag_update(bmain); } /* ******** Node Types ******** */ static void rna_NodeInternalSocketTemplate_name_get(PointerRNA *ptr, char *value) { bNodeSocketTemplate *stemp = ptr->data; strcpy(value, stemp->name); } static int rna_NodeInternalSocketTemplate_name_length(PointerRNA *ptr) { bNodeSocketTemplate *stemp = ptr->data; return strlen(stemp->name); } static void rna_NodeInternalSocketTemplate_identifier_get(PointerRNA *ptr, char *value) { bNodeSocketTemplate *stemp = ptr->data; strcpy(value, stemp->identifier); } static int rna_NodeInternalSocketTemplate_identifier_length(PointerRNA *ptr) { bNodeSocketTemplate *stemp = ptr->data; return strlen(stemp->identifier); } static int rna_NodeInternalSocketTemplate_type_get(PointerRNA *ptr) { bNodeSocketTemplate *stemp = ptr->data; return stemp->type; } static PointerRNA rna_NodeInternal_input_template(StructRNA *srna, int index) { bNodeType *ntype = RNA_struct_blender_type_get(srna); if (ntype && ntype->inputs) { bNodeSocketTemplate *stemp = ntype->inputs; int i = 0; while (i < index && stemp->type >= 0) { i++; stemp++; } if (i == index && stemp->type >= 0) { PointerRNA ptr; RNA_pointer_create(NULL, &RNA_NodeInternalSocketTemplate, stemp, &ptr); return ptr; } } return PointerRNA_NULL; } static PointerRNA rna_NodeInternal_output_template(StructRNA *srna, int index) { bNodeType *ntype = RNA_struct_blender_type_get(srna); if (ntype && ntype->outputs) { bNodeSocketTemplate *stemp = ntype->outputs; int i = 0; while (i < index && stemp->type >= 0) { i++; stemp++; } if (i == index && stemp->type >= 0) { PointerRNA ptr; RNA_pointer_create(NULL, &RNA_NodeInternalSocketTemplate, stemp, &ptr); return ptr; } } return PointerRNA_NULL; } static bool rna_NodeInternal_poll(StructRNA *srna, bNodeTree *ntree) { bNodeType *ntype = RNA_struct_blender_type_get(srna); const char *disabled_hint; return ntype && (!ntype->poll || ntype->poll(ntype, ntree, &disabled_hint)); } static bool rna_NodeInternal_poll_instance(bNode *node, bNodeTree *ntree) { bNodeType *ntype = node->typeinfo; const char *disabled_hint; if (ntype->poll_instance) { return ntype->poll_instance(node, ntree, &disabled_hint); } else { /* fall back to basic poll function */ return !ntype->poll || ntype->poll(ntype, ntree, &disabled_hint); } } static void rna_NodeInternal_update(ID *id, bNode *node, Main *bmain) { bNodeTree *ntree = (bNodeTree *)id; BKE_ntree_update_tag_node_property(ntree, node); ED_node_tree_propagate_change(NULL, bmain, ntree); } static void rna_NodeInternal_draw_buttons(ID *id, bNode *node, struct bContext *C, struct uiLayout *layout) { if (node->typeinfo->draw_buttons) { PointerRNA ptr; RNA_pointer_create(id, &RNA_Node, node, &ptr); node->typeinfo->draw_buttons(layout, C, &ptr); } } static void rna_NodeInternal_draw_buttons_ext(ID *id, bNode *node, struct bContext *C, struct uiLayout *layout) { if (node->typeinfo->draw_buttons_ex) { PointerRNA ptr; RNA_pointer_create(id, &RNA_Node, node, &ptr); node->typeinfo->draw_buttons_ex(layout, C, &ptr); } else if (node->typeinfo->draw_buttons) { PointerRNA ptr; RNA_pointer_create(id, &RNA_Node, node, &ptr); node->typeinfo->draw_buttons(layout, C, &ptr); } } static StructRNA *rna_NodeCustomGroup_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base( bmain, reports, &RNA_NodeCustomGroup, data, identifier, validate, call, free); if (!nt) { return NULL; } /* this updates the group node instance from the tree's interface */ nt->group_update_func = node_group_update; nodeRegisterType(nt); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return nt->rna_ext.srna; } static StructRNA *rna_GeometryNodeCustomGroup_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base( bmain, reports, &RNA_GeometryNodeCustomGroup, data, identifier, validate, call, free); if (!nt) { return NULL; } nt->group_update_func = node_group_update; nt->type = NODE_CUSTOM_GROUP; register_node_type_geo_custom_group(nt); nodeRegisterType(nt); WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return nt->rna_ext.srna; } void register_node_type_geo_custom_group(bNodeType *ntype); static StructRNA *rna_ShaderNodeCustomGroup_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base( bmain, reports, &RNA_ShaderNodeCustomGroup, data, identifier, validate, call, free); if (!nt) { return NULL; } nt->group_update_func = node_group_update; nt->type = NODE_CUSTOM_GROUP; register_node_type_sh_custom_group(nt); nodeRegisterType(nt); WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return nt->rna_ext.srna; } static StructRNA *rna_CompositorNodeCustomGroup_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base( bmain, reports, &RNA_CompositorNodeCustomGroup, data, identifier, validate, call, free); if (!nt) { return NULL; } nt->group_update_func = node_group_update; nt->type = NODE_CUSTOM_GROUP; register_node_type_cmp_custom_group(nt); nodeRegisterType(nt); WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); return nt->rna_ext.srna; } static void rna_CompositorNode_tag_need_exec(bNode *node) { node->need_exec = true; } static void rna_Node_tex_image_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; BKE_ntree_update_tag_node_property(ntree, node); ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_IMAGE, NULL); } static void rna_NodeGroup_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; BKE_ntree_update_tag_node_property(ntree, node); ED_node_tree_propagate_change(NULL, bmain, ntree); DEG_relations_tag_update(bmain); } static void rna_NodeGroup_node_tree_set(PointerRNA *ptr, const PointerRNA value, struct ReportList *UNUSED(reports)) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = ptr->data; bNodeTree *ngroup = value.data; const char *disabled_hint = NULL; if (nodeGroupPoll(ntree, ngroup, &disabled_hint)) { if (node->id) { id_us_min(node->id); } if (ngroup) { id_us_plus(&ngroup->id); } node->id = &ngroup->id; } } static bool rna_NodeGroup_node_tree_poll(PointerRNA *ptr, const PointerRNA value) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNodeTree *ngroup = value.data; /* only allow node trees of the same type as the group node's tree */ if (ngroup->type != ntree->type) { return false; } const char *disabled_hint = NULL; return nodeGroupPoll(ntree, ngroup, &disabled_hint); } static StructRNA *rna_NodeGroup_interface_typef(PointerRNA *ptr) { bNode *node = ptr->data; bNodeTree *ngroup = (bNodeTree *)node->id; if (ngroup) { StructRNA *srna = ntreeInterfaceTypeGet(ngroup, true); if (srna) { return srna; } } return &RNA_PropertyGroup; } static StructRNA *rna_NodeGroupInputOutput_interface_typef(PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; if (ntree) { StructRNA *srna = ntreeInterfaceTypeGet(ntree, true); if (srna) { return srna; } } return &RNA_PropertyGroup; } static void rna_distance_matte_t1_set(PointerRNA *ptr, float value) { bNode *node = (bNode *)ptr->data; NodeChroma *chroma = node->storage; chroma->t1 = value; } static void rna_distance_matte_t2_set(PointerRNA *ptr, float value) { bNode *node = (bNode *)ptr->data; NodeChroma *chroma = node->storage; chroma->t2 = value; } static void rna_difference_matte_t1_set(PointerRNA *ptr, float value) { bNode *node = (bNode *)ptr->data; NodeChroma *chroma = node->storage; chroma->t1 = value; } static void rna_difference_matte_t2_set(PointerRNA *ptr, float value) { bNode *node = (bNode *)ptr->data; NodeChroma *chroma = node->storage; chroma->t2 = value; } /* Button Set Funcs for Matte Nodes */ static void rna_Matte_t1_set(PointerRNA *ptr, float value) { bNode *node = (bNode *)ptr->data; NodeChroma *chroma = node->storage; chroma->t1 = value; if (value < chroma->t2) { chroma->t2 = value; } } static void rna_Matte_t2_set(PointerRNA *ptr, float value) { bNode *node = (bNode *)ptr->data; NodeChroma *chroma = node->storage; if (value > chroma->t1) { value = chroma->t1; } chroma->t2 = value; } static void rna_Node_scene_set(PointerRNA *ptr, PointerRNA value, struct ReportList *UNUSED(reports)) { bNode *node = (bNode *)ptr->data; if (node->id) { id_us_min(node->id); node->id = NULL; } node->id = value.data; id_us_plus(node->id); } static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; Image *ima = (Image *)node->id; ImageUser *iuser = node->storage; if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) { return; } BKE_image_multilayer_index(ima->rr, iuser); BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_SRC_CHANGE); rna_Node_update(bmain, scene, ptr); if (scene != NULL && scene->nodetree != NULL) { ntreeCompositUpdateRLayers(scene->nodetree); } } static const EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl) { EnumPropertyItem *item = NULL; EnumPropertyItem tmp = {0}; int i = 0, totitem = 0; while (rl) { tmp.identifier = rl->name; /* Little trick: using space char instead empty string * makes the item selectable in the drop-down. */ if (rl->name[0] == '\0') { tmp.name = " "; } else { tmp.name = rl->name; } tmp.value = i++; RNA_enum_item_add(&item, &totitem, &tmp); rl = rl->next; } RNA_enum_item_end(&item, &totitem); return item; } static const EnumPropertyItem *rna_Node_image_layer_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { bNode *node = (bNode *)ptr->data; Image *ima = (Image *)node->id; const EnumPropertyItem *item = NULL; RenderLayer *rl; if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) { return DummyRNA_NULL_items; } if (ima == NULL || ima->rr == NULL) { *r_free = false; return DummyRNA_NULL_items; } rl = ima->rr->layers.first; item = renderresult_layers_add_enum(rl); *r_free = true; return item; } static bool rna_Node_image_has_layers_get(PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; Image *ima = (Image *)node->id; if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) { return false; } if (!ima || !(ima->rr)) { return false; } return RE_layers_have_name(ima->rr); } static bool rna_Node_image_has_views_get(PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; Image *ima = (Image *)node->id; if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) { return false; } if (!ima || !(ima->rr)) { return false; } return BLI_listbase_count_at_most(&ima->rr->views, 2) > 1; } static const EnumPropertyItem *renderresult_views_add_enum(RenderView *rv) { EnumPropertyItem *item = NULL; EnumPropertyItem tmp = {0, "ALL", 0, "All", ""}; int i = 1, totitem = 0; /* option to use all views */ RNA_enum_item_add(&item, &totitem, &tmp); while (rv) { tmp.identifier = rv->name; /* Little trick: using space char instead empty string * makes the item selectable in the drop-down. */ if (rv->name[0] == '\0') { tmp.name = " "; } else { tmp.name = rv->name; } tmp.value = i++; RNA_enum_item_add(&item, &totitem, &tmp); rv = rv->next; } RNA_enum_item_end(&item, &totitem); return item; } static const EnumPropertyItem *rna_Node_image_view_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { bNode *node = (bNode *)ptr->data; Image *ima = (Image *)node->id; const EnumPropertyItem *item = NULL; RenderView *rv; if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) { return DummyRNA_NULL_items; } if (ima == NULL || ima->rr == NULL) { *r_free = false; return DummyRNA_NULL_items; } rv = ima->rr->views.first; item = renderresult_views_add_enum(rv); *r_free = true; return item; } static const EnumPropertyItem *rna_Node_view_layer_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { bNode *node = (bNode *)ptr->data; Scene *sce = (Scene *)node->id; const EnumPropertyItem *item = NULL; RenderLayer *rl; if (sce == NULL) { *r_free = false; return DummyRNA_NULL_items; } rl = sce->view_layers.first; item = renderresult_layers_add_enum(rl); *r_free = true; return item; } static void rna_Node_view_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr) { rna_Node_update(bmain, scene, ptr); if (scene != NULL && scene->nodetree != NULL) { ntreeCompositUpdateRLayers(scene->nodetree); } } static const EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { bNode *node = (bNode *)ptr->data; EnumPropertyItem *item = NULL; EnumPropertyItem tmp = {0}; int totitem = 0; switch (node->custom1) { case CMP_NODE_CHANNEL_MATTE_CS_RGB: tmp.identifier = "R"; tmp.name = "R"; tmp.value = 1; RNA_enum_item_add(&item, &totitem, &tmp); tmp.identifier = "G"; tmp.name = "G"; tmp.value = 2; RNA_enum_item_add(&item, &totitem, &tmp); tmp.identifier = "B"; tmp.name = "B"; tmp.value = 3; RNA_enum_item_add(&item, &totitem, &tmp); break; case CMP_NODE_CHANNEL_MATTE_CS_HSV: tmp.identifier = "H"; tmp.name = "H"; tmp.value = 1; RNA_enum_item_add(&item, &totitem, &tmp); tmp.identifier = "S"; tmp.name = "S"; tmp.value = 2; RNA_enum_item_add(&item, &totitem, &tmp); tmp.identifier = "V"; tmp.name = "V"; tmp.value = 3; RNA_enum_item_add(&item, &totitem, &tmp); break; case CMP_NODE_CHANNEL_MATTE_CS_YUV: tmp.identifier = "Y"; tmp.name = "Y"; tmp.value = 1; RNA_enum_item_add(&item, &totitem, &tmp); tmp.identifier = "G"; tmp.name = "U"; tmp.value = 2; RNA_enum_item_add(&item, &totitem, &tmp); tmp.identifier = "V"; tmp.name = "V"; tmp.value = 3; RNA_enum_item_add(&item, &totitem, &tmp); break; case CMP_NODE_CHANNEL_MATTE_CS_YCC: tmp.identifier = "Y"; tmp.name = "Y"; tmp.value = 1; RNA_enum_item_add(&item, &totitem, &tmp); tmp.identifier = "CB"; tmp.name = "Cr"; tmp.value = 2; RNA_enum_item_add(&item, &totitem, &tmp); tmp.identifier = "CR"; tmp.name = "Cb"; tmp.value = 3; RNA_enum_item_add(&item, &totitem, &tmp); break; default: return DummyRNA_NULL_items; } RNA_enum_item_end(&item, &totitem); *r_free = true; return item; } static void rna_Image_Node_update_id(Main *bmain, Scene *scene, PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; node->update |= NODE_UPDATE_ID; rna_Node_update(bmain, scene, ptr); } static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { bNode *node = ptr->data; rna_iterator_listbase_begin(iter, &node->inputs, NULL); } static PointerRNA rna_NodeOutputFile_slot_file_get(CollectionPropertyIterator *iter) { PointerRNA ptr; bNodeSocket *sock = rna_iterator_listbase_get(iter); RNA_pointer_create(iter->parent.owner_id, &RNA_NodeOutputFileSlotFile, sock->storage, &ptr); return ptr; } static void rna_NodeColorBalance_update_lgg(Main *bmain, Scene *scene, PointerRNA *ptr) { ntreeCompositColorBalanceSyncFromLGG((bNodeTree *)ptr->owner_id, ptr->data); rna_Node_update(bmain, scene, ptr); } static void rna_NodeColorBalance_update_cdl(Main *bmain, Scene *scene, PointerRNA *ptr) { ntreeCompositColorBalanceSyncFromCDL((bNodeTree *)ptr->owner_id, ptr->data); rna_Node_update(bmain, scene, ptr); } static void rna_NodeCryptomatte_source_set(PointerRNA *ptr, int value) { bNode *node = (bNode *)ptr->data; if (node->id && node->custom1 != value) { id_us_min((ID *)node->id); node->id = NULL; } node->custom1 = value; } static int rna_NodeCryptomatte_layer_name_get(PointerRNA *ptr) { int index = 0; bNode *node = (bNode *)ptr->data; NodeCryptomatte *storage = node->storage; LISTBASE_FOREACH_INDEX (CryptomatteLayer *, layer, &storage->runtime.layers, index) { if (STREQLEN(storage->layer_name, layer->name, sizeof(storage->layer_name))) { return index; } } return 0; } static void rna_NodeCryptomatte_layer_name_set(PointerRNA *ptr, int new_value) { bNode *node = (bNode *)ptr->data; NodeCryptomatte *storage = node->storage; CryptomatteLayer *layer = BLI_findlink(&storage->runtime.layers, new_value); if (layer) { STRNCPY(storage->layer_name, layer->name); } } static const EnumPropertyItem *rna_NodeCryptomatte_layer_name_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { bNode *node = (bNode *)ptr->data; NodeCryptomatte *storage = node->storage; EnumPropertyItem *item = NULL; EnumPropertyItem template = {0, "", 0, "", ""}; int totitem = 0; ntreeCompositCryptomatteUpdateLayerNames(CTX_data_scene(C), node); int layer_index; LISTBASE_FOREACH_INDEX (CryptomatteLayer *, layer, &storage->runtime.layers, layer_index) { template.value = layer_index; template.identifier = layer->name; template.name = layer->name; RNA_enum_item_add(&item, &totitem, &template); } RNA_enum_item_end(&item, &totitem); *r_free = true; return item; } static PointerRNA rna_NodeCryptomatte_scene_get(PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; Scene *scene = (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) ? (Scene *)node->id : NULL; return rna_pointer_inherit_refine(ptr, &RNA_Scene, scene); } static void rna_NodeCryptomatte_scene_set(PointerRNA *ptr, PointerRNA value, struct ReportList *reports) { bNode *node = (bNode *)ptr->data; if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) { rna_Node_scene_set(ptr, value, reports); } } static PointerRNA rna_NodeCryptomatte_image_get(PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; Image *image = (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) ? (Image *)node->id : NULL; return rna_pointer_inherit_refine(ptr, &RNA_Image, image); } static void rna_NodeCryptomatte_image_set(PointerRNA *ptr, PointerRNA value, struct ReportList *UNUSED(reports)) { bNode *node = (bNode *)ptr->data; if (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) { if (node->id) id_us_min((ID *)node->id); if (value.data) id_us_plus((ID *)value.data); node->id = value.data; } } static bool rna_NodeCryptomatte_image_poll(PointerRNA *UNUSED(ptr), PointerRNA value) { Image *image = (Image *)value.owner_id; return image->type == IMA_TYPE_MULTILAYER; } static void rna_NodeCryptomatte_matte_get(PointerRNA *ptr, char *value) { bNode *node = (bNode *)ptr->data; NodeCryptomatte *nc = node->storage; char *matte_id = BKE_cryptomatte_entries_to_matte_id(nc); strcpy(value, matte_id); MEM_freeN(matte_id); } static int rna_NodeCryptomatte_matte_length(PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; NodeCryptomatte *nc = node->storage; char *matte_id = BKE_cryptomatte_entries_to_matte_id(nc); int result = strlen(matte_id); MEM_freeN(matte_id); return result; } static void rna_NodeCryptomatte_matte_set(PointerRNA *ptr, const char *value) { bNode *node = (bNode *)ptr->data; NodeCryptomatte *nc = node->storage; BKE_cryptomatte_matte_id_to_entries(nc, value); } static void rna_NodeCryptomatte_update_add(Main *bmain, Scene *scene, PointerRNA *ptr) { ntreeCompositCryptomatteSyncFromAdd(scene, ptr->data); rna_Node_update(bmain, scene, ptr); } static void rna_NodeCryptomatte_update_remove(Main *bmain, Scene *scene, PointerRNA *ptr) { ntreeCompositCryptomatteSyncFromRemove(ptr->data); rna_Node_update(bmain, scene, ptr); } /* ******** Node Socket Types ******** */ static PointerRNA rna_NodeOutputFile_slot_layer_get(CollectionPropertyIterator *iter) { PointerRNA ptr; bNodeSocket *sock = rna_iterator_listbase_get(iter); RNA_pointer_create(iter->parent.owner_id, &RNA_NodeOutputFileSlotLayer, sock->storage, &ptr); return ptr; } static int rna_NodeOutputFileSocket_find_node(bNodeTree *ntree, NodeImageMultiFileSocket *data, bNode **nodep, bNodeSocket **sockp) { bNode *node; bNodeSocket *sock; for (node = ntree->nodes.first; node; node = node->next) { for (sock = node->inputs.first; sock; sock = sock->next) { NodeImageMultiFileSocket *sockdata = sock->storage; if (sockdata == data) { *nodep = node; *sockp = sock; return 1; } } } *nodep = NULL; *sockp = NULL; return 0; } static void rna_NodeOutputFileSlotFile_path_set(PointerRNA *ptr, const char *value) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; NodeImageMultiFileSocket *sockdata = ptr->data; bNode *node; bNodeSocket *sock; if (rna_NodeOutputFileSocket_find_node(ntree, sockdata, &node, &sock)) { ntreeCompositOutputFileSetPath(node, sock, value); } } static void rna_NodeOutputFileSlotLayer_name_set(PointerRNA *ptr, const char *value) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; NodeImageMultiFileSocket *sockdata = ptr->data; bNode *node; bNodeSocket *sock; if (rna_NodeOutputFileSocket_find_node(ntree, sockdata, &node, &sock)) { ntreeCompositOutputFileSetLayer(node, sock, value); } } static bNodeSocket *rna_NodeOutputFile_slots_new( ID *id, bNode *node, bContext *C, ReportList *UNUSED(reports), const char *name) { bNodeTree *ntree = (bNodeTree *)id; Scene *scene = CTX_data_scene(C); ImageFormatData *im_format = NULL; bNodeSocket *sock; if (scene) { im_format = &scene->r.im_format; } sock = ntreeCompositOutputFileAddSocket(ntree, node, name, im_format); ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); return sock; } static void rna_ShaderNodeTexIES_mode_set(PointerRNA *ptr, int value) { bNode *node = (bNode *)ptr->data; NodeShaderTexIES *nss = node->storage; if (nss->mode != value) { nss->mode = value; nss->filepath[0] = '\0'; /* replace text datablock by filepath */ if (node->id) { Text *text = (Text *)node->id; if (value == NODE_IES_EXTERNAL && text->filepath) { BLI_strncpy(nss->filepath, text->filepath, sizeof(nss->filepath)); BLI_path_rel(nss->filepath, BKE_main_blendfile_path_from_global()); } id_us_min(node->id); node->id = NULL; } } } static void rna_ShaderNodeScript_mode_set(PointerRNA *ptr, int value) { bNode *node = (bNode *)ptr->data; NodeShaderScript *nss = node->storage; if (nss->mode != value) { nss->mode = value; nss->filepath[0] = '\0'; nss->flag &= ~NODE_SCRIPT_AUTO_UPDATE; /* replace text data-block by filepath */ if (node->id) { Text *text = (Text *)node->id; if (value == NODE_SCRIPT_EXTERNAL && text->filepath) { BLI_strncpy(nss->filepath, text->filepath, sizeof(nss->filepath)); BLI_path_rel(nss->filepath, BKE_main_blendfile_path_from_global()); } id_us_min(node->id); node->id = NULL; } /* remove any bytecode */ if (nss->bytecode) { MEM_freeN(nss->bytecode); nss->bytecode = NULL; } nss->bytecode_hash[0] = '\0'; } } static void rna_ShaderNodeScript_bytecode_get(PointerRNA *ptr, char *value) { bNode *node = (bNode *)ptr->data; NodeShaderScript *nss = node->storage; strcpy(value, (nss->bytecode) ? nss->bytecode : ""); } static int rna_ShaderNodeScript_bytecode_length(PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; NodeShaderScript *nss = node->storage; return (nss->bytecode) ? strlen(nss->bytecode) : 0; } static void rna_ShaderNodeScript_bytecode_set(PointerRNA *ptr, const char *value) { bNode *node = (bNode *)ptr->data; NodeShaderScript *nss = node->storage; if (nss->bytecode) { MEM_freeN(nss->bytecode); } if (value && value[0]) { nss->bytecode = BLI_strdup(value); } else { nss->bytecode = NULL; } } static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; RenderEngineType *engine_type = (scene != NULL) ? RE_engines_find(scene->r.engine) : NULL; if (engine_type && engine_type->update_script_node) { /* auto update node */ RenderEngine *engine = RE_engine_create(engine_type); engine_type->update_script_node(engine, ntree, node); RE_engine_free(engine); } BKE_ntree_update_tag_node_property(ntree, node); ED_node_tree_propagate_change(NULL, bmain, ntree); } static void rna_ShaderNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr) { rna_Node_update(bmain, scene, ptr); } static void rna_Node_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr) { rna_Node_update(bmain, scene, ptr); } static void rna_GeometryNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr) { rna_Node_update(bmain, scene, ptr); } static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA *ptr) { rna_Node_update(bmain, scene, ptr); } static void rna_ShaderNode_is_active_output_set(PointerRNA *ptr, bool value) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = ptr->data; if (value) { /* If this node becomes the active output, the others of the same type can't be the active * output anymore. */ LISTBASE_FOREACH (bNode *, other_node, &ntree->nodes) { if (other_node->type == node->type) { other_node->flag &= ~NODE_DO_OUTPUT; } } node->flag |= NODE_DO_OUTPUT; } else { node->flag &= ~NODE_DO_OUTPUT; } } static void rna_GroupOutput_is_active_output_set(PointerRNA *ptr, bool value) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = ptr->data; if (value) { /* Make sure that no other group output is active at the same time. */ LISTBASE_FOREACH (bNode *, other_node, &ntree->nodes) { if (other_node->type == NODE_GROUP_OUTPUT) { other_node->flag &= ~NODE_DO_OUTPUT; } } node->flag |= NODE_DO_OUTPUT; } else { node->flag &= ~NODE_DO_OUTPUT; } } static PointerRNA rna_ShaderNodePointDensity_psys_get(PointerRNA *ptr) { bNode *node = ptr->data; NodeShaderTexPointDensity *shader_point_density = node->storage; Object *ob = (Object *)node->id; ParticleSystem *psys = NULL; PointerRNA value; if (ob && shader_point_density->particle_system) { psys = BLI_findlink(&ob->particlesystem, shader_point_density->particle_system - 1); } RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &value); return value; } static void rna_ShaderNodePointDensity_psys_set(PointerRNA *ptr, PointerRNA value, struct ReportList *UNUSED(reports)) { bNode *node = ptr->data; NodeShaderTexPointDensity *shader_point_density = node->storage; Object *ob = (Object *)node->id; if (ob && value.owner_id == &ob->id) { shader_point_density->particle_system = BLI_findindex(&ob->particlesystem, value.data) + 1; } else { shader_point_density->particle_system = 0; } } static int point_density_particle_color_source_from_shader( NodeShaderTexPointDensity *shader_point_density) { switch (shader_point_density->color_source) { case SHD_POINTDENSITY_COLOR_PARTAGE: return TEX_PD_COLOR_PARTAGE; case SHD_POINTDENSITY_COLOR_PARTSPEED: return TEX_PD_COLOR_PARTSPEED; case SHD_POINTDENSITY_COLOR_PARTVEL: return TEX_PD_COLOR_PARTVEL; default: BLI_assert_msg(0, "Unknown color source"); return TEX_PD_COLOR_CONSTANT; } } static int point_density_vertex_color_source_from_shader( NodeShaderTexPointDensity *shader_point_density) { switch (shader_point_density->ob_color_source) { case SHD_POINTDENSITY_COLOR_VERTCOL: return TEX_PD_COLOR_VERTCOL; case SHD_POINTDENSITY_COLOR_VERTWEIGHT: return TEX_PD_COLOR_VERTWEIGHT; case SHD_POINTDENSITY_COLOR_VERTNOR: return TEX_PD_COLOR_VERTNOR; default: BLI_assert_msg(0, "Unknown color source"); return TEX_PD_COLOR_CONSTANT; } } void rna_ShaderNodePointDensity_density_cache(bNode *self, Depsgraph *depsgraph) { NodeShaderTexPointDensity *shader_point_density = self->storage; PointDensity *pd = &shader_point_density->pd; if (depsgraph == NULL) { return; } /* Make sure there's no cached data. */ BKE_texture_pointdensity_free_data(pd); RE_point_density_free(pd); /* Create PointDensity structure from node for sampling. */ BKE_texture_pointdensity_init_data(pd); pd->object = (Object *)self->id; pd->radius = shader_point_density->radius; if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) { pd->source = TEX_PD_PSYS; pd->psys = shader_point_density->particle_system; pd->psys_cache_space = TEX_PD_OBJECTSPACE; pd->color_source = point_density_particle_color_source_from_shader(shader_point_density); } else { BLI_assert(shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_OBJECT); pd->source = TEX_PD_OBJECT; pd->ob_cache_space = TEX_PD_OBJECTSPACE; pd->ob_color_source = point_density_vertex_color_source_from_shader(shader_point_density); BLI_strncpy(pd->vertex_attribute_name, shader_point_density->vertex_attribute_name, sizeof(pd->vertex_attribute_name)); } /* Store resolution, so it can be changed in the UI. */ shader_point_density->cached_resolution = shader_point_density->resolution; /* Single-threaded sampling of the voxel domain. */ RE_point_density_cache(depsgraph, pd); } void rna_ShaderNodePointDensity_density_calc(bNode *self, Depsgraph *depsgraph, int *length, float **values) { NodeShaderTexPointDensity *shader_point_density = self->storage; PointDensity *pd = &shader_point_density->pd; const int resolution = shader_point_density->cached_resolution; if (depsgraph == NULL) { *length = 0; return; } /* TODO(sergey): Will likely overflow, but how to pass size_t via RNA? */ *length = 4 * resolution * resolution * resolution; if (*values == NULL) { *values = MEM_mallocN(sizeof(float) * (*length), "point density dynamic array"); } /* Single-threaded sampling of the voxel domain. */ RE_point_density_sample(depsgraph, pd, resolution, *values); /* We're done, time to clean up. */ BKE_texture_pointdensity_free_data(pd); memset(pd, 0, sizeof(*pd)); shader_point_density->cached_resolution = 0.0f; } void rna_ShaderNodePointDensity_density_minmax(bNode *self, Depsgraph *depsgraph, float r_min[3], float r_max[3]) { NodeShaderTexPointDensity *shader_point_density = self->storage; PointDensity *pd = &shader_point_density->pd; if (depsgraph == NULL) { zero_v3(r_min); zero_v3(r_max); return; } RE_point_density_minmax(depsgraph, pd, r_min, r_max); } bool rna_NodeSocketMaterial_default_value_poll(PointerRNA *UNUSED(ptr), PointerRNA value) { /* Do not show grease pencil materials for now. */ Material *ma = (Material *)value.data; return ma->gp_style == NULL; } static int rna_NodeConvertColorSpace_from_color_space_get(struct PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; NodeConvertColorSpace *node_storage = node->storage; return IMB_colormanagement_colorspace_get_named_index(node_storage->from_color_space); } static void rna_NodeConvertColorSpace_from_color_space_set(struct PointerRNA *ptr, int value) { bNode *node = (bNode *)ptr->data; NodeConvertColorSpace *node_storage = node->storage; const char *name = IMB_colormanagement_colorspace_get_indexed_name(value); if (name && name[0]) { BLI_strncpy(node_storage->from_color_space, name, sizeof(node_storage->from_color_space)); } } static int rna_NodeConvertColorSpace_to_color_space_get(struct PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; NodeConvertColorSpace *node_storage = node->storage; return IMB_colormanagement_colorspace_get_named_index(node_storage->to_color_space); } static void rna_NodeConvertColorSpace_to_color_space_set(struct PointerRNA *ptr, int value) { bNode *node = (bNode *)ptr->data; NodeConvertColorSpace *node_storage = node->storage; const char *name = IMB_colormanagement_colorspace_get_indexed_name(value); if (name && name[0]) { BLI_strncpy(node_storage->to_color_space, name, sizeof(node_storage->to_color_space)); } } static const EnumPropertyItem *rna_NodeConvertColorSpace_color_space_itemf( bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { EnumPropertyItem *items = NULL; int totitem = 0; IMB_colormanagement_colorspace_items_add(&items, &totitem); RNA_enum_item_end(&items, &totitem); *r_free = true; return items; } #else static const EnumPropertyItem prop_image_layer_items[] = { {0, "PLACEHOLDER", 0, "Placeholder", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_image_view_items[] = { {0, "ALL", 0, "All", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_view_layer_items[] = { {0, "PLACEHOLDER", 0, "Placeholder", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_tri_channel_items[] = { {1, "R", 0, "R", "Red"}, {2, "G", 0, "G", "Green"}, {3, "B", 0, "B", "Blue"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_flip_items[] = { {0, "X", 0, "Flip X", ""}, {1, "Y", 0, "Flip Y", ""}, {2, "XY", 0, "Flip X & Y", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_ycc_items[] = { {0, "ITUBT601", 0, "ITU 601", ""}, {1, "ITUBT709", 0, "ITU 709", ""}, {2, "JFIF", 0, "Jpeg", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_glossy_items[] = { {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", "Results in perfectly sharp reflections like a mirror. The Roughness value is not used"}, {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", "Slower than GGX but gives a more energy conserving results, which would otherwise be " "visible as excessive darkening"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_anisotropic_items[] = { {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", "Slower than GGX but gives a more energy conserving results, which would otherwise be " "visible as excessive darkening"}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_glass_items[] = { {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", "Results in perfectly sharp reflections like a mirror. The Roughness value is not used"}, {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", "Slower than GGX but gives a more energy conserving results, which would otherwise be " "visible as excessive darkening"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_refraction_items[] = { {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", "Results in perfectly sharp reflections like a mirror. The Roughness value is not used"}, {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_toon_items[] = { {SHD_TOON_DIFFUSE, "DIFFUSE", 0, "Diffuse", "Use diffuse BSDF"}, {SHD_TOON_GLOSSY, "GLOSSY", 0, "Glossy", "Use glossy BSDF"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_hair_items[] = { {SHD_HAIR_REFLECTION, "Reflection", 0, "Reflection", "The light that bounces off the surface of the hair"}, {SHD_HAIR_TRANSMISSION, "Transmission", 0, "Transmission", "The light that passes through the hair and exits on the other side"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_principled_hair_items[] = { {SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION, "ABSORPTION", 0, "Absorption Coefficient", "Directly set the absorption coefficient \"sigma_a\" (this is not the most intuitive way to " "color hair)"}, {SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION, "MELANIN", 0, "Melanin Concentration", "Define the melanin concentrations below to get the most realistic-looking hair " "(you can get the concentrations for different types of hair online)"}, {SHD_PRINCIPLED_HAIR_REFLECTANCE, "COLOR", 0, "Direct Coloring", "Choose the color of your preference, and the shader will approximate the absorption " "coefficient to render lookalike hair"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_script_mode_items[] = { {NODE_SCRIPT_INTERNAL, "INTERNAL", 0, "Internal", "Use internal text data-block"}, {NODE_SCRIPT_EXTERNAL, "EXTERNAL", 0, "External", "Use external .osl or .oso file"}, {0, NULL, 0, NULL, NULL}, }; static EnumPropertyItem node_ies_mode_items[] = { {NODE_IES_INTERNAL, "INTERNAL", 0, "Internal", "Use internal text data-block"}, {NODE_IES_EXTERNAL, "EXTERNAL", 0, "External", "Use external .ies file"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_principled_distribution_items[] = { {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", "Slower than GGX but gives a more energy conserving results, which would otherwise be " "visible as excessive darkening"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem node_subsurface_method_items[] = { {SHD_SUBSURFACE_BURLEY, "BURLEY", 0, "Christensen-Burley", "Approximation to physically based volume scattering"}, {SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS, "RANDOM_WALK_FIXED_RADIUS", 0, "Random Walk (Fixed Radius)", "Volumetric approximation to physically based volume scattering, using the scattering radius " "as specified"}, {SHD_SUBSURFACE_RANDOM_WALK, "RANDOM_WALK", 0, "Random Walk", "Volumetric approximation to physically based volume scattering, with scattering radius " "automatically adjusted to match color textures"}, {0, NULL, 0, NULL, NULL}}; /* -- Common nodes ---------------------------------------------------------- */ static void def_group_input(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "interface", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_funcs( prop, NULL, NULL, "rna_NodeGroupInputOutput_interface_typef", NULL); RNA_def_property_struct_type(prop, "PropertyGroup"); RNA_def_property_flag(prop, PROP_IDPROPERTY); RNA_def_property_ui_text(prop, "Interface", "Interface socket data"); } static void def_group_output(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "interface", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_funcs( prop, NULL, NULL, "rna_NodeGroupInputOutput_interface_typef", NULL); RNA_def_property_struct_type(prop, "PropertyGroup"); RNA_def_property_flag(prop, PROP_IDPROPERTY); RNA_def_property_ui_text(prop, "Interface", "Interface socket data"); prop = RNA_def_property(srna, "is_active_output", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_DO_OUTPUT); RNA_def_property_ui_text( prop, "Active Output", "True if this node is used as the active group output"); RNA_def_property_boolean_funcs(prop, NULL, "rna_GroupOutput_is_active_output_set"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_group(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "NodeTree"); RNA_def_property_pointer_funcs( prop, NULL, "rna_NodeGroup_node_tree_set", NULL, "rna_NodeGroup_node_tree_poll"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Node Tree", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeGroup_update"); prop = RNA_def_property(srna, "interface", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_funcs(prop, NULL, NULL, "rna_NodeGroup_interface_typef", NULL); RNA_def_property_struct_type(prop, "PropertyGroup"); RNA_def_property_flag(prop, PROP_IDPROPERTY); RNA_def_property_ui_text(prop, "Interface", "Interface socket data"); } static void def_custom_group(BlenderRNA *brna, const char *struct_name, const char *base_name, const char *ui_name, const char *ui_desc, const char *reg_func) { StructRNA *srna; srna = RNA_def_struct(brna, struct_name, base_name); RNA_def_struct_ui_text(srna, ui_name, ui_desc); RNA_def_struct_sdna(srna, "bNode"); RNA_def_struct_register_funcs(srna, reg_func, "rna_Node_unregister", NULL); def_group(srna); } static void def_frame(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "text", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Text"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Text", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeFrame", "storage"); RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_ID_NODETREE); prop = RNA_def_property(srna, "shrink", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_FRAME_SHRINK); RNA_def_property_ui_text(prop, "Shrink", "Shrink the frame to minimal bounding box"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "label_size", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "label_size"); RNA_def_property_range(prop, 8, 64); RNA_def_property_ui_text(prop, "Label Font Size", "Font size to use for displaying the label"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); } static void def_clamp(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "clamp_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_node_clamp_items); RNA_def_property_ui_text(prop, "Clamp Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); } static void def_map_range(StructRNA *srna) { static const EnumPropertyItem rna_enum_data_type_items[] = { {CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating-point value"}, {CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeMapRange", "storage"); PropertyRNA *prop; prop = RNA_def_property(srna, "clamp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "clamp", 1); RNA_def_property_ui_text(prop, "Clamp", "Clamp the result to the target range [To Min, To Max]"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "interpolation_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "interpolation_type"); RNA_def_property_enum_items(prop, rna_enum_node_map_range_items); RNA_def_property_ui_text(prop, "Interpolation Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_type"); RNA_def_property_enum_items(prop, rna_enum_data_type_items); RNA_def_property_ui_text(prop, "Data Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); } static void def_math(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_node_math_items); RNA_def_property_ui_text(prop, "Operation", ""); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_NODETREE); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); prop = RNA_def_property(srna, "use_clamp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_MATH_CLAMP); RNA_def_property_ui_text(prop, "Clamp", "Clamp result of the node to 0.0 to 1.0 range"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_boolean_math(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_node_boolean_math_items); RNA_def_property_ui_text(prop, "Operation", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_compare(StructRNA *srna) { static const EnumPropertyItem mode_items[] = { {NODE_COMPARE_MODE_ELEMENT, "ELEMENT", 0, "Element-Wise", "Compare each element of the input vectors"}, {NODE_COMPARE_MODE_LENGTH, "LENGTH", 0, "Length", "Compare the length of the input vectors"}, {NODE_COMPARE_MODE_AVERAGE, "AVERAGE", 0, "Average", "Compare the average of the input vectors elements"}, {NODE_COMPARE_MODE_DOT_PRODUCT, "DOT_PRODUCT", 0, "Dot Product", "Compare the dot products of the input vectors"}, {NODE_COMPARE_MODE_DIRECTION, "DIRECTION", 0, "Direction", "Compare the direction of the input vectors"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeFunctionCompare", "storage"); prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_FunctionNodeCompare_operation_itemf"); RNA_def_property_enum_items(prop, rna_enum_node_compare_operation_items); RNA_def_property_enum_default(prop, NODE_COMPARE_EQUAL); RNA_def_property_ui_text(prop, "Operation", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_FunctionNodeCompare_type_itemf"); RNA_def_property_enum_items(prop, node_socket_data_type_items); RNA_def_property_enum_default(prop, SOCK_FLOAT); RNA_def_property_ui_text(prop, "Input Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNodeCompare_data_type_update"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_enum_default(prop, NODE_COMPARE_MODE_ELEMENT); RNA_def_property_ui_text(prop, "Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_sh_mix(StructRNA *srna) { static const EnumPropertyItem rna_enum_mix_data_type_items[] = { {SOCK_FLOAT, "FLOAT", 0, "Float", ""}, {SOCK_VECTOR, "VECTOR", 0, "Vector", ""}, {SOCK_RGBA, "RGBA", 0, "Color", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem rna_enum_mix_mode_items[] = { {NODE_MIX_MODE_UNIFORM, "UNIFORM", 0, "Uniform", "Use a single factor for all components"}, {NODE_MIX_MODE_NON_UNIFORM, "NON_UNIFORM", 0, "Non-Uniform", "Per component factor"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeShaderMix", "storage"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_mix_data_type_items); RNA_def_property_enum_default(prop, SOCK_FLOAT); RNA_def_property_ui_text(prop, "Data Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "factor_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_mix_mode_items); RNA_def_property_enum_default(prop, NODE_MIX_MODE_UNIFORM); RNA_def_property_ui_text(prop, "Factor Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "blend_type"); RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items); RNA_def_property_ui_text(prop, "Blending Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "clamp_factor", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "clamp_factor", 1); RNA_def_property_ui_text(prop, "Clamp Factor", "Clamp the factor to [0,1] range"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "clamp_result", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "clamp_result", 1); RNA_def_property_ui_text(prop, "Clamp Result", "Clamp the result to [0,1] range"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_float_to_int(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "rounding_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_node_float_to_int_items); RNA_def_property_ui_text( prop, "Rounding Mode", "Method used to convert the float to an integer"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_vector_math(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_node_vec_math_items); RNA_def_property_ui_text(prop, "Operation", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); } static void def_rgb_curve(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "mapping", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "CurveMapping"); RNA_def_property_ui_text(prop, "Mapping", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_vector_curve(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "mapping", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "CurveMapping"); RNA_def_property_ui_text(prop, "Mapping", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_float_curve(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "mapping", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "CurveMapping"); RNA_def_property_ui_text(prop, "Mapping", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_time(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "CurveMapping"); RNA_def_property_ui_text(prop, "Curve", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_ui_text(prop, "Start Frame", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); RNA_def_property_ui_text(prop, "End Frame", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_colorramp(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "ColorRamp"); RNA_def_property_ui_text(prop, "Color Ramp", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_mix_rgb(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items); RNA_def_property_ui_text(prop, "Blending Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_MIXRGB_USE_ALPHA); RNA_def_property_ui_text(prop, "Alpha", "Include alpha of second input in this operation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_clamp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_MIXRGB_CLAMP); RNA_def_property_ui_text(prop, "Clamp", "Clamp result of the node to 0.0 to 1.0 range"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_texture(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Texture"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Texture", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "node_output", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_ui_text( prop, "Node Output", "For node-based textures, which output node to use"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_fn_input_color(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeInputColor", "storage"); prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); RNA_def_property_array(prop, 4); RNA_def_property_float_sdna(prop, NULL, "color"); RNA_def_property_ui_text(prop, "Color", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_fn_input_bool(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeInputBool", "storage"); prop = RNA_def_property(srna, "boolean", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "boolean", 1); RNA_def_property_ui_text(prop, "Boolean", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_fn_input_int(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeInputInt", "storage"); prop = RNA_def_property(srna, "integer", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "integer"); RNA_def_property_int_default(prop, 1); RNA_def_property_ui_text(prop, "Integer", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_fn_input_vector(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeInputVector", "storage"); prop = RNA_def_property(srna, "vector", PROP_FLOAT, PROP_XYZ); RNA_def_property_array(prop, 3); RNA_def_property_float_sdna(prop, NULL, "vector"); RNA_def_property_ui_text(prop, "Vector", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_fn_input_string(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeInputString", "storage"); prop = RNA_def_property(srna, "string", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "String", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_fn_combsep_color(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeCombSepColor", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_node_combsep_color_items); RNA_def_property_ui_text(prop, "Mode", "Mode of color processing"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } /* -- Shader Nodes ---------------------------------------------------------- */ static void def_sh_output(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "is_active_output", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_DO_OUTPUT); RNA_def_property_ui_text( prop, "Active Output", "True if this node is used as the active output"); RNA_def_property_boolean_funcs(prop, NULL, "rna_ShaderNode_is_active_output_set"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "target", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, prop_shader_output_target_items); RNA_def_property_ui_text( prop, "Target", "Which renderer and viewport shading types to use the shaders for"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_sh_output_linestyle(StructRNA *srna) { def_sh_output(srna); def_mix_rgb(srna); } static void def_sh_mapping(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_mapping_type_items); RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); } static void def_sh_vector_rotate(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "rotation_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_vector_rotate_type_items); RNA_def_property_ui_text(prop, "Type", "Type of rotation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", 0); RNA_def_property_ui_text(prop, "Invert", "Invert angle"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_sh_attribute(StructRNA *srna) { static const EnumPropertyItem prop_attribute_type[] = { {SHD_ATTRIBUTE_GEOMETRY, "GEOMETRY", 0, "Geometry", "The attribute is associated with the object geometry, and its value " "varies from vertex to vertex, or within the object volume"}, {SHD_ATTRIBUTE_OBJECT, "OBJECT", 0, "Object", "The attribute is associated with the object or mesh data-block itself, " "and its value is uniform"}, {SHD_ATTRIBUTE_INSTANCER, "INSTANCER", 0, "Instancer", "The attribute is associated with the instancer particle system or object, " "falling back to the Object mode if the attribute isn't found, or the object " "is not instanced"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeShaderAttribute", "storage"); prop = RNA_def_property(srna, "attribute_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, prop_attribute_type); RNA_def_property_ui_text(prop, "Attribute Type", "General type of the attribute"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "attribute_name", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "name"); RNA_def_property_ui_text(prop, "Attribute Name", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_sh_tex(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "texture_mapping", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "base.tex_mapping"); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_ui_text(prop, "Texture Mapping", "Texture coordinate mapping settings"); prop = RNA_def_property(srna, "color_mapping", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "base.color_mapping"); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_ui_text(prop, "Color Mapping", "Color mapping settings"); } static void def_sh_tex_sky(StructRNA *srna) { static const EnumPropertyItem prop_sky_type[] = { {SHD_SKY_PREETHAM, "PREETHAM", 0, "Preetham", "Preetham 1999"}, {SHD_SKY_HOSEK, "HOSEK_WILKIE", 0, "Hosek / Wilkie", "Hosek / Wilkie 2012"}, {SHD_SKY_NISHITA, "NISHITA", 0, "Nishita", "Nishita 1993 improved"}, {0, NULL, 0, NULL, NULL}, }; static float default_dir[3] = {0.0f, 0.0f, 1.0f}; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeTexSky", "storage"); def_sh_tex(srna); prop = RNA_def_property(srna, "sky_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "sky_model"); RNA_def_property_enum_items(prop, prop_sky_type); RNA_def_property_ui_text(prop, "Sky Type", "Which sky model should be used"); RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update"); prop = RNA_def_property(srna, "sun_direction", PROP_FLOAT, PROP_DIRECTION); RNA_def_property_ui_text(prop, "Sun Direction", "Direction from where the sun is shining"); RNA_def_property_array(prop, 3); RNA_def_property_float_array_default(prop, default_dir); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "turbidity", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 1.0f, 10.0f); RNA_def_property_ui_range(prop, 1.0f, 10.0f, 10, 3); RNA_def_property_ui_text(prop, "Turbidity", "Atmospheric turbidity"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "ground_albedo", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Ground Albedo", "Ground color that is subtly reflected in the sky"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "sun_disc", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text(prop, "Sun Disc", "Include the sun itself in the output"); RNA_def_property_boolean_sdna(prop, NULL, "sun_disc", 1); RNA_def_property_boolean_default(prop, true); RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update"); prop = RNA_def_property(srna, "sun_size", PROP_FLOAT, PROP_ANGLE); RNA_def_property_ui_text(prop, "Sun Size", "Size of sun disc"); RNA_def_property_range(prop, 0.0f, M_PI_2); RNA_def_property_float_default(prop, DEG2RADF(0.545)); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "sun_intensity", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_text(prop, "Sun Intensity", "Strength of sun"); RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "sun_elevation", PROP_FLOAT, PROP_ANGLE); RNA_def_property_ui_text(prop, "Sun Elevation", "Sun angle from horizon"); RNA_def_property_float_default(prop, M_PI_2); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "sun_rotation", PROP_FLOAT, PROP_ANGLE); RNA_def_property_ui_text(prop, "Sun Rotation", "Rotation of sun around zenith"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "altitude", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_ui_text(prop, "Altitude", "Height from sea level"); RNA_def_property_range(prop, 0.0f, 60000.0f); RNA_def_property_ui_range(prop, 0.0f, 60000.0f, 10, 1); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "air_density", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Air", "Density of air molecules"); RNA_def_property_range(prop, 0.0f, 10.0f); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "dust_density", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Dust", "Density of dust molecules and water droplets"); RNA_def_property_range(prop, 0.0f, 10.0f); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "ozone_density", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Ozone", "Density of ozone layer"); RNA_def_property_range(prop, 0.0f, 10.0f); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static const EnumPropertyItem sh_tex_prop_interpolation_items[] = { {SHD_INTERP_LINEAR, "Linear", 0, "Linear", "Linear interpolation"}, {SHD_INTERP_CLOSEST, "Closest", 0, "Closest", "No interpolation (sample closest texel)"}, {SHD_INTERP_CUBIC, "Cubic", 0, "Cubic", "Cubic interpolation"}, {SHD_INTERP_SMART, "Smart", 0, "Smart", "Bicubic when magnifying, else bilinear (OSL only)"}, {0, NULL, 0, NULL, NULL}, }; static void def_sh_tex_environment(StructRNA *srna) { static const EnumPropertyItem prop_projection_items[] = { {SHD_PROJ_EQUIRECTANGULAR, "EQUIRECTANGULAR", 0, "Equirectangular", "Equirectangular or latitude-longitude projection"}, {SHD_PROJ_MIRROR_BALL, "MIRROR_BALL", 0, "Mirror Ball", "Projection from an orthographic photo of a mirror ball"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Image"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Image", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_tex_image_update"); RNA_def_struct_sdna_from(srna, "NodeTexEnvironment", "storage"); def_sh_tex(srna); prop = RNA_def_property(srna, "projection", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_projection_items); RNA_def_property_ui_text(prop, "Projection", "Projection of the input image"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, sh_tex_prop_interpolation_items); RNA_def_property_ui_text(prop, "Interpolation", "Texture interpolation"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "iuser"); RNA_def_property_ui_text( prop, "Image User", "Parameters defining which layer, pass and frame of the image is displayed"); RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_sh_tex_image(StructRNA *srna) { static const EnumPropertyItem prop_projection_items[] = { {SHD_PROJ_FLAT, "FLAT", 0, "Flat", "Image is projected flat using the X and Y coordinates of the texture vector"}, {SHD_PROJ_BOX, "BOX", 0, "Box", "Image is projected using different components for each side of the object space bounding " "box"}, {SHD_PROJ_SPHERE, "SPHERE", 0, "Sphere", "Image is projected spherically using the Z axis as central"}, {SHD_PROJ_TUBE, "TUBE", 0, "Tube", "Image is projected from the tube using the Z axis as central"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_image_extension[] = { {SHD_IMAGE_EXTENSION_REPEAT, "REPEAT", 0, "Repeat", "Cause the image to repeat horizontally and vertically"}, {SHD_IMAGE_EXTENSION_EXTEND, "EXTEND", 0, "Extend", "Extend by repeating edge pixels of the image"}, {SHD_IMAGE_EXTENSION_CLIP, "CLIP", 0, "Clip", "Clip to image size and set exterior pixels as transparent"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Image"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Image", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_tex_image_update"); RNA_def_struct_sdna_from(srna, "NodeTexImage", "storage"); def_sh_tex(srna); prop = RNA_def_property(srna, "projection", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_projection_items); RNA_def_property_ui_text( prop, "Projection", "Method to project 2D image on object with a 3D texture vector"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, sh_tex_prop_interpolation_items); RNA_def_property_ui_text(prop, "Interpolation", "Texture interpolation"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "projection_blend", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text( prop, "Projection Blend", "For box projection, amount of blend to use between sides"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "extension", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_image_extension); RNA_def_property_ui_text( prop, "Extension", "How the image is extrapolated past its original bounds"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "iuser"); RNA_def_property_ui_text( prop, "Image User", "Parameters defining which layer, pass and frame of the image is displayed"); RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_tex_combsep_color(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_node_combsep_color_items); RNA_def_property_ui_text(prop, "Mode", "Mode of color processing"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_image_texture(StructRNA *srna) { static const EnumPropertyItem fn_tex_prop_interpolation_items[] = { {SHD_INTERP_LINEAR, "Linear", 0, "Linear", "Linear interpolation"}, {SHD_INTERP_CLOSEST, "Closest", 0, "Closest", "No interpolation (sample closest texel)"}, {SHD_INTERP_CUBIC, "Cubic", 0, "Cubic", "Cubic interpolation"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_image_extension[] = { {SHD_IMAGE_EXTENSION_REPEAT, "REPEAT", 0, "Repeat", "Cause the image to repeat horizontally and vertically"}, {SHD_IMAGE_EXTENSION_EXTEND, "EXTEND", 0, "Extend", "Extend by repeating edge pixels of the image"}, {SHD_IMAGE_EXTENSION_CLIP, "CLIP", 0, "Clip", "Clip to image size and set exterior pixels as transparent"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryImageTexture", "storage"); prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, fn_tex_prop_interpolation_items); RNA_def_property_ui_text(prop, "Interpolation", "Method for smoothing values between pixels"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "extension", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_image_extension); RNA_def_property_ui_text( prop, "Extension", "How the image is extrapolated past its original bounds"); RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_sh_tex_gradient(StructRNA *srna) { static const EnumPropertyItem prop_gradient_type[] = { {SHD_BLEND_LINEAR, "LINEAR", 0, "Linear", "Create a linear progression"}, {SHD_BLEND_QUADRATIC, "QUADRATIC", 0, "Quadratic", "Create a quadratic progression"}, {SHD_BLEND_EASING, "EASING", 0, "Easing", "Create a progression easing from one step to the next"}, {SHD_BLEND_DIAGONAL, "DIAGONAL", 0, "Diagonal", "Create a diagonal progression"}, {SHD_BLEND_SPHERICAL, "SPHERICAL", 0, "Spherical", "Create a spherical progression"}, {SHD_BLEND_QUADRATIC_SPHERE, "QUADRATIC_SPHERE", 0, "Quadratic Sphere", "Create a quadratic progression in the shape of a sphere"}, {SHD_BLEND_RADIAL, "RADIAL", 0, "Radial", "Create a radial progression"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeTexGradient", "storage"); def_sh_tex(srna); prop = RNA_def_property(srna, "gradient_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_gradient_type); RNA_def_property_ui_text(prop, "Gradient Type", "Style of the color blending"); RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_sh_tex_noise(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeTexNoise", "storage"); def_sh_tex(srna); prop = RNA_def_property(srna, "noise_dimensions", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "dimensions"); RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items); RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for"); RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update"); } static void def_sh_tex_checker(StructRNA *srna) { RNA_def_struct_sdna_from(srna, "NodeTexChecker", "storage"); def_sh_tex(srna); } static void def_sh_tex_brick(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeTexBrick", "storage"); def_sh_tex(srna); prop = RNA_def_property(srna, "offset_frequency", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "offset_freq"); RNA_def_property_int_default(prop, 2); RNA_def_property_range(prop, 1, 99); RNA_def_property_ui_text(prop, "Offset Frequency", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "squash_frequency", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "squash_freq"); RNA_def_property_int_default(prop, 2); RNA_def_property_range(prop, 1, 99); RNA_def_property_ui_text(prop, "Squash Frequency", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "offset"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Offset Amount", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "squash", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "squash"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0.0f, 99.0f); RNA_def_property_ui_text(prop, "Squash Amount", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_sh_tex_magic(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeTexMagic", "storage"); def_sh_tex(srna); prop = RNA_def_property(srna, "turbulence_depth", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "depth"); RNA_def_property_range(prop, 0, 10); RNA_def_property_ui_text(prop, "Depth", "Level of detail in the added turbulent noise"); RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_sh_tex_musgrave(StructRNA *srna) { static const EnumPropertyItem prop_musgrave_type[] = { {SHD_MUSGRAVE_MULTIFRACTAL, "MULTIFRACTAL", 0, "Multifractal", "More uneven result (varies with location), more similar to a real terrain"}, {SHD_MUSGRAVE_RIDGED_MULTIFRACTAL, "RIDGED_MULTIFRACTAL", 0, "Ridged Multifractal", "Create sharp peaks"}, {SHD_MUSGRAVE_HYBRID_MULTIFRACTAL, "HYBRID_MULTIFRACTAL", 0, "Hybrid Multifractal", "Create peaks and valleys with different roughness values"}, {SHD_MUSGRAVE_FBM, "FBM", 0, "fBM", "Produce an unnatural homogeneous and isotropic result"}, {SHD_MUSGRAVE_HETERO_TERRAIN, "HETERO_TERRAIN", 0, "Hetero Terrain", "Similar to Hybrid Multifractal creates a heterogeneous terrain, but with the likeness of " "river channels"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeTexMusgrave", "storage"); def_sh_tex(srna); prop = RNA_def_property(srna, "musgrave_dimensions", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "dimensions"); RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items); RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for"); RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update"); prop = RNA_def_property(srna, "musgrave_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "musgrave_type"); RNA_def_property_enum_items(prop, prop_musgrave_type); RNA_def_property_ui_text(prop, "Type", "Type of the Musgrave texture"); RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update"); } static void def_sh_tex_voronoi(StructRNA *srna) { static EnumPropertyItem prop_distance_items[] = { {SHD_VORONOI_EUCLIDEAN, "EUCLIDEAN", 0, "Euclidean", "Euclidean distance"}, {SHD_VORONOI_MANHATTAN, "MANHATTAN", 0, "Manhattan", "Manhattan distance"}, {SHD_VORONOI_CHEBYCHEV, "CHEBYCHEV", 0, "Chebychev", "Chebychev distance"}, {SHD_VORONOI_MINKOWSKI, "MINKOWSKI", 0, "Minkowski", "Minkowski distance"}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem prop_feature_items[] = { {SHD_VORONOI_F1, "F1", 0, "F1", "Computes the distance to the closest point as well as its position and color"}, {SHD_VORONOI_F2, "F2", 0, "F2", "Computes the distance to the second closest point as well as its position and color"}, {SHD_VORONOI_SMOOTH_F1, "SMOOTH_F1", 0, "Smooth F1", "Smoothed version of F1. Weighted sum of neighbor voronoi cells"}, {SHD_VORONOI_DISTANCE_TO_EDGE, "DISTANCE_TO_EDGE", 0, "Distance to Edge", "Computes the distance to the edge of the voronoi cell"}, {SHD_VORONOI_N_SPHERE_RADIUS, "N_SPHERE_RADIUS", 0, "N-Sphere Radius", "Computes the radius of the n-sphere inscribed in the voronoi cell"}, {0, NULL, 0, NULL, NULL}}; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeTexVoronoi", "storage"); def_sh_tex(srna); prop = RNA_def_property(srna, "voronoi_dimensions", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "dimensions"); RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items); RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for"); RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update"); prop = RNA_def_property(srna, "distance", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "distance"); RNA_def_property_enum_items(prop, prop_distance_items); RNA_def_property_ui_text( prop, "Distance Metric", "The distance metric used to compute the texture"); RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update"); prop = RNA_def_property(srna, "feature", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "feature"); RNA_def_property_enum_items(prop, prop_feature_items); RNA_def_property_ui_text( prop, "Feature Output", "The Voronoi feature that the node will compute"); RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update"); } static void def_sh_tex_wave(StructRNA *srna) { static const EnumPropertyItem prop_wave_type_items[] = { {SHD_WAVE_BANDS, "BANDS", 0, "Bands", "Use standard wave texture in bands"}, {SHD_WAVE_RINGS, "RINGS", 0, "Rings", "Use wave texture in rings"}, {0, NULL, 0, NULL, NULL}, }; static EnumPropertyItem prop_wave_bands_direction_items[] = { {SHD_WAVE_BANDS_DIRECTION_X, "X", 0, "X", "Bands across X axis"}, {SHD_WAVE_BANDS_DIRECTION_Y, "Y", 0, "Y", "Bands across Y axis"}, {SHD_WAVE_BANDS_DIRECTION_Z, "Z", 0, "Z", "Bands across Z axis"}, {SHD_WAVE_BANDS_DIRECTION_DIAGONAL, "DIAGONAL", 0, "Diagonal", "Bands across diagonal axis"}, {0, NULL, 0, NULL, NULL}, }; static EnumPropertyItem prop_wave_rings_direction_items[] = { {SHD_WAVE_RINGS_DIRECTION_X, "X", 0, "X", "Rings along X axis"}, {SHD_WAVE_RINGS_DIRECTION_Y, "Y", 0, "Y", "Rings along Y axis"}, {SHD_WAVE_RINGS_DIRECTION_Z, "Z", 0, "Z", "Rings along Z axis"}, {SHD_WAVE_RINGS_DIRECTION_SPHERICAL, "SPHERICAL", 0, "Spherical", "Rings along spherical distance"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_wave_profile_items[] = { {SHD_WAVE_PROFILE_SIN, "SIN", 0, "Sine", "Use a standard sine profile"}, {SHD_WAVE_PROFILE_SAW, "SAW", 0, "Saw", "Use a sawtooth profile"}, {SHD_WAVE_PROFILE_TRI, "TRI", 0, "Triangle", "Use a triangle profile"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeTexWave", "storage"); def_sh_tex(srna); prop = RNA_def_property(srna, "wave_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "wave_type"); RNA_def_property_enum_items(prop, prop_wave_type_items); RNA_def_property_ui_text(prop, "Wave Type", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "bands_direction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "bands_direction"); RNA_def_property_enum_items(prop, prop_wave_bands_direction_items); RNA_def_property_ui_text(prop, "Bands Direction", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "rings_direction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "rings_direction"); RNA_def_property_enum_items(prop, prop_wave_rings_direction_items); RNA_def_property_ui_text(prop, "Rings Direction", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "wave_profile", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "wave_profile"); RNA_def_property_enum_items(prop, prop_wave_profile_items); RNA_def_property_ui_text(prop, "Wave Profile", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_sh_tex_white_noise(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "noise_dimensions", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items); RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); } static void def_sh_tex_coord(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Object"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Object", "Use coordinates from this object (for object texture coordinates output)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update_relations"); prop = RNA_def_property(srna, "from_instancer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_ui_text( prop, "From Instancer", "Use the parent of the instance object if possible"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_sh_vect_transform(StructRNA *srna) { static const EnumPropertyItem prop_vect_type_items[] = { {SHD_VECT_TRANSFORM_TYPE_POINT, "POINT", 0, "Point", "Transform a point"}, {SHD_VECT_TRANSFORM_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"}, {SHD_VECT_TRANSFORM_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_vect_space_items[] = { {SHD_VECT_TRANSFORM_SPACE_WORLD, "WORLD", 0, "World", ""}, {SHD_VECT_TRANSFORM_SPACE_OBJECT, "OBJECT", 0, "Object", ""}, {SHD_VECT_TRANSFORM_SPACE_CAMERA, "CAMERA", 0, "Camera", ""}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeShaderVectTransform", "storage"); prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, prop_vect_type_items); RNA_def_property_ui_text(prop, "Type", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "convert_from", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_vect_space_items); RNA_def_property_ui_text(prop, "Convert From", "Space to convert from"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "convert_to", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_vect_space_items); RNA_def_property_ui_text(prop, "Convert To", "Space to convert to"); RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_sh_tex_wireframe(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "use_pixel_size", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_ui_text(prop, "Pixel Size", "Use screen pixel size instead of world units"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_sh_tex_pointdensity(StructRNA *srna) { PropertyRNA *prop; FunctionRNA *func; PropertyRNA *parm; static const EnumPropertyItem point_source_items[] = { {SHD_POINTDENSITY_SOURCE_PSYS, "PARTICLE_SYSTEM", 0, "Particle System", "Generate point density from a particle system"}, {SHD_POINTDENSITY_SOURCE_OBJECT, "OBJECT", 0, "Object Vertices", "Generate point density from an object's vertices"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_interpolation_items[] = { {SHD_INTERP_CLOSEST, "Closest", 0, "Closest", "No interpolation (sample closest texel)"}, {SHD_INTERP_LINEAR, "Linear", 0, "Linear", "Linear interpolation"}, {SHD_INTERP_CUBIC, "Cubic", 0, "Cubic", "Cubic interpolation"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem space_items[] = { {SHD_POINTDENSITY_SPACE_OBJECT, "OBJECT", 0, "Object Space", ""}, {SHD_POINTDENSITY_SPACE_WORLD, "WORLD", 0, "World Space", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem particle_color_source_items[] = { {SHD_POINTDENSITY_COLOR_PARTAGE, "PARTICLE_AGE", 0, "Particle Age", "Lifetime mapped as 0.0 to 1.0 intensity"}, {SHD_POINTDENSITY_COLOR_PARTSPEED, "PARTICLE_SPEED", 0, "Particle Speed", "Particle speed (absolute magnitude of velocity) mapped as 0.0 to 1.0 intensity"}, {SHD_POINTDENSITY_COLOR_PARTVEL, "PARTICLE_VELOCITY", 0, "Particle Velocity", "XYZ velocity mapped to RGB colors"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem vertex_color_source_items[] = { {SHD_POINTDENSITY_COLOR_VERTCOL, "VERTEX_COLOR", 0, "Vertex Color", "Vertex color layer"}, {SHD_POINTDENSITY_COLOR_VERTWEIGHT, "VERTEX_WEIGHT", 0, "Vertex Weight", "Vertex group weight"}, {SHD_POINTDENSITY_COLOR_VERTNOR, "VERTEX_NORMAL", 0, "Vertex Normal", "XYZ normal vector mapped to RGB colors"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Object"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Object", "Object to take point data from"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeShaderTexPointDensity", "storage"); prop = RNA_def_property(srna, "point_source", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, point_source_items); RNA_def_property_ui_text(prop, "Point Source", "Point data to use as renderable point density"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Particle System", "Particle System to render as points"); RNA_def_property_struct_type(prop, "ParticleSystem"); RNA_def_property_pointer_funcs(prop, "rna_ShaderNodePointDensity_psys_get", "rna_ShaderNodePointDensity_psys_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "resolution", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 1, 32768); RNA_def_property_ui_text( prop, "Resolution", "Resolution used by the texture holding the point density"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "radius"); RNA_def_property_range(prop, 0.001, FLT_MAX); RNA_def_property_ui_text( prop, "Radius", "Radius from the shaded sample to look for points within"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, space_items); RNA_def_property_ui_text(prop, "Space", "Coordinate system to calculate voxels in"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_interpolation_items); RNA_def_property_ui_text(prop, "Interpolation", "Texture interpolation"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "particle_color_source", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "color_source"); RNA_def_property_enum_items(prop, particle_color_source_items); RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "vertex_color_source", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "ob_color_source"); RNA_def_property_enum_items(prop, vertex_color_source_items); RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "vertex_attribute_name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Vertex Attribute Name", "Vertex attribute to use for color"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); func = RNA_def_function(srna, "cache_point_density", "rna_ShaderNodePointDensity_density_cache"); RNA_def_function_ui_description(func, "Cache point density data for later calculation"); RNA_def_pointer(func, "depsgraph", "Depsgraph", "", ""); func = RNA_def_function(srna, "calc_point_density", "rna_ShaderNodePointDensity_density_calc"); RNA_def_function_ui_description(func, "Calculate point density"); RNA_def_pointer(func, "depsgraph", "Depsgraph", "", ""); /* TODO: See how array size of 0 works, this shouldn't be used. */ parm = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0); RNA_def_parameter_flags(parm, PROP_DYNAMIC, 0); RNA_def_function_output(func, parm); func = RNA_def_function( srna, "calc_point_density_minmax", "rna_ShaderNodePointDensity_density_minmax"); RNA_def_function_ui_description(func, "Calculate point density"); RNA_def_pointer(func, "depsgraph", "Depsgraph", "", ""); parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_COORDS); RNA_def_property_array(parm, 3); RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); parm = RNA_def_property(func, "max", PROP_FLOAT, PROP_COORDS); RNA_def_property_array(parm, 3); RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); } static void def_glossy(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_glossy_items); RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_glass(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_glass_items); RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_principled(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_principled_distribution_items); RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); prop = RNA_def_property(srna, "subsurface_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, node_subsurface_method_items); RNA_def_property_ui_text( prop, "Subsurface Method", "Method for rendering subsurface scattering"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); } static void def_refraction(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_refraction_items); RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_anisotropic(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_anisotropic_items); RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_toon(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_toon_items); RNA_def_property_ui_text(prop, "Component", "Toon BSDF component to use"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_sh_bump(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_ui_text( prop, "Invert", "Invert the bump mapping direction to push into the surface instead of out"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_hair(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_hair_items); RNA_def_property_ui_text(prop, "Component", "Hair BSDF component to use"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } /* RNA initialization for the custom property. */ static void def_hair_principled(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "parametrization", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_ui_text( prop, "Color Parametrization", "Select the shader's color parametrization"); RNA_def_property_enum_items(prop, node_principled_hair_items); RNA_def_property_enum_default(prop, SHD_PRINCIPLED_HAIR_REFLECTANCE); /* Upon editing, update both the node data AND the UI representation */ /* (This effectively shows/hides the relevant sockets) */ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); } static void def_sh_uvmap(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "from_instancer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_ui_text( prop, "From Instancer", "Use the parent of the instance object if possible"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeShaderUVMap", "storage"); prop = RNA_def_property(srna, "uv_map", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "UV Map", "UV coordinates to be used for mapping"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "bNode", NULL); } static void def_sh_vertex_color(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeShaderVertexColor", "storage"); prop = RNA_def_property(srna, "layer_name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Color Attribute", "Color Attribute"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "bNode", NULL); } static void def_sh_uvalongstroke(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "use_tips", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_ui_text( prop, "Use Tips", "Lower half of the texture is for tips of the stroke"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_sh_normal_map(StructRNA *srna) { static const EnumPropertyItem prop_space_items[] = { {SHD_SPACE_TANGENT, "TANGENT", 0, "Tangent Space", "Tangent space normal mapping"}, {SHD_SPACE_OBJECT, "OBJECT", 0, "Object Space", "Object space normal mapping"}, {SHD_SPACE_WORLD, "WORLD", 0, "World Space", "World space normal mapping"}, {SHD_SPACE_BLENDER_OBJECT, "BLENDER_OBJECT", 0, "Blender Object Space", "Object space normal mapping, compatible with Blender render baking"}, {SHD_SPACE_BLENDER_WORLD, "BLENDER_WORLD", 0, "Blender World Space", "World space normal mapping, compatible with Blender render baking"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeShaderNormalMap", "storage"); prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_space_items); RNA_def_property_ui_text(prop, "Space", "Space of the input normal"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "uv_map", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "UV Map", "UV Map for tangent space maps"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "bNode", NULL); } static void def_sh_displacement(StructRNA *srna) { static const EnumPropertyItem prop_space_items[] = { {SHD_SPACE_OBJECT, "OBJECT", 0, "Object Space", "Displacement is in object space, affected by object scale"}, {SHD_SPACE_WORLD, "WORLD", 0, "World Space", "Displacement is in world space, not affected by object scale"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, prop_space_items); RNA_def_property_ui_text(prop, "Space", "Space of the input height"); RNA_def_property_update(prop, 0, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "bNode", NULL); } static void def_sh_vector_displacement(StructRNA *srna) { static const EnumPropertyItem prop_space_items[] = { {SHD_SPACE_TANGENT, "TANGENT", 0, "Tangent Space", "Tangent space vector displacement mapping"}, {SHD_SPACE_OBJECT, "OBJECT", 0, "Object Space", "Object space vector displacement mapping"}, {SHD_SPACE_WORLD, "WORLD", 0, "World Space", "World space vector displacement mapping"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, prop_space_items); RNA_def_property_ui_text(prop, "Space", "Space of the input height"); RNA_def_property_update(prop, 0, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "bNode", NULL); } static void def_sh_tangent(StructRNA *srna) { static const EnumPropertyItem prop_direction_type_items[] = { {SHD_TANGENT_RADIAL, "RADIAL", 0, "Radial", "Radial tangent around the X, Y or Z axis"}, {SHD_TANGENT_UVMAP, "UV_MAP", 0, "UV Map", "Tangent from UV map"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_axis_items[] = { {SHD_TANGENT_AXIS_X, "X", 0, "X", "X axis"}, {SHD_TANGENT_AXIS_Y, "Y", 0, "Y", "Y axis"}, {SHD_TANGENT_AXIS_Z, "Z", 0, "Z", "Z axis"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeShaderTangent", "storage"); prop = RNA_def_property(srna, "direction_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_direction_type_items); RNA_def_property_ui_text(prop, "Direction", "Method to use for the tangent"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_axis_items); RNA_def_property_ui_text(prop, "Axis", "Axis for radial tangents"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "uv_map", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "UV Map", "UV Map for tangent generated from UV"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "bNode", NULL); } static void def_sh_bevel(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "samples", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 2, 128); RNA_def_property_ui_range(prop, 2, 16, 1, 1); RNA_def_property_ui_text(prop, "Samples", "Number of rays to trace per shader evaluation"); RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_sh_ambient_occlusion(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "samples", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 1, 128); RNA_def_property_ui_text(prop, "Samples", "Number of rays to trace per shader evaluation"); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "inside", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_AO_INSIDE); RNA_def_property_ui_text(prop, "Inside", "Trace rays towards the inside of the object"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "only_local", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_AO_LOCAL); RNA_def_property_ui_text( prop, "Only Local", "Only consider the object itself when computing AO"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_sh_subsurface(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "falloff", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_subsurface_method_items); RNA_def_property_ui_text(prop, "Method", "Method for rendering subsurface scattering"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); } static void def_sh_tex_ies(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "ies", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Text"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "IES Text", "Internal IES file"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeShaderTexIES", "storage"); prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); RNA_def_property_ui_text(prop, "File Path", "IES light path"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_funcs(prop, NULL, "rna_ShaderNodeTexIES_mode_set", NULL); RNA_def_property_enum_items(prop, node_ies_mode_items); RNA_def_property_ui_text( prop, "Source", "Whether the IES file is loaded from disk or from a text data-block"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "bNode", NULL); } static void def_sh_output_aov(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeShaderOutputAOV", "storage"); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Name", "Name of the AOV that this output writes to"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "bNode", NULL); } static void def_sh_combsep_color(StructRNA *srna) { static const EnumPropertyItem type_items[] = { {NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"}, {NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"}, {NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeCombSepColor", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text(prop, "Mode", "Mode of color processing"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_sh_script(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "script", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Text"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Script", "Internal shader script to define the shader"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodeScript_update"); RNA_def_struct_sdna_from(srna, "NodeShaderScript", "storage"); prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); RNA_def_property_ui_text(prop, "File Path", "Shader script path"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodeScript_update"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_funcs(prop, NULL, "rna_ShaderNodeScript_mode_set", NULL); RNA_def_property_enum_items(prop, node_script_mode_items); RNA_def_property_ui_text(prop, "Script Source", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_auto_update", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_SCRIPT_AUTO_UPDATE); RNA_def_property_ui_text( prop, "Auto Update", "Automatically update the shader when the .osl file changes (external scripts only)"); prop = RNA_def_property(srna, "bytecode", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs(prop, "rna_ShaderNodeScript_bytecode_get", "rna_ShaderNodeScript_bytecode_length", "rna_ShaderNodeScript_bytecode_set"); RNA_def_property_ui_text(prop, "Bytecode", "Compile bytecode for shader script node"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "bytecode_hash", PROP_STRING, PROP_NONE); RNA_def_property_ui_text( prop, "Bytecode Hash", "Hash of compile bytecode, for quick equality checking"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); /* needs to be reset to avoid bad pointer type in API functions below */ RNA_def_struct_sdna_from(srna, "bNode", NULL); /* API functions */ # if 0 /* XXX TODO: use general node api for this. */ func = RNA_def_function(srna, "find_socket", "rna_ShaderNodeScript_find_socket"); RNA_def_function_ui_description(func, "Find a socket by name"); parm = RNA_def_string(func, "name", NULL, 0, "Socket name", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /*parm =*/RNA_def_boolean(func, "is_output", false, "Output", "Whether the socket is an output"); parm = RNA_def_pointer(func, "result", "NodeSocket", "", ""); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "add_socket", "rna_ShaderNodeScript_add_socket"); RNA_def_function_ui_description(func, "Add a socket"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_string(func, "name", NULL, 0, "Name", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", node_socket_type_items, SOCK_FLOAT, "Type", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /*parm =*/RNA_def_boolean(func, "is_output", false, "Output", "Whether the socket is an output"); parm = RNA_def_pointer(func, "result", "NodeSocket", "", ""); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove_socket", "rna_ShaderNodeScript_remove_socket"); RNA_def_function_ui_description(func, "Remove a socket"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_pointer(func, "sock", "NodeSocket", "Socket", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); # endif } /* -- Compositor Nodes ------------------------------------------------------ */ static void def_cmp_alpha_over(StructRNA *srna) { PropertyRNA *prop; /* XXX: Tooltip */ prop = RNA_def_property(srna, "use_premultiply", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_ui_text(prop, "Convert Premultiplied", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeTwoFloats", "storage"); prop = RNA_def_property(srna, "premul", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "x"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Premultiplied", "Mix Factor"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_blur(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem filter_type_items[] = { {R_FILTER_BOX, "FLAT", 0, "Flat", ""}, {R_FILTER_TENT, "TENT", 0, "Tent", ""}, {R_FILTER_QUAD, "QUAD", 0, "Quadratic", ""}, {R_FILTER_CUBIC, "CUBIC", 0, "Cubic", ""}, {R_FILTER_GAUSS, "GAUSS", 0, "Gaussian", ""}, {R_FILTER_FAST_GAUSS, "FAST_GAUSS", 0, "Fast Gaussian", ""}, {R_FILTER_CATROM, "CATROM", 0, "Catrom", ""}, {R_FILTER_MITCH, "MITCH", 0, "Mitch", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem aspect_correction_type_items[] = { {CMP_NODE_BLUR_ASPECT_NONE, "NONE", 0, "None", ""}, {CMP_NODE_BLUR_ASPECT_Y, "Y", 0, "Y", ""}, {CMP_NODE_BLUR_ASPECT_X, "X", 0, "X", ""}, {0, NULL, 0, NULL, NULL}, }; /* duplicated in def_cmp_bokehblur */ prop = RNA_def_property(srna, "use_variable_size", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_NODEFLAG_BLUR_VARIABLE_SIZE); RNA_def_property_ui_text( prop, "Variable Size", "Support variable blur per pixel when using an image for size input"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_extended_bounds", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_NODEFLAG_BLUR_EXTEND_BOUNDS); RNA_def_property_ui_text( prop, "Extend Bounds", "Extend bounds of the input image to fully fit blurred image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeBlurData", "storage"); prop = RNA_def_property(srna, "size_x", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "sizex"); RNA_def_property_range(prop, 0, 2048); RNA_def_property_ui_text(prop, "Size X", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "size_y", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "sizey"); RNA_def_property_range(prop, 0, 2048); RNA_def_property_ui_text(prop, "Size Y", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_relative", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "relative", 1); RNA_def_property_ui_text( prop, "Relative", "Use relative (percent) values to define blur radius"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "aspect_correction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "aspect"); RNA_def_property_enum_items(prop, aspect_correction_type_items); RNA_def_property_ui_text(prop, "Aspect Correction", "Type of aspect correction to use"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fac"); RNA_def_property_range(prop, 0.0f, 2.0f); RNA_def_property_ui_text(prop, "Factor", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "factor_x", PROP_FLOAT, PROP_PERCENTAGE); RNA_def_property_float_sdna(prop, NULL, "percentx"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_text(prop, "Relative Size X", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "factor_y", PROP_FLOAT, PROP_PERCENTAGE); RNA_def_property_float_sdna(prop, NULL, "percenty"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_text(prop, "Relative Size Y", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "filtertype"); RNA_def_property_enum_items(prop, filter_type_items); RNA_def_property_ui_text(prop, "Filter Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_bokeh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "bokeh", 1); RNA_def_property_ui_text(prop, "Bokeh", "Use circular filter (slower)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_gamma_correction", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gamma", 1); RNA_def_property_ui_text(prop, "Gamma", "Apply filter on gamma corrected values"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_filter(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_node_filter_items); RNA_def_property_ui_text(prop, "Filter Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_map_value(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "TexMapping", "storage"); prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "loc"); RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Offset", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "size"); RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Size", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_min", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MIN); RNA_def_property_ui_text(prop, "Use Minimum", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_max", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MAX); RNA_def_property_ui_text(prop, "Use Maximum", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "min"); RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Minimum", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "max"); RNA_def_property_array(prop, 1); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_text(prop, "Maximum", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_map_range(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "use_clamp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_ui_text(prop, "Clamp", "Clamp result of the node to 0.0 to 1.0 range"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_vector_blur(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeBlurData", "storage"); prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "samples"); RNA_def_property_range(prop, 1, 256); RNA_def_property_ui_text(prop, "Samples", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "speed_min", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "minspeed"); RNA_def_property_range(prop, 0, 1024); RNA_def_property_ui_text( prop, "Min Speed", "Minimum speed for a pixel to be blurred (used to separate background from foreground)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "speed_max", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "maxspeed"); RNA_def_property_range(prop, 0, 1024); RNA_def_property_ui_text(prop, "Max Speed", "Maximum speed, or zero for none"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fac"); RNA_def_property_range(prop, 0.0, 20.0); RNA_def_property_ui_range(prop, 0.0, 2.0, 1.0, 2); RNA_def_property_ui_text( prop, "Blur Factor", "Scaling factor for motion vectors (actually, 'shutter speed', in frames)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_curved", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "curved", 1); RNA_def_property_ui_text( prop, "Curved", "Interpolate between frames in a Bezier curve, rather than linearly"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_set_alpha(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem mode_items[] = { {CMP_NODE_SETALPHA_MODE_APPLY, "APPLY", 0, "Apply Mask", "Multiply the input image's RGBA channels by the alpha input value"}, {CMP_NODE_SETALPHA_MODE_REPLACE_ALPHA, "REPLACE_ALPHA", 0, "Replace Alpha", "Replace the input image's alpha channel by the alpha input value"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeSetAlpha", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_levels(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem channel_items[] = { {1, "COMBINED_RGB", 0, "Combined", "Combined RGB"}, {2, "RED", 0, "Red", "Red Channel"}, {3, "GREEN", 0, "Green", "Green Channel"}, {4, "BLUE", 0, "Blue", "Blue Channel"}, {5, "LUMINANCE", 0, "Luminance", "Luminance Channel"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "channel", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, channel_items); RNA_def_property_ui_text(prop, "Channel", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_node_image_user(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "frame_duration", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "frames"); RNA_def_property_range(prop, 0, MAXFRAMEF); RNA_def_property_ui_text( prop, "Frames", "Number of images of a movie to use"); /* copied from the rna_image.c */ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "sfra"); RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF); /* copied from the rna_image.c */ RNA_def_property_ui_text( prop, "Start Frame", "Global starting frame of the movie/sequence, assuming first picture has a #1"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "frame_offset", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "offset"); RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF); /* copied from the rna_image.c */ RNA_def_property_ui_text( prop, "Offset", "Offset the number of the frame to use in the animation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_cyclic", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "cycl", 1); RNA_def_property_ui_text( prop, "Cyclic", "Cycle the images in the movie"); /* copied from the rna_image.c */ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_auto_refresh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_ANIM_ALWAYS); /* copied from the rna_image.c */ RNA_def_property_ui_text(prop, "Auto-Refresh", "Always refresh image on frame changes"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "layer", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "layer"); RNA_def_property_enum_items(prop, prop_image_layer_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_image_layer_itemf"); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); RNA_def_property_ui_text(prop, "Layer", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_image_layer_update"); prop = RNA_def_property(srna, "has_layers", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_Node_image_has_layers_get", NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Has Layers", "True if this image has any named layer"); prop = RNA_def_property(srna, "view", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "view"); RNA_def_property_enum_items(prop, prop_image_view_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_image_view_itemf"); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); RNA_def_property_ui_text(prop, "View", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "has_views", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_Node_image_has_views_get", NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Has View", "True if this image has multiple views"); } static void def_cmp_image(StructRNA *srna) { PropertyRNA *prop; # if 0 static const EnumPropertyItem type_items[] = { {IMA_SRC_FILE, "IMAGE", 0, "Image", ""}, {IMA_SRC_MOVIE, "MOVIE", "Movie", ""}, {IMA_SRC_SEQUENCE, "SEQUENCE", "Sequence", ""}, {IMA_SRC_GENERATED, "GENERATED", "Generated", ""}, {0, NULL, 0, NULL, NULL}, }; # endif prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Image"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Image", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Image_Node_update_id"); prop = RNA_def_property(srna, "use_straight_alpha_output", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT); RNA_def_property_ui_text(prop, "Straight Alpha Output", "Put node output buffer to straight alpha instead of premultiplied"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); /* NOTE: Image user properties used in the UI are redefined in def_node_image_user, * to trigger correct updates of the node editor. RNA design problem that prevents * updates from nested structs. */ RNA_def_struct_sdna_from(srna, "ImageUser", "storage"); def_node_image_user(srna); } static void def_cmp_render_layers(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Node_scene_set", NULL, NULL); RNA_def_property_struct_type(prop, "Scene"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Scene", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_view_layer_update"); prop = RNA_def_property(srna, "layer", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, prop_view_layer_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_view_layer_itemf"); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); RNA_def_property_ui_text(prop, "Layer", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_view_layer_update"); } static void rna_def_cmp_output_file_slot_file(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, "NodeOutputFileSlotFile", NULL); RNA_def_struct_sdna(srna, "NodeImageMultiFileSocket"); RNA_def_struct_ui_text( srna, "Output File Slot", "Single layer file slot of the file output node"); prop = RNA_def_property(srna, "use_node_format", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_node_format", 1); RNA_def_property_ui_text(prop, "Use Node Format", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL); prop = RNA_def_property(srna, "save_as_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "save_as_render", 1); RNA_def_property_ui_text( prop, "Save as Render", "Apply render part of display transform when saving byte image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL); prop = RNA_def_property(srna, "format", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "ImageFormatSettings"); prop = RNA_def_property(srna, "path", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "path"); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NodeOutputFileSlotFile_path_set"); RNA_def_struct_name_property(srna, prop); RNA_def_property_ui_text(prop, "Path", "Subpath used for this slot"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL); } static void rna_def_cmp_output_file_slot_layer(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, "NodeOutputFileSlotLayer", NULL); RNA_def_struct_sdna(srna, "NodeImageMultiFileSocket"); RNA_def_struct_ui_text( srna, "Output File Layer Slot", "Multilayer slot of the file output node"); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "layer"); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NodeOutputFileSlotLayer_name_set"); RNA_def_struct_name_property(srna, prop); RNA_def_property_ui_text(prop, "Name", "OpenEXR layer name used for this slot"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL); } static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, PropertyRNA *cprop, const char *struct_name) { StructRNA *srna; PropertyRNA *parm; FunctionRNA *func; RNA_def_property_srna(cprop, struct_name); srna = RNA_def_struct(brna, struct_name, NULL); RNA_def_struct_sdna(srna, "bNode"); RNA_def_struct_ui_text(srna, "File Output Slots", "Collection of File Output node slots"); func = RNA_def_function(srna, "new", "rna_NodeOutputFile_slots_new"); RNA_def_function_ui_description(func, "Add a file slot to this node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS | FUNC_USE_CONTEXT); parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return value */ parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket"); RNA_def_function_return(func, parm); /* NOTE: methods below can use the standard node socket API functions, * included here for completeness. */ func = RNA_def_function(srna, "remove", "rna_Node_socket_remove"); RNA_def_function_ui_description(func, "Remove a file slot from this node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "The socket to remove"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "clear", "rna_Node_inputs_clear"); RNA_def_function_ui_description(func, "Remove all file slots from this node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); func = RNA_def_function(srna, "move", "rna_Node_inputs_move"); RNA_def_function_ui_description(func, "Move a file slot to another position"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); parm = RNA_def_int( func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int( func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } static void def_cmp_output_file(BlenderRNA *brna, StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeImageMultiFile", "storage"); prop = RNA_def_property(srna, "base_path", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "base_path"); RNA_def_property_ui_text(prop, "Base Path", "Base output path for the image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "active_input_index", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "active_input"); RNA_def_property_ui_text(prop, "Active Input Index", "Active input index in details view list"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "format", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "ImageFormatSettings"); /* XXX using two different collections here for the same basic DNA list! * Details of the output slots depend on whether the node is in Multilayer EXR mode. */ prop = RNA_def_property(srna, "file_slots", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_funcs(prop, "rna_NodeOutputFile_slots_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_NodeOutputFile_slot_file_get", NULL, NULL, NULL, NULL); RNA_def_property_struct_type(prop, "NodeOutputFileSlotFile"); RNA_def_property_ui_text(prop, "File Slots", ""); rna_def_cmp_output_file_slots_api(brna, prop, "CompositorNodeOutputFileFileSlots"); prop = RNA_def_property(srna, "layer_slots", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_funcs(prop, "rna_NodeOutputFile_slots_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_NodeOutputFile_slot_layer_get", NULL, NULL, NULL, NULL); RNA_def_property_struct_type(prop, "NodeOutputFileSlotLayer"); RNA_def_property_ui_text(prop, "EXR Layer Slots", ""); rna_def_cmp_output_file_slots_api(brna, prop, "CompositorNodeOutputFileLayerSlots"); } static void def_cmp_dilate_erode(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem mode_items[] = { {CMP_NODE_DILATE_ERODE_STEP, "STEP", 0, "Step", ""}, {CMP_NODE_DILATE_ERODE_DISTANCE_THRESHOLD, "THRESHOLD", 0, "Threshold", ""}, {CMP_NODE_DILATE_ERODE_DISTANCE, "DISTANCE", 0, "Distance", ""}, {CMP_NODE_DILATE_ERODE_DISTANCE_FEATHER, "FEATHER", 0, "Feather", ""}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", "Growing/shrinking mode"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); RNA_def_property_range(prop, -5000, 5000); RNA_def_property_ui_range(prop, -100, 100, 1, -1); RNA_def_property_ui_text(prop, "Distance", "Distance to grow/shrink (number of iterations)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); /* CMP_NODE_DILATE_ERODE_DISTANCE_THRESH only */ prop = RNA_def_property(srna, "edge", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom3"); RNA_def_property_range(prop, -100, 100); RNA_def_property_ui_text(prop, "Edge", "Edge to inset"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeDilateErode", "storage"); /* CMP_NODE_DILATE_ERODE_DISTANCE_FEATHER only */ prop = RNA_def_property(srna, "falloff", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "falloff"); RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items); RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE_LEGACY); /* Abusing id_curve :/ */ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_inpaint(StructRNA *srna) { PropertyRNA *prop; # if 0 prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text(prop, "Type", "Type of inpaint algorithm"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); # endif prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "Distance", "Distance to inpaint (number of iterations)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_despeckle(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom3"); RNA_def_property_range(prop, 0.0, 1.0f); RNA_def_property_ui_text(prop, "Threshold", "Threshold for detecting pixels to despeckle"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "threshold_neighbor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom4"); RNA_def_property_range(prop, 0.0, 1.0f); RNA_def_property_ui_text( prop, "Neighbor", "Threshold for the number of neighbor pixels that must match"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_scale(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem space_items[] = { {CMP_NODE_SCALE_RELATIVE, "RELATIVE", 0, "Relative", ""}, {CMP_NODE_SCALE_ABSOLUTE, "ABSOLUTE", 0, "Absolute", ""}, {CMP_NODE_SCALE_RENDER_PERCENT, "SCENE_SIZE", 0, "Scene Size", ""}, {CMP_NODE_SCALE_RENDER_SIZE, "RENDER_SIZE", 0, "Render Size", ""}, {0, NULL, 0, NULL, NULL}, }; /* matching bgpic_camera_frame_items[] */ static const EnumPropertyItem space_frame_items[] = { {CMP_NODE_SCALE_RENDER_SIZE_STRETCH, "STRETCH", 0, "Stretch", ""}, {CMP_NODE_SCALE_RENDER_SIZE_FIT, "FIT", 0, "Fit", ""}, {CMP_NODE_SCALE_RENDER_SIZE_CROP, "CROP", 0, "Crop", ""}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, space_items); RNA_def_property_ui_text(prop, "Space", "Coordinate space to scale relative to"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_CompositorNodeScale_update"); /* expose 2 flags as a enum of 3 items */ prop = RNA_def_property(srna, "frame_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, space_frame_items); RNA_def_property_ui_text(prop, "Frame Method", "How the image fits in the camera frame"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "offset_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom3"); RNA_def_property_ui_text(prop, "X Offset", "Offset image horizontally (factor of image size)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "offset_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom4"); RNA_def_property_ui_text(prop, "Y Offset", "Offset image vertically (factor of image size)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_rotate(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_sampler_type_items); RNA_def_property_ui_text(prop, "Filter", "Method to use to filter rotation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_diff_matte(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeChroma", "storage"); prop = RNA_def_property(srna, "tolerance", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_float_funcs(prop, NULL, "rna_difference_matte_t1_set", NULL); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Tolerance", "Color distances below this threshold are keyed"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_float_funcs(prop, NULL, "rna_difference_matte_t2_set", NULL); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Falloff", "Color distances below this additional threshold are partially keyed"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_color_matte(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeChroma", "storage"); prop = RNA_def_property(srna, "color_hue", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "H", "Hue tolerance for colors to be considered a keying color"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "color_saturation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "S", "Saturation tolerance for the color"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "color_value", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t3"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "V", "Value tolerance for the color"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_distance_matte(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem color_space_items[] = { {1, "RGB", 0, "RGB", "RGB color space"}, {2, "YCC", 0, "YCC", "YCbCr suppression"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeChroma", "storage"); prop = RNA_def_property(srna, "channel", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "channel"); RNA_def_property_enum_items(prop, color_space_items); RNA_def_property_ui_text(prop, "Channel", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "tolerance", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_float_funcs(prop, NULL, "rna_distance_matte_t1_set", NULL); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Tolerance", "Color distances below this threshold are keyed"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_float_funcs(prop, NULL, "rna_distance_matte_t2_set", NULL); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Falloff", "Color distances below this additional threshold are partially keyed"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_convert_color_space(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeConvertColorSpace", "storage"); static const EnumPropertyItem color_space_items[] = { {0, "NONE", 0, "None", "Do not perform any color transform on load, treat colors as in scene linear space " "already"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "from_color_space", PROP_ENUM, PROP_NONE); RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); RNA_def_property_enum_items(prop, color_space_items); RNA_def_property_enum_funcs(prop, "rna_NodeConvertColorSpace_from_color_space_get", "rna_NodeConvertColorSpace_from_color_space_set", "rna_NodeConvertColorSpace_color_space_itemf"); RNA_def_property_ui_text(prop, "From", "Color space of the input image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "to_color_space", PROP_ENUM, PROP_NONE); RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); RNA_def_property_enum_items(prop, color_space_items); RNA_def_property_enum_funcs(prop, "rna_NodeConvertColorSpace_to_color_space_get", "rna_NodeConvertColorSpace_to_color_space_set", "rna_NodeConvertColorSpace_color_space_itemf"); RNA_def_property_ui_text(prop, "To", "Color space of the output image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_color_spill(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem channel_items[] = { {1, "R", 0, "R", "Red spill suppression"}, {2, "G", 0, "G", "Green spill suppression"}, {3, "B", 0, "B", "Blue spill suppression"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem limit_channel_items[] = { {0, "R", 0, "R", "Limit by red"}, {1, "G", 0, "G", "Limit by green"}, {2, "B", 0, "B", "Limit by blue"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem algorithm_items[] = { {0, "SIMPLE", 0, "Simple", "Simple limit algorithm"}, {1, "AVERAGE", 0, "Average", "Average limit algorithm"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "channel", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, channel_items); RNA_def_property_ui_text(prop, "Channel", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "limit_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, algorithm_items); RNA_def_property_ui_text(prop, "Algorithm", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeColorspill", "storage"); prop = RNA_def_property(srna, "limit_channel", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "limchan"); RNA_def_property_enum_items(prop, limit_channel_items); RNA_def_property_ui_text(prop, "Limit Channel", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "ratio", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "limscale"); RNA_def_property_range(prop, 0.5f, 1.5f); RNA_def_property_ui_text(prop, "Ratio", "Scale limit by value"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_unspill", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "unspill", 0); RNA_def_property_ui_text(prop, "Unspill", "Compensate all channels (differently) by hand"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "unspill_red", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "uspillr"); RNA_def_property_range(prop, 0.0f, 1.5f); RNA_def_property_ui_text(prop, "R", "Red spillmap scale"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "unspill_green", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "uspillg"); RNA_def_property_range(prop, 0.0f, 1.5f); RNA_def_property_ui_text(prop, "G", "Green spillmap scale"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "unspill_blue", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "uspillb"); RNA_def_property_range(prop, 0.0f, 1.5f); RNA_def_property_ui_text(prop, "B", "Blue spillmap scale"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_luma_matte(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeChroma", "storage"); prop = RNA_def_property(srna, "limit_max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t1_set", NULL); RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3); RNA_def_property_ui_text(prop, "High", "Values higher than this setting are 100% opaque"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "limit_min", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t2_set", NULL); RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3); RNA_def_property_ui_text(prop, "Low", "Values lower than this setting are 100% keyed"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_brightcontrast(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "use_premultiply", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_ui_text(prop, "Convert Premultiplied", "Keep output image premultiplied alpha"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_chroma_matte(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeChroma", "storage"); prop = RNA_def_property(srna, "tolerance", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t1_set", NULL); RNA_def_property_range(prop, DEG2RADF(1.0f), DEG2RADF(80.0f)); RNA_def_property_ui_text( prop, "Acceptance", "Tolerance for a color to be considered a keying color"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t2_set", NULL); RNA_def_property_range(prop, 0.0f, DEG2RADF(30.0f)); RNA_def_property_ui_text( prop, "Cutoff", "Tolerance below which colors will be considered as exact matches"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "lift", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fsize"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Lift", "Alpha lift"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "gain", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fstrength"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Falloff", "Alpha falloff"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "shadow_adjust", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t3"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Shadow Adjust", "Adjusts the brightness of any shadows captured"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_channel_matte(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem color_space_items[] = { {CMP_NODE_CHANNEL_MATTE_CS_RGB, "RGB", 0, "RGB", "RGB color space"}, {CMP_NODE_CHANNEL_MATTE_CS_HSV, "HSV", 0, "HSV", "HSV color space"}, {CMP_NODE_CHANNEL_MATTE_CS_YUV, "YUV", 0, "YUV", "YUV color space"}, {CMP_NODE_CHANNEL_MATTE_CS_YCC, "YCC", 0, "YCbCr", "YCbCr color space"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem algorithm_items[] = { {0, "SINGLE", 0, "Single", "Limit by single channel"}, {1, "MAX", 0, "Max", "Limit by maximum of other channels"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, color_space_items); RNA_def_property_ui_text(prop, "Color Space", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "matte_channel", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, prop_tri_channel_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_channel_itemf"); RNA_def_property_ui_text(prop, "Channel", "Channel used to determine matte"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeChroma", "storage"); prop = RNA_def_property(srna, "limit_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "algorithm"); RNA_def_property_enum_items(prop, algorithm_items); RNA_def_property_ui_text(prop, "Algorithm", "Algorithm to use to limit channel"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "limit_channel", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "channel"); RNA_def_property_enum_items(prop, prop_tri_channel_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_channel_itemf"); RNA_def_property_ui_text(prop, "Limit Channel", "Limit by this channel's value"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "limit_max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t1_set", NULL); RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3); RNA_def_property_ui_text(prop, "High", "Values higher than this setting are 100% opaque"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "limit_min", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t2_set", NULL); RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3); RNA_def_property_ui_text(prop, "Low", "Values lower than this setting are 100% keyed"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_flip(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_flip_items); RNA_def_property_ui_text(prop, "Axis", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_splitviewer(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, rna_enum_axis_xy_items); RNA_def_property_ui_text(prop, "Axis", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "factor", PROP_INT, PROP_FACTOR); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 0, 100); RNA_def_property_ui_text(prop, "Factor", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_id_mask(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 0, 32767); RNA_def_property_ui_text(prop, "Index", "Pass index number to convert to alpha"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_antialiasing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", 0); RNA_def_property_ui_text(prop, "Anti-Aliasing", "Apply an anti-aliasing filter to the mask"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_double_edge_mask(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem BufEdgeMode_items[] = { {0, "BLEED_OUT", 0, "Bleed Out", "Allow mask pixels to bleed along edges"}, {1, "KEEP_IN", 0, "Keep In", "Restrict mask pixels from touching edges"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem InnerEdgeMode_items[] = { {0, "ALL", 0, "All", "All pixels on inner mask edge are considered during mask calculation"}, {1, "ADJACENT_ONLY", 0, "Adjacent Only", "Only inner mask pixels adjacent to outer mask pixels are considered during mask " "calculation"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "inner_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, InnerEdgeMode_items); RNA_def_property_ui_text(prop, "Inner Edge Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "edge_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, BufEdgeMode_items); RNA_def_property_ui_text(prop, "Buffer Edge Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_map_uv(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "alpha", PROP_INT, PROP_FACTOR); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 0, 100); RNA_def_property_ui_text(prop, "Alpha", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_defocus(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem bokeh_items[] = { {8, "OCTAGON", 0, "Octagonal", "8 sides"}, {7, "HEPTAGON", 0, "Heptagonal", "7 sides"}, {6, "HEXAGON", 0, "Hexagonal", "6 sides"}, {5, "PENTAGON", 0, "Pentagonal", "5 sides"}, {4, "SQUARE", 0, "Square", "4 sides"}, {3, "TRIANGLE", 0, "Triangular", "3 sides"}, {0, "CIRCLE", 0, "Circular", ""}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Node_scene_set", NULL, NULL); RNA_def_property_struct_type(prop, "Scene"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Scene", "Scene from which to select the active camera (render scene if undefined)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeDefocus", "storage"); prop = RNA_def_property(srna, "bokeh", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "bktype"); RNA_def_property_enum_items(prop, bokeh_items); RNA_def_property_ui_text(prop, "Bokeh Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "rotation"); RNA_def_property_range(prop, 0.0f, DEG2RADF(90.0f)); RNA_def_property_ui_text(prop, "Angle", "Bokeh shape rotation offset"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_gamma_correction", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gamco", 1); RNA_def_property_ui_text( prop, "Gamma Correction", "Enable gamma correction before and after main process"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); /* TODO */ prop = RNA_def_property(srna, "f_stop", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fstop"); RNA_def_property_range(prop, 0.0f, 128.0f); RNA_def_property_ui_text( prop, "F-Stop", "Amount of focal blur, 128 (infinity) is perfect focus, half the value doubles " "the blur radius"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "blur_max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "maxblur"); RNA_def_property_range(prop, 0.0f, 10000.0f); RNA_def_property_ui_text(prop, "Max Blur", "Blur limit, maximum CoC radius"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "bthresh"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_text( prop, "Threshold", "CoC radius threshold, prevents background bleed on in-focus midground, 0 is disabled"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_preview", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "preview", 1); RNA_def_property_ui_text(prop, "Preview", "Enable low quality mode, useful for preview"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_zbuffer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "no_zbuf", 1); RNA_def_property_ui_text(prop, "Use Z-Buffer", "Disable when using an image as input instead of actual z-buffer " "(auto enabled if node not image based, eg. time node)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "z_scale", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "scale"); RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_ui_text( prop, "Z-Scale", "Scale the Z input when not using a z-buffer, controls maximum blur designated " "by the color white or input value 1"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_invert(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "invert_rgb", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_CHAN_RGB); RNA_def_property_ui_text(prop, "RGB", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "invert_alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_CHAN_A); RNA_def_property_ui_text(prop, "Alpha", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_crop(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "use_crop_size", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_ui_text(prop, "Crop Image Size", "Whether to crop the size of the input image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "relative", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", 1); RNA_def_property_ui_text(prop, "Relative", "Use relative values to crop image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeTwoXYs", "storage"); prop = RNA_def_property(srna, "min_x", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "x1"); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "X1", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "max_x", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "x2"); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "X2", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "min_y", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "y1"); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "Y1", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "max_y", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "y2"); RNA_def_property_range(prop, 0, 10000); RNA_def_property_ui_text(prop, "Y2", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "rel_min_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fac_x1"); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_ui_text(prop, "X1", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "rel_max_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fac_x2"); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_ui_text(prop, "X2", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "rel_min_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fac_y1"); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_ui_text(prop, "Y1", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "rel_max_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fac_y2"); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_ui_text(prop, "Y2", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_dblur(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeDBlurData", "storage"); prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "iter"); RNA_def_property_range(prop, 1, 32); RNA_def_property_ui_text(prop, "Iterations", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_wrap", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "wrap", 1); RNA_def_property_ui_text(prop, "Wrap", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "center_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "center_x"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Center X", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "center_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "center_y"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Center Y", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "distance"); RNA_def_property_range(prop, -1.0f, 1.0f); RNA_def_property_ui_text(prop, "Distance", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "angle"); RNA_def_property_range(prop, 0.0f, DEG2RADF(360.0f)); RNA_def_property_ui_text(prop, "Angle", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "spin", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "spin"); RNA_def_property_range(prop, DEG2RADF(-360.0f), DEG2RADF(360.0f)); RNA_def_property_ui_text(prop, "Spin", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "zoom", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "zoom"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_text(prop, "Zoom", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_bilateral_blur(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeBilateralBlurData", "storage"); prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "iter"); RNA_def_property_range(prop, 1, 128); RNA_def_property_ui_text(prop, "Iterations", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "sigma_color", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "sigma_color"); RNA_def_property_range(prop, 0.01f, 3.0f); RNA_def_property_ui_text(prop, "Color Sigma", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "sigma_space", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "sigma_space"); RNA_def_property_range(prop, 0.01f, 30.0f); RNA_def_property_ui_text(prop, "Space Sigma", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_premul_key(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem type_items[] = { {0, "STRAIGHT_TO_PREMUL", 0, "To Premultiplied", "Convert straight to premultiplied"}, {1, "PREMUL_TO_STRAIGHT", 0, "To Straight", "Convert premultiplied to straight"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text( prop, "Mapping", "Conversion between premultiplied alpha and key alpha"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_glare(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem type_items[] = { {3, "GHOSTS", 0, "Ghosts", ""}, {2, "STREAKS", 0, "Streaks", ""}, {1, "FOG_GLOW", 0, "Fog Glow", ""}, {0, "SIMPLE_STAR", 0, "Simple Star", ""}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem quality_items[] = { {0, "HIGH", 0, "High", ""}, {1, "MEDIUM", 0, "Medium", ""}, {2, "LOW", 0, "Low", ""}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGlare", "storage"); prop = RNA_def_property(srna, "glare_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text(prop, "Glare Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "quality", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "quality"); RNA_def_property_enum_items(prop, quality_items); RNA_def_property_ui_text( prop, "Quality", "If not set to high quality, the effect will be applied to a low-res copy " "of the source image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "iter"); RNA_def_property_range(prop, 2, 5); RNA_def_property_ui_text(prop, "Iterations", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "color_modulation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "colmod"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Color Modulation", "Amount of Color Modulation, modulates colors of streaks and ghosts for " "a spectral dispersion effect"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "mix", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "mix"); RNA_def_property_range(prop, -1.0f, 1.0f); RNA_def_property_ui_text( prop, "Mix", "-1 is original image only, 0 is exact 50/50 mix, 1 is processed image only"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "threshold"); RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_ui_text( prop, "Threshold", "The glare filter will only be applied to pixels brighter than this value"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "streaks", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "streaks"); RNA_def_property_range(prop, 1, 16); RNA_def_property_ui_text(prop, "Streaks", "Total number of streaks"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "angle_offset", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "angle_ofs"); RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f)); RNA_def_property_ui_text(prop, "Angle Offset", "Streak angle offset"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "fade", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fade"); RNA_def_property_range(prop, 0.75f, 1.0f); RNA_def_property_ui_text(prop, "Fade", "Streak fade-out factor"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_rotate_45", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "star_45", 0); RNA_def_property_ui_text(prop, "Rotate 45", "Simple star filter: add 45 degree rotation offset"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "size", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "size"); RNA_def_property_range(prop, 6, 9); RNA_def_property_ui_text( prop, "Size", "Glow/glare size (not actual size; relative to initial size of bright area of pixels)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); /* TODO */ } static void def_cmp_tonemap(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem type_items[] = { {1, "RD_PHOTORECEPTOR", 0, "R/D Photoreceptor", ""}, {0, "RH_SIMPLE", 0, "Rh Simple", ""}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeTonemap", "storage"); prop = RNA_def_property(srna, "tonemap_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text(prop, "Tonemap Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "key", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "key"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Key", "The value the average luminance is mapped to"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "offset"); RNA_def_property_range(prop, 0.001f, 10.0f); RNA_def_property_ui_text( prop, "Offset", "Normally always 1, but can be used as an extra control to alter the brightness curve"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "gamma", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "gamma"); RNA_def_property_range(prop, 0.001f, 3.0f); RNA_def_property_ui_text(prop, "Gamma", "If not used, set to 1"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f"); RNA_def_property_range(prop, -8.0f, 8.0f); RNA_def_property_ui_text( prop, "Intensity", "If less than zero, darkens image; otherwise, makes it brighter"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "contrast", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "m"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Contrast", "Set to 0 to use estimate from input image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "adaptation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "a"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Adaptation", "If 0, global; if 1, based on pixel intensity"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "correction", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "c"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Color Correction", "If 0, same for all channels; if 1, each independent"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_lensdist(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeLensDist", "storage"); prop = RNA_def_property(srna, "use_projector", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "proj", 1); RNA_def_property_ui_text( prop, "Projector", "Enable/disable projector mode (the effect is applied in horizontal direction only)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_jitter", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "jit", 1); RNA_def_property_ui_text(prop, "Jitter", "Enable/disable jittering (faster, but also noisier)"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_NODETREE); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_fit", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "fit", 1); RNA_def_property_ui_text( prop, "Fit", "For positive distortion factor only: scale image such that black areas are not visible"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_colorbalance(StructRNA *srna) { PropertyRNA *prop; static float default_1[3] = {1.0f, 1.0f, 1.0f}; static const EnumPropertyItem type_items[] = { {0, "LIFT_GAMMA_GAIN", 0, "Lift/Gamma/Gain", ""}, {1, "OFFSET_POWER_SLOPE", 0, "Offset/Power/Slope (ASC-CDL)", "ASC-CDL standard color correction"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "correction_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text(prop, "Correction Formula", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeColorBalance", "storage"); prop = RNA_def_property(srna, "lift", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "lift"); RNA_def_property_array(prop, 3); RNA_def_property_float_array_default(prop, default_1); RNA_def_property_ui_range(prop, 0, 2, 0.1, 3); RNA_def_property_ui_text(prop, "Lift", "Correction for shadows"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeColorBalance_update_lgg"); prop = RNA_def_property(srna, "gamma", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "gamma"); RNA_def_property_array(prop, 3); RNA_def_property_float_array_default(prop, default_1); RNA_def_property_ui_range(prop, 0, 2, 0.1, 3); RNA_def_property_ui_text(prop, "Gamma", "Correction for midtones"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeColorBalance_update_lgg"); prop = RNA_def_property(srna, "gain", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "gain"); RNA_def_property_array(prop, 3); RNA_def_property_float_array_default(prop, default_1); RNA_def_property_ui_range(prop, 0, 2, 0.1, 3); RNA_def_property_ui_text(prop, "Gain", "Correction for highlights"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeColorBalance_update_lgg"); prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "offset"); RNA_def_property_array(prop, 3); RNA_def_property_ui_range(prop, 0, 1, 0.1, 3); RNA_def_property_ui_text(prop, "Offset", "Correction for entire tonal range"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeColorBalance_update_cdl"); prop = RNA_def_property(srna, "power", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "power"); RNA_def_property_array(prop, 3); RNA_def_property_float_array_default(prop, default_1); RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_range(prop, 0, 2, 0.1, 3); RNA_def_property_ui_text(prop, "Power", "Correction for midtones"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeColorBalance_update_cdl"); prop = RNA_def_property(srna, "slope", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "slope"); RNA_def_property_array(prop, 3); RNA_def_property_float_array_default(prop, default_1); RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_range(prop, 0, 2, 0.1, 3); RNA_def_property_ui_text(prop, "Slope", "Correction for highlights"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeColorBalance_update_cdl"); prop = RNA_def_property(srna, "offset_basis", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_ui_range(prop, -1.0, 1.0, 1.0, 2); RNA_def_property_ui_text(prop, "Basis", "Support negative color by using this as the RGB basis"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeColorBalance_update_cdl"); } static void def_cmp_huecorrect(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "mapping", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "CurveMapping"); RNA_def_property_ui_text(prop, "Mapping", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_zcombine(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 0); RNA_def_property_ui_text( prop, "Use Alpha", "Take alpha channel into account when doing the Z operation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_antialias_z", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "custom2", 0); RNA_def_property_ui_text( prop, "Anti-Alias Z", "Anti-alias the z-buffer to try to avoid artifacts, mostly useful for Blender renders"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_ycc(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_ycc_items); RNA_def_property_ui_text(prop, "Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_combsep_color(StructRNA *srna) { static const EnumPropertyItem mode_items[] = { {CMP_NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"}, {CMP_NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"}, {CMP_NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"}, {CMP_NODE_COMBSEP_COLOR_YCC, "YCC", ICON_NONE, "YCbCr", "Use YCbCr color processing"}, {CMP_NODE_COMBSEP_COLOR_YUV, "YUV", ICON_NONE, "YUV", "Use YUV color processing"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeCMPCombSepColor", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", "Mode of color processing"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "ycc_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, node_ycc_items); RNA_def_property_ui_text(prop, "Color Space", "Color space used for YCbCrA processing"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_movieclip(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "MovieClipUser", "storage"); } static void def_cmp_stabilize2d(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_sampler_type_items); RNA_def_property_ui_text(prop, "Filter", "Method to use to filter stabilization"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", CMP_NODEFLAG_STABILIZE_INVERSE); RNA_def_property_ui_text( prop, "Invert", "Invert stabilization to re-introduce motion to the frame"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_moviedistortion(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem distortion_type_items[] = { {0, "UNDISTORT", 0, "Undistort", ""}, {1, "DISTORT", 0, "Distort", ""}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "distortion_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, distortion_type_items); RNA_def_property_ui_text(prop, "Distortion", "Distortion to use to filter image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_mask(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem aspect_type_items[] = { {0, "SCENE", 0, "Scene Size", ""}, {CMP_NODEFLAG_MASK_FIXED, "FIXED", 0, "Fixed", "Use pixel size for the buffer"}, {CMP_NODEFLAG_MASK_FIXED_SCENE, "FIXED_SCENE", 0, "Fixed/Scene", "Pixel size scaled by scene percentage"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "mask", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Mask"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Mask", ""); prop = RNA_def_property(srna, "use_feather", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "custom1", CMP_NODEFLAG_MASK_NO_FEATHER); RNA_def_property_ui_text(prop, "Feather", "Use feather information from the mask"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_motion_blur", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_NODEFLAG_MASK_MOTION_BLUR); RNA_def_property_ui_text(prop, "Motion Blur", "Use multi-sampled motion blur of the mask"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); RNA_def_property_range(prop, 1, CMP_NODE_MASK_MBLUR_SAMPLES_MAX); RNA_def_property_ui_text(prop, "Samples", "Number of motion blur samples"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom3"); RNA_def_property_range(prop, 0.0, 1.0f); RNA_def_property_ui_text(prop, "Shutter", "Exposure for motion blur as a factor of FPS"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "size_source", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, aspect_type_items); RNA_def_property_ui_text( prop, "Size Source", "Where to get the mask size from for aspect/size information"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeMask", "storage"); prop = RNA_def_property(srna, "size_x", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 1.0f, 10000.0f); RNA_def_property_ui_text(prop, "X", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "size_y", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 1.0f, 10000.0f); RNA_def_property_ui_text(prop, "Y", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void dev_cmd_transform(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_sampler_type_items); RNA_def_property_ui_text(prop, "Filter", "Method to use to filter transform"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } /* -- Compositor Nodes ------------------------------------------------------ */ static const EnumPropertyItem node_masktype_items[] = { {0, "ADD", 0, "Add", ""}, {1, "SUBTRACT", 0, "Subtract", ""}, {2, "MULTIPLY", 0, "Multiply", ""}, {3, "NOT", 0, "Not", ""}, {0, NULL, 0, NULL, NULL}, }; static void def_cmp_boxmask(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "mask_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_masktype_items); RNA_def_property_ui_text(prop, "Mask Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeBoxMask", "storage"); prop = RNA_def_property(srna, "x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "x"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, -1.0f, 2.0f); RNA_def_property_ui_text(prop, "X", "X position of the middle of the box"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "y"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, -1.0f, 2.0f); RNA_def_property_ui_text(prop, "Y", "Y position of the middle of the box"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "width", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "width"); RNA_def_property_float_default(prop, 0.3f); RNA_def_property_range(prop, 0.0f, 2.0f); RNA_def_property_ui_text(prop, "Width", "Width of the box"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "height"); RNA_def_property_float_default(prop, 0.2f); RNA_def_property_range(prop, 0.0f, 2.0f); RNA_def_property_ui_text(prop, "Height", "Height of the box"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "rotation"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, DEG2RADF(-1800.0f), DEG2RADF(1800.0f)); RNA_def_property_ui_text(prop, "Rotation", "Rotation angle of the box"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_ellipsemask(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "mask_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_masktype_items); RNA_def_property_ui_text(prop, "Mask Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeEllipseMask", "storage"); prop = RNA_def_property(srna, "x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "x"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, -1.0f, 2.0f); RNA_def_property_ui_text(prop, "X", "X position of the middle of the ellipse"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "y"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, -1.0f, 2.0f); RNA_def_property_ui_text(prop, "Y", "Y position of the middle of the ellipse"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "width", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "width"); RNA_def_property_float_default(prop, 0.3f); RNA_def_property_range(prop, 0.0f, 2.0f); RNA_def_property_ui_text(prop, "Width", "Width of the ellipse"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "height"); RNA_def_property_float_default(prop, 0.2f); RNA_def_property_range(prop, 0.0f, 2.0f); RNA_def_property_ui_text(prop, "Height", "Height of the ellipse"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "rotation"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, DEG2RADF(-1800.0f), DEG2RADF(1800.0f)); RNA_def_property_ui_text(prop, "Rotation", "Rotation angle of the ellipse"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_bokehblur(StructRNA *srna) { PropertyRNA *prop; /* duplicated in def_cmp_blur */ prop = RNA_def_property(srna, "use_variable_size", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_NODEFLAG_BLUR_VARIABLE_SIZE); RNA_def_property_ui_text( prop, "Variable Size", "Support variable blur per pixel when using an image for size input"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_extended_bounds", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_NODEFLAG_BLUR_EXTEND_BOUNDS); RNA_def_property_ui_text( prop, "Extend Bounds", "Extend bounds of the input image to fully fit blurred image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); # if 0 prop = RNA_def_property(srna, "f_stop", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom3"); RNA_def_property_range(prop, 0.0f, 128.0f); RNA_def_property_ui_text( prop, "F-Stop", "Amount of focal blur, 128 (infinity) is perfect focus, half the value doubles " "the blur radius"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); # endif prop = RNA_def_property(srna, "blur_max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom4"); RNA_def_property_range(prop, 0.0f, 10000.0f); RNA_def_property_ui_text(prop, "Max Blur", "Blur limit, maximum CoC radius"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_bokehimage(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeBokehImage", "storage"); prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "angle"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, DEG2RADF(-720.0f), DEG2RADF(720.0f)); RNA_def_property_ui_text(prop, "Angle", "Angle of the bokeh"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "flaps", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "flaps"); RNA_def_property_int_default(prop, 5); RNA_def_property_range(prop, 3, 24); RNA_def_property_ui_text(prop, "Flaps", "Number of flaps"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "rounding", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "rounding"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, -0.0f, 1.0f); RNA_def_property_ui_text(prop, "Rounding", "Level of rounding of the bokeh"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "catadioptric", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "catadioptric"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, -0.0f, 1.0f); RNA_def_property_ui_text(prop, "Catadioptric", "Level of catadioptric of the bokeh"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "shift", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "lensshift"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, -1.0f, 1.0f); RNA_def_property_ui_text(prop, "Lens Shift", "Shift of the lens components"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_switch(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "check", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 0); RNA_def_property_ui_text(prop, "Switch", "Off: first socket, On: second socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_switch_view(StructRNA *UNUSED(srna)) { } static void def_cmp_colorcorrection(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "red", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); RNA_def_property_boolean_default(prop, true); RNA_def_property_ui_text(prop, "Red", "Red channel active"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "green", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 2); RNA_def_property_boolean_default(prop, true); RNA_def_property_ui_text(prop, "Green", "Green channel active"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "blue", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 4); RNA_def_property_boolean_default(prop, true); RNA_def_property_ui_text(prop, "Blue", "Blue channel active"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeColorCorrection", "storage"); prop = RNA_def_property(srna, "midtones_start", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "startmidtones"); RNA_def_property_float_default(prop, 0.2f); RNA_def_property_range(prop, 0, 1); RNA_def_property_ui_text(prop, "Midtones Start", "Start of midtones"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "midtones_end", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "endmidtones"); RNA_def_property_float_default(prop, 0.7f); RNA_def_property_range(prop, 0, 1); RNA_def_property_ui_text(prop, "Midtones End", "End of midtones"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "master_saturation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "master.saturation"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Master Saturation", "Master saturation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "master_contrast", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "master.contrast"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Master Contrast", "Master contrast"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "master_gamma", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "master.gamma"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Master Gamma", "Master gamma"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "master_gain", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "master.gain"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Master Gain", "Master gain"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "master_lift", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "master.lift"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, -1, 1); RNA_def_property_ui_text(prop, "Master Lift", "Master lift"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); // prop = RNA_def_property(srna, "shadows_saturation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "shadows.saturation"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Shadows Saturation", "Shadows saturation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "shadows_contrast", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "shadows.contrast"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Shadows Contrast", "Shadows contrast"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "shadows_gamma", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "shadows.gamma"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Shadows Gamma", "Shadows gamma"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "shadows_gain", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "shadows.gain"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Shadows Gain", "Shadows gain"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "shadows_lift", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "shadows.lift"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, -1, 1); RNA_def_property_ui_text(prop, "Shadows Lift", "Shadows lift"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); // prop = RNA_def_property(srna, "midtones_saturation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "midtones.saturation"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Midtones Saturation", "Midtones saturation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "midtones_contrast", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "midtones.contrast"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Midtones Contrast", "Midtones contrast"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "midtones_gamma", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "midtones.gamma"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Midtones Gamma", "Midtones gamma"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "midtones_gain", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "midtones.gain"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Midtones Gain", "Midtones gain"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "midtones_lift", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "midtones.lift"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, -1, 1); RNA_def_property_ui_text(prop, "Midtones Lift", "Midtones lift"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); // prop = RNA_def_property(srna, "highlights_saturation", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "highlights.saturation"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Highlights Saturation", "Highlights saturation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "highlights_contrast", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "highlights.contrast"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Highlights Contrast", "Highlights contrast"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "highlights_gamma", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "highlights.gamma"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Highlights Gamma", "Highlights gamma"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "highlights_gain", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "highlights.gain"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0, 4); RNA_def_property_ui_text(prop, "Highlights Gain", "Highlights gain"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "highlights_lift", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "highlights.lift"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, -1, 1); RNA_def_property_ui_text(prop, "Highlights Lift", "Highlights lift"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_viewer(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem tileorder_items[] = { {0, "CENTEROUT", 0, "Center", "Expand from center"}, {1, "RANDOM", 0, "Random", "Random tiles"}, {2, "BOTTOMUP", 0, "Bottom Up", "Expand from bottom"}, {3, "RULE_OF_THIRDS", 0, "Rule of Thirds", "Expand from 9 places"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "tile_order", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, tileorder_items); RNA_def_property_ui_text(prop, "Tile Order", "Tile order"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "center_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom3"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "X", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "center_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom4"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Y", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "custom2", CMP_NODE_OUTPUT_IGNORE_ALPHA); RNA_def_property_ui_text( prop, "Use Alpha", "Colors are treated alpha premultiplied, or colors output straight (alpha gets set to 1)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_composite(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "custom2", CMP_NODE_OUTPUT_IGNORE_ALPHA); RNA_def_property_ui_text( prop, "Use Alpha", "Colors are treated alpha premultiplied, or colors output straight (alpha gets set to 1)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_keyingscreen(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeKeyingScreenData", "storage"); prop = RNA_def_property(srna, "tracking_object", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "tracking_object"); RNA_def_property_ui_text(prop, "Tracking Object", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_keying(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeKeyingData", "storage"); prop = RNA_def_property(srna, "screen_balance", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "screen_balance"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Screen Balance", "Balance between two non-primary channels primary channel is comparing against"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "despill_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "despill_factor"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Despill Factor", "Factor of despilling screen color from image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "despill_balance", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "despill_balance"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Despill Balance", "Balance between non-key colors used to detect amount of key color to be removed"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "clip_black", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "clip_black"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Clip Black", "Value of non-scaled matte pixel which considers as fully background pixel"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "clip_white", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "clip_white"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Clip White", "Value of non-scaled matte pixel which considers as fully foreground pixel"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "blur_pre", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "blur_pre"); RNA_def_property_range(prop, 0, 2048); RNA_def_property_ui_text( prop, "Pre Blur", "Chroma pre-blur size which applies before running keyer"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "blur_post", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "blur_post"); RNA_def_property_range(prop, 0, 2048); RNA_def_property_ui_text( prop, "Post Blur", "Matte blur size which applies after clipping and dilate/eroding"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "dilate_distance", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "dilate_distance"); RNA_def_property_range(prop, -100, 100); RNA_def_property_ui_text(prop, "Dilate/Erode", "Matte dilate/erode side"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "edge_kernel_radius", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "edge_kernel_radius"); RNA_def_property_range(prop, 0, 100); RNA_def_property_ui_text( prop, "Edge Kernel Radius", "Radius of kernel used to detect whether pixel belongs to edge"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "edge_kernel_tolerance", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "edge_kernel_tolerance"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( prop, "Edge Kernel Tolerance", "Tolerance to pixels inside kernel which are treating as belonging to the same plane"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "feather_falloff", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "feather_falloff"); RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items); RNA_def_property_ui_text(prop, "Feather Falloff", "Falloff type the feather"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE_LEGACY); /* Abusing id_curve :/ */ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "feather_distance", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "feather_distance"); RNA_def_property_range(prop, -100, 100); RNA_def_property_ui_text(prop, "Feather Distance", "Distance to grow/shrink the feather"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_trackpos(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem position_items[] = { {CMP_TRACKPOS_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Output absolute position of a marker"}, {CMP_TRACKPOS_RELATIVE_START, "RELATIVE_START", 0, "Relative Start", "Output position of a marker relative to first marker of a track"}, {CMP_TRACKPOS_RELATIVE_FRAME, "RELATIVE_FRAME", 0, "Relative Frame", "Output position of a marker relative to marker at given frame number"}, {CMP_TRACKPOS_ABSOLUTE_FRAME, "ABSOLUTE_FRAME", 0, "Absolute Frame", "Output absolute position of a marker at given frame number"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "position", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, position_items); RNA_def_property_ui_text(prop, "Position", "Which marker position to use for output"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "frame_relative", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); RNA_def_property_ui_text(prop, "Frame", "Frame to be used for relative position"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeTrackPosData", "storage"); prop = RNA_def_property(srna, "tracking_object", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "tracking_object"); RNA_def_property_ui_text(prop, "Tracking Object", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "track_name", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "track_name"); RNA_def_property_ui_text(prop, "Track", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_translate(StructRNA *srna) { static const EnumPropertyItem translate_items[] = { {CMP_NODE_WRAP_NONE, "NONE", 0, "None", "No wrapping on X and Y"}, {CMP_NODE_WRAP_X, "XAXIS", 0, "X Axis", "Wrap all pixels on the X axis"}, {CMP_NODE_WRAP_Y, "YAXIS", 0, "Y Axis", "Wrap all pixels on the Y axis"}, {CMP_NODE_WRAP_XY, "BOTH", 0, "Both Axes", "Wrap all pixels on both axes"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeTranslateData", "storage"); prop = RNA_def_property(srna, "use_relative", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "relative", 1); RNA_def_property_ui_text( prop, "Relative", "Use relative (fraction of input image size) values to define translation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "wrap_axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "wrap_axis"); RNA_def_property_enum_items(prop, translate_items); RNA_def_property_ui_text(prop, "Wrapping", "Wrap image on a specific axis"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_planetrackdeform(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "MovieClip"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Movie Clip", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodePlaneTrackDeformData", "storage"); prop = RNA_def_property(srna, "tracking_object", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "tracking_object"); RNA_def_property_ui_text(prop, "Tracking Object", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "plane_track_name", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "plane_track_name"); RNA_def_property_ui_text(prop, "Plane Track", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_motion_blur", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR); RNA_def_property_ui_text(prop, "Motion Blur", "Use multi-sampled motion blur of the mask"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 1, CMP_NODE_PLANETRACKDEFORM_MBLUR_SAMPLES_MAX); RNA_def_property_ui_text(prop, "Samples", "Number of motion blur samples"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.0, 1.0f); RNA_def_property_ui_text(prop, "Shutter", "Exposure for motion blur as a factor of FPS"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_sunbeams(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeSunBeams", "storage"); prop = RNA_def_property(srna, "source", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "source"); RNA_def_property_range(prop, -100.0f, 100.0f); RNA_def_property_ui_range(prop, -10.0f, 10.0f, 10, 3); RNA_def_property_ui_text( prop, "Source", "Source point of rays as a factor of the image width and height"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "ray_length", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "ray_length"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_range(prop, 0.0f, 1.0f, 10, 3); RNA_def_property_ui_text(prop, "Ray Length", "Length of rays as a factor of the image size"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_cryptomatte_entry(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, "CryptomatteEntry", NULL); RNA_def_struct_sdna(srna, "CryptomatteEntry"); prop = RNA_def_property(srna, "encoded_hash", PROP_FLOAT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_float_sdna(prop, NULL, "encoded_hash"); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Name", ""); RNA_def_struct_name_property(srna, prop); } static void def_cmp_cryptomatte_common(StructRNA *srna) { PropertyRNA *prop; static float default_1[3] = {1.0f, 1.0f, 1.0f}; prop = RNA_def_property(srna, "matte_id", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs(prop, "rna_NodeCryptomatte_matte_get", "rna_NodeCryptomatte_matte_length", "rna_NodeCryptomatte_matte_set"); RNA_def_property_ui_text( prop, "Matte Objects", "List of object and material crypto IDs to include in matte"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "add", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "runtime.add"); RNA_def_property_float_array_default(prop, default_1); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_ui_text( prop, "Add", "Add object or material to matte, by picking a color from the Pick output"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_add"); prop = RNA_def_property(srna, "remove", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "runtime.remove"); RNA_def_property_float_array_default(prop, default_1); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_ui_text( prop, "Remove", "Remove object or material from matte, by picking a color from the Pick output"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_remove"); } static void def_cmp_cryptomatte_legacy(StructRNA *srna) { RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage"); def_cmp_cryptomatte_common(srna); } static void def_cmp_cryptomatte(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem cryptomatte_source_items[] = { {CMP_CRYPTOMATTE_SRC_RENDER, "RENDER", 0, "Render", "Use Cryptomatte passes from a render"}, {CMP_CRYPTOMATTE_SRC_IMAGE, "IMAGE", 0, "Image", "Use Cryptomatte passes from an image"}, {0, NULL, 0, NULL, NULL}}; prop = RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, cryptomatte_source_items); RNA_def_property_enum_funcs(prop, NULL, "rna_NodeCryptomatte_source_set", NULL); RNA_def_property_ui_text(prop, "Source", "Where the Cryptomatte passes are loaded from"); prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_funcs( prop, "rna_NodeCryptomatte_scene_get", "rna_NodeCryptomatte_scene_set", NULL, NULL); RNA_def_property_struct_type(prop, "Scene"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Scene", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_funcs(prop, "rna_NodeCryptomatte_image_get", "rna_NodeCryptomatte_image_set", NULL, "rna_NodeCryptomatte_image_poll"); RNA_def_property_struct_type(prop, "Image"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Image", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage"); def_cmp_cryptomatte_common(srna); prop = RNA_def_property(srna, "layer_name", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, node_cryptomatte_layer_name_items); RNA_def_property_enum_funcs(prop, "rna_NodeCryptomatte_layer_name_get", "rna_NodeCryptomatte_layer_name_set", "rna_NodeCryptomatte_layer_name_itemf"); RNA_def_property_ui_text(prop, "Cryptomatte Layer", "What Cryptomatte layer is used"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "entries", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "entries", NULL); RNA_def_property_struct_type(prop, "CryptomatteEntry"); RNA_def_property_ui_text(prop, "Mattes", ""); RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* Included here instead of defining image_user as a property of the node, * see def_cmp_image for details. * As mentioned in DNA_node_types.h, iuser is the first member of the Cryptomatte * storage type, so we can cast node->storage to ImageUser. * That is required since we can't define the properties from storage->iuser directly... */ RNA_def_struct_sdna_from(srna, "ImageUser", "storage"); def_node_image_user(srna); } static void def_cmp_denoise(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem prefilter_items[] = { {CMP_NODE_DENOISE_PREFILTER_NONE, "NONE", 0, "None", "No prefiltering, use when guiding passes are noise-free"}, {CMP_NODE_DENOISE_PREFILTER_FAST, "FAST", 0, "Fast", "Denoise image and guiding passes together. Improves quality when guiding passes are noisy " "using least amount of extra processing time"}, {CMP_NODE_DENOISE_PREFILTER_ACCURATE, "ACCURATE", 0, "Accurate", "Prefilter noisy guiding passes before denoising image. Improves quality when guiding " "passes are noisy using extra processing time"}, {0, NULL, 0, NULL, NULL}}; RNA_def_struct_sdna_from(srna, "NodeDenoise", "storage"); prop = RNA_def_property(srna, "use_hdr", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "hdr", 0); RNA_def_property_ui_text(prop, "HDR", "Process HDR images"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "prefilter", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prefilter_items); RNA_def_property_ui_text(prop, "", "Denoising prefilter"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_cmp_antialiasing(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeAntiAliasingData", "storage"); prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "threshold"); RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); RNA_def_property_ui_text( prop, "Threshold", "Threshold to detect edges (smaller threshold makes more sensitive detection)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "contrast_limit", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "contrast_limit"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); RNA_def_property_ui_text( prop, "Contrast Limit", "How much to eliminate spurious edges to avoid artifacts (the larger value makes less " "active; the value 2.0, for example, means discard a detected edge if there is a " "neighboring edge that has 2.0 times bigger contrast than the current one)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "corner_rounding", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "corner_rounding"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); RNA_def_property_ui_text(prop, "Corner Rounding", "How much sharp corners will be rounded"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } /* -- Texture Nodes --------------------------------------------------------- */ static void def_tex_output(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "TexNodeOutput", "storage"); prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "name"); RNA_def_property_ui_text(prop, "Output Name", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_tex_image(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Image"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Image", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "storage"); RNA_def_property_struct_type(prop, "ImageUser"); RNA_def_property_ui_text( prop, "Image User", "Parameters defining the image duration, offset and related settings"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_tex_bricks(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom3"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Offset Amount", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "offset_frequency", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom1"); RNA_def_property_range(prop, 2, 99); RNA_def_property_ui_text(prop, "Offset Frequency", "Offset every N rows"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "squash", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom4"); RNA_def_property_range(prop, 0.0f, 99.0f); RNA_def_property_ui_text(prop, "Squash Amount", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "squash_frequency", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); RNA_def_property_range(prop, 2, 99); RNA_def_property_ui_text(prop, "Squash Frequency", "Squash every N rows"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } /* -- Geometry Nodes --------------------------------------------------------- */ static void def_geo_boolean(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem rna_node_geometry_boolean_method_items[] = { {GEO_NODE_BOOLEAN_INTERSECT, "INTERSECT", 0, "Intersect", "Keep the part of the mesh that is common between all operands"}, {GEO_NODE_BOOLEAN_UNION, "UNION", 0, "Union", "Combine meshes in an additive way"}, {GEO_NODE_BOOLEAN_DIFFERENCE, "DIFFERENCE", 0, "Difference", "Combine meshes in a subtractive way"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_node_geometry_boolean_method_items); RNA_def_property_enum_default(prop, GEO_NODE_BOOLEAN_INTERSECT); RNA_def_property_ui_text(prop, "Operation", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_attribute_domain_size(StructRNA *srna) { PropertyRNA *prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_geometry_component_type_items); RNA_def_property_enum_default(prop, GEO_COMPONENT_TYPE_MESH); RNA_def_property_ui_text(prop, "Component", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_primitive_bezier_segment(StructRNA *srna) { static const EnumPropertyItem mode_items[] = { {GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION, "POSITION", ICON_NONE, "Position", "The start and end handles are fixed positions"}, {GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_OFFSET, "OFFSET", ICON_NONE, "Offset", "The start and end handles are offsets from the spline's control points"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryCurvePrimitiveBezierSegment", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", "Method used to determine control handles"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_sample(StructRNA *srna) { static EnumPropertyItem mode_items[] = { {GEO_NODE_CURVE_SAMPLE_FACTOR, "FACTOR", 0, "Factor", "Find sample positions on the curve using a factor of its total length"}, {GEO_NODE_CURVE_SAMPLE_LENGTH, "LENGTH", 0, "Length", "Find sample positions on the curve using a distance from its beginning"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSample", "storage"); PropertyRNA *prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", "Method for sampling input"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_triangulate(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem rna_node_geometry_triangulate_quad_method_items[] = { {GEO_NODE_TRIANGULATE_QUAD_BEAUTY, "BEAUTY", 0, "Beauty", "Split the quads in nice triangles, slower method"}, {GEO_NODE_TRIANGULATE_QUAD_FIXED, "FIXED", 0, "Fixed", "Split the quads on the first and third vertices"}, {GEO_NODE_TRIANGULATE_QUAD_ALTERNATE, "FIXED_ALTERNATE", 0, "Fixed Alternate", "Split the quads on the 2nd and 4th vertices"}, {GEO_NODE_TRIANGULATE_QUAD_SHORTEDGE, "SHORTEST_DIAGONAL", 0, "Shortest Diagonal", "Split the quads along their shortest diagonal"}, {GEO_NODE_TRIANGULATE_QUAD_LONGEDGE, "LONGEST_DIAGONAL", 0, "Longest Diagonal", "Split the quads along their longest diagonal"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem rna_node_geometry_triangulate_ngon_method_items[] = { {GEO_NODE_TRIANGULATE_NGON_BEAUTY, "BEAUTY", 0, "Beauty", "Arrange the new triangles evenly (slow)"}, {GEO_NODE_TRIANGULATE_NGON_EARCLIP, "CLIP", 0, "Clip", "Split the polygons with an ear clipping algorithm"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "quad_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_node_geometry_triangulate_quad_method_items); RNA_def_property_enum_default(prop, GEO_NODE_TRIANGULATE_QUAD_SHORTEDGE); RNA_def_property_ui_text(prop, "Quad Method", "Method for splitting the quads into triangles"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "ngon_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, rna_node_geometry_triangulate_ngon_method_items); RNA_def_property_enum_default(prop, GEO_NODE_TRIANGULATE_NGON_BEAUTY); RNA_def_property_ui_text(prop, "N-gon Method", "Method for splitting the n-gons into triangles"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_subdivision_surface(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometrySubdivisionSurface", "storage"); prop = RNA_def_property(srna, "uv_smooth", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "uv_smooth"); RNA_def_property_enum_items(prop, rna_enum_subdivision_uv_smooth_items); RNA_def_property_enum_default(prop, SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES); RNA_def_property_ui_text(prop, "UV Smooth", "Controls how smoothing is applied to UVs"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "boundary_smooth", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "boundary_smooth"); RNA_def_property_enum_items(prop, rna_enum_subdivision_boundary_smooth_items); RNA_def_property_enum_default(prop, SUBSURF_BOUNDARY_SMOOTH_ALL); RNA_def_property_ui_text(prop, "Boundary Smooth", "Controls how open boundaries are smoothed"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_accumulate_field(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeAccumulateField", "storage"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "data_type"); RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeoNodeAccumulateField_type_itemf"); RNA_def_property_enum_default(prop, CD_PROP_FLOAT); RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "domain"); RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT); RNA_def_property_ui_text(prop, "Domain", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_geo_smooth_attribute(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); + RNA_def_property_enum_funcs( + prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf"); + RNA_def_property_enum_default(prop, CD_PROP_FLOAT); + RNA_def_property_ui_text(prop, "Data Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); +} + static void def_fn_random_value(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeRandomValue", "storage"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "data_type"); RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_FunctionNodeRandomValue_type_itemf"); RNA_def_property_enum_default(prop, CD_PROP_FLOAT); RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_attribute_statistic(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeStatistic_type_itemf"); RNA_def_property_enum_default(prop, CD_PROP_FLOAT); RNA_def_property_ui_text( prop, "Data Type", "The data type the attribute is converted to before calculating the results"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT); RNA_def_property_ui_text(prop, "Domain", "Which domain to read the data from"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_extrude_mesh(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem mode_items[] = { {GEO_NODE_EXTRUDE_MESH_VERTICES, "VERTICES", 0, "Vertices", ""}, {GEO_NODE_EXTRUDE_MESH_EDGES, "EDGES", 0, "Edges", ""}, {GEO_NODE_EXTRUDE_MESH_FACES, "FACES", 0, "Faces", ""}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryExtrudeMesh", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_enum_default(prop, GEO_NODE_EXTRUDE_MESH_FACES); RNA_def_property_ui_text(prop, "Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_distribute_points_on_faces(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem rna_node_geometry_distribute_points_on_faces_mode_items[] = { {GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM, "RANDOM", 0, "Random", "Distribute points randomly on the surface"}, {GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON, "POISSON", 0, "Poisson Disk", "Distribute the points randomly on the surface while taking a minimum distance between " "points into account"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "distribute_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_node_geometry_distribute_points_on_faces_mode_items); RNA_def_property_enum_default(prop, GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM); RNA_def_property_ui_text(prop, "Distribution Method", "Method to use for scattering points"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_spline_type(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSplineType", "storage"); prop = RNA_def_property(srna, "spline_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "spline_type"); RNA_def_property_enum_items(prop, rna_enum_curves_types); RNA_def_property_ui_text(prop, "Type", "The curve type to change the selected curves to"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_set_handle_type(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSetHandles", "storage"); prop = RNA_def_property(srna, "handle_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "handle_type"); RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_type_items); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_side_items); RNA_def_property_ui_text(prop, "Mode", "Whether to update left and right handles"); RNA_def_property_flag(prop, PROP_ENUM_FLAG); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_set_handle_positions(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometrySetCurveHandlePositions", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_side_items); RNA_def_property_ui_text(prop, "Mode", "Whether to update left and right handles"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_handle_type_selection(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSelectHandles", "storage"); prop = RNA_def_property(srna, "handle_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "handle_type"); RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_type_items); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_side_items); RNA_def_property_ui_text(prop, "Mode", "Whether to check the type of left and right handles"); RNA_def_property_flag(prop, PROP_ENUM_FLAG); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_primitive_circle(StructRNA *srna) { static const EnumPropertyItem mode_items[] = { {GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS, "POINTS", ICON_NONE, "Points", "Define the radius and location with three points"}, {GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS, "RADIUS", ICON_NONE, "Radius", "Define the radius with a float"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryCurvePrimitiveCircle", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", "Method used to determine radius and placement"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_primitive_arc(StructRNA *srna) { static const EnumPropertyItem mode_items[] = { {GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS, "POINTS", ICON_NONE, "Points", "Define arc by 3 points on circle. Arc is calculated between start and end points"}, {GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS, "RADIUS", ICON_NONE, "Radius", "Define radius with a float"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryCurvePrimitiveArc", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", "Method used to determine radius and placement"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_primitive_line(StructRNA *srna) { static const EnumPropertyItem mode_items[] = { {GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS, "POINTS", ICON_NONE, "Points", "Define the start and end points of the line"}, {GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION, "DIRECTION", ICON_NONE, "Direction", "Define a line with a start point, direction and length"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryCurvePrimitiveLine", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", "Method used to determine radius and placement"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_fn_rotate_euler(StructRNA *srna) { static const EnumPropertyItem type_items[] = { {FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE, "AXIS_ANGLE", ICON_NONE, "Axis Angle", "Rotate around an axis by an angle"}, {FN_NODE_ROTATE_EULER_TYPE_EULER, "EULER", ICON_NONE, "Euler", "Rotate around the X, Y, and Z axes"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem space_items[] = { {FN_NODE_ROTATE_EULER_SPACE_OBJECT, "OBJECT", ICON_NONE, "Object", "Rotate the input rotation in the local space of the object"}, {FN_NODE_ROTATE_EULER_SPACE_LOCAL, "LOCAL", ICON_NONE, "Local", "Rotate the input rotation in its local space"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, type_items); RNA_def_property_ui_text(prop, "Type", "Method used to describe the rotation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, space_items); RNA_def_property_ui_text(prop, "Space", "Base orientation for rotation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_fn_align_euler_to_vector(StructRNA *srna) { static const EnumPropertyItem axis_items[] = { {FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_X, "X", ICON_NONE, "X", "Align the X axis with the vector"}, {FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_Y, "Y", ICON_NONE, "Y", "Align the Y axis with the vector"}, {FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_Z, "Z", ICON_NONE, "Z", "Align the Z axis with the vector"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem pivot_axis_items[] = { {FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_AUTO, "AUTO", ICON_NONE, "Auto", "Automatically detect the best rotation axis to rotate towards the vector"}, {FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_X, "X", ICON_NONE, "X", "Rotate around the local X axis"}, {FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_Y, "Y", ICON_NONE, "Y", "Rotate around the local Y axis"}, {FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_Z, "Z", ICON_NONE, "Z", "Rotate around the local Z axis"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, axis_items); RNA_def_property_ui_text(prop, "Axis", "Axis to align to the vector"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "pivot_axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, pivot_axis_items); RNA_def_property_ui_text(prop, "Pivot Axis", "Axis to rotate around"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_object_info(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem rna_node_geometry_object_info_transform_space_items[] = { {GEO_NODE_TRANSFORM_SPACE_ORIGINAL, "ORIGINAL", 0, "Original", "Output the geometry relative to the input object transform, and the location, rotation " "and " "scale relative to the world origin"}, {GEO_NODE_TRANSFORM_SPACE_RELATIVE, "RELATIVE", 0, "Relative", "Bring the input object geometry, location, rotation and scale into the modified object, " "maintaining the relative position between the two objects in the scene"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryObjectInfo", "storage"); prop = RNA_def_property(srna, "transform_space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_node_geometry_object_info_transform_space_items); RNA_def_property_ui_text( prop, "Transform Space", "The transformation of the vector and geometry outputs"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update_relations"); } static void def_geo_points_to_volume(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem resolution_mode_items[] = { {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT, "VOXEL_AMOUNT", 0, "Amount", "Specify the approximate number of voxels along the diagonal"}, {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE, "VOXEL_SIZE", 0, "Size", "Specify the voxel side length"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryPointsToVolume", "storage"); prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, resolution_mode_items); RNA_def_property_ui_text(prop, "Resolution Mode", "How the voxel size is specified"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_uv_unwrap(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem rna_node_geometry_uv_unwrap_method_items[] = { {GEO_NODE_UV_UNWRAP_METHOD_ANGLE_BASED, "ANGLE_BASED", 0, "Angle Based", "This method gives a good 2D representation of a mesh"}, {GEO_NODE_UV_UNWRAP_METHOD_CONFORMAL, "CONFORMAL", 0, "Conformal", "Uses LSCM (Least Squares Conformal Mapping). This usually gives a less accurate UV " "mapping than Angle Based, but works better for simpler objects"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryUVUnwrap", "storage"); prop = RNA_def_property(srna, "method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_node_geometry_uv_unwrap_method_items); RNA_def_property_ui_text(prop, "Method", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_collection_info(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem rna_node_geometry_collection_info_transform_space_items[] = { {GEO_NODE_TRANSFORM_SPACE_ORIGINAL, "ORIGINAL", 0, "Original", "Output the geometry relative to the collection offset"}, {GEO_NODE_TRANSFORM_SPACE_RELATIVE, "RELATIVE", 0, "Relative", "Bring the input collection geometry into the modified object, maintaining the relative " "position between the objects in the scene"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryCollectionInfo", "storage"); prop = RNA_def_property(srna, "transform_space", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_node_geometry_collection_info_transform_space_items); RNA_def_property_ui_text(prop, "Transform Space", "The transformation of the geometry output"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update_relations"); } static void def_geo_proximity(StructRNA *srna) { static const EnumPropertyItem target_element_items[] = { {GEO_NODE_PROX_TARGET_POINTS, "POINTS", ICON_NONE, "Points", "Calculate the proximity to the target's points (faster than the other modes)"}, {GEO_NODE_PROX_TARGET_EDGES, "EDGES", ICON_NONE, "Edges", "Calculate the proximity to the target's edges"}, {GEO_NODE_PROX_TARGET_FACES, "FACES", ICON_NONE, "Faces", "Calculate the proximity to the target's faces"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryProximity", "storage"); prop = RNA_def_property(srna, "target_element", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, target_element_items); RNA_def_property_enum_default(prop, GEO_NODE_PROX_TARGET_FACES); RNA_def_property_ui_text( prop, "Target Geometry", "Element of the target geometry to calculate the distance from"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_volume_to_mesh(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem resolution_mode_items[] = { {VOLUME_TO_MESH_RESOLUTION_MODE_GRID, "GRID", 0, "Grid", "Use resolution of the volume grid"}, {VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT, "VOXEL_AMOUNT", 0, "Amount", "Desired number of voxels along one axis"}, {VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE, "VOXEL_SIZE", 0, "Size", "Desired voxel side length"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryVolumeToMesh", "storage"); prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, resolution_mode_items); RNA_def_property_ui_text(prop, "Resolution Mode", "How the voxel size is specified"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_mesh_to_volume(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem resolution_mode_items[] = { {MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT, "VOXEL_AMOUNT", 0, "Amount", "Desired number of voxels along one axis"}, {MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE, "VOXEL_SIZE", 0, "Size", "Desired voxel side length"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryMeshToVolume", "storage"); prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, resolution_mode_items); RNA_def_property_ui_text(prop, "Resolution Mode", "How the voxel size is specified"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_mesh_circle(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryMeshCircle", "storage"); prop = RNA_def_property(srna, "fill_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_node_geometry_mesh_circle_fill_type_items); RNA_def_property_ui_text(prop, "Fill Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_mesh_cylinder(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryMeshCylinder", "storage"); prop = RNA_def_property(srna, "fill_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_node_geometry_mesh_circle_fill_type_items); RNA_def_property_ui_text(prop, "Fill Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_mesh_cone(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryMeshCone", "storage"); prop = RNA_def_property(srna, "fill_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_node_geometry_mesh_circle_fill_type_items); RNA_def_property_ui_text(prop, "Fill Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_merge_by_distance(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem mode_items[] = { {GEO_NODE_MERGE_BY_DISTANCE_MODE_ALL, "ALL", 0, "All", "Merge all close selected points, whether or not they are connected"}, {GEO_NODE_MERGE_BY_DISTANCE_MODE_CONNECTED, "CONNECTED", 0, "Connected", "Only merge mesh vertices along existing edges. This method can be much faster"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryMergeByDistance", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_mesh_line(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem mode_items[] = { {GEO_NODE_MESH_LINE_MODE_OFFSET, "OFFSET", 0, "Offset", "Specify the offset from one vertex to the next"}, {GEO_NODE_MESH_LINE_MODE_END_POINTS, "END_POINTS", 0, "End Points", "Specify the line's start and end points"}, {0, NULL, 0, NULL, NULL}, }; static EnumPropertyItem count_mode_items[] = { {GEO_NODE_MESH_LINE_COUNT_TOTAL, "TOTAL", 0, "Count", "Specify the total number of vertices"}, {GEO_NODE_MESH_LINE_COUNT_RESOLUTION, "RESOLUTION", 0, "Resolution", "Specify the distance between vertices"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryMeshLine", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "count_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, count_mode_items); RNA_def_property_ui_text(prop, "Count Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_switch(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeSwitch", "storage"); prop = RNA_def_property(srna, "input_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "input_type"); RNA_def_property_enum_items(prop, node_socket_data_type_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeSwitch_type_itemf"); RNA_def_property_ui_text(prop, "Input Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_primitive_quadrilateral(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem mode_items[] = { {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE, "RECTANGLE", 0, "Rectangle", "Create a rectangle"}, {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM, "PARALLELOGRAM", 0, "Parallelogram", "Create a parallelogram"}, {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID, "TRAPEZOID", 0, "Trapezoid", "Create a trapezoid"}, {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE, "KITE", 0, "Kite", "Create a Kite / Dart"}, {GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS, "POINTS", 0, "Points", "Create a quadrilateral from four points"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryCurvePrimitiveQuad", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_enum_default(prop, GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE); RNA_def_property_ui_text(prop, "Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_resample(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem mode_items[] = { {GEO_NODE_CURVE_RESAMPLE_EVALUATED, "EVALUATED", 0, "Evaluated", "Output the input spline's evaluated points, based on the resolution attribute for NURBS " "and Bezier splines. Poly splines are unchanged"}, {GEO_NODE_CURVE_RESAMPLE_COUNT, "COUNT", 0, "Count", "Sample the specified number of points along each spline"}, {GEO_NODE_CURVE_RESAMPLE_LENGTH, "LENGTH", 0, "Length", "Calculate the number of samples by splitting each spline into segments with the specified " "length"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryCurveResample", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", "How to specify the amount of samples"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_fillet(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem mode_items[] = { {GEO_NODE_CURVE_FILLET_BEZIER, "BEZIER", 0, "Bezier", "Align Bezier handles to create circular arcs at each control point"}, {GEO_NODE_CURVE_FILLET_POLY, "POLY", 0, "Poly", "Add control points along a circular arc (handle type is vector if Bezier Spline)"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryCurveFillet", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", "How to choose number of vertices on fillet"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_curve_to_points(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem mode_items[] = { {GEO_NODE_CURVE_RESAMPLE_EVALUATED, "EVALUATED", 0, "Evaluated", "Create points from the curve's evaluated points, based on the resolution attribute for " "NURBS and Bezier splines"}, {GEO_NODE_CURVE_RESAMPLE_COUNT, "COUNT", 0, "Count", "Sample each spline by evenly distributing the specified number of points"}, {GEO_NODE_CURVE_RESAMPLE_LENGTH, "LENGTH", 0, "Length", "Sample each spline by splitting it into segments with the specified length"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryCurveToPoints", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", "How to generate points from the input curve"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_mesh_to_points(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem mode_items[] = { {GEO_NODE_MESH_TO_POINTS_VERTICES, "VERTICES", 0, "Vertices", "Create a point in the point cloud for each selected vertex"}, {GEO_NODE_MESH_TO_POINTS_EDGES, "EDGES", 0, "Edges", "Create a point in the point cloud for each selected edge"}, {GEO_NODE_MESH_TO_POINTS_FACES, "FACES", 0, "Faces", "Create a point in the point cloud for each selected face"}, {GEO_NODE_MESH_TO_POINTS_CORNERS, "CORNERS", 0, "Corners", "Create a point in the point cloud for each selected face corner"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryMeshToPoints", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_curve_trim(StructRNA *srna) { PropertyRNA *prop; static EnumPropertyItem mode_items[] = { {GEO_NODE_CURVE_SAMPLE_FACTOR, "FACTOR", 0, "Factor", "Find the endpoint positions using a factor of each spline's length"}, {GEO_NODE_CURVE_RESAMPLE_LENGTH, "LENGTH", 0, "Length", "Find the endpoint positions using a length from the start of each spline"}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryCurveTrim", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", "How to find endpoint positions for the trimmed spline"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_transfer_attribute(StructRNA *srna) { static EnumPropertyItem mapping_items[] = { {GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED, "NEAREST_FACE_INTERPOLATED", 0, "Nearest Face Interpolated", "Transfer the attribute from the nearest face on a surface (loose points and edges are " "ignored)"}, {GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST, "NEAREST", 0, "Nearest", "Transfer the element from the nearest element (using face and edge centers for the " "distance computation)"}, {GEO_NODE_ATTRIBUTE_TRANSFER_INDEX, "INDEX", 0, "Index", "Transfer the data from the element with the corresponding index in the target geometry"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryTransferAttribute", "storage"); prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, mapping_items); RNA_def_property_ui_text(prop, "Mapping", "Mapping between geometries"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_NodeGeometryTransferAttribute_type_itemf"); RNA_def_property_enum_default(prop, CD_PROP_FLOAT); RNA_def_property_ui_text(prop, "Data Type", "The type for the source and result data"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT); RNA_def_property_ui_text(prop, "Domain", "The domain to use on the target geometry"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_input_material(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "Material"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_raycast(StructRNA *srna) { static EnumPropertyItem mapping_items[] = { {GEO_NODE_RAYCAST_INTERPOLATED, "INTERPOLATED", 0, "Interpolated", "Interpolate the attribute from the corners of the hit face"}, {GEO_NODE_RAYCAST_NEAREST, "NEAREST", 0, "Nearest", "Use the attribute value of the closest mesh element"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryRaycast", "storage"); prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mapping_items); RNA_def_property_ui_text(prop, "Mapping", "Mapping from the target geometry to hit points"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); RNA_def_property_enum_funcs( prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf"); RNA_def_property_enum_default(prop, CD_PROP_FLOAT); RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); } static void def_geo_curve_fill(StructRNA *srna) { static const EnumPropertyItem mode_items[] = { {GEO_NODE_CURVE_FILL_MODE_TRIANGULATED, "TRIANGLES", 0, "Triangles", ""}, {GEO_NODE_CURVE_FILL_MODE_NGONS, "NGONS", 0, "N-gons", ""}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryCurveFill", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_ui_text(prop, "Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_store_named_attribute(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryStoreNamedAttribute", "storage"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf"); RNA_def_property_enum_default(prop, CD_PROP_FLOAT); RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT); RNA_def_property_ui_text(prop, "Domain", "Which domain to store the data in"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_input_named_attribute(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryInputNamedAttribute", "storage"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); RNA_def_property_enum_funcs( prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf"); RNA_def_property_enum_default(prop, CD_PROP_FLOAT); RNA_def_property_ui_text(prop, "Data Type", "The data type used to read the attribute values"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); } static void def_geo_attribute_capture(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryAttributeCapture", "storage"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); RNA_def_property_enum_funcs( prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf"); RNA_def_property_enum_default(prop, CD_PROP_FLOAT); RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT); RNA_def_property_ui_text(prop, "Domain", "Which domain to store the data in"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_delete_geometry(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem mode_items[] = { {GEO_NODE_DELETE_GEOMETRY_MODE_ALL, "ALL", 0, "All", ""}, {GEO_NODE_DELETE_GEOMETRY_MODE_EDGE_FACE, "EDGE_FACE", 0, "Only Edges & Faces", ""}, {GEO_NODE_DELETE_GEOMETRY_MODE_ONLY_FACE, "ONLY_FACE", 0, "Only Faces", ""}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryDeleteGeometry", "storage"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mode_items); RNA_def_property_enum_default(prop, GEO_NODE_DELETE_GEOMETRY_MODE_ALL); RNA_def_property_ui_text(prop, "Mode", "Which parts of the mesh component to delete"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_domain_without_corner_items); RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT); RNA_def_property_ui_text(prop, "Domain", "Which domain to delete in"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_duplicate_elements(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem domain_items[] = { {ATTR_DOMAIN_POINT, "POINT", 0, "Point", ""}, {ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", ""}, {ATTR_DOMAIN_FACE, "FACE", 0, "Face", ""}, {ATTR_DOMAIN_CURVE, "SPLINE", 0, "Spline", ""}, {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", ""}, {0, NULL, 0, NULL, NULL}, }; RNA_def_struct_sdna_from(srna, "NodeGeometryDuplicateElements", "storage"); prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, domain_items); RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT); RNA_def_property_ui_text(prop, "Domain", "Which domain to duplicate"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_string_to_curves(StructRNA *srna) { static const EnumPropertyItem rna_node_geometry_string_to_curves_overflow_items[] = { {GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW, "OVERFLOW", ICON_NONE, "Overflow", "Let the text use more space than the specified height"}, {GEO_NODE_STRING_TO_CURVES_MODE_SCALE_TO_FIT, "SCALE_TO_FIT", ICON_NONE, "Scale To Fit", "Scale the text size to fit inside the width and height"}, {GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE, "TRUNCATE", ICON_NONE, "Truncate", "Only output curves that fit within the width and height. Output the remainder to the " "\"Remainder\" output"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem rna_node_geometry_string_to_curves_align_x_items[] = { {GEO_NODE_STRING_TO_CURVES_ALIGN_X_LEFT, "LEFT", ICON_ALIGN_LEFT, "Left", "Align text to the left"}, {GEO_NODE_STRING_TO_CURVES_ALIGN_X_CENTER, "CENTER", ICON_ALIGN_CENTER, "Center", "Align text to the center"}, {GEO_NODE_STRING_TO_CURVES_ALIGN_X_RIGHT, "RIGHT", ICON_ALIGN_RIGHT, "Right", "Align text to the right"}, {GEO_NODE_STRING_TO_CURVES_ALIGN_X_JUSTIFY, "JUSTIFY", ICON_ALIGN_JUSTIFY, "Justify", "Align text to the left and the right"}, {GEO_NODE_STRING_TO_CURVES_ALIGN_X_FLUSH, "FLUSH", ICON_ALIGN_FLUSH, "Flush", "Align text to the left and the right, with equal character spacing"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem rna_node_geometry_string_to_curves_align_y_items[] = { {GEO_NODE_STRING_TO_CURVES_ALIGN_Y_TOP_BASELINE, "TOP_BASELINE", ICON_ALIGN_TOP, "Top Baseline", "Align text to the top baseline"}, {GEO_NODE_STRING_TO_CURVES_ALIGN_Y_TOP, "TOP", ICON_ALIGN_TOP, "Top", "Align text to the top"}, {GEO_NODE_STRING_TO_CURVES_ALIGN_Y_MIDDLE, "MIDDLE", ICON_ALIGN_MIDDLE, "Middle", "Align text to the middle"}, {GEO_NODE_STRING_TO_CURVES_ALIGN_Y_BOTTOM_BASELINE, "BOTTOM_BASELINE", ICON_ALIGN_BOTTOM, "Bottom Baseline", "Align text to the bottom baseline"}, {GEO_NODE_STRING_TO_CURVES_ALIGN_Y_BOTTOM, "BOTTOM", ICON_ALIGN_BOTTOM, "Bottom", "Align text to the bottom"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem rna_node_geometry_string_to_curves_pivot_mode[] = { {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_MIDPOINT, "MIDPOINT", 0, "Midpoint", "Midpoint"}, {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_LEFT, "TOP_LEFT", 0, "Top Left", "Top Left"}, {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_CENTER, "TOP_CENTER", 0, "Top Center", "Top Center"}, {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_RIGHT, "TOP_RIGHT", 0, "Top Right", "Top Right"}, {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_LEFT, "BOTTOM_LEFT", 0, "Bottom Left", "Bottom Left"}, {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_CENTER, "BOTTOM_CENTER", 0, "Bottom Center", "Bottom Center"}, {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_RIGHT, "BOTTOM_RIGHT", 0, "Bottom Right", "Bottom Right"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; prop = RNA_def_property(srna, "font", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "id"); RNA_def_property_struct_type(prop, "VectorFont"); RNA_def_property_ui_text(prop, "Font", "Font of the text. Falls back to the UI font by default"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeGeometryStringToCurves", "storage"); prop = RNA_def_property(srna, "overflow", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "overflow"); RNA_def_property_enum_items(prop, rna_node_geometry_string_to_curves_overflow_items); RNA_def_property_enum_default(prop, GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW); RNA_def_property_ui_text(prop, "Overflow", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "align_x"); RNA_def_property_enum_items(prop, rna_node_geometry_string_to_curves_align_x_items); RNA_def_property_enum_default(prop, GEO_NODE_STRING_TO_CURVES_ALIGN_X_LEFT); RNA_def_property_ui_text(prop, "Align X", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "align_y"); RNA_def_property_enum_items(prop, rna_node_geometry_string_to_curves_align_y_items); RNA_def_property_enum_default(prop, GEO_NODE_STRING_TO_CURVES_ALIGN_Y_TOP_BASELINE); RNA_def_property_ui_text(prop, "Align Y", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "pivot_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "pivot_mode"); RNA_def_property_enum_items(prop, rna_node_geometry_string_to_curves_pivot_mode); RNA_def_property_enum_default(prop, GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_LEFT); RNA_def_property_ui_text(prop, "Pivot Point", "Pivot point position relative to character"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_separate_geometry(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometrySeparateGeometry", "storage"); prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_domain_without_corner_items); RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT); RNA_def_property_ui_text(prop, "Domain", "Which domain to separate on"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_viewer(StructRNA *srna) { PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeGeometryViewer", "storage"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); RNA_def_property_enum_funcs( prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf"); RNA_def_property_enum_default(prop, CD_PROP_FLOAT); RNA_def_property_ui_text(prop, "Data Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); } static void def_geo_realize_instances(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "legacy_behavior", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR); RNA_def_property_ui_text( prop, "Legacy Behavior", "Behave like before instance attributes existed"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); } static void def_geo_field_at_index(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); RNA_def_property_ui_text(prop, "Domain", "Domain the field is evaluated in"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); RNA_def_property_enum_funcs( prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf"); RNA_def_property_ui_text(prop, "Data Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); } static void def_geo_interpolate_domain(StructRNA *srna) { PropertyRNA *prop; prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); RNA_def_property_ui_text(prop, "Domain", "Domain the field is evaluated in"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); RNA_def_property_enum_funcs( prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_with_socket_itemf"); RNA_def_property_ui_text(prop, "Data Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); } static void def_geo_scale_elements(StructRNA *srna) { PropertyRNA *prop; static const EnumPropertyItem domain_items[] = { {ATTR_DOMAIN_FACE, "FACE", ICON_NONE, "Face", "Scale individual faces or neighboring face islands"}, {ATTR_DOMAIN_EDGE, "EDGE", ICON_NONE, "Edge", "Scale individual edges or neighboring edge islands"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem scale_mode_items[] = { {GEO_NODE_SCALE_ELEMENTS_UNIFORM, "UNIFORM", ICON_NONE, "Uniform", "Scale elements by the same factor in every direction"}, {GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS, "SINGLE_AXIS", ICON_NONE, "Single Axis", "Scale elements in a single direction"}, {0, NULL, 0, NULL, NULL}, }; prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, domain_items); RNA_def_property_enum_default(prop, ATTR_DOMAIN_FACE); RNA_def_property_ui_text(prop, "Domain", "Element type to transform"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); prop = RNA_def_property(srna, "scale_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, scale_mode_items); RNA_def_property_ui_text(prop, "Scale Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); } /* -------------------------------------------------------------------------- */ static void rna_def_shader_node(BlenderRNA *brna) { StructRNA *srna; srna = RNA_def_struct(brna, "ShaderNode", "NodeInternal"); RNA_def_struct_ui_text(srna, "Shader Node", "Material shader node"); RNA_def_struct_sdna(srna, "bNode"); RNA_def_struct_register_funcs(srna, "rna_ShaderNode_register", "rna_Node_unregister", NULL); } static void rna_def_compositor_node(BlenderRNA *brna) { StructRNA *srna; FunctionRNA *func; srna = RNA_def_struct(brna, "CompositorNode", "NodeInternal"); RNA_def_struct_ui_text(srna, "Compositor Node", ""); RNA_def_struct_sdna(srna, "bNode"); RNA_def_struct_register_funcs(srna, "rna_CompositorNode_register", "rna_Node_unregister", NULL); /* compositor node need_exec flag */ func = RNA_def_function(srna, "tag_need_exec", "rna_CompositorNode_tag_need_exec"); RNA_def_function_ui_description(func, "Tag the node for compositor update"); def_cmp_cryptomatte_entry(brna); } static void rna_def_texture_node(BlenderRNA *brna) { StructRNA *srna; srna = RNA_def_struct(brna, "TextureNode", "NodeInternal"); RNA_def_struct_ui_text(srna, "Texture Node", ""); RNA_def_struct_sdna(srna, "bNode"); RNA_def_struct_register_funcs(srna, "rna_TextureNode_register", "rna_Node_unregister", NULL); } static void rna_def_geometry_node(BlenderRNA *brna) { StructRNA *srna; srna = RNA_def_struct(brna, "GeometryNode", "NodeInternal"); RNA_def_struct_ui_text(srna, "Geometry Node", ""); RNA_def_struct_sdna(srna, "bNode"); RNA_def_struct_register_funcs(srna, "rna_GeometryNode_register", "rna_Node_unregister", NULL); } static void rna_def_function_node(BlenderRNA *brna) { StructRNA *srna; srna = RNA_def_struct(brna, "FunctionNode", "NodeInternal"); RNA_def_struct_ui_text(srna, "Function Node", ""); RNA_def_struct_sdna(srna, "bNode"); RNA_def_struct_register_funcs(srna, "rna_FunctionNode_register", "rna_Node_unregister", NULL); } /* -------------------------------------------------------------------------- */ static void rna_def_node_socket(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; PropertyRNA *parm; FunctionRNA *func; static float default_draw_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; srna = RNA_def_struct(brna, "NodeSocket", NULL); RNA_def_struct_ui_text(srna, "Node Socket", "Input or output socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_refine_func(srna, "rna_NodeSocket_refine"); RNA_def_struct_ui_icon(srna, ICON_NONE); RNA_def_struct_path_func(srna, "rna_NodeSocket_path"); RNA_def_struct_register_funcs( srna, "rna_NodeSocket_register", "rna_NodeSocket_unregister", NULL); RNA_def_struct_idprops_func(srna, "rna_NodeSocket_idprops"); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Name", "Socket name"); RNA_def_struct_name_property(srna, prop); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocket_update"); prop = RNA_def_property(srna, "label", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "label"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Label", "Custom dynamic defined socket label"); prop = RNA_def_property(srna, "identifier", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "identifier"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Identifier", "Unique identifier for mapping sockets"); prop = RNA_def_property(srna, "description", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "description"); RNA_def_property_ui_text(prop, "Tooltip", "Socket tooltip"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocket_update"); prop = RNA_def_property(srna, "is_output", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_NodeSocket_is_output_get", NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Is Output", "True if the socket is an output, otherwise input"); prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_HIDDEN); RNA_def_property_boolean_funcs(prop, NULL, "rna_NodeSocket_hide_set"); RNA_def_property_ui_text(prop, "Hide", "Hide the socket"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SOCK_UNAVAIL); RNA_def_property_ui_text(prop, "Enabled", "Enable the socket"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "link_limit", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "limit"); RNA_def_property_int_funcs(prop, NULL, "rna_NodeSocket_link_limit_set", NULL); RNA_def_property_range(prop, 1, 0xFFF); RNA_def_property_ui_text(prop, "Link Limit", "Max number of links allowed for this socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL); prop = RNA_def_property(srna, "is_linked", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_IN_USE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Linked", "True if the socket is connected"); prop = RNA_def_property(srna, "is_unavailable", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_UNAVAIL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Unavailable", "True if the socket is unavailable"); prop = RNA_def_property(srna, "is_multi_input", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_MULTI_INPUT); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text( prop, "Multi Input", "True if the socket can accept multiple ordered input links"); prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SOCK_COLLAPSED); RNA_def_property_ui_text(prop, "Expanded", "Socket links are expanded in the user interface"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL); prop = RNA_def_property(srna, "hide_value", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_HIDE_VALUE); RNA_def_property_ui_text(prop, "Hide Value", "Hide the socket input value"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "node", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_funcs(prop, "rna_NodeSocket_node_get", NULL, NULL, NULL); RNA_def_property_struct_type(prop, "Node"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_ui_text(prop, "Node", "Node owning this socket"); /* NOTE: The type property is used by standard sockets. * Ideally should be defined only for the registered subclass, * but to use the existing DNA is added in the base type here. * Future socket types can ignore or override this if needed. */ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, node_socket_type_items); RNA_def_property_enum_default(prop, SOCK_FLOAT); RNA_def_property_enum_funcs(prop, NULL, "rna_NodeSocket_type_set", NULL); RNA_def_property_ui_text(prop, "Type", "Data type"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocket_update"); prop = RNA_def_property(srna, "display_shape", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "display_shape"); RNA_def_property_enum_items(prop, rna_enum_node_socket_display_shape_items); RNA_def_property_enum_default(prop, SOCK_DISPLAY_SHAPE_CIRCLE); RNA_def_property_ui_text(prop, "Shape", "Socket shape"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocket_update"); /* registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname"); RNA_def_property_flag(prop, PROP_REGISTER); RNA_def_property_ui_text(prop, "ID Name", ""); prop = RNA_def_property(srna, "bl_label", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "typeinfo->label"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_ui_text(prop, "Type Label", "Label to display for the socket type in the UI"); /* draw socket */ func = RNA_def_function(srna, "draw", NULL); RNA_def_function_ui_description(func, "Draw socket"); RNA_def_function_flag(func, FUNC_REGISTER); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "Node"); RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_property(func, "text", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(parm, "Text", "Text label to draw alongside properties"); // RNA_def_property_string_default(parm, ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "draw_color", NULL); RNA_def_function_ui_description(func, "Color of the socket icon"); RNA_def_function_flag(func, FUNC_REGISTER); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "Node"); RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_float_array( func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f); RNA_def_function_output(func, parm); } static void rna_def_node_socket_interface(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; PropertyRNA *parm; FunctionRNA *func; static float default_draw_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; srna = RNA_def_struct(brna, "NodeSocketInterface", NULL); RNA_def_struct_ui_text(srna, "Node Socket Template", "Parameters to define node sockets"); /* XXX Using bNodeSocket DNA for templates is a compatibility hack. * This allows to keep the inputs/outputs lists in bNodeTree working for earlier versions * and at the same time use them for socket templates in groups. */ RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_refine_func(srna, "rna_NodeSocketInterface_refine"); RNA_def_struct_path_func(srna, "rna_NodeSocketInterface_path"); RNA_def_struct_idprops_func(srna, "rna_NodeSocketInterface_idprops"); RNA_def_struct_register_funcs( srna, "rna_NodeSocketInterface_register", "rna_NodeSocketInterface_unregister", NULL); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Name", "Socket name"); RNA_def_struct_name_property(srna, prop); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); prop = RNA_def_property(srna, "identifier", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "identifier"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Identifier", "Unique identifier for mapping sockets"); prop = RNA_def_property(srna, "description", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "description"); RNA_def_property_ui_text(prop, "Tooltip", "Socket tooltip"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); prop = RNA_def_property(srna, "is_output", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_NodeSocket_is_output_get", NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Is Output", "True if the socket is an output, otherwise input"); prop = RNA_def_property(srna, "hide_value", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_HIDE_VALUE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text( prop, "Hide Value", "Hide the socket input value even when the socket is not connected"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); prop = RNA_def_property(srna, "attribute_domain", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); RNA_def_property_ui_text( prop, "Attribute Domain", "Attribute domain used by the geometry nodes modifier to create an attribute output"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); prop = RNA_def_property(srna, "default_attribute_name", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "default_attribute_name"); RNA_def_property_ui_text(prop, "Default Attribute", "The attribute name used by default when the node group is used by a " "geometry nodes modifier"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); /* registration */ prop = RNA_def_property(srna, "bl_socket_idname", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname"); RNA_def_property_flag(prop, PROP_REGISTER); RNA_def_property_ui_text(prop, "ID Name", ""); prop = RNA_def_property(srna, "bl_label", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "typeinfo->label"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_ui_text(prop, "Type Label", "Label to display for the socket type in the UI"); func = RNA_def_function(srna, "draw", NULL); RNA_def_function_ui_description(func, "Draw template settings"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); func = RNA_def_function(srna, "draw_color", NULL); RNA_def_function_ui_description(func, "Color of the socket icon"); RNA_def_function_flag(func, FUNC_REGISTER); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_float_array( func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f); RNA_def_function_output(func, parm); func = RNA_def_function(srna, "register_properties", NULL); RNA_def_function_ui_description(func, "Define RNA properties of a socket"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer( func, "data_rna_type", "Struct", "Data RNA Type", "RNA type for special socket properties"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "init_socket", NULL); RNA_def_function_ui_description(func, "Initialize a node socket instance"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "node", "Node", "Node", "Node of the socket to initialize"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_pointer(func, "socket", "NodeSocket", "Socket", "Socket to initialize"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string( func, "data_path", NULL, 0, "Data Path", "Path to specialized socket data"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "from_socket", NULL); RNA_def_function_ui_description(func, "Setup template parameters from an existing socket"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "node", "Node", "Node", "Node of the original socket"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_pointer(func, "socket", "NodeSocket", "Socket", "Original socket"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); } static void rna_def_node_socket_float(BlenderRNA *brna, const char *idname, const char *interface_idname, PropertySubType subtype) { StructRNA *srna; PropertyRNA *prop; float value_default; /* choose sensible common default based on subtype */ switch (subtype) { case PROP_FACTOR: value_default = 1.0f; break; case PROP_PERCENTAGE: value_default = 100.0f; break; default: value_default = 0.0f; break; } srna = RNA_def_struct(brna, idname, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Float Node Socket", "Floating-point number socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueFloat", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_FLOAT, subtype); RNA_def_property_float_sdna(prop, NULL, "value"); RNA_def_property_float_funcs(prop, NULL, NULL, "rna_NodeSocketStandard_float_range"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text( srna, "Float Node Socket Interface", "Floating-point number socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueFloat", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_FLOAT, subtype); RNA_def_property_float_sdna(prop, NULL, "value"); RNA_def_property_float_default(prop, value_default); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_float_funcs(prop, NULL, NULL, "rna_NodeSocketStandard_float_range"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); prop = RNA_def_property(srna, "min_value", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "min"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Minimum Value", "Minimum value"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); prop = RNA_def_property(srna, "max_value", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "max"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Maximum Value", "Maximum value"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); } static void rna_def_node_socket_int(BlenderRNA *brna, const char *identifier, const char *interface_idname, PropertySubType subtype) { StructRNA *srna; PropertyRNA *prop; int value_default; /* choose sensible common default based on subtype */ switch (subtype) { case PROP_FACTOR: value_default = 1; break; case PROP_PERCENTAGE: value_default = 100; break; default: value_default = 0; break; } srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Integer Node Socket", "Integer number socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueInt", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_INT, subtype); RNA_def_property_int_sdna(prop, NULL, "value"); RNA_def_property_int_default(prop, value_default); RNA_def_property_int_funcs(prop, NULL, NULL, "rna_NodeSocketStandard_int_range"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Integer Node Socket Interface", "Integer number socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueInt", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_INT, subtype); RNA_def_property_int_sdna(prop, NULL, "value"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_int_funcs(prop, NULL, NULL, "rna_NodeSocketStandard_int_range"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); prop = RNA_def_property(srna, "min_value", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "min"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Minimum Value", "Minimum value"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); prop = RNA_def_property(srna, "max_value", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "max"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Maximum Value", "Maximum value"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); } static void rna_def_node_socket_bool(BlenderRNA *brna, const char *identifier, const char *interface_idname) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Boolean Node Socket", "Boolean value socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueBoolean", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "value", 1); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Boolean Node Socket Interface", "Boolean value socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueBoolean", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "value", 1); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); } static void rna_def_node_socket_vector(BlenderRNA *brna, const char *identifier, const char *interface_idname, PropertySubType subtype) { StructRNA *srna; PropertyRNA *prop; const float *value_default; /* choose sensible common default based on subtype */ switch (subtype) { case PROP_DIRECTION: { static const float default_direction[3] = {0.0f, 0.0f, 1.0f}; value_default = default_direction; break; } default: { static const float default_vector[3] = {0.0f, 0.0f, 0.0f}; value_default = default_vector; break; } } srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Vector Node Socket", "3D vector socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueVector", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_FLOAT, subtype); RNA_def_property_float_sdna(prop, NULL, "value"); RNA_def_property_float_array_default(prop, value_default); RNA_def_property_float_funcs(prop, NULL, NULL, "rna_NodeSocketStandard_vector_range"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Vector Node Socket Interface", "3D vector socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueVector", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_FLOAT, subtype); RNA_def_property_float_sdna(prop, NULL, "value"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_float_funcs(prop, NULL, NULL, "rna_NodeSocketStandard_vector_range"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); prop = RNA_def_property(srna, "min_value", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "min"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Minimum Value", "Minimum value"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); prop = RNA_def_property(srna, "max_value", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "max"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Maximum Value", "Maximum value"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); } static void rna_def_node_socket_color(BlenderRNA *brna, const char *identifier, const char *interface_idname) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Color Node Socket", "RGBA color socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueRGBA", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "value"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Color Node Socket Interface", "RGBA color socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueRGBA", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "value"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); } static void rna_def_node_socket_string(BlenderRNA *brna, const char *identifier, const char *interface_idname) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "String Node Socket", "String socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueString", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "value"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "String Node Socket Interface", "String socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueString", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "value"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); } static void rna_def_node_socket_shader(BlenderRNA *brna, const char *identifier, const char *interface_idname) { StructRNA *srna; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Shader Node Socket", "Shader socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Shader Node Socket Interface", "Shader socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); } static void rna_def_node_socket_virtual(BlenderRNA *brna, const char *identifier) { StructRNA *srna; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Virtual Node Socket", "Virtual socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); } static void rna_def_node_socket_object(BlenderRNA *brna, const char *identifier, const char *interface_idname) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Object Node Socket", "Object socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueObject", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "value"); RNA_def_property_struct_type(prop, "Object"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update( prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Object Node Socket Interface", "Object socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueObject", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "value"); RNA_def_property_struct_type(prop, "Object"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); } static void rna_def_node_socket_image(BlenderRNA *brna, const char *identifier, const char *interface_idname) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Image Node Socket", "Image socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueImage", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "value"); RNA_def_property_struct_type(prop, "Image"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update( prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Image Node Socket Interface", "Image socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueImage", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "value"); RNA_def_property_struct_type(prop, "Image"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); } static void rna_def_node_socket_geometry(BlenderRNA *brna, const char *identifier, const char *interface_idname) { StructRNA *srna; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Geometry Node Socket", "Geometry socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Geometry Node Socket Interface", "Geometry socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); } static void rna_def_node_socket_collection(BlenderRNA *brna, const char *identifier, const char *interface_idname) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Collection Node Socket", "Collection socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueCollection", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "value"); RNA_def_property_struct_type(prop, "Collection"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update( prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Collection Node Socket Interface", "Collection socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueCollection", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "value"); RNA_def_property_struct_type(prop, "Collection"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); } static void rna_def_node_socket_texture(BlenderRNA *brna, const char *identifier, const char *interface_idname) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Texture Node Socket", "Texture socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueTexture", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "value"); RNA_def_property_struct_type(prop, "Texture"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update( prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Texture Node Socket Interface", "Texture socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueTexture", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "value"); RNA_def_property_struct_type(prop, "Texture"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); } static void rna_def_node_socket_material(BlenderRNA *brna, const char *identifier, const char *interface_idname) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Material Node Socket", "Material socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueMaterial", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "value"); RNA_def_property_struct_type(prop, "Material"); RNA_def_property_pointer_funcs( prop, NULL, NULL, NULL, "rna_NodeSocketMaterial_default_value_poll"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update( prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); /* socket interface */ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Material Node Socket Interface", "Material socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_sdna_from(srna, "bNodeSocketValueMaterial", "default_value"); prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "value"); RNA_def_property_struct_type(prop, "Material"); RNA_def_property_pointer_funcs( prop, NULL, NULL, NULL, "rna_NodeSocketMaterial_default_value_poll"); RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); } static void rna_def_node_socket_standard_types(BlenderRNA *brna) { /* XXX Workaround: Registered functions are not exposed in python by bpy, * it expects them to be registered from python and use the native implementation. * However, the standard socket types below are not registering these functions from python, * so in order to call them in py scripts we need to overload and * replace them with plain C callbacks. * These types provide a usable basis for socket types defined in C. */ StructRNA *srna; PropertyRNA *parm, *prop; FunctionRNA *func; static float default_draw_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; srna = RNA_def_struct(brna, "NodeSocketStandard", "NodeSocket"); RNA_def_struct_sdna(srna, "bNodeSocket"); /* draw socket */ func = RNA_def_function(srna, "draw", "rna_NodeSocketStandard_draw"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Draw socket"); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "Node"); RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_property(func, "text", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(parm, "Text", "Text label to draw alongside properties"); // RNA_def_property_string_default(parm, ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "draw_color", "rna_NodeSocketStandard_draw_color"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Color of the socket icon"); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "Node"); RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_float_array( func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f); RNA_def_function_output(func, parm); srna = RNA_def_struct(brna, "NodeSocketInterfaceStandard", "NodeSocketInterface"); RNA_def_struct_sdna(srna, "bNodeSocket"); /* for easier type comparison in python */ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "typeinfo->type"); RNA_def_property_enum_items(prop, node_socket_type_items); RNA_def_property_enum_default(prop, SOCK_FLOAT); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Type", "Data type"); func = RNA_def_function(srna, "draw", "rna_NodeSocketInterfaceStandard_draw"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Draw template settings"); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); func = RNA_def_function(srna, "draw_color", "rna_NodeSocketInterfaceStandard_draw_color"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Color of the socket icon"); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_float_array( func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f); RNA_def_function_output(func, parm); /* XXX These types should eventually be registered at runtime. * Then use the nodeStaticSocketType and nodeStaticSocketInterfaceType functions * to get the idname strings from int type and subtype * (see node_socket.cc, register_standard_node_socket_types). */ rna_def_node_socket_float(brna, "NodeSocketFloat", "NodeSocketInterfaceFloat", PROP_NONE); rna_def_node_socket_float( brna, "NodeSocketFloatUnsigned", "NodeSocketInterfaceFloatUnsigned", PROP_UNSIGNED); rna_def_node_socket_float( brna, "NodeSocketFloatPercentage", "NodeSocketInterfaceFloatPercentage", PROP_PERCENTAGE); rna_def_node_socket_float( brna, "NodeSocketFloatFactor", "NodeSocketInterfaceFloatFactor", PROP_FACTOR); rna_def_node_socket_float( brna, "NodeSocketFloatAngle", "NodeSocketInterfaceFloatAngle", PROP_ANGLE); rna_def_node_socket_float( brna, "NodeSocketFloatTime", "NodeSocketInterfaceFloatTime", PROP_TIME); rna_def_node_socket_float(brna, "NodeSocketFloatTimeAbsolute", "NodeSocketInterfaceFloatTimeAbsolute", PROP_TIME_ABSOLUTE); rna_def_node_socket_float( brna, "NodeSocketFloatDistance", "NodeSocketInterfaceFloatDistance", PROP_DISTANCE); rna_def_node_socket_int(brna, "NodeSocketInt", "NodeSocketInterfaceInt", PROP_NONE); rna_def_node_socket_int( brna, "NodeSocketIntUnsigned", "NodeSocketInterfaceIntUnsigned", PROP_UNSIGNED); rna_def_node_socket_int( brna, "NodeSocketIntPercentage", "NodeSocketInterfaceIntPercentage", PROP_PERCENTAGE); rna_def_node_socket_int( brna, "NodeSocketIntFactor", "NodeSocketInterfaceIntFactor", PROP_FACTOR); rna_def_node_socket_bool(brna, "NodeSocketBool", "NodeSocketInterfaceBool"); rna_def_node_socket_vector(brna, "NodeSocketVector", "NodeSocketInterfaceVector", PROP_NONE); rna_def_node_socket_vector(brna, "NodeSocketVectorTranslation", "NodeSocketInterfaceVectorTranslation", PROP_TRANSLATION); rna_def_node_socket_vector( brna, "NodeSocketVectorDirection", "NodeSocketInterfaceVectorDirection", PROP_DIRECTION); rna_def_node_socket_vector( brna, "NodeSocketVectorVelocity", "NodeSocketInterfaceVectorVelocity", PROP_VELOCITY); rna_def_node_socket_vector(brna, "NodeSocketVectorAcceleration", "NodeSocketInterfaceVectorAcceleration", PROP_ACCELERATION); rna_def_node_socket_vector( brna, "NodeSocketVectorEuler", "NodeSocketInterfaceVectorEuler", PROP_EULER); rna_def_node_socket_vector( brna, "NodeSocketVectorXYZ", "NodeSocketInterfaceVectorXYZ", PROP_XYZ); rna_def_node_socket_color(brna, "NodeSocketColor", "NodeSocketInterfaceColor"); rna_def_node_socket_string(brna, "NodeSocketString", "NodeSocketInterfaceString"); rna_def_node_socket_shader(brna, "NodeSocketShader", "NodeSocketInterfaceShader"); rna_def_node_socket_virtual(brna, "NodeSocketVirtual"); rna_def_node_socket_object(brna, "NodeSocketObject", "NodeSocketInterfaceObject"); rna_def_node_socket_image(brna, "NodeSocketImage", "NodeSocketInterfaceImage"); rna_def_node_socket_geometry(brna, "NodeSocketGeometry", "NodeSocketInterfaceGeometry"); rna_def_node_socket_collection(brna, "NodeSocketCollection", "NodeSocketInterfaceCollection"); rna_def_node_socket_texture(brna, "NodeSocketTexture", "NodeSocketInterfaceTexture"); rna_def_node_socket_material(brna, "NodeSocketMaterial", "NodeSocketInterfaceMaterial"); } static void rna_def_internal_node(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop, *parm; FunctionRNA *func; srna = RNA_def_struct(brna, "NodeInternalSocketTemplate", NULL); RNA_def_struct_ui_text(srna, "Socket Template", "Type and default value of a node socket"); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs(prop, "rna_NodeInternalSocketTemplate_name_get", "rna_NodeInternalSocketTemplate_name_length", NULL); RNA_def_property_ui_text(prop, "Name", "Name of the socket"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_property(srna, "identifier", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs(prop, "rna_NodeInternalSocketTemplate_identifier_get", "rna_NodeInternalSocketTemplate_identifier_length", NULL); RNA_def_property_ui_text(prop, "Identifier", "Identifier of the socket"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_funcs(prop, "rna_NodeInternalSocketTemplate_type_get", NULL, NULL); RNA_def_property_enum_items(prop, node_socket_type_items); RNA_def_property_ui_text(prop, "Type", "Data type of the socket"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* XXX Workaround: Registered functions are not exposed in python by bpy, * it expects them to be registered from python and use the native implementation. * * However, the standard node types are not registering these functions from python, * so in order to call them in py scripts we need to overload and * replace them with plain C callbacks. * This type provides a usable basis for node types defined in C. */ srna = RNA_def_struct(brna, "NodeInternal", "Node"); RNA_def_struct_sdna(srna, "bNode"); /* poll */ func = RNA_def_function(srna, "poll", "rna_NodeInternal_poll"); RNA_def_function_ui_description( func, "If non-null output is returned, the node type can be added to the tree"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE); RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", "")); parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "poll_instance", "rna_NodeInternal_poll_instance"); RNA_def_function_ui_description( func, "If non-null output is returned, the node can be added to the tree"); RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", "")); parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* update */ func = RNA_def_function(srna, "update", "rna_NodeInternal_update"); RNA_def_function_ui_description( func, "Update on node graph topology changes (adding or removing nodes and links)"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_ALLOW_WRITE); /* draw buttons */ func = RNA_def_function(srna, "draw_buttons", "rna_NodeInternal_draw_buttons"); RNA_def_function_ui_description(func, "Draw node buttons"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* draw buttons extended */ func = RNA_def_function(srna, "draw_buttons_ext", "rna_NodeInternal_draw_buttons_ext"); RNA_def_function_ui_description(func, "Draw node buttons in the sidebar"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); } static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int in_out) { StructRNA *srna; PropertyRNA *parm; FunctionRNA *func; const char *structtype = (in_out == SOCK_IN ? "NodeInputs" : "NodeOutputs"); const char *uiname = (in_out == SOCK_IN ? "Node Inputs" : "Node Outputs"); const char *newfunc = (in_out == SOCK_IN ? "rna_Node_inputs_new" : "rna_Node_outputs_new"); const char *clearfunc = (in_out == SOCK_IN ? "rna_Node_inputs_clear" : "rna_Node_outputs_clear"); const char *movefunc = (in_out == SOCK_IN ? "rna_Node_inputs_move" : "rna_Node_outputs_move"); RNA_def_property_srna(cprop, structtype); srna = RNA_def_struct(brna, structtype, NULL); RNA_def_struct_sdna(srna, "bNode"); RNA_def_struct_ui_text(srna, uiname, "Collection of Node Sockets"); func = RNA_def_function(srna, "new", newfunc); RNA_def_function_ui_description(func, "Add a socket to this node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_string(func, "identifier", NULL, MAX_NAME, "Identifier", "Unique socket identifier"); /* return value */ parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_Node_socket_remove"); RNA_def_function_ui_description(func, "Remove a socket from this node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "The socket to remove"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "clear", clearfunc); RNA_def_function_ui_description(func, "Remove all sockets from this node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); func = RNA_def_function(srna, "move", movefunc); RNA_def_function_ui_description(func, "Move a socket to another position"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); parm = RNA_def_int( func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int( func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } static void rna_def_node(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; FunctionRNA *func; PropertyRNA *parm; static const EnumPropertyItem dummy_static_type_items[] = { {NODE_CUSTOM, "CUSTOM", 0, "Custom", "Custom Node"}, {0, NULL, 0, NULL, NULL}, }; srna = RNA_def_struct(brna, "Node", NULL); RNA_def_struct_ui_text(srna, "Node", "Node in a node tree"); RNA_def_struct_sdna(srna, "bNode"); RNA_def_struct_ui_icon(srna, ICON_NODE); RNA_def_struct_refine_func(srna, "rna_Node_refine"); RNA_def_struct_path_func(srna, "rna_Node_path"); RNA_def_struct_register_funcs(srna, "rna_Node_register", "rna_Node_unregister", NULL); RNA_def_struct_idprops_func(srna, "rna_Node_idprops"); prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, dummy_static_type_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_node_static_type_itemf"); RNA_def_property_enum_default(prop, NODE_CUSTOM); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text( prop, "Type", "Node type (deprecated, use bl_static_type or bl_idname for the actual identifier string)"); prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "locx"); RNA_def_property_array(prop, 2); RNA_def_property_range(prop, -100000.0f, 100000.0f); RNA_def_property_ui_text(prop, "Location", ""); RNA_def_property_update(prop, NC_NODE, "rna_Node_update"); prop = RNA_def_property(srna, "width", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "width"); RNA_def_property_float_funcs(prop, NULL, NULL, "rna_Node_width_range"); RNA_def_property_ui_text(prop, "Width", "Width of the node"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "width_hidden", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "miniwidth"); RNA_def_property_float_funcs(prop, NULL, NULL, "rna_Node_width_range"); RNA_def_property_ui_text(prop, "Width Hidden", "Width of the node in hidden state"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "height"); RNA_def_property_float_funcs(prop, NULL, NULL, "rna_Node_height_range"); RNA_def_property_ui_text(prop, "Height", "Height of the node"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "dimensions", PROP_FLOAT, PROP_XYZ_LENGTH); RNA_def_property_array(prop, 2); RNA_def_property_float_funcs(prop, "rna_Node_dimensions_get", NULL, NULL); RNA_def_property_ui_text(prop, "Dimensions", "Absolute bounding box dimensions of the node"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Name", "Unique node identifier"); RNA_def_struct_name_property(srna, prop); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Node_name_set"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "label", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "label"); RNA_def_property_ui_text(prop, "Label", "Optional custom node label"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "inputs", NULL); RNA_def_property_struct_type(prop, "NodeSocket"); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Inputs", ""); rna_def_node_sockets_api(brna, prop, SOCK_IN); prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "outputs", NULL); RNA_def_property_struct_type(prop, "NodeSocket"); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Outputs", ""); rna_def_node_sockets_api(brna, prop, SOCK_OUT); prop = RNA_def_property(srna, "internal_links", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "internal_links", NULL); RNA_def_property_struct_type(prop, "NodeLink"); RNA_def_property_ui_text( prop, "Internal Links", "Internal input-to-output connections for muting"); prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "parent"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Node_parent_set", NULL, "rna_Node_parent_poll"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_struct_type(prop, "Node"); RNA_def_property_ui_text(prop, "Parent", "Parent this node is attached to"); prop = RNA_def_property(srna, "use_custom_color", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_CUSTOM_COLOR); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Custom Color", "Use custom color for the node"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Color", "Custom color of the node body"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SELECT); RNA_def_property_boolean_funcs(prop, NULL, "rna_Node_select_set"); RNA_def_property_ui_text(prop, "Select", "Node selection state"); RNA_def_property_update(prop, NC_NODE | NA_SELECTED, NULL); prop = RNA_def_property(srna, "show_options", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_OPTIONS); RNA_def_property_ui_text(prop, "Show Options", ""); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "show_preview", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_PREVIEW); RNA_def_property_ui_text(prop, "Show Preview", ""); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_HIDDEN); RNA_def_property_ui_text(prop, "Hide", ""); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_MUTED); RNA_def_property_ui_text(prop, "Mute", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "show_texture", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_ACTIVE_TEXTURE); RNA_def_property_ui_text(prop, "Show Texture", "Display node in viewport textured shading mode"); RNA_def_property_update(prop, 0, "rna_Node_update"); /* generic property update function */ func = RNA_def_function(srna, "socket_value_update", "rna_Node_socket_value_update"); RNA_def_function_ui_description(func, "Update after property changes"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); func = RNA_def_function(srna, "is_registered_node_type", "rna_Node_is_registered_node_type"); RNA_def_function_ui_description(func, "True if a registered node type"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE); parm = RNA_def_boolean(func, "result", false, "Result", ""); RNA_def_function_return(func, parm); /* registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname"); RNA_def_property_flag(prop, PROP_REGISTER); RNA_def_property_ui_text(prop, "ID Name", ""); prop = RNA_def_property(srna, "bl_label", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "typeinfo->ui_name"); RNA_def_property_flag(prop, PROP_REGISTER); RNA_def_property_ui_text(prop, "Label", "The node label"); prop = RNA_def_property(srna, "bl_description", PROP_STRING, PROP_TRANSLATION); RNA_def_property_string_sdna(prop, NULL, "typeinfo->ui_description"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_icon", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "typeinfo->ui_icon"); RNA_def_property_enum_items(prop, rna_enum_icon_items); RNA_def_property_enum_default(prop, ICON_NODE); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_ui_text(prop, "Icon", "The node icon"); prop = RNA_def_property(srna, "bl_static_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "typeinfo->type"); RNA_def_property_enum_items(prop, dummy_static_type_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_node_static_type_itemf"); RNA_def_property_enum_default(prop, NODE_CUSTOM); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_ui_text(prop, "Static Type", "Node type (deprecated, use with care)"); /* type-based size properties */ prop = RNA_def_property(srna, "bl_width_default", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "typeinfo->width"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_width_min", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "typeinfo->minwidth"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_width_max", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "typeinfo->maxwidth"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_height_default", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "typeinfo->height"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_height_min", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "typeinfo->minheight"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_height_max", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_sdna(prop, NULL, "typeinfo->minheight"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); /* poll */ func = RNA_def_function(srna, "poll", NULL); RNA_def_function_ui_description( func, "If non-null output is returned, the node type can be added to the tree"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER); RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", "")); parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "poll_instance", NULL); RNA_def_function_ui_description( func, "If non-null output is returned, the node can be added to the tree"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", "")); parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* update */ func = RNA_def_function(srna, "update", NULL); RNA_def_function_ui_description( func, "Update on node graph topology changes (adding or removing nodes and links)"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); /* insert_link */ func = RNA_def_function(srna, "insert_link", NULL); RNA_def_function_ui_description(func, "Handle creation of a link to or from the node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "link", "NodeLink", "Link", "Node link that will be inserted"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* init */ func = RNA_def_function(srna, "init", NULL); RNA_def_function_ui_description(func, "Initialize a new instance of this node"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* copy */ func = RNA_def_function(srna, "copy", NULL); RNA_def_function_ui_description(func, "Initialize a new instance of this node from an existing node"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "node", "Node", "Node", "Existing node to copy"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* free */ func = RNA_def_function(srna, "free", NULL); RNA_def_function_ui_description(func, "Clean up node on removal"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); /* draw buttons */ func = RNA_def_function(srna, "draw_buttons", NULL); RNA_def_function_ui_description(func, "Draw node buttons"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* draw buttons extended */ func = RNA_def_function(srna, "draw_buttons_ext", NULL); RNA_def_function_ui_description(func, "Draw node buttons in the sidebar"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* dynamic label */ func = RNA_def_function(srna, "draw_label", NULL); RNA_def_function_ui_description(func, "Returns a dynamic label string"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_string(func, "label", NULL, MAX_NAME, "Label", ""); RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */ RNA_def_function_output(func, parm); } static void rna_def_node_link(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, "NodeLink", NULL); RNA_def_struct_ui_text(srna, "NodeLink", "Link between nodes in a node tree"); RNA_def_struct_sdna(srna, "bNodeLink"); RNA_def_struct_ui_icon(srna, ICON_NODE); prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_LINK_VALID); RNA_def_property_ui_text(prop, "Valid", "Link is valid"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL); prop = RNA_def_property(srna, "is_muted", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_LINK_MUTED); RNA_def_property_ui_text(prop, "Muted", "Link is muted and can be ignored"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL); prop = RNA_def_property(srna, "from_node", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "fromnode"); RNA_def_property_struct_type(prop, "Node"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_ui_text(prop, "From node", ""); prop = RNA_def_property(srna, "to_node", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "tonode"); RNA_def_property_struct_type(prop, "Node"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_ui_text(prop, "To node", ""); prop = RNA_def_property(srna, "from_socket", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "fromsock"); RNA_def_property_struct_type(prop, "NodeSocket"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_ui_text(prop, "From socket", ""); prop = RNA_def_property(srna, "to_socket", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "tosock"); RNA_def_property_struct_type(prop, "NodeSocket"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_ui_text(prop, "To socket", ""); prop = RNA_def_property(srna, "is_hidden", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_NodeLink_is_hidden_get", NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_ui_text(prop, "Is Hidden", "Link is hidden due to invisible sockets"); } static void rna_def_nodetree_nodes_api(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; PropertyRNA *parm, *prop; FunctionRNA *func; RNA_def_property_srna(cprop, "Nodes"); srna = RNA_def_struct(brna, "Nodes", NULL); RNA_def_struct_sdna(srna, "bNodeTree"); RNA_def_struct_ui_text(srna, "Nodes", "Collection of Nodes"); func = RNA_def_function(srna, "new", "rna_NodeTree_node_new"); RNA_def_function_ui_description(func, "Add a node to this node tree"); RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); /* XXX warning note should eventually be removed, * added this here to avoid frequent confusion with API changes from "type" to "bl_idname" */ parm = RNA_def_string( func, "type", NULL, MAX_NAME, "Type", "Type of node to add (Warning: should be same as node.bl_idname, not node.type!)"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return value */ parm = RNA_def_pointer(func, "node", "Node", "", "New node"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_NodeTree_node_remove"); RNA_def_function_ui_description(func, "Remove a node from this node tree"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "node", "Node", "", "The node to remove"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_NodeTree_node_clear"); RNA_def_function_ui_description(func, "Remove all nodes from this node tree"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Node"); RNA_def_property_pointer_funcs( prop, "rna_NodeTree_active_node_get", "rna_NodeTree_active_node_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); RNA_def_property_ui_text(prop, "Active Node", "Active node in this tree"); RNA_def_property_update(prop, NC_SCENE | ND_OB_ACTIVE, "rna_NodeTree_update"); } static void rna_def_nodetree_link_api(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; PropertyRNA *parm; FunctionRNA *func; RNA_def_property_srna(cprop, "NodeLinks"); srna = RNA_def_struct(brna, "NodeLinks", NULL); RNA_def_struct_sdna(srna, "bNodeTree"); RNA_def_struct_ui_text(srna, "Node Links", "Collection of Node Links"); func = RNA_def_function(srna, "new", "rna_NodeTree_link_new"); RNA_def_function_ui_description(func, "Add a node link to this node tree"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "input", "NodeSocket", "", "The input socket"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer(func, "output", "NodeSocket", "", "The output socket"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); RNA_def_boolean(func, "verify_limits", true, "Verify Limits", "Remove existing links if connection limit is exceeded"); /* return */ parm = RNA_def_pointer(func, "link", "NodeLink", "", "New node link"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_NodeTree_link_remove"); RNA_def_function_ui_description(func, "remove a node link from the node tree"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "link", "NodeLink", "", "The node link to remove"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_NodeTree_link_clear"); RNA_def_function_ui_description(func, "remove all node links from the node tree"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); } static void rna_def_node_tree_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int in_out) { StructRNA *srna; PropertyRNA *parm; FunctionRNA *func; const char *structtype = (in_out == SOCK_IN ? "NodeTreeInputs" : "NodeTreeOutputs"); const char *uiname = (in_out == SOCK_IN ? "Node Tree Inputs" : "Node Tree Outputs"); const char *newfunc = (in_out == SOCK_IN ? "rna_NodeTree_inputs_new" : "rna_NodeTree_outputs_new"); const char *clearfunc = (in_out == SOCK_IN ? "rna_NodeTree_inputs_clear" : "rna_NodeTree_outputs_clear"); const char *movefunc = (in_out == SOCK_IN ? "rna_NodeTree_inputs_move" : "rna_NodeTree_outputs_move"); RNA_def_property_srna(cprop, structtype); srna = RNA_def_struct(brna, structtype, NULL); RNA_def_struct_sdna(srna, "bNodeTree"); RNA_def_struct_ui_text(srna, uiname, "Collection of Node Tree Sockets"); func = RNA_def_function(srna, "new", newfunc); RNA_def_function_ui_description(func, "Add a socket to this node tree"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return value */ parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "New socket"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_NodeTree_socket_remove"); RNA_def_function_ui_description(func, "Remove a socket from this node tree"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "The socket to remove"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "clear", clearfunc); RNA_def_function_ui_description(func, "Remove all sockets from this node tree"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); func = RNA_def_function(srna, "move", movefunc); RNA_def_function_ui_description(func, "Move a socket to another position"); RNA_def_function_flag(func, FUNC_USE_MAIN); parm = RNA_def_int( func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int( func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } static void rna_def_nodetree(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; FunctionRNA *func; PropertyRNA *parm; static const EnumPropertyItem static_type_items[] = { {NTREE_UNDEFINED, "UNDEFINED", ICON_QUESTION, "Undefined", "Undefined type of nodes (can happen e.g. when a linked node tree goes missing)"}, {NTREE_SHADER, "SHADER", ICON_MATERIAL, "Shader", "Shader nodes"}, {NTREE_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture nodes"}, {NTREE_COMPOSIT, "COMPOSITING", ICON_RENDERLAYERS, "Compositing", "Compositing nodes"}, {NTREE_GEOMETRY, "GEOMETRY", ICON_GEOMETRY_NODES, "Geometry", "Geometry nodes"}, {0, NULL, 0, NULL, NULL}, }; srna = RNA_def_struct(brna, "NodeTree", "ID"); RNA_def_struct_ui_text( srna, "Node Tree", "Node tree consisting of linked nodes used for shading, textures and compositing"); RNA_def_struct_sdna(srna, "bNodeTree"); RNA_def_struct_ui_icon(srna, ICON_NODETREE); RNA_def_struct_refine_func(srna, "rna_NodeTree_refine"); RNA_def_struct_register_funcs(srna, "rna_NodeTree_register", "rna_NodeTree_unregister", NULL); prop = RNA_def_property(srna, "view_center", PROP_FLOAT, PROP_XYZ); RNA_def_property_array(prop, 2); RNA_def_property_float_sdna(prop, NULL, "view_center"); RNA_def_property_ui_text( prop, "", "The current location (offset) of the view for this Node Tree"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* AnimData */ rna_def_animdata_common(srna); /* Nodes Collection */ prop = RNA_def_property(srna, "nodes", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "nodes", NULL); RNA_def_property_struct_type(prop, "Node"); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Nodes", ""); rna_def_nodetree_nodes_api(brna, prop); /* NodeLinks Collection */ prop = RNA_def_property(srna, "links", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "links", NULL); RNA_def_property_struct_type(prop, "NodeLink"); RNA_def_property_ui_text(prop, "Links", ""); rna_def_nodetree_link_api(brna, prop); /* Grease Pencil */ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); RNA_def_property_struct_type(prop, "GreasePencil"); RNA_def_property_pointer_funcs( prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block"); RNA_def_property_update(prop, NC_NODE, NULL); prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_enum_items(prop, static_type_items); RNA_def_property_ui_text( prop, "Type", "Node Tree type (deprecated, bl_idname is the actual node tree type identifier)"); prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "inputs", NULL); RNA_def_property_struct_type(prop, "NodeSocketInterface"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Inputs", "Node tree inputs"); rna_def_node_tree_sockets_api(brna, prop, SOCK_IN); prop = RNA_def_property(srna, "active_input", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_funcs( prop, "rna_NodeTree_active_input_get", "rna_NodeTree_active_input_set", NULL); RNA_def_property_ui_text(prop, "Active Input", "Index of the active input"); RNA_def_property_update(prop, NC_NODE, NULL); prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "outputs", NULL); RNA_def_property_struct_type(prop, "NodeSocketInterface"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Outputs", "Node tree outputs"); rna_def_node_tree_sockets_api(brna, prop, SOCK_OUT); prop = RNA_def_property(srna, "active_output", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_funcs( prop, "rna_NodeTree_active_output_get", "rna_NodeTree_active_output_set", NULL); RNA_def_property_ui_text(prop, "Active Output", "Index of the active output"); RNA_def_property_update(prop, NC_NODE, NULL); /* exposed as a function for runtime interface type properties */ func = RNA_def_function(srna, "interface_update", "rna_NodeTree_interface_update"); RNA_def_function_ui_description(func, "Updated node group interface"); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname"); RNA_def_property_flag(prop, PROP_REGISTER); RNA_def_property_ui_text(prop, "ID Name", ""); prop = RNA_def_property(srna, "bl_label", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "typeinfo->ui_name"); RNA_def_property_flag(prop, PROP_REGISTER); RNA_def_property_ui_text(prop, "Label", "The node tree label"); prop = RNA_def_property(srna, "bl_description", PROP_STRING, PROP_TRANSLATION); RNA_def_property_string_sdna(prop, NULL, "typeinfo->ui_description"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_icon", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "typeinfo->ui_icon"); RNA_def_property_enum_items(prop, rna_enum_icon_items); RNA_def_property_enum_default(prop, ICON_NODETREE); RNA_def_property_flag(prop, PROP_REGISTER); RNA_def_property_ui_text(prop, "Icon", "The node tree icon"); /* poll */ func = RNA_def_function(srna, "poll", NULL); RNA_def_function_ui_description(func, "Check visibility in the editor"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", "")); /* update */ func = RNA_def_function(srna, "update", NULL); RNA_def_function_ui_description(func, "Update on editor changes"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); /* get a node tree from context */ func = RNA_def_function(srna, "get_from_context", NULL); RNA_def_function_ui_description(func, "Get a node tree from the context"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer( func, "result_1", "NodeTree", "Node Tree", "Active node tree from context"); RNA_def_function_output(func, parm); parm = RNA_def_pointer( func, "result_2", "ID", "Owner ID", "ID data-block that owns the node tree"); RNA_def_function_output(func, parm); parm = RNA_def_pointer( func, "result_3", "ID", "From ID", "Original ID data-block selected from the context"); RNA_def_function_output(func, parm); /* Check for support of a socket type with a type identifier. */ func = RNA_def_function(srna, "valid_socket_type", NULL); RNA_def_function_ui_description(func, "Check if the socket type is valid for the node tree"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL); parm = RNA_def_string( func, "idname", "NodeSocket", MAX_NAME, "Socket Type", "Identifier of the socket type"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL | PROP_THICK_WRAP, PARM_REQUIRED); RNA_def_function_return(func, RNA_def_boolean(func, "valid", false, "", "")); } static void rna_def_composite_nodetree(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, "CompositorNodeTree", "NodeTree"); RNA_def_struct_ui_text( srna, "Compositor Node Tree", "Node tree consisting of linked nodes used for compositing"); RNA_def_struct_sdna(srna, "bNodeTree"); RNA_def_struct_ui_icon(srna, ICON_RENDERLAYERS); prop = RNA_def_property(srna, "execution_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "execution_mode"); RNA_def_property_enum_items(prop, rna_enum_execution_mode_items); RNA_def_property_ui_text(prop, "Execution Mode", "Set how compositing is executed"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update"); prop = RNA_def_property(srna, "render_quality", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "render_quality"); RNA_def_property_enum_items(prop, node_quality_items); RNA_def_property_ui_text(prop, "Render Quality", "Quality when rendering"); prop = RNA_def_property(srna, "edit_quality", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "edit_quality"); RNA_def_property_enum_items(prop, node_quality_items); RNA_def_property_ui_text(prop, "Edit Quality", "Quality when editing"); prop = RNA_def_property(srna, "chunk_size", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "chunksize"); RNA_def_property_enum_items(prop, node_chunksize_items); RNA_def_property_ui_text(prop, "Chunksize", "Max size of a tile (smaller values gives better distribution " "of multiple threads, but more overhead)"); prop = RNA_def_property(srna, "use_opencl", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NTREE_COM_OPENCL); RNA_def_property_ui_text(prop, "OpenCL", "Enable GPU calculations"); prop = RNA_def_property(srna, "use_groupnode_buffer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NTREE_COM_GROUPNODE_BUFFER); RNA_def_property_ui_text(prop, "Buffer Groups", "Enable buffering of group nodes"); prop = RNA_def_property(srna, "use_two_pass", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NTREE_TWO_PASS); RNA_def_property_ui_text(prop, "Two Pass", "Use two pass execution during editing: first calculate fast nodes, " "second pass calculate all nodes"); prop = RNA_def_property(srna, "use_viewer_border", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NTREE_VIEWER_BORDER); RNA_def_property_ui_text( prop, "Viewer Region", "Use boundaries for viewer nodes and composite backdrop"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update"); } static void rna_def_shader_nodetree(BlenderRNA *brna) { StructRNA *srna; FunctionRNA *func; PropertyRNA *parm; srna = RNA_def_struct(brna, "ShaderNodeTree", "NodeTree"); RNA_def_struct_ui_text( srna, "Shader Node Tree", "Node tree consisting of linked nodes used for materials (and other shading data-blocks)"); RNA_def_struct_sdna(srna, "bNodeTree"); RNA_def_struct_ui_icon(srna, ICON_MATERIAL); func = RNA_def_function(srna, "get_output_node", "ntreeShaderOutputNode"); RNA_def_function_ui_description(func, "Return active shader output node for the specified target"); parm = RNA_def_enum( func, "target", prop_shader_output_target_items, SHD_OUTPUT_ALL, "Target", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "node", "ShaderNode", "Node", ""); RNA_def_function_return(func, parm); } static void rna_def_texture_nodetree(BlenderRNA *brna) { StructRNA *srna; srna = RNA_def_struct(brna, "TextureNodeTree", "NodeTree"); RNA_def_struct_ui_text( srna, "Texture Node Tree", "Node tree consisting of linked nodes used for textures"); RNA_def_struct_sdna(srna, "bNodeTree"); RNA_def_struct_ui_icon(srna, ICON_TEXTURE); } static void rna_def_geometry_nodetree(BlenderRNA *brna) { StructRNA *srna; srna = RNA_def_struct(brna, "GeometryNodeTree", "NodeTree"); RNA_def_struct_ui_text( srna, "Geometry Node Tree", "Node tree consisting of linked nodes used for geometries"); RNA_def_struct_sdna(srna, "bNodeTree"); RNA_def_struct_ui_icon(srna, ICON_NODETREE); } static StructRNA *define_specific_node(BlenderRNA *brna, const char *struct_name, const char *base_name, const char *ui_name, const char *ui_desc, void (*def_func)(StructRNA *)) { StructRNA *srna; FunctionRNA *func; PropertyRNA *parm; /* XXX hack, want to avoid "NodeInternal" prefix, * so use "Node" in NOD_static_types.h and replace here */ if (STREQ(base_name, "Node")) { base_name = "NodeInternal"; } srna = RNA_def_struct(brna, struct_name, base_name); RNA_def_struct_ui_text(srna, ui_name, ui_desc); RNA_def_struct_sdna(srna, "bNode"); func = RNA_def_function(srna, "is_registered_node_type", "rna_Node_is_registered_node_type"); RNA_def_function_ui_description(func, "True if a registered node type"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE); parm = RNA_def_boolean(func, "result", false, "Result", ""); RNA_def_function_return(func, parm); /* Exposes the socket template type lists in RNA for use in scripts * Only used in the C nodes and not exposed in the base class to * keep the namespace clean for py-nodes. */ func = RNA_def_function(srna, "input_template", "rna_NodeInternal_input_template"); RNA_def_function_ui_description(func, "Input socket template"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE); parm = RNA_def_property(func, "index", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text(parm, "Index", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_property(func, "result", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "NodeInternalSocketTemplate"); RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "output_template", "rna_NodeInternal_output_template"); RNA_def_function_ui_description(func, "Output socket template"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE); parm = RNA_def_property(func, "index", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text(parm, "Index", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_property(func, "result", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "NodeInternalSocketTemplate"); RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); if (def_func) { def_func(srna); } return srna; } static void rna_def_node_instance_hash(BlenderRNA *brna) { StructRNA *srna; srna = RNA_def_struct(brna, "NodeInstanceHash", NULL); RNA_def_struct_ui_text(srna, "Node Instance Hash", "Hash table containing node instance data"); /* XXX This type is a stub for now, only used to store instance hash in the context. * Eventually could use a StructRNA pointer to define a specific data type * and expose lookup functions. */ } void RNA_def_nodetree(BlenderRNA *brna) { StructRNA *srna; rna_def_node_socket(brna); rna_def_node_socket_interface(brna); rna_def_node(brna); rna_def_node_link(brna); rna_def_internal_node(brna); rna_def_shader_node(brna); rna_def_compositor_node(brna); rna_def_texture_node(brna); rna_def_geometry_node(brna); rna_def_function_node(brna); rna_def_nodetree(brna); rna_def_node_socket_standard_types(brna); rna_def_composite_nodetree(brna); rna_def_shader_nodetree(brna); rna_def_texture_nodetree(brna); rna_def_geometry_nodetree(brna); # define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ { \ srna = define_specific_node( \ brna, #Category #StructName, #Category, UIName, UIDesc, DefFunc); \ if (ID == CMP_NODE_OUTPUT_FILE) { \ /* needs brna argument, can't use NOD_static_types.h */ \ def_cmp_output_file(brna, srna); \ } \ } /* hack, don't want to add include path to RNA just for this, since in the future RNA types * for nodes should be defined locally at runtime anyway ... */ # include "../../nodes/NOD_static_types.h" /* Node group types need to be defined for shader, compositor, texture, geometry nodes * individually. Cannot use the static types header for this, since they share the same int id. */ define_specific_node(brna, "ShaderNodeGroup", "ShaderNode", "Group", "", def_group); define_specific_node(brna, "CompositorNodeGroup", "CompositorNode", "Group", "", def_group); define_specific_node(brna, "TextureNodeGroup", "TextureNode", "Group", "", def_group); define_specific_node(brna, "GeometryNodeGroup", "GeometryNode", "Group", "", def_group); def_custom_group(brna, "ShaderNodeCustomGroup", "ShaderNode", "Shader Custom Group", "Custom Shader Group Node for Python nodes", "rna_ShaderNodeCustomGroup_register"); def_custom_group(brna, "CompositorNodeCustomGroup", "CompositorNode", "Compositor Custom Group", "Custom Compositor Group Node for Python nodes", "rna_CompositorNodeCustomGroup_register"); def_custom_group(brna, "NodeCustomGroup", "Node", "Custom Group", "Base node type for custom registered node group types", "rna_NodeCustomGroup_register"); def_custom_group(brna, "GeometryNodeCustomGroup", "GeometryNode", "Geometry Custom Group", "Custom Geometry Group Node for Python nodes", "rna_GeometryNodeCustomGroup_register"); /* special socket types */ rna_def_cmp_output_file_slot_file(brna); rna_def_cmp_output_file_slot_layer(brna); rna_def_node_instance_hash(brna); } /* clean up macro definition */ # undef NODE_DEFINE_SUBTYPES #endif diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index e16cd7a253f..3701694b14a 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -1,152 +1,153 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include "BKE_node.h" #ifdef __cplusplus extern "C" { #endif extern struct bNodeTreeType *ntreeType_Geometry; void register_node_tree_type_geo(void); void register_node_type_geo_group(void); void register_node_type_geo_custom_group(bNodeType *ntype); void register_node_type_geo_accumulate_field(void); void register_node_type_geo_attribute_capture(void); void register_node_type_geo_attribute_domain_size(void); void register_node_type_geo_attribute_separate_xyz(void); void register_node_type_geo_attribute_statistic(void); void register_node_type_geo_boolean(void); void register_node_type_geo_bounding_box(void); void register_node_type_geo_collection_info(void); void register_node_type_geo_convex_hull(void); void register_node_type_geo_curve_endpoint_selection(void); void register_node_type_geo_curve_fill(void); void register_node_type_geo_curve_fillet(void); void register_node_type_geo_curve_handle_type_selection(void); void register_node_type_geo_curve_length(void); void register_node_type_geo_curve_primitive_arc(void); void register_node_type_geo_curve_primitive_bezier_segment(void); void register_node_type_geo_curve_primitive_circle(void); void register_node_type_geo_curve_primitive_line(void); void register_node_type_geo_curve_primitive_quadratic_bezier(void); void register_node_type_geo_curve_primitive_quadrilateral(void); void register_node_type_geo_curve_primitive_spiral(void); void register_node_type_geo_curve_primitive_star(void); void register_node_type_geo_curve_resample(void); void register_node_type_geo_curve_reverse(void); void register_node_type_geo_curve_sample(void); void register_node_type_geo_curve_set_handle_type(void); void register_node_type_geo_curve_spline_parameter(void); void register_node_type_geo_curve_spline_type(void); void register_node_type_geo_curve_subdivide(void); void register_node_type_geo_curve_to_mesh(void); void register_node_type_geo_curve_to_points(void); void register_node_type_geo_curve_trim(void); void register_node_type_geo_deform_curves_on_surface(void); void register_node_type_geo_delete_geometry(void); void register_node_type_geo_distribute_points_on_faces(void); void register_node_type_geo_dual_mesh(void); void register_node_type_geo_duplicate_elements(void); void register_node_type_geo_edge_paths_to_curves(void); void register_node_type_geo_edge_paths_to_selection(void); void register_node_type_geo_edge_split(void); void register_node_type_geo_extrude_mesh(void); void register_node_type_geo_field_at_index(void); void register_node_type_geo_flip_faces(void); void register_node_type_geo_geometry_to_instance(void); void register_node_type_geo_image_texture(void); void register_node_type_geo_input_curve_handles(void); void register_node_type_geo_input_curve_tilt(void); void register_node_type_geo_input_id(void); void register_node_type_geo_input_index(void); void register_node_type_geo_input_instance_rotation(void); void register_node_type_geo_input_instance_scale(void); void register_node_type_geo_input_material_index(void); void register_node_type_geo_input_material(void); void register_node_type_geo_input_mesh_edge_angle(void); void register_node_type_geo_input_mesh_edge_neighbors(void); void register_node_type_geo_input_mesh_edge_vertices(void); void register_node_type_geo_input_mesh_face_area(void); void register_node_type_geo_input_mesh_face_is_planar(void); void register_node_type_geo_input_mesh_face_neighbors(void); void register_node_type_geo_input_mesh_island(void); void register_node_type_geo_input_mesh_vertex_neighbors(void); void register_node_type_geo_input_named_attribute(void); void register_node_type_geo_input_normal(void); void register_node_type_geo_input_position(void); void register_node_type_geo_input_radius(void); void register_node_type_geo_input_scene_time(void); void register_node_type_geo_input_shade_smooth(void); void register_node_type_geo_input_shortest_edge_paths(void); void register_node_type_geo_input_spline_cyclic(void); void register_node_type_geo_input_spline_length(void); void register_node_type_geo_input_spline_resolution(void); void register_node_type_geo_input_tangent(void); void register_node_type_geo_instance_on_points(void); void register_node_type_geo_instances_to_points(void); void register_node_type_geo_interpolate_domain(void); void register_node_type_geo_is_viewport(void); void register_node_type_geo_join_geometry(void); void register_node_type_geo_material_replace(void); void register_node_type_geo_material_selection(void); void register_node_type_geo_merge_by_distance(void); void register_node_type_geo_mesh_primitive_circle(void); void register_node_type_geo_mesh_primitive_cone(void); void register_node_type_geo_mesh_primitive_cube(void); void register_node_type_geo_mesh_primitive_cylinder(void); void register_node_type_geo_mesh_primitive_grid(void); void register_node_type_geo_mesh_primitive_ico_sphere(void); void register_node_type_geo_mesh_primitive_line(void); void register_node_type_geo_mesh_primitive_uv_sphere(void); void register_node_type_geo_mesh_subdivide(void); void register_node_type_geo_mesh_to_curve(void); void register_node_type_geo_mesh_to_points(void); void register_node_type_geo_mesh_to_volume(void); void register_node_type_geo_object_info(void); void register_node_type_geo_points_to_vertices(void); void register_node_type_geo_points_to_volume(void); void register_node_type_geo_points(void); void register_node_type_geo_proximity(void); void register_node_type_geo_raycast(void); void register_node_type_geo_realize_instances(void); void register_node_type_geo_remove_attribute(void); void register_node_type_geo_rotate_instances(void); void register_node_type_geo_scale_elements(void); void register_node_type_geo_scale_instances(void); void register_node_type_geo_select_by_handle_type(void); void register_node_type_geo_separate_components(void); void register_node_type_geo_separate_geometry(void); void register_node_type_geo_set_curve_handles(void); void register_node_type_geo_set_curve_radius(void); void register_node_type_geo_set_curve_tilt(void); void register_node_type_geo_set_id(void); void register_node_type_geo_set_material_index(void); void register_node_type_geo_set_material(void); void register_node_type_geo_set_point_radius(void); void register_node_type_geo_set_position(void); void register_node_type_geo_set_shade_smooth(void); void register_node_type_geo_set_spline_cyclic(void); void register_node_type_geo_set_spline_resolution(void); +void register_node_type_geo_smooth_attribute(void); void register_node_type_geo_store_named_attribute(void); void register_node_type_geo_string_join(void); void register_node_type_geo_string_to_curves(void); void register_node_type_geo_subdivision_surface(void); void register_node_type_geo_switch(void); void register_node_type_geo_transfer_attribute(void); void register_node_type_geo_transform(void); void register_node_type_geo_translate_instances(void); void register_node_type_geo_triangulate(void); void register_node_type_geo_uv_pack_islands(void); void register_node_type_geo_uv_unwrap(void); void register_node_type_geo_viewer(void); void register_node_type_geo_volume_cube(void); void register_node_type_geo_volume_to_mesh(void); #ifdef __cplusplus } #endif diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index d587da823f1..151ef41669d 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -1,416 +1,417 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup nodes */ /* intentionally no include guard */ /* Keep aligned args for readability. */ /* clang-format off */ /* Empty definitions for undefined macros to avoid warnings */ #ifndef DefNode #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) #endif /* WARNING! If you edit those strings, please do the same in relevant nodes files (under blender/nodes/...)! */ /* Tree type Node ID RNA def function Enum name Struct name UI Name UI Description */ DefNode(Node, NODE_FRAME, def_frame, "FRAME", Frame, "Frame", "Collect related nodes together in a common area. Useful for organization when the re-usability of a node group is not required") DefNode(Node, NODE_GROUP, def_group, "GROUP", Group, "Group", "") DefNode(Node, NODE_GROUP_INPUT, def_group_input, "GROUP_INPUT", GroupInput, "Group Input", "Expose connected data from inside a node group as inputs to its interface") DefNode(Node, NODE_GROUP_OUTPUT, def_group_output, "GROUP_OUTPUT", GroupOutput, "Group Output", "Output data from inside of a node group") DefNode(Node, NODE_REROUTE, 0, "REROUTE", Reroute, "Reroute", "A single-socket organization tool that supports one input and multiple outputs") DefNode(ShaderNode, SH_NODE_RGB, 0, "RGB", RGB, "RGB", "A color picker") DefNode(ShaderNode, SH_NODE_VALUE, 0, "VALUE", Value, "Value", "Used to Input numerical values to other nodes in the tree") DefNode(ShaderNode, SH_NODE_MIX_RGB_LEGACY, def_mix_rgb, "MIX_RGB", MixRGB, "MixRGB", "Mix two input colors") DefNode(ShaderNode, SH_NODE_VALTORGB, def_colorramp, "VALTORGB", ValToRGB, "ColorRamp", "Map values to colors with the use of a gradient") DefNode(ShaderNode, SH_NODE_RGBTOBW, 0, "RGBTOBW", RGBToBW, "RGB to BW", "Convert a color's luminance to a grayscale value") DefNode(ShaderNode, SH_NODE_SHADERTORGB, 0, "SHADERTORGB", ShaderToRGB, "Shader to RGB", "Convert rendering effect (such as light and shadow) to color. Typically used for non-photorealistic rendering, to apply additional effects on the output of BSDFs.\nNote: only supported for Eevee") DefNode(ShaderNode, SH_NODE_NORMAL, 0, "NORMAL", Normal, "Normal", "Generate a normal vector and a dot product") DefNode(ShaderNode, SH_NODE_GAMMA, 0, "GAMMA", Gamma, "Gamma", "Apply a gamma correction") DefNode(ShaderNode, SH_NODE_BRIGHTCONTRAST, 0, "BRIGHTCONTRAST", BrightContrast, "Bright Contrast", "Control the brightness and contrast of the input color") DefNode(ShaderNode, SH_NODE_MAPPING, def_sh_mapping, "MAPPING", Mapping, "Mapping", "Transform the input vector by applying translation, rotation, and scale") DefNode(ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_VEC", VectorCurve, "Vector Curves", "Map an input vectors to curves, used to fine-tune the interpolation of the input") DefNode(ShaderNode, SH_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", RGBCurve, "RGB Curves", "Apply color corrections for each color channel") DefNode(ShaderNode, SH_NODE_CAMERA, 0, "CAMERA", CameraData, "Camera Data", "Retrieve information about the camera and how it relates to the current shading point's position") DefNode(ShaderNode, SH_NODE_MAP_RANGE, def_map_range, "MAP_RANGE", MapRange, "Map Range", "Remap a value from a range to a target range") DefNode(ShaderNode, SH_NODE_CLAMP, def_clamp, "CLAMP", Clamp, "Clamp", "Clamp a value between a minimum and a maximum") DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "Perform math operations") DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "Perform vector math operation") DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "") DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "Invert a color, producing a negative") DefNode(ShaderNode, SH_NODE_SEPRGB_LEGACY, 0, "SEPRGB", SeparateRGB, "Separate RGB", "Split a color into its red, green, and blue channels (Deprecated)") DefNode(ShaderNode, SH_NODE_COMBRGB_LEGACY, 0, "COMBRGB", CombineRGB, "Combine RGB", "Generate a color from its red, green, and blue channels (Deprecated)") DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue Saturation Value","Apply a color transformation in the HSV color model") DefNode(ShaderNode, SH_NODE_OUTPUT_MATERIAL, def_sh_output, "OUTPUT_MATERIAL", OutputMaterial, "Material Output", "Output surface material information for use in rendering") DefNode(ShaderNode, SH_NODE_EEVEE_SPECULAR, 0, "EEVEE_SPECULAR", EeveeSpecular, "Specular BSDF", "Similar to the Principled BSDF node but uses the specular workflow instead of metallic, which functions by specifying the facing (along normal) reflection color. Energy is not conserved, so the result may not be physically accurate") DefNode(ShaderNode, SH_NODE_OUTPUT_LIGHT, def_sh_output, "OUTPUT_LIGHT", OutputLight, "Light Output", "Output light information to a light object") DefNode(ShaderNode, SH_NODE_OUTPUT_WORLD, def_sh_output, "OUTPUT_WORLD", OutputWorld, "World Output", "Output light color information to the scene's World") DefNode(ShaderNode, SH_NODE_OUTPUT_LINESTYLE, def_sh_output_linestyle,"OUTPUT_LINESTYLE", OutputLineStyle, "Line Style Output", "") DefNode(ShaderNode, SH_NODE_FRESNEL, 0, "FRESNEL", Fresnel, "Fresnel", "Produce a blending factor depending on the angle between the surface normal and the view direction using Fresnel equations.\nTypically used for mixing reflections at grazing angles") DefNode(ShaderNode, SH_NODE_LAYER_WEIGHT, 0, "LAYER_WEIGHT", LayerWeight, "Layer Weight", "Produce a blending factor depending on the angle between the surface normal and the view direction.\nTypically used for layering shaders with the Mix Shader node") DefNode(ShaderNode, SH_NODE_MIX_SHADER, 0, "MIX_SHADER", MixShader, "Mix Shader", "Mix two shaders together. Typically used for material layering") DefNode(ShaderNode, SH_NODE_ADD_SHADER, 0, "ADD_SHADER", AddShader, "Add Shader", "Add two Shaders together") DefNode(ShaderNode, SH_NODE_ATTRIBUTE, def_sh_attribute, "ATTRIBUTE", Attribute, "Attribute", "Retrieve attributes attached to objects or geometry") DefNode(ShaderNode, SH_NODE_AMBIENT_OCCLUSION, def_sh_ambient_occlusion,"AMBIENT_OCCLUSION", AmbientOcclusion, "Ambient Occlusion", "Compute how much the hemisphere above the shading point is occluded, for example to add weathering effects to corners.\nNote: For Cycles, this may slow down renders significantly") DefNode(ShaderNode, SH_NODE_BACKGROUND, 0, "BACKGROUND", Background, "Background", "Add background light emission.\nNote: This node should only be used for the world surface output") DefNode(ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "Create a \"hole\" in the image with zero alpha transparency, which is useful for compositing.\nNote: the holdout shader can only create alpha when transparency is enabled in the film settings") DefNode(ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic BSDF", "Glossy reflection with separate control over U and V direction roughness") DefNode(ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "Lambertian and Oren-Nayar diffuse reflection") DefNode(ShaderNode, SH_NODE_BSDF_PRINCIPLED, def_principled, "BSDF_PRINCIPLED", BsdfPrincipled, "Principled BSDF", "Physically-based, easy-to-use shader for rendering surface materials, based on the Disney principled model also known as the \"PBR\" shader") DefNode(ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "Reflection with microfacet distribution, used for materials such as metal or mirrors") DefNode(ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "Glass-like shader mixing refraction and reflection at grazing angles") DefNode(ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "Glossy refraction with sharp or microfacet distribution, typically used for materials that transmit light") DefNode(ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "Lambertian diffuse transmission") DefNode(ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "Transparency without refraction, passing straight through the surface as if there were no geometry") DefNode(ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "Reflection for materials such as cloth.\nTypically mixed with other shaders (such as a Diffuse Shader) and is not particularly useful on its own") DefNode(ShaderNode, SH_NODE_BSDF_TOON, def_toon, "BSDF_TOON", BsdfToon, "Toon BSDF", "Diffuse and Glossy shaders with cartoon light effects") DefNode(ShaderNode, SH_NODE_BSDF_HAIR, def_hair, "BSDF_HAIR", BsdfHair, "Hair BSDF", "Reflection and transmission shaders optimized for hair rendering") DefNode(ShaderNode, SH_NODE_BSDF_HAIR_PRINCIPLED, def_hair_principled, "BSDF_HAIR_PRINCIPLED", BsdfHairPrincipled, "Principled Hair BSDF", "Physically-based, easy-to-use shader for rendering hair and fur") DefNode(ShaderNode, SH_NODE_SUBSURFACE_SCATTERING, def_sh_subsurface, "SUBSURFACE_SCATTERING",SubsurfaceScattering,"Subsurface Scattering","Subsurface multiple scattering shader to simulate light entering the surface and bouncing internally.\nTypically used for materials such as skin, wax, marble or milk") DefNode(ShaderNode, SH_NODE_VOLUME_ABSORPTION, 0, "VOLUME_ABSORPTION", VolumeAbsorption, "Volume Absorption", "Absorb light as it passes through the volume") DefNode(ShaderNode, SH_NODE_VOLUME_SCATTER, 0, "VOLUME_SCATTER", VolumeScatter, "Volume Scatter", "Scatter light as it passes through the volume, often used to add fog to a scene") DefNode(ShaderNode, SH_NODE_VOLUME_PRINCIPLED, 0, "PRINCIPLED_VOLUME", VolumePrincipled, "Principled Volume", "Combine all volume shading components into a single easy to use node") DefNode(ShaderNode, SH_NODE_EMISSION, 0, "EMISSION", Emission, "Emission", "Lambertian emission shader") DefNode(ShaderNode, SH_NODE_NEW_GEOMETRY, 0, "NEW_GEOMETRY", NewGeometry, "Geometry", "Retrieve geometric information about the current shading point") DefNode(ShaderNode, SH_NODE_LIGHT_PATH, 0, "LIGHT_PATH", LightPath, "Light Path", "Retrieve the type of incoming ray for which the shader is being executed.\nTypically used for non-physically-based tricks") DefNode(ShaderNode, SH_NODE_LIGHT_FALLOFF, 0, "LIGHT_FALLOFF", LightFalloff, "Light Falloff", "Manipulate how light intensity decreases over distance. Typically used for non-physically-based effects; in reality light always falls off quadratically") DefNode(ShaderNode, SH_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "Retrieve information about the object instance") DefNode(ShaderNode, SH_NODE_PARTICLE_INFO, 0, "PARTICLE_INFO", ParticleInfo, "Particle Info", "Retrieve the data of the particle that spawned the object instance, for example to give variation to multiple instances of an object") DefNode(ShaderNode, SH_NODE_HAIR_INFO, 0, "HAIR_INFO", HairInfo, "Curves Info", "Retrieve hair curve information") DefNode(ShaderNode, SH_NODE_POINT_INFO, 0, "POINT_INFO", PointInfo, "Point Info", "Retrieve information about points in a point cloud") DefNode(ShaderNode, SH_NODE_VOLUME_INFO, 0, "VOLUME_INFO", VolumeInfo, "Volume Info", "Read volume data attributes from volume grids") DefNode(ShaderNode, SH_NODE_WIREFRAME, def_sh_tex_wireframe, "WIREFRAME", Wireframe, "Wireframe", "Retrieve the edges of an object as it appears to Cycles.\nNote: as meshes are triangulated before being processed by Cycles, topology will always appear triangulated") DefNode(ShaderNode, SH_NODE_WAVELENGTH, 0, "WAVELENGTH", Wavelength, "Wavelength", "Convert a wavelength value to an RGB value") DefNode(ShaderNode, SH_NODE_BLACKBODY, 0, "BLACKBODY", Blackbody, "Blackbody", "Convert a blackbody temperature to an RGB value") DefNode(ShaderNode, SH_NODE_BUMP, def_sh_bump, "BUMP", Bump, "Bump", "Generate a perturbed normal from a height texture for bump mapping. Typically used for faking highly detailed surfaces") DefNode(ShaderNode, SH_NODE_NORMAL_MAP, def_sh_normal_map, "NORMAL_MAP", NormalMap, "Normal Map", "Generate a perturbed normal from an RGB normal map image. Typically used for faking highly detailed surfaces") DefNode(ShaderNode, SH_NODE_TANGENT, def_sh_tangent, "TANGENT", Tangent, "Tangent", "Generate a tangent direction for the Anisotropic BSDF") DefNode(ShaderNode, SH_NODE_SCRIPT, def_sh_script, "SCRIPT", Script, "Script", "Generate an OSL shader from a file or text data-block.\nNote: OSL shaders are not supported on the GPU") DefNode(ShaderNode, SH_NODE_TEX_IMAGE, def_sh_tex_image, "TEX_IMAGE", TexImage, "Image Texture", "Sample an image file as a texture") DefNode(ShaderNode, SH_NODE_TEX_ENVIRONMENT, def_sh_tex_environment, "TEX_ENVIRONMENT", TexEnvironment, "Environment Texture","Sample an image file as an environment texture. Typically used to light the scene with the background node") DefNode(ShaderNode, SH_NODE_TEX_SKY, def_sh_tex_sky, "TEX_SKY", TexSky, "Sky Texture", "Generate a procedural sky texture") DefNode(ShaderNode, SH_NODE_TEX_GRADIENT, def_sh_tex_gradient, "TEX_GRADIENT", TexGradient, "Gradient Texture", "Generate interpolated color and intensity values based on the input vector") DefNode(ShaderNode, SH_NODE_TEX_NOISE, def_sh_tex_noise, "TEX_NOISE", TexNoise, "Noise Texture", "Generate fractal Perlin noise") DefNode(ShaderNode, SH_NODE_TEX_MAGIC, def_sh_tex_magic, "TEX_MAGIC", TexMagic, "Magic Texture", "Generate a psychedelic color texture") DefNode(ShaderNode, SH_NODE_TEX_WAVE, def_sh_tex_wave, "TEX_WAVE", TexWave, "Wave Texture", "Generate procedural bands or rings with noise") DefNode(ShaderNode, SH_NODE_TEX_MUSGRAVE, def_sh_tex_musgrave, "TEX_MUSGRAVE", TexMusgrave, "Musgrave Texture", "Generate fractal Perlin noise. Allows for greater control over how octaves are combined than the Noise Texture node") DefNode(ShaderNode, SH_NODE_TEX_VORONOI, def_sh_tex_voronoi, "TEX_VORONOI", TexVoronoi, "Voronoi Texture", "Generate Worley noise based on the distance to random points. Typically used to generate textures such as stones, water, or biological cells") DefNode(ShaderNode, SH_NODE_TEX_CHECKER, def_sh_tex_checker, "TEX_CHECKER", TexChecker, "Checker Texture", "Generate a checkerboard texture") DefNode(ShaderNode, SH_NODE_TEX_BRICK, def_sh_tex_brick, "TEX_BRICK", TexBrick, "Brick Texture", "Generate a procedural texture producing bricks") DefNode(ShaderNode, SH_NODE_TEX_POINTDENSITY, def_sh_tex_pointdensity,"TEX_POINTDENSITY", TexPointDensity, "Point Density", "Generate a volumetric point for each particle or vertex of another object") DefNode(ShaderNode, SH_NODE_TEX_COORD, def_sh_tex_coord, "TEX_COORD", TexCoord, "Texture Coordinate","Retrieve multiple types of texture coordinates.\nTypically used as inputs for texture nodes") DefNode(ShaderNode, SH_NODE_VECTOR_ROTATE, def_sh_vector_rotate, "VECTOR_ROTATE", VectorRotate, "Vector Rotate", "Rotate a vector around a pivot point (center)") DefNode(ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VECT_TRANSFORM", VectorTransform, "Vector Transform", "Convert a vector, point, or normal between world, camera, and object coordinate space") DefNode(ShaderNode, SH_NODE_SEPHSV_LEGACY, 0, "SEPHSV", SeparateHSV, "Separate HSV", "Split a color into its hue, saturation, and value channels") DefNode(ShaderNode, SH_NODE_COMBHSV_LEGACY, 0, "COMBHSV", CombineHSV, "Combine HSV", "Create a color from its hue, saturation, and value channels") DefNode(ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UVMAP", UVMap, "UV Map", "Retrieve a UV map from the geometry, or the default fallback if none is specified") DefNode(ShaderNode, SH_NODE_VERTEX_COLOR, def_sh_vertex_color, "VERTEX_COLOR", VertexColor, "Color Attribute", "Retrieve a color attribute, or the default fallback if none is specified") DefNode(ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "") DefNode(ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "Split a vector into its X, Y, and Z components") DefNode(ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "Create a vector from X, Y, and Z components") DefNode(ShaderNode, SH_NODE_BEVEL, def_sh_bevel, "BEVEL", Bevel, "Bevel", "Generates normals with round corners.\nNote: only supported in Cycles, and may slow down renders") DefNode(ShaderNode, SH_NODE_DISPLACEMENT, def_sh_displacement, "DISPLACEMENT", Displacement, "Displacement", "Displace the surface along the surface normal") DefNode(ShaderNode, SH_NODE_VECTOR_DISPLACEMENT,def_sh_vector_displacement,"VECTOR_DISPLACEMENT",VectorDisplacement,"Vector Displacement","Displace the surface along an arbitrary direction") DefNode(ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX_IES", TexIES, "IES Texture", "Used to match real world lights with IES files, which store the directional intensity distribution of light sources") DefNode(ShaderNode, SH_NODE_TEX_WHITE_NOISE, def_sh_tex_white_noise, "TEX_WHITE_NOISE", TexWhiteNoise, "White Noise", "Return a random value or color based on an input seed") DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUTPUT_AOV", OutputAOV, "AOV Output", "Arbitrary Output Variables.\nProvide custom render passes for arbitrary shader node outputs") DefNode(ShaderNode, SH_NODE_CURVE_FLOAT, def_float_curve, "CURVE_FLOAT", FloatCurve, "Float Curve", "Map an input float to a curve and outputs a float value") DefNode(ShaderNode, SH_NODE_COMBINE_COLOR, def_sh_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "Create a color from individual components using multiple models") DefNode(ShaderNode, SH_NODE_SEPARATE_COLOR, def_sh_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "Split a color into its individual components using multiple models") DefNode(ShaderNode, SH_NODE_MIX, def_sh_mix, "MIX", Mix, "Mix", "Mix values by a factor") DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" ) DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" ) DefNode(CompositorNode, CMP_NODE_VALUE, 0, "VALUE", Value, "Value", "" ) DefNode(CompositorNode, CMP_NODE_MIX_RGB, def_mix_rgb, "MIX_RGB", MixRGB, "Mix", "" ) DefNode(CompositorNode, CMP_NODE_VALTORGB, def_colorramp, "VALTORGB", ValToRGB, "ColorRamp", "" ) DefNode(CompositorNode, CMP_NODE_RGBTOBW, 0, "RGBTOBW", RGBToBW, "RGB to BW", "" ) DefNode(CompositorNode, CMP_NODE_NORMAL, 0, "NORMAL", Normal, "Normal", "" ) DefNode(CompositorNode, CMP_NODE_CURVE_VEC, def_vector_curve, "CURVE_VEC", CurveVec, "Vector Curves", "" ) DefNode(CompositorNode, CMP_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", CurveRGB, "RGB Curves", "" ) DefNode(CompositorNode, CMP_NODE_ALPHAOVER, def_cmp_alpha_over, "ALPHAOVER", AlphaOver, "Alpha Over", "" ) DefNode(CompositorNode, CMP_NODE_BLUR, def_cmp_blur, "BLUR", Blur, "Blur", "" ) DefNode(CompositorNode, CMP_NODE_FILTER, def_cmp_filter, "FILTER", Filter, "Filter", "" ) DefNode(CompositorNode, CMP_NODE_MAP_VALUE, def_cmp_map_value, "MAP_VALUE", MapValue, "Map Value", "" ) DefNode(CompositorNode, CMP_NODE_MAP_RANGE, def_cmp_map_range, "MAP_RANGE", MapRange, "Map Range", "" ) DefNode(CompositorNode, CMP_NODE_TIME, def_time, "TIME", Time, "Time Curve", "" ) DefNode(CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBLUR", VecBlur, "Vector Blur", "" ) DefNode(CompositorNode, CMP_NODE_SEPRGBA_LEGACY, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" ) DefNode(CompositorNode, CMP_NODE_SEPHSVA_LEGACY, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" ) DefNode(CompositorNode, CMP_NODE_SETALPHA, def_cmp_set_alpha, "SETALPHA", SetAlpha, "Set Alpha", "" ) DefNode(CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SAT", HueSat, "Hue Saturation Value","" ) DefNode(CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" ) DefNode(CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" ) DefNode(CompositorNode, CMP_NODE_COMPOSITE, def_cmp_composite, "COMPOSITE", Composite, "Composite", "" ) /* NOTE: #OutputFile node has special RNA setup function called in rna_nodetree.c */ DefNode(CompositorNode, CMP_NODE_OUTPUT_FILE, 0, "OUTPUT_FILE", OutputFile, "File Output", "" ) DefNode(CompositorNode, CMP_NODE_TEXTURE, def_texture, "TEXTURE", Texture, "Texture", "" ) DefNode(CompositorNode, CMP_NODE_TRANSLATE, def_cmp_translate, "TRANSLATE", Translate, "Translate", "" ) DefNode(CompositorNode, CMP_NODE_ZCOMBINE, def_cmp_zcombine, "ZCOMBINE", Zcombine, "Z Combine", "" ) DefNode(CompositorNode, CMP_NODE_COMBRGBA_LEGACY,0, "COMBRGBA", CombRGBA, "Combine RGBA", "" ) DefNode(CompositorNode, CMP_NODE_DILATEERODE, def_cmp_dilate_erode, "DILATEERODE", DilateErode, "Dilate/Erode", "" ) DefNode(CompositorNode, CMP_NODE_INPAINT, def_cmp_inpaint, "INPAINT", Inpaint, "Inpaint", "" ) DefNode(CompositorNode, CMP_NODE_DESPECKLE, def_cmp_despeckle, "DESPECKLE", Despeckle, "Despeckle", "" ) DefNode(CompositorNode, CMP_NODE_ROTATE, def_cmp_rotate, "ROTATE", Rotate, "Rotate", "" ) DefNode(CompositorNode, CMP_NODE_SCALE, def_cmp_scale, "SCALE", Scale, "Scale", "" ) DefNode(CompositorNode, CMP_NODE_SEPYCCA_LEGACY, def_cmp_ycc, "SEPYCCA", SepYCCA, "Separate YCbCrA", "" ) DefNode(CompositorNode, CMP_NODE_COMBYCCA_LEGACY,def_cmp_ycc, "COMBYCCA", CombYCCA, "Combine YCbCrA", "" ) DefNode(CompositorNode, CMP_NODE_SEPYUVA_LEGACY, 0, "SEPYUVA", SepYUVA, "Separate YUVA", "" ) DefNode(CompositorNode, CMP_NODE_COMBYUVA_LEGACY,0, "COMBYUVA", CombYUVA, "Combine YUVA", "" ) DefNode(CompositorNode, CMP_NODE_DIFF_MATTE, def_cmp_diff_matte, "DIFF_MATTE", DiffMatte, "Difference Key", "" ) DefNode(CompositorNode, CMP_NODE_COLOR_SPILL, def_cmp_color_spill, "COLOR_SPILL", ColorSpill, "Color Spill", "" ) DefNode(CompositorNode, CMP_NODE_CHROMA_MATTE, def_cmp_chroma_matte, "CHROMA_MATTE", ChromaMatte, "Chroma Key", "" ) DefNode(CompositorNode, CMP_NODE_CHANNEL_MATTE, def_cmp_channel_matte, "CHANNEL_MATTE", ChannelMatte, "Channel Key", "" ) DefNode(CompositorNode, CMP_NODE_FLIP, def_cmp_flip, "FLIP", Flip, "Flip", "" ) DefNode(CompositorNode, CMP_NODE_SPLITVIEWER, def_cmp_splitviewer, "SPLITVIEWER", SplitViewer, "Split Viewer", "" ) DefNode(CompositorNode, CMP_NODE_MAP_UV, def_cmp_map_uv, "MAP_UV", MapUV, "Map UV", "" ) DefNode(CompositorNode, CMP_NODE_ID_MASK, def_cmp_id_mask, "ID_MASK", IDMask, "ID Mask", "" ) DefNode(CompositorNode, CMP_NODE_DOUBLEEDGEMASK, def_cmp_double_edge_mask,"DOUBLEEDGEMASK", DoubleEdgeMask, "Double Edge Mask", "" ) DefNode(CompositorNode, CMP_NODE_DEFOCUS, def_cmp_defocus, "DEFOCUS", Defocus, "Defocus", "" ) DefNode(CompositorNode, CMP_NODE_DISPLACE, 0, "DISPLACE", Displace, "Displace", "" ) DefNode(CompositorNode, CMP_NODE_COMBHSVA_LEGACY,0, "COMBHSVA", CombHSVA, "Combine HSVA", "" ) DefNode(CompositorNode, CMP_NODE_MATH, def_math, "MATH", Math, "Math", "" ) DefNode(CompositorNode, CMP_NODE_LUMA_MATTE, def_cmp_luma_matte, "LUMA_MATTE", LumaMatte, "Luminance Key", "" ) DefNode(CompositorNode, CMP_NODE_BRIGHTCONTRAST, def_cmp_brightcontrast, "BRIGHTCONTRAST", BrightContrast, "Bright/Contrast", "" ) DefNode(CompositorNode, CMP_NODE_GAMMA, 0, "GAMMA", Gamma, "Gamma", "" ) DefNode(CompositorNode, CMP_NODE_INVERT, def_cmp_invert, "INVERT", Invert, "Invert", "" ) DefNode(CompositorNode, CMP_NODE_NORMALIZE, 0, "NORMALIZE", Normalize, "Normalize", "" ) DefNode(CompositorNode, CMP_NODE_CROP, def_cmp_crop, "CROP", Crop, "Crop", "" ) DefNode(CompositorNode, CMP_NODE_DBLUR, def_cmp_dblur, "DBLUR", DBlur, "Directional Blur", "" ) DefNode(CompositorNode, CMP_NODE_BILATERALBLUR, def_cmp_bilateral_blur, "BILATERALBLUR", Bilateralblur, "Bilateral Blur", "" ) DefNode(CompositorNode, CMP_NODE_PREMULKEY, def_cmp_premul_key, "PREMULKEY", PremulKey, "Alpha Convert", "" ) DefNode(CompositorNode, CMP_NODE_GLARE, def_cmp_glare, "GLARE", Glare, "Glare", "" ) DefNode(CompositorNode, CMP_NODE_TONEMAP, def_cmp_tonemap, "TONEMAP", Tonemap, "Tonemap", "" ) DefNode(CompositorNode, CMP_NODE_LENSDIST, def_cmp_lensdist, "LENSDIST", Lensdist, "Lens Distortion", "" ) DefNode(CompositorNode, CMP_NODE_VIEW_LEVELS, def_cmp_levels, "LEVELS", Levels, "Levels", "" ) DefNode(CompositorNode, CMP_NODE_COLOR_MATTE, def_cmp_color_matte, "COLOR_MATTE", ColorMatte, "Color Key", "" ) DefNode(CompositorNode, CMP_NODE_DIST_MATTE, def_cmp_distance_matte, "DISTANCE_MATTE", DistanceMatte, "Distance Key", "" ) DefNode(CompositorNode, CMP_NODE_COLORBALANCE, def_cmp_colorbalance, "COLORBALANCE", ColorBalance, "Color Balance", "" ) DefNode(CompositorNode, CMP_NODE_HUECORRECT, def_cmp_huecorrect, "HUECORRECT", HueCorrect, "Hue Correct", "" ) DefNode(CompositorNode, CMP_NODE_MOVIECLIP, def_cmp_movieclip, "MOVIECLIP", MovieClip, "Movie Clip", "" ) DefNode(CompositorNode, CMP_NODE_TRANSFORM, dev_cmd_transform, "TRANSFORM", Transform, "Transform", "" ) DefNode(CompositorNode, CMP_NODE_STABILIZE2D, def_cmp_stabilize2d, "STABILIZE2D", Stabilize, "Stabilize 2D", "" ) DefNode(CompositorNode, CMP_NODE_MOVIEDISTORTION,def_cmp_moviedistortion,"MOVIEDISTORTION",MovieDistortion, "Movie Distortion", "" ) DefNode(CompositorNode, CMP_NODE_MASK_BOX, def_cmp_boxmask, "BOXMASK", BoxMask, "Box Mask", "" ) DefNode(CompositorNode, CMP_NODE_MASK_ELLIPSE, def_cmp_ellipsemask, "ELLIPSEMASK", EllipseMask, "Ellipse Mask", "" ) DefNode(CompositorNode, CMP_NODE_BOKEHIMAGE, def_cmp_bokehimage, "BOKEHIMAGE", BokehImage, "Bokeh Image", "" ) DefNode(CompositorNode, CMP_NODE_BOKEHBLUR, def_cmp_bokehblur, "BOKEHBLUR", BokehBlur, "Bokeh Blur", "" ) DefNode(CompositorNode, CMP_NODE_SWITCH, def_cmp_switch, "SWITCH", Switch, "Switch", "" ) DefNode(CompositorNode, CMP_NODE_SWITCH_VIEW, def_cmp_switch_view, "VIEWSWITCH", SwitchView, "Switch View", "" ) DefNode(CompositorNode, CMP_NODE_COLORCORRECTION,def_cmp_colorcorrection,"COLORCORRECTION",ColorCorrection, "Color Correction", "" ) DefNode(CompositorNode, CMP_NODE_MASK, def_cmp_mask, "MASK", Mask, "Mask", "" ) DefNode(CompositorNode, CMP_NODE_KEYINGSCREEN, def_cmp_keyingscreen, "KEYINGSCREEN", KeyingScreen, "Keying Screen", "" ) DefNode(CompositorNode, CMP_NODE_KEYING, def_cmp_keying, "KEYING", Keying, "Keying", "" ) DefNode(CompositorNode, CMP_NODE_TRACKPOS, def_cmp_trackpos, "TRACKPOS", TrackPos, "Track Position", "" ) DefNode(CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELATE", Pixelate, "Pixelate", "" ) DefNode(CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" ) DefNode(CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" ) DefNode(CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" ) DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE_V2", CryptomatteV2, "Cryptomatte", "" ) DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE_LEGACY, def_cmp_cryptomatte_legacy, "CRYPTOMATTE", Cryptomatte, "Cryptomatte (Legacy)", "" ) DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOISE", Denoise, "Denoise", "" ) DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" ) DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIALIASING", AntiAliasing, "Anti-Aliasing", "" ) DefNode(CompositorNode, CMP_NODE_POSTERIZE, 0, "POSTERIZE", Posterize, "Posterize", "" ) DefNode(CompositorNode, CMP_NODE_CONVERT_COLOR_SPACE,def_cmp_convert_color_space, "CONVERT_COLORSPACE", ConvertColorSpace, "Color Space", "" ) DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" ) DefNode(CompositorNode, CMP_NODE_COMBINE_XYZ, 0, "COMBINE_XYZ", CombineXYZ, "Combine XYZ", "" ) DefNode(CompositorNode, CMP_NODE_SEPARATE_XYZ, 0, "SEPARATE_XYZ", SeparateXYZ, "Separate XYZ", "" ) DefNode(CompositorNode, CMP_NODE_SEPARATE_COLOR, def_cmp_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" ) DefNode(CompositorNode, CMP_NODE_COMBINE_COLOR, def_cmp_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" ) DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" ) DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" ) DefNode(TextureNode, TEX_NODE_TEXTURE, def_texture, "TEXTURE", Texture, "Texture", "" ) DefNode(TextureNode, TEX_NODE_BRICKS, def_tex_bricks, "BRICKS", Bricks, "Bricks", "" ) DefNode(TextureNode, TEX_NODE_MATH, def_math, "MATH", Math, "Math", "" ) DefNode(TextureNode, TEX_NODE_MIX_RGB, def_mix_rgb, "MIX_RGB", MixRGB, "Mix RGB", "" ) DefNode(TextureNode, TEX_NODE_RGBTOBW, 0, "RGBTOBW", RGBToBW, "RGB to BW", "" ) DefNode(TextureNode, TEX_NODE_VALTORGB, def_colorramp, "VALTORGB", ValToRGB, "ColorRamp", "" ) DefNode(TextureNode, TEX_NODE_IMAGE, def_tex_image, "IMAGE", Image, "Image", "" ) DefNode(TextureNode, TEX_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", CurveRGB, "RGB Curves", "" ) DefNode(TextureNode, TEX_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" ) DefNode(TextureNode, TEX_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue Saturation Value", "" ) DefNode(TextureNode, TEX_NODE_CURVE_TIME, def_time, "CURVE_TIME", CurveTime, "Curve Time", "" ) DefNode(TextureNode, TEX_NODE_ROTATE, 0, "ROTATE", Rotate, "Rotate", "" ) DefNode(TextureNode, TEX_NODE_VIEWER, 0, "VIEWER", Viewer, "Viewer", "" ) DefNode(TextureNode, TEX_NODE_TRANSLATE, 0, "TRANSLATE", Translate, "Translate", "" ) DefNode(TextureNode, TEX_NODE_COORD, 0, "COORD", Coordinates, "Coordinates", "" ) DefNode(TextureNode, TEX_NODE_DISTANCE, 0, "DISTANCE", Distance, "Distance", "" ) DefNode(TextureNode, TEX_NODE_COMPOSE_LEGACY, 0, "COMPOSE", Compose, "Combine RGBA", "" ) DefNode(TextureNode, TEX_NODE_DECOMPOSE_LEGACY,0, "DECOMPOSE", Decompose, "Separate RGBA", "" ) DefNode(TextureNode, TEX_NODE_VALTONOR, 0, "VALTONOR", ValToNor, "Value to Normal", "" ) DefNode(TextureNode, TEX_NODE_SCALE, 0, "SCALE", Scale, "Scale", "" ) DefNode(TextureNode, TEX_NODE_AT, 0, "AT", At, "At", "" ) DefNode(TextureNode, TEX_NODE_COMBINE_COLOR, def_tex_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" ) DefNode(TextureNode, TEX_NODE_SEPARATE_COLOR, def_tex_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" ) /* procedural textures */ DefNode(TextureNode, TEX_NODE_PROC+TEX_VORONOI, 0, "TEX_VORONOI", TexVoronoi, "Voronoi", "" ) DefNode(TextureNode, TEX_NODE_PROC+TEX_BLEND, 0, "TEX_BLEND", TexBlend, "Blend", "" ) DefNode(TextureNode, TEX_NODE_PROC+TEX_MAGIC, 0, "TEX_MAGIC", TexMagic, "Magic", "" ) DefNode(TextureNode, TEX_NODE_PROC+TEX_MARBLE, 0, "TEX_MARBLE", TexMarble, "Marble", "" ) DefNode(TextureNode, TEX_NODE_PROC+TEX_CLOUDS, 0, "TEX_CLOUDS", TexClouds, "Clouds", "" ) DefNode(TextureNode, TEX_NODE_PROC+TEX_WOOD, 0, "TEX_WOOD", TexWood, "Wood", "" ) DefNode(TextureNode, TEX_NODE_PROC+TEX_MUSGRAVE, 0, "TEX_MUSGRAVE", TexMusgrave, "Musgrave", "" ) DefNode(TextureNode, TEX_NODE_PROC+TEX_NOISE, 0, "TEX_NOISE", TexNoise, "Noise", "" ) DefNode(TextureNode, TEX_NODE_PROC+TEX_STUCCI, 0, "TEX_STUCCI", TexStucci, "Stucci", "" ) DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DISTNOISE", TexDistNoise, "Distorted Noise", "" ) DefNode(FunctionNode, FN_NODE_ALIGN_EULER_TO_VECTOR, def_fn_align_euler_to_vector, "ALIGN_EULER_TO_VECTOR", AlignEulerToVector, "Align Euler to Vector", "") DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "") DefNode(FunctionNode, FN_NODE_COMBINE_COLOR, def_fn_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "") DefNode(FunctionNode, FN_NODE_COMPARE, def_compare, "COMPARE", Compare, "Compare", "") DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "") DefNode(FunctionNode, FN_NODE_INPUT_BOOL, def_fn_input_bool, "INPUT_BOOL", InputBool, "Boolean", "") DefNode(FunctionNode, FN_NODE_INPUT_COLOR, def_fn_input_color, "INPUT_COLOR", InputColor, "Color", "") DefNode(FunctionNode, FN_NODE_INPUT_INT, def_fn_input_int, "INPUT_INT", InputInt, "Integer", "") DefNode(FunctionNode, FN_NODE_INPUT_SPECIAL_CHARACTERS, 0, "INPUT_SPECIAL_CHARACTERS", InputSpecialCharacters, "Special Characters", "") DefNode(FunctionNode, FN_NODE_INPUT_STRING, def_fn_input_string, "INPUT_STRING", InputString, "String", "") DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR", InputVector, "Vector", "") DefNode(FunctionNode, FN_NODE_RANDOM_VALUE, def_fn_random_value, "RANDOM_VALUE", RandomValue, "Random Value", "") DefNode(FunctionNode, FN_NODE_REPLACE_STRING, 0, "REPLACE_STRING", ReplaceString, "Replace String", "") DefNode(FunctionNode, FN_NODE_ROTATE_EULER, def_fn_rotate_euler, "ROTATE_EULER", RotateEuler, "Rotate Euler", "") DefNode(FunctionNode, FN_NODE_SEPARATE_COLOR, def_fn_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "") DefNode(FunctionNode, FN_NODE_SLICE_STRING, 0, "SLICE_STRING", SliceString, "Slice String", "") DefNode(FunctionNode, FN_NODE_STRING_LENGTH, 0, "STRING_LENGTH", StringLength, "String Length", "") DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "") DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, def_geo_accumulate_field, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "Add the values of an evaluated field together and output the running total for each element") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "Retrieve the number of elements in a geometry for each attribute domain") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC",AttributeStatistic, "Attribute Statistic","Calculate statistics about a data set from a field evaluated on a geometry") +DefNode(GeometryNode, GEO_NODE_SMOOTH_ATTRIBUTE, def_geo_smooth_attribute, "SMOOTH_ATTRIBUTE", SmoothAttribute, "Smooth Attribute", "") DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "Calculate the limits of a geometry's positions and generate a box mesh with those dimensions") DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture,"CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "Store the result of a field on a geometry and output the data as a node socket. Allows remembering or interpolating data as the geometry changes, such as positions before deformation") DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "Retrieve geometry from a collection") DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Convex Hull", "Create a mesh that encloses all points in the input geometry with the smallest number of points") DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINT_SELECTION, 0, "CURVE_ENDPOINT_SELECTION", CurveEndpointSelection, "Endpoint Selection", "Provide a selection for an arbitrary number of endpoints in each spline") DefNode(GeometryNode, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, def_geo_curve_handle_type_selection, "CURVE_HANDLE_TYPE_SELECTION", CurveHandleTypeSelection, "Handle Type Selection", "Provide a selection based on the handle types of Bézier control points") DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "Retrieve the length of all splines added together") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_ARC, def_geo_curve_primitive_arc, "CURVE_PRIMITIVE_ARC",CurveArc, "Arc", "Generate a poly spline arc") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "Generate a 2D Bézier spline from the given control points and handles") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE,def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "Generate a poly spline circle") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "Generate a poly spline line with two points") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, 0, "CURVE_PRIMITIVE_QUADRATIC_BEZIER", CurveQuadraticBezier, "Quadratic Bezier", "Generate a poly spline in a parabola shape with control points positions") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, def_geo_curve_primitive_quadrilateral, "CURVE_PRIMITIVE_QUADRILATERAL", CurvePrimitiveQuadrilateral, "Quadrilateral", "Generate a polygon with four points") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL,0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "Generate a poly spline in a spiral shape") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "Generate a poly spline in a star pattern by connecting alternating points of two circles") DefNode(GeometryNode, GEO_NODE_CURVE_SET_HANDLE_TYPE, def_geo_curve_set_handle_type, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "Set the handle type for the control points of a Bézier curve") DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER,0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "Retrieve how far along each spline a control point is") DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_TYPE, def_geo_curve_spline_type,"CURVE_SPLINE_TYPE", CurveSplineType, "Set Spline Type", "Change the type of curves") DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "Convert curves into a mesh, optionally with a custom profile shape defined by curves") DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "Generate a point cloud by sampling positions along curves") DefNode(GeometryNode, GEO_NODE_DEFORM_CURVES_ON_SURFACE, 0, "DEFORM_CURVES_ON_SURFACE", DeformCurvesOnSurface, "Deform Curves on Surface", "Translate and rotate curves based on changes between the object's original and evaluated surface mesh") DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "Remove selected elements of a geometry") DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "Generate points spread out on the surface of a mesh") DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh", "Convert Faces into vertices and vertices into faces") DefNode(GeometryNode, GEO_NODE_DUPLICATE_ELEMENTS, def_geo_duplicate_elements, "DUPLICATE_ELEMENTS", DuplicateElements, "Duplicate Elements", "Generate an arbitrary number copies of each selected input element") DefNode(GeometryNode, GEO_NODE_EDGE_PATHS_TO_CURVES, 0, "EDGE_PATHS_TO_CURVES", EdgePathsToCurves, "Edge Paths to Curves", "") DefNode(GeometryNode, GEO_NODE_EDGE_PATHS_TO_SELECTION, 0, "EDGE_PATHS_TO_SELECTION", EdgePathsToSelection, "Edge Paths to Selection", "") DefNode(GeometryNode, GEO_NODE_EXTRUDE_MESH, def_geo_extrude_mesh, "EXTRUDE_MESH", ExtrudeMesh, "Extrude Mesh", "Generate new vertices, edges, or faces from selected elements and move them based on an offset while keeping them connected by their boundary") DefNode(GeometryNode, GEO_NODE_FIELD_AT_INDEX, def_geo_field_at_index, "FIELD_AT_INDEX", FieldAtIndex, "Field at Index", "Retrieve data of other elements in the context's geometry") DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "Generate a mesh on the XY plane with faces on the inside of input curves") DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "Round corners by generating circular arcs on each control point") DefNode(GeometryNode, GEO_NODE_FLIP_FACES, 0, "FLIP_FACES", FlipFaces, "Flip Faces", "Reverse the order of the vertices and edges of selected faces, flipping their normal direction") DefNode(GeometryNode, GEO_NODE_GEOMETRY_TO_INSTANCE, 0, "GEOMETRY_TO_INSTANCE", GeometryToInstance, "Geometry to Instance", "Convert each input geometry into an instance, which can be much faster than the Join Geometry node when the inputs are large") DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "Sample values from an image texture") DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES",InputCurveHandlePositions,"Curve Handle Positions", "Retrieve the position of each Bézier control point's handles") DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "Retrieve the angle at each control point used to twist the curve's normal around its tangent") DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "Retrieve a stable random identifier value from the \"id\" attribute on the point domain, or the index if the attribute does not exist") DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "Retrieve an integer value indicating the position of each element in the list, starting at zero") DefNode(GeometryNode, GEO_NODE_INPUT_INSTANCE_ROTATION, 0, "INPUT_INSTANCE_ROTATION", InputInstanceRotation, "Instance Rotation", "Retrieve the rotation of each instance in the geometry") DefNode(GeometryNode, GEO_NODE_INPUT_INSTANCE_SCALE, 0, "INPUT_INSTANCE_SCALE", InputInstanceScale, "Instance Scale", "Retrieve the scale of each instance in the geometry") DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL_INDEX, 0, "INPUT_MATERIAL_INDEX", InputMaterialIndex, "Material Index", "Retrieve the index of the material used for each element in the geometry's list of materials") DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "Output a single material") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_ANGLE, 0, "MESH_EDGE_ANGLE", InputMeshEdgeAngle, "Edge Angle", "Calculate the surface area of each face in a mesh") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, 0, "MESH_EDGE_NEIGHBORS",InputMeshEdgeNeighbors, "Edge Neighbors", "Retrieve the number of faces that use each edge as one of their sides") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_VERTICES, 0, "MESH_EDGE_VERTICES", InputMeshEdgeVertices, "Edge Vertices", "Retrieve topology information relating to each edge of a mesh") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_AREA, 0, "MESH_FACE_AREA", InputMeshFaceArea, "Face Area", "Calculate the surface area of a mesh's faces") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_IS_PLANAR, 0, "MESH_FACE_IS_PLANAR",InputMeshFaceIsPlanar, "Is Face Planar", "Retrieve whether all triangles in a face are on the same plane, i.e. whether have the same normal") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, 0, "MESH_FACE_NEIGHBORS",InputMeshFaceNeighbors, "Face Neighbors", "Retrieve topology information relating to each face of a mesh") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_ISLAND, 0, "MESH_ISLAND", InputMeshIsland, "Mesh Island", "Retrieve information about separate connected regions in a mesh") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, 0, "MESH_VERTEX_NEIGHBORS", InputMeshVertexNeighbors, "Vertex Neighbors", "Retrieve topology information relating to each vertex of a mesh") DefNode(GeometryNode, GEO_NODE_INPUT_NAMED_ATTRIBUTE, def_geo_input_named_attribute, "INPUT_ATTRIBUTE", InputNamedAttribute, "Named Attribute", "Retrieve the data of a specified attribute") DefNode(GeometryNode, GEO_NODE_INPUT_NORMAL, 0, "INPUT_NORMAL", InputNormal, "Normal", "Retrieve a unit length vector indicating the direction pointing away from the geometry at each element") DefNode(GeometryNode, GEO_NODE_INPUT_POSITION, 0, "POSITION", InputPosition, "Position", "Retrieve a vector indicating the location of each element") DefNode(GeometryNode, GEO_NODE_INPUT_RADIUS, 0, "INPUT_RADIUS", InputRadius, "Radius", "Retrieve the radius at each point on curve or point cloud geometry") DefNode(GeometryNode, GEO_NODE_INPUT_SCENE_TIME, 0, "INPUT_SCENE_TIME", InputSceneTime, "Scene Time", "Retrieve the current time in the scene's animation in units of seconds or frames") DefNode(GeometryNode, GEO_NODE_INPUT_SHADE_SMOOTH, 0, "INPUT_SHADE_SMOOTH", InputShadeSmooth, "Is Shade Smooth", "Retrieve whether each face is marked for smooth shading") DefNode(GeometryNode, GEO_NODE_INPUT_SHORTEST_EDGE_PATHS, 0, "SHORTEST_EDGE_PATHS", InputShortestEdgePaths, "Shortest Edge Paths", "") DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_CYCLIC, 0, "INPUT_SPLINE_CYCLIC",InputSplineCyclic, "Is Spline Cyclic", "Retrieve whether each spline endpoint connects to the beginning") DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_LENGTH, 0, "SPLINE_LENGTH", SplineLength, "Spline Length", "Retrieve the total length of each spline, as a distance or as a number of points") DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_RESOLUTION, 0, "INPUT_SPLINE_RESOLUTION", InputSplineResolution, "Spline Resolution", "Retrieve the number of evaluated points that will be generated for every control point on curves") DefNode(GeometryNode, GEO_NODE_INPUT_TANGENT, 0, "INPUT_TANGENT", InputTangent, "Curve Tangent", "Retrieve the direction of curves at each control point") DefNode(GeometryNode, GEO_NODE_INSTANCE_ON_POINTS, 0, "INSTANCE_ON_POINTS", InstanceOnPoints, "Instance on Points", "Generate a reference to geometry at each of the input points, without duplicating its underlying data") DefNode(GeometryNode, GEO_NODE_INSTANCES_TO_POINTS, 0, "INSTANCES_TO_POINTS",InstancesToPoints, "Instances to Points","Generate points at the origins of instances.\nNote: Nested instances are not affected by this node") DefNode(GeometryNode, GEO_NODE_INTERPOLATE_DOMAIN, def_geo_interpolate_domain, "FIELD_ON_DOMAIN", FieldOnDomain, "Interpolate Domain", "Retrieve values from a field on a different domain besides the domain from the context") DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "Retrieve whether the nodes are being evaluated for the viewport rather than the final render") DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "Merge separately generated geometries into a single one") DefNode(GeometryNode, GEO_NODE_MATERIAL_SELECTION, 0, "MATERIAL_SELECTION", MaterialSelection, "Material Selection", "Provide a selection of faces that use the specified material") DefNode(GeometryNode, GEO_NODE_MERGE_BY_DISTANCE, def_geo_merge_by_distance,"MERGE_BY_DISTANCE", MergeByDistance, "Merge by Distance", "Merge vertices or points within a given distance") DefNode(GeometryNode, GEO_NODE_MESH_BOOLEAN, def_geo_boolean, "MESH_BOOLEAN", MeshBoolean, "Mesh Boolean", "Cut, subtract, or join multiple mesh inputs") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Mesh Circle", "Generate a circular ring of edges") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE",MeshCone, "Cone", "Generate a cone mesh") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CUBE, 0, "MESH_PRIMITIVE_CUBE",MeshCube, "Cube", "Generate a cuboid mesh with variable side lengths and subdivisions") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CYLINDER, def_geo_mesh_cylinder, "MESH_PRIMITIVE_CYLINDER", MeshCylinder, "Cylinder", "Generate a cylinder mesh") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_GRID, 0, "MESH_PRIMITIVE_GRID",MeshGrid, "Grid", "Generate a planar mesh on the XY plane") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO_SPHERE", MeshIcoSphere, "Ico Sphere", "Generate a spherical mesh that consists of equally sized triangles") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE",MeshLine, "Mesh Line", "Generate vertices in a line and connect them with edges") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "Generate a spherical mesh with quads, except for triangles at the top and bottom") DefNode(GeometryNode, GEO_NODE_MESH_TO_CURVE, 0, "MESH_TO_CURVE", MeshToCurve, "Mesh to Curve", "Generate a curve from a mesh") DefNode(GeometryNode, GEO_NODE_MESH_TO_POINTS, def_geo_mesh_to_points, "MESH_TO_POINTS", MeshToPoints, "Mesh to Points", "Generate a point cloud from a mesh's vertices") DefNode(GeometryNode, GEO_NODE_MESH_TO_VOLUME, def_geo_mesh_to_volume, "MESH_TO_VOLUME", MeshToVolume, "Mesh to Volume", "Create a fog volume with the shape of the input mesh's surface") DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "Retrieve information from an object") DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", PointsToVertices, "Points to Vertices", "Generate a mesh vertex for each point cloud point") DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "Generate a fog volume sphere around every point") DefNode(GeometryNode, GEO_NODE_POINTS, 0, "POINTS", Points, "Points", "Generate a point cloud with positions and radii defined by fields") DefNode(GeometryNode, GEO_NODE_PROXIMITY, def_geo_proximity, "PROXIMITY", Proximity, "Geometry Proximity", "Compute the closest location on the target geometry") DefNode(GeometryNode, GEO_NODE_RAYCAST, def_geo_raycast, "RAYCAST", Raycast, "Raycast", "Cast rays from the context geometry onto a target geometry, and retrieve information from each hit point") DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, def_geo_realize_instances,"REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "Change the direction of the curve by swapping each spline's start and end data") DefNode(GeometryNode, GEO_NODE_REMOVE_ATTRIBUTE, 0, "REMOVE_ATTRIBUTE", RemoveAttribute, "Remove Named Attribute", "Delete an attribute with a specified name from a geometry. Typically used to optimize performance") DefNode(GeometryNode, GEO_NODE_REPLACE_MATERIAL, 0, "REPLACE_MATERIAL", ReplaceMaterial, "Replace Material", "Swap one material with another") DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, def_geo_curve_resample, "RESAMPLE_CURVE", ResampleCurve, "Resample Curve", "Generate a poly spline for each input spline") DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, "Reverse Curve", "Swap the start and end of splines") DefNode(GeometryNode, GEO_NODE_ROTATE_INSTANCES, 0, "ROTATE_INSTANCES", RotateInstances, "Rotate Instances", "Rotate geometry instances in local or global space") DefNode(GeometryNode, GEO_NODE_SAMPLE_CURVE, def_geo_curve_sample, "SAMPLE_CURVE", SampleCurve, "Sample Curve", "Retrieve data from a point on a curve at a certain distance from its start") DefNode(GeometryNode, GEO_NODE_SCALE_ELEMENTS, def_geo_scale_elements, "SCALE_ELEMENTS", ScaleElements, "Scale Elements", "Scale groups of connected edges and faces") DefNode(GeometryNode, GEO_NODE_SCALE_INSTANCES, 0, "SCALE_INSTANCES", ScaleInstances, "Scale Instances", "Scale geometry instances in local or global space") DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS",SeparateComponents, "Separate Components","Split a geometry into a separate output for each type of data in the geometry") DefNode(GeometryNode, GEO_NODE_SEPARATE_GEOMETRY, def_geo_separate_geometry,"SEPARATE_GEOMETRY", SeparateGeometry, "Separate Geometry", "Split a geometry into two geometry outputs based on a selection") DefNode(GeometryNode, GEO_NODE_SET_CURVE_HANDLES, def_geo_curve_set_handle_positions, "SET_CURVE_HANDLES", SetCurveHandlePositions, "Set Handle Positions", "Set the positions for the handles of Bézier curves") DefNode(GeometryNode, GEO_NODE_SET_CURVE_RADIUS, 0, "SET_CURVE_RADIUS", SetCurveRadius, "Set Curve Radius", "Set the radius of the curve at each control point") DefNode(GeometryNode, GEO_NODE_SET_CURVE_TILT, 0, "SET_CURVE_TILT", SetCurveTilt, "Set Curve Tilt", "Set the tilt angle at each curve control point") DefNode(GeometryNode, GEO_NODE_SET_ID, 0, "SET_ID", SetID, "Set ID", "Set the id attribute on the input geometry, mainly used internally for randomizing") DefNode(GeometryNode, GEO_NODE_SET_MATERIAL_INDEX, 0, "SET_MATERIAL_INDEX", SetMaterialIndex, "Set Material Index", "Set the material index for each selected geometry element") DefNode(GeometryNode, GEO_NODE_SET_MATERIAL, 0, "SET_MATERIAL", SetMaterial, "Set Material", "Assign a material to geometry elements") DefNode(GeometryNode, GEO_NODE_SET_POINT_RADIUS, 0, "SET_POINT_RADIUS", SetPointRadius, "Set Point Radius", "Set the display size of point cloud points") DefNode(GeometryNode, GEO_NODE_SET_POSITION, 0, "SET_POSITION", SetPosition, "Set Position", "Set the location of each point") DefNode(GeometryNode, GEO_NODE_SET_SHADE_SMOOTH, 0, "SET_SHADE_SMOOTH", SetShadeSmooth, "Set Shade Smooth", "Control the smoothness of mesh normals around each face by changing the \"shade smooth\" attribute") DefNode(GeometryNode, GEO_NODE_SET_SPLINE_CYCLIC, 0, "SET_SPLINE_CYCLIC", SetSplineCyclic, "Set Spline Cyclic", "Control whether each spline loops back on itself by changing the \"cyclic\" attribute") DefNode(GeometryNode, GEO_NODE_SET_SPLINE_RESOLUTION, 0, "SET_SPLINE_RESOLUTION", SetSplineResolution, "Set Spline Resolution", "Control how many evaluated points should be generated on every curve segment") DefNode(GeometryNode, GEO_NODE_SPLIT_EDGES, 0, "SPLIT_EDGES", SplitEdges, "Split Edges", "Duplicate mesh edges and break connections with the surrounding faces") DefNode(GeometryNode, GEO_NODE_STORE_NAMED_ATTRIBUTE, def_geo_store_named_attribute, "STORE_NAMED_ATTRIBUTE", StoreNamedAttribute, "Store Named Attribute", "Store the result of a field on a geometry as an attribute with the specified name") DefNode(GeometryNode, GEO_NODE_STRING_JOIN, 0, "STRING_JOIN", StringJoin, "Join Strings", "Combine any number of input strings") DefNode(GeometryNode, GEO_NODE_STRING_TO_CURVES, def_geo_string_to_curves, "STRING_TO_CURVES", StringToCurves, "String to Curves", "Generate a paragraph of text with a specific font, using a curve instance to store each character") DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_CURVE, 0, "SUBDIVIDE_CURVE", SubdivideCurve, "Subdivide Curve", "Dividing each curve segment into a specified number of pieces") DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_MESH, 0, "SUBDIVIDE_MESH", SubdivideMesh, "Subdivide Mesh", "Divide mesh faces into smaller ones without changing the shape or volume, using linear interpolation to place the new vertices") DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "SUBDIVISION_SURFACE",SubdivisionSurface, "Subdivision Surface","Divide mesh faces to form a smooth surface, using the Catmull-Clark subdivision method") DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "Switch between two inputs") DefNode(GeometryNode, GEO_NODE_TRANSFER_ATTRIBUTE, def_geo_transfer_attribute, "ATTRIBUTE_TRANSFER", AttributeTransfer, "Transfer Attribute", "Retrieve values from a source geometry and provides them as a field by interpolating them with the context geometry") DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "Translate, rotate or scale the geometry") DefNode(GeometryNode, GEO_NODE_TRANSLATE_INSTANCES, 0, "TRANSLATE_INSTANCES",TranslateInstances, "Translate Instances","Move top-level geometry instances in local or global space") DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "Convert all faces in a mesh to triangular faces") DefNode(GeometryNode, GEO_NODE_TRIM_CURVE, def_geo_curve_trim, "TRIM_CURVE", TrimCurve, "Trim Curve", "Shorten curves by removing portions at the start or end") DefNode(GeometryNode, GEO_NODE_UV_PACK_ISLANDS, 0, "UV_PACK_ISLANDS", UVPackIslands, "Pack UV Islands", "Scale islands of a UV map and move them so they fill the UV space as much as possible") DefNode(GeometryNode, GEO_NODE_UV_UNWRAP, def_geo_uv_unwrap, "UV_UNWRAP", UVUnwrap, "UV Unwrap", "Generate a UV map based on seam edges") DefNode(GeometryNode, GEO_NODE_VIEWER, def_geo_viewer, "VIEWER", Viewer, "Viewer", "Display the input data in the Spreadsheet Editor") DefNode(GeometryNode, GEO_NODE_VOLUME_CUBE, 0, "VOLUME_CUBE", VolumeCube, "Volume Cube", "Generate a dense volume with a field that controls the density at each grid voxel based on its position") DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "Generate a mesh on the \"surface\" of a volume") /* undefine macros */ #undef DefNode /* clang-format on */ diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 31c00cc6b82..c4a4fa39c1d 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -1,251 +1,252 @@ # SPDX-License-Identifier: GPL-2.0-or-later set(INC . .. ../intern ../../editors/include ../../blenkernel ../../blenlib ../../blentranslation ../../bmesh ../../depsgraph ../../functions ../../geometry ../../gpu ../../imbuf ../../makesdna ../../makesrna ../../render ../../windowmanager ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) set(SRC nodes/node_geo_accumulate_field.cc nodes/node_geo_attribute_capture.cc nodes/node_geo_attribute_domain_size.cc nodes/node_geo_attribute_statistic.cc nodes/node_geo_boolean.cc nodes/node_geo_bounding_box.cc nodes/node_geo_collection_info.cc nodes/node_geo_common.cc nodes/node_geo_convex_hull.cc nodes/node_geo_curve_endpoint_selection.cc nodes/node_geo_curve_fill.cc nodes/node_geo_curve_fillet.cc nodes/node_geo_curve_handle_type_selection.cc nodes/node_geo_curve_length.cc nodes/node_geo_curve_primitive_arc.cc nodes/node_geo_curve_primitive_bezier_segment.cc nodes/node_geo_curve_primitive_circle.cc nodes/node_geo_curve_primitive_line.cc nodes/node_geo_curve_primitive_quadratic_bezier.cc nodes/node_geo_curve_primitive_quadrilateral.cc nodes/node_geo_curve_primitive_spiral.cc nodes/node_geo_curve_primitive_star.cc nodes/node_geo_curve_resample.cc nodes/node_geo_curve_reverse.cc nodes/node_geo_curve_sample.cc nodes/node_geo_curve_set_handle_type.cc nodes/node_geo_curve_spline_parameter.cc nodes/node_geo_curve_spline_type.cc nodes/node_geo_curve_subdivide.cc nodes/node_geo_curve_to_mesh.cc nodes/node_geo_curve_to_points.cc nodes/node_geo_curve_trim.cc nodes/node_geo_deform_curves_on_surface.cc nodes/node_geo_delete_geometry.cc nodes/node_geo_distribute_points_on_faces.cc nodes/node_geo_dual_mesh.cc nodes/node_geo_duplicate_elements.cc nodes/node_geo_edge_paths_to_curves.cc nodes/node_geo_edge_paths_to_selection.cc nodes/node_geo_edge_split.cc nodes/node_geo_extrude_mesh.cc nodes/node_geo_field_at_index.cc nodes/node_geo_flip_faces.cc nodes/node_geo_geometry_to_instance.cc nodes/node_geo_image_texture.cc nodes/node_geo_input_curve_handles.cc nodes/node_geo_input_curve_tilt.cc nodes/node_geo_input_id.cc nodes/node_geo_input_index.cc nodes/node_geo_input_instance_rotation.cc nodes/node_geo_input_instance_scale.cc nodes/node_geo_input_material.cc nodes/node_geo_input_material_index.cc nodes/node_geo_input_mesh_edge_angle.cc nodes/node_geo_input_mesh_edge_neighbors.cc nodes/node_geo_input_mesh_edge_vertices.cc nodes/node_geo_input_mesh_face_area.cc nodes/node_geo_input_mesh_face_is_planar.cc nodes/node_geo_input_mesh_face_neighbors.cc nodes/node_geo_input_mesh_island.cc nodes/node_geo_input_mesh_vertex_neighbors.cc nodes/node_geo_input_named_attribute.cc nodes/node_geo_input_normal.cc nodes/node_geo_input_position.cc nodes/node_geo_input_radius.cc nodes/node_geo_input_scene_time.cc nodes/node_geo_input_shade_smooth.cc nodes/node_geo_input_shortest_edge_paths.cc nodes/node_geo_input_spline_cyclic.cc nodes/node_geo_input_spline_length.cc nodes/node_geo_input_spline_resolution.cc nodes/node_geo_input_tangent.cc nodes/node_geo_instance_on_points.cc nodes/node_geo_instances_to_points.cc nodes/node_geo_interpolate_domain.cc nodes/node_geo_is_viewport.cc nodes/node_geo_join_geometry.cc nodes/node_geo_material_replace.cc nodes/node_geo_material_selection.cc nodes/node_geo_merge_by_distance.cc nodes/node_geo_mesh_primitive_circle.cc nodes/node_geo_mesh_primitive_cone.cc nodes/node_geo_mesh_primitive_cube.cc nodes/node_geo_mesh_primitive_cylinder.cc nodes/node_geo_mesh_primitive_grid.cc nodes/node_geo_mesh_primitive_ico_sphere.cc nodes/node_geo_mesh_primitive_line.cc nodes/node_geo_mesh_primitive_uv_sphere.cc nodes/node_geo_mesh_subdivide.cc nodes/node_geo_mesh_to_curve.cc nodes/node_geo_mesh_to_points.cc nodes/node_geo_mesh_to_volume.cc nodes/node_geo_object_info.cc nodes/node_geo_points.cc nodes/node_geo_points_to_vertices.cc nodes/node_geo_points_to_volume.cc nodes/node_geo_proximity.cc nodes/node_geo_raycast.cc nodes/node_geo_realize_instances.cc nodes/node_geo_remove_attribute.cc nodes/node_geo_rotate_instances.cc nodes/node_geo_scale_elements.cc nodes/node_geo_scale_instances.cc nodes/node_geo_separate_components.cc nodes/node_geo_separate_geometry.cc nodes/node_geo_set_curve_handles.cc nodes/node_geo_set_curve_radius.cc nodes/node_geo_set_curve_tilt.cc nodes/node_geo_set_id.cc nodes/node_geo_set_material.cc nodes/node_geo_set_material_index.cc nodes/node_geo_set_point_radius.cc nodes/node_geo_set_position.cc nodes/node_geo_set_shade_smooth.cc nodes/node_geo_set_spline_cyclic.cc nodes/node_geo_set_spline_resolution.cc + nodes/node_geo_smooth_attribute.cc nodes/node_geo_store_named_attribute.cc nodes/node_geo_string_join.cc nodes/node_geo_string_to_curves.cc nodes/node_geo_subdivision_surface.cc nodes/node_geo_switch.cc nodes/node_geo_transfer_attribute.cc nodes/node_geo_transform.cc nodes/node_geo_translate_instances.cc nodes/node_geo_triangulate.cc nodes/node_geo_uv_pack_islands.cc nodes/node_geo_uv_unwrap.cc nodes/node_geo_viewer.cc nodes/node_geo_volume_cube.cc nodes/node_geo_volume_to_mesh.cc node_geometry_exec.cc node_geometry_tree.cc node_geometry_util.cc node_geometry_util.hh ) set(LIB bf_bmesh bf_functions bf_geometry bf_nodes ) if(WITH_BULLET) list(APPEND INC_SYS ${BULLET_INCLUDE_DIRS} ../../../../intern/rigidbody ) if(NOT WITH_SYSTEM_BULLET) list(APPEND LIB extern_bullet ) endif() list(APPEND LIB ${BULLET_LIBRARIES} ) add_definitions(-DWITH_BULLET) endif() if(WITH_PYTHON) list(APPEND INC ../../python ) list(APPEND INC_SYS ${PYTHON_INCLUDE_DIRS} ) list(APPEND LIB ${PYTHON_LINKFLAGS} ${PYTHON_LIBRARIES} ) add_definitions(-DWITH_PYTHON) endif() if(WITH_TBB) list(APPEND INC_SYS ${TBB_INCLUDE_DIRS} ) add_definitions(-DWITH_TBB) if(WIN32) # TBB includes Windows.h which will define min/max macros # that will collide with the stl versions. add_definitions(-DNOMINMAX) endif() endif() if(WITH_IMAGE_OPENEXR) add_definitions(-DWITH_OPENEXR) endif() if(WITH_OPENSUBDIV) add_definitions(-DWITH_OPENSUBDIV) endif() if(WITH_GMP) add_definitions(-DWITH_GMP) list(APPEND INC_SYS ${GMP_INCLUDE_DIRS} ) list(APPEND LIB ${GMP_LIBRARIES} ) endif() if(WITH_OPENVDB) list(APPEND INC_SYS ${OPENVDB_INCLUDE_DIRS} ) add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS}) endif() blender_add_lib(bf_nodes_geometry "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(WITH_UNITY_BUILD) set_target_properties(bf_nodes_geometry PROPERTIES UNITY_BUILD ON) set_target_properties(bf_nodes_geometry PROPERTIES UNITY_BUILD_BATCH_SIZE 10) endif() # RNA_prototypes.h add_dependencies(bf_nodes_geometry bf_rna) diff --git a/source/blender/nodes/geometry/nodes/node_geo_smooth_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_smooth_attribute.cc new file mode 100644 index 00000000000..8029d0e30d2 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_smooth_attribute.cc @@ -0,0 +1,807 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * Smooth is an algorithm for blending the values of adjacent domain elements. + * For the number of iterations field, values mask are grouped. + * Groups know the difference between each other in the count of repetitions. + * When iterating over groups, each group is iterated over all the next ones. + * For group collection span: + * |A B C D E F G H| + * Iteration: + * A : |A B C D E F G H| + * B : |B C D E F G H| + * C : |C D E F G H| + * D : |D E F G H| + * ... + * Due to this, grouping only by equality to repeat count is cheap. + * + * For curves, the algorithm is more complicated. + * The standard mixing of value and + - indices occurs only for the inner mask. + * Edge values (idnex 0 and size()-1) are smoothed separately. + * This simplifies and facilitates the main loop. + */ + +#include "BLI_index_mask_ops.hh" +#include "BLI_sort.hh" +#include "BLI_task.hh" +#include "BLI_vector_set.hh" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_attribute_math.hh" +#include "BKE_curves.hh" +#include "BKE_mesh.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_smooth_attribute_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input(N_("Value"), "Value_Bool") + .default_value(false) + .supports_field() + .hide_value(); + b.add_input(N_("Value"), "Value_Float") + .default_value(0.0f) + .supports_field() + .hide_value(); + b.add_input(N_("Value"), "Value_Int").default_value(0).supports_field().hide_value(); + b.add_input(N_("Value"), "Value_Vector") + .default_value({0.0f, 0.0f, 0.0f}) + .supports_field() + .hide_value(); + b.add_input(N_("Value"), "Value_Color") + .default_value({0.0f, 0.0f, 0.0f, 1.0f}) + .supports_field() + .hide_value(); + + b.add_input("Factor") + .default_value(0.5f) + .subtype(PROP_FACTOR) + .min(0.0f) + .max(1.0f) + .supports_field() + .description(N_("The power of blending a value with its neighbors in one step")); + b.add_input("Iterations").default_value(1).min(0).supports_field(); + + b.add_input("Selection") + .default_value(true) + .supports_field() + .hide_value() + .description(N_("Smooth only selected the values. Other values are not affected")); + + b.add_output(N_("Value"), "Value_Bool").field_source().dependent_field(); + b.add_output(N_("Value"), "Value_Float").field_source().dependent_field(); + b.add_output(N_("Value"), "Value_Int").field_source().dependent_field(); + b.add_output(N_("Value"), "Value_Vector").field_source().dependent_field(); + b.add_output(N_("Value"), "Value_Color").field_source().dependent_field(); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); +} + +static void node_init(bNodeTree *UNUSED(tree), bNode *node) +{ + node->custom1 = CD_PROP_FLOAT; +} + +static void node_update(bNodeTree *ntree, bNode *node) +{ + const eCustomDataType data_type = static_cast(node->custom1); + + bNodeSocket *socket_value_bool = (bNodeSocket *)node->inputs.first; + bNodeSocket *socket_value_float = socket_value_bool->next; + bNodeSocket *socket_value_int32 = socket_value_float->next; + bNodeSocket *socket_value_vector = socket_value_int32->next; + bNodeSocket *socket_value_color4f = socket_value_vector->next; + + nodeSetSocketAvailability(ntree, socket_value_bool, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_value_color4f, data_type == CD_PROP_COLOR); + + bNodeSocket *out_socket_value_bool = (bNodeSocket *)node->outputs.first; + bNodeSocket *out_socket_value_float = out_socket_value_bool->next; + bNodeSocket *out_socket_value_int32 = out_socket_value_float->next; + bNodeSocket *out_socket_value_vector = out_socket_value_int32->next; + bNodeSocket *out_socket_value_color4f = out_socket_value_vector->next; + + nodeSetSocketAvailability(ntree, out_socket_value_bool, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, out_socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, out_socket_value_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, out_socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, out_socket_value_color4f, data_type == CD_PROP_COLOR); +} + +/* + * A structure for collecting all the data required for a smoothing. + * For a comfortable movement. Passed by value. + */ +struct SmoothCore { + const Span factor; + const VArray selection; + const VArray count; + GMutableSpan buffer; + GMutableSpan output; + const CPPType &type; +}; + +/* + * Smooth algorithm buffer. Created from ranges. Passed by value. + */ +template struct SmoothBuffer { + attribute_math::DefaultMixer write_a; + attribute_math::DefaultMixer write_b; + MutableSpan read_a; + MutableSpan read_b; + + SmoothBuffer(MutableSpan values_a, MutableSpan values_b) + : write_a(values_a, IndexMask(0)), + write_b(values_b, IndexMask(0)), + read_a(values_a), + read_b(values_b) + { + BLI_assert(values_a.size() == values_b.size()); + } + + /* + * Swaps read and write locations. Fast enough to use after every loop iteration. + */ + void swap() + { + std::swap(write_a, write_b); + std::swap(read_a, read_b); + } +}; + +/* + * Smoothing group. Key is the number of iterations for sorting. + * After sorting, each group has the count of iterations to the next grout. + * Passed by value. + */ +struct SmoothGroup { + IndexMask mask; + int count; + int iterate_count; + + enum EndpointTypes : int8_t { + None = 0, + First = 1 << 0, + Last = 1 << 1, + }; + + /* + * Endpoints belong to a group and are handled differently. + */ + int8_t curve_endpoints; +}; + +/* + * The mask can be evaluated for all geometry by feild valuator. + * But for curves, need to compute a separate mask. + * Indexes are local in range. + */ +static IndexMask mask_from_selection(VArray selection, + IndexRange range, + Vector &r_indices) +{ + if (selection.is_single()) { + if (selection.get_internal_single()) { + return IndexMask(range.size()); + } + else { + return IndexMask(0); + } + } + r_indices.reinitialize(range.size()); + IndexMask mask = index_mask_ops::find_indices_from_virtual_array( + range, selection, 1024, r_indices); + + r_indices.resize(mask.size()); + threading::parallel_for(mask.index_range(), 1024, [&](IndexRange l_range) { + for (const int64_t index : l_range) { + r_indices[index] = mask[index] - range.first(); + } + }); + return IndexMask(r_indices.as_span()); +} + +static void create_vertex_to_vertex_map(const Mesh &mesh, Array> &r_map) +{ + const Span edges = mesh.edges(); + r_map.reinitialize(mesh.totvert); + for (const MEdge &edge : edges) { + r_map[edge.v1].append(edge.v2); + r_map[edge.v2].append(edge.v1); + } +} + +static void create_vertex_to_edge_map(const Mesh &mesh, Array> &r_map) +{ + const Span verts = mesh.verts(); + const Span edges = mesh.edges(); + r_map.reinitialize(verts.size()); + for (const int64_t i : edges.index_range()) { + r_map[edges[i].v1].append(i); + r_map[edges[i].v2].append(i); + } +} + +static void create_edge_to_edge_map(const Mesh &mesh, + const IndexMask mask, + Array> &r_map) +{ + r_map.reinitialize(mesh.totedge); + Array> edges_by_vert; + create_vertex_to_edge_map(mesh, edges_by_vert); + + const Span edges = mesh.edges(); + + threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) { + for (const int self_edge : mask.slice(range)) { + + Vector &self_edges = r_map[self_edge]; + const Vector &connections_vert_1 = edges_by_vert[edges[self_edge].v1]; + const Vector &connections_vert_2 = edges_by_vert[edges[self_edge].v2]; + + self_edges.reserve(connections_vert_1.size() - 1 + connections_vert_2.size() - 1); + + for (const int64_t edge_i : connections_vert_1) { + if (edge_i != self_edge) { + self_edges.append(edge_i); + } + } + for (const int64_t edge_i : connections_vert_2) { + if (edge_i != self_edge) { + self_edges.append(edge_i); + } + } + } + }); +} + +static void create_face_to_edge_map(const Mesh &mesh, Array> &r_map) +{ + const Span polys = mesh.polys(); + const Span loops = mesh.loops(); + r_map.reinitialize(mesh.totedge); + + for (const int poly_i : polys.index_range()) { + const MPoly &poly = polys[poly_i]; + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + r_map[loop.e].append(poly_i); + } + } +} + +static void create_face_to_face_map(const Mesh &mesh, + const IndexMask mask, + Array> &r_map) +{ + const Span polys = mesh.polys(); + const Span loops = mesh.loops(); + r_map.reinitialize(polys.size()); + Array> faces_by_edge; + create_face_to_edge_map(mesh, faces_by_edge); + + threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) { + for (const int64_t poly_i : mask.slice(range)) { + const MPoly &poly = polys[poly_i]; + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + const int edge_i = loop.e; + if (faces_by_edge[edge_i].size() > 1) { + for (const int64_t neighbor : faces_by_edge[edge_i]) { + if (neighbor != poly_i) { + r_map[poly_i].append(neighbor); + } + } + } + } + } + }); +} + +static void create_mesh_map(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask mask, + Array> &r_map) +{ + switch (domain) { + case ATTR_DOMAIN_POINT: + create_vertex_to_vertex_map(mesh, r_map); + break; + case ATTR_DOMAIN_EDGE: + create_edge_to_edge_map(mesh, mask, r_map); + break; + case ATTR_DOMAIN_FACE: + create_face_to_face_map(mesh, mask, r_map); + break; + default: + BLI_assert_unreachable(); + } +} + +/* + * Param: empty_groups is mask for always empty optional groups. + */ +static Array smooth_groups_evaluate(const VArray &counts, + const IndexRange range, + const IndexMask mask, + const IndexMask empty_groups, + MultiValueMap &r_groups) +{ + if (counts.is_single()) { + if (counts.get_internal_single() > 0) { + /* If count is single and more than 0, smooth groups is actually single group. */ + Array groups(1); + groups[0].mask = mask; + groups[0].count = counts.get_internal_single(); + groups[0].iterate_count = counts.get_internal_single(); + groups[0].curve_endpoints = SmoothGroup::EndpointTypes::None; + return groups; + } + return {}; + } + else { + /* Grouping all mask elements by iterate count keys. */ + int cap = 0; + for (const int64_t i : mask) { + if (const int count = counts[range[i]]; count > 0) { + r_groups.add(count, i); + cap++; + } + } + for (const int64_t i : empty_groups) { + if (const int count = counts[range[i]]; count > 0) { + r_groups.add_multiple(count, {}); + cap++; + } + } + + /* Filling all group by info about mask of smoothing, count, endpoints .*/ + Array groups(r_groups.size()); + int index = 0; + for (const int count : r_groups.keys()) { + groups[index].count = count; + groups[index].mask = IndexMask(r_groups.lookup(count)); + groups[index].curve_endpoints = SmoothGroup::EndpointTypes::None; + index++; + } + + /* Smoothing of each group will do by count order.*/ + parallel_sort(groups.begin(), groups.end(), [](const SmoothGroup &a, const SmoothGroup &b) { + return a.count < b.count; + }); + + /* Field iterate count in value for smoothing. The difference between self and previous smooth + * group iteration. */ + int diff_count = 0; + for (SmoothGroup &group : groups) { + group.iterate_count = group.count - diff_count; + diff_count = group.count; + } + return groups; + } +} + +static Array smooth_groups_evaluate_for_curve(const VArray &count, + const IndexRange range, + const IndexMask mask, + MultiValueMap &r_groups) +{ + IndexMask curve_mask = mask; + const int64_t first_index = 0; + const int64_t last_index = range.size() - 1; + + Vector endpoints; + + const bool first_endpoint_in_mask = mask[0] == first_index; + const bool last_endpoint_in_mask = mask.last() == last_index; + if (first_endpoint_in_mask) { + endpoints.append(first_index); + curve_mask = curve_mask.slice(1, curve_mask.size() - 1); + } + if (last_endpoint_in_mask) { + endpoints.append(last_index); + curve_mask = curve_mask.slice(0, curve_mask.size() - 1); + } + + Array groups = smooth_groups_evaluate( + count, range, curve_mask, endpoints.as_span(), r_groups); + + const int first_endpoint_count = count[range[first_index]]; + const int last_endpoint_count = count[range[last_index]]; + + const bool first_endpoint = (first_endpoint_count > 0) && first_endpoint_in_mask; + const bool last_endpoint = (last_endpoint_count > 0) && last_endpoint_in_mask; + + int first_endpoint_group_index = 0; + int last_endpoint_group_index = 0; + + threading::parallel_invoke( + 1024 < groups.size() && first_endpoint && last_endpoint, + [&]() { + if (first_endpoint) { + for (const int64_t index : groups.index_range()) { + if (groups[index].count == first_endpoint_count) { + first_endpoint_group_index = index; + break; + } + } + } + }, + [&]() { + if (last_endpoint) { + for (const int64_t index : groups.index_range()) { + if (groups[index].count == last_endpoint_count) { + last_endpoint_group_index = index; + break; + } + } + } + }); + + if (first_endpoint) { + groups[first_endpoint_group_index].curve_endpoints |= SmoothGroup::EndpointTypes::First; + } + if (last_endpoint) { + groups[last_endpoint_group_index].curve_endpoints |= SmoothGroup::EndpointTypes::Last; + } + + return groups; +} + +template +static void smooth_mesh_exec(const Span factors, + const Span> map, + const Span groups, + SmoothBuffer buffer) +{ + for (const int64_t group_index : groups.index_range()) { + const Span current_collection = groups.slice(group_index, + groups.size() - group_index); + for ([[maybe_unused]] const int64_t repeat : IndexRange(groups[group_index].iterate_count)) { + threading::parallel_for_each(current_collection, [&](const SmoothGroup group) { + threading::parallel_for(group.mask.index_range(), 1024, [&](const IndexRange range) { + const IndexMask slice = group.mask.slice(range); + for (const int64_t index : slice) { + const float count = float(map[index].size()); + const float factor = factors[index] * count; + buffer.write_a.set(index, buffer.read_b[index], count - factor); + for (const int neighbor : map[index]) { + buffer.write_a.mix_in(index, buffer.read_b[neighbor], factor); + } + } + buffer.write_a.finalize(slice); + }); + }); + buffer.swap(); + } + /* After smoothing, actual values may be required from both buffers in next iteration. Copy. */ + groups[group_index].mask.foreach_index( + [&](const int64_t index) { buffer.read_a[index] = buffer.read_b[index]; }); + } +} + +template +static void smooth_curve_exec(const Span factors, + const Span groups, + SmoothBuffer buffer) +{ + const int64_t first_endpoint = 0; + const int64_t last_endpoint = buffer.read_a.size() - 1; + + const Span first_endpoint_span(&first_endpoint, 1); + const Span last_endpoint_span(&last_endpoint, 1); + + for (const int64_t group_index : groups.index_range()) { + const Span current_collection = groups.slice(group_index, + groups.size() - group_index); + for ([[maybe_unused]] const int64_t repeat : IndexRange(groups[group_index].iterate_count)) { + threading::parallel_for_each(current_collection, [&](const SmoothGroup group) { + threading::parallel_for(group.mask.index_range(), 1024, [&](const IndexRange range) { + const IndexMask slice = group.mask.slice(range); + for (const int64_t index : slice) { + const float factor = factors[index] * 2.0f; + buffer.write_a.set(index, buffer.read_b[index], 2.0f - factor); + buffer.write_a.mix_in(index, buffer.read_b[index + 1], factor); + buffer.write_a.mix_in(index, buffer.read_b[index - 1], factor); + } + buffer.write_a.finalize(slice); + }); + if constexpr (is_cyclic) { + if (group.curve_endpoints & SmoothGroup::EndpointTypes::First) { + const float factor = factors[first_endpoint] * 2.0f; + buffer.write_a.set(first_endpoint, buffer.read_b[first_endpoint], 2.0f - factor); + buffer.write_a.mix_in(first_endpoint, buffer.read_b[first_endpoint + 1], factor); + buffer.write_a.mix_in(first_endpoint, buffer.read_b[last_endpoint], factor); + buffer.write_a.finalize(first_endpoint_span); + } + if (group.curve_endpoints & SmoothGroup::EndpointTypes::Last) { + const float factor = factors[last_endpoint] * 2.0f; + buffer.write_a.set(last_endpoint, buffer.read_b[last_endpoint], 2.0f - factor); + buffer.write_a.mix_in(last_endpoint, buffer.read_b[last_endpoint - 1], factor); + buffer.write_a.mix_in(last_endpoint, buffer.read_b[first_endpoint], factor); + buffer.write_a.finalize(last_endpoint_span); + } + } + else { + if (group.curve_endpoints & SmoothGroup::EndpointTypes::First) { + const float factor = factors[first_endpoint]; + buffer.write_a.set(first_endpoint, buffer.read_b[first_endpoint], 1.0f - factor); + buffer.write_a.mix_in(first_endpoint, buffer.read_b[first_endpoint + 1], factor); + buffer.write_a.finalize(first_endpoint_span); + } + if (group.curve_endpoints & SmoothGroup::EndpointTypes::Last) { + const float factor = factors[last_endpoint]; + buffer.write_a.set(last_endpoint, buffer.read_b[last_endpoint], 1.0f - factor); + buffer.write_a.mix_in(last_endpoint, buffer.read_b[last_endpoint - 1], factor); + buffer.write_a.finalize(last_endpoint_span); + } + } + }); + buffer.swap(); + } + + groups[group_index].mask.foreach_index( + [&](const int64_t index) { buffer.read_a[index] = buffer.read_b[index]; }); + + const SmoothGroup group = groups[group_index]; + if (group.curve_endpoints & SmoothGroup::EndpointTypes::First) { + buffer.read_a[first_endpoint] = buffer.read_b[first_endpoint]; + } + if (group.curve_endpoints & SmoothGroup::EndpointTypes::Last) { + buffer.read_a[last_endpoint] = buffer.read_b[last_endpoint]; + } + } +} + +static void smooth_mesh(const Mesh &mesh, + const int64_t domain_size, + const eAttrDomain domain, + const IndexMask mask, + SmoothCore smooth) +{ + Array groups; + MultiValueMap r_groups; + Array> smooth_map; + threading::parallel_invoke( + 1024 < domain_size, + [&]() { + groups = smooth_groups_evaluate( + std::move(smooth.count), IndexRange(domain_size), mask, {}, r_groups); + }, + [&]() { create_mesh_map(mesh, domain, mask, smooth_map); }); + attribute_math::convert_to_static_type(smooth.type, [&](auto dummy) { + using T = decltype(dummy); + SmoothBuffer buffer(smooth.output.typed(), smooth.buffer.typed()); + smooth_mesh_exec(smooth.factor, smooth_map, groups.as_span(), buffer); + }); +} + +static void smooth_curves(const bke::CurvesGeometry &curves, SmoothCore smooth) +{ + const VArray cyclic = curves.cyclic(); + + const int points_average = curves.points_num() / curves.curves_num(); + const int grain_size_ = math::clamp(1, 4096, 1024 / points_average); + float grain_slow = grain_size_; + /* Power to reduce the inverse relationship between the number of dots to granulation. Found + * during experiments. */ + for ([[maybe_unused]] const int i : IndexRange(22)) { + grain_slow = sqrtf(grain_slow); + } + const int grain_size = threading::prepair_grain_size(math::clamp(int(grain_slow), 1, 4096)); + threading::parallel_for(curves.curves_range(), grain_size, [&](IndexRange curves_range) { + Vector curve_mask; + + for (const int64_t curve_index : curves_range) { + const IndexRange points = curves.points_for_curve(curve_index); + if (points.size() < 2) { + continue; + } + /* Vector curve_mask reinitialize in mask_from_selection for requisite size if need. */ + const IndexMask mask = mask_from_selection(smooth.selection, points, curve_mask); + if (mask.is_empty()) { + continue; + } + MultiValueMap r_groups; + Array groups = smooth_groups_evaluate_for_curve( + std::move(smooth.count), points, mask, r_groups); + + attribute_math::convert_to_static_type(smooth.type, [&](auto dummy) { + using T = decltype(dummy); + SmoothBuffer buffer(smooth.output.typed().slice(points), + smooth.buffer.typed().slice(points)); + if (cyclic[curve_index]) { + smooth_curve_exec(smooth.factor.slice(points), groups.as_span(), buffer); + } + else { + smooth_curve_exec(smooth.factor.slice(points), groups.as_span(), buffer); + } + }); + } + }); +} + +class SmoothField final : public bke::GeometryFieldInput { + private: + Field selection_field_; + Field count_field_; + Field factor_field_; + GField value_field_; + + public: + SmoothField(Field selection_field, + Field count_field, + Field factor_field, + GField value_field) + : bke::GeometryFieldInput(value_field.cpp_type(), "Smoothed Attribute"), + selection_field_(std::move(selection_field)), + count_field_(std::move(count_field)), + factor_field_(std::move(factor_field)), + value_field_(std::move(value_field)) + { + } + + GVArray get_varray_for_context(const bke::GeometryFieldContext &context, + const IndexMask mask) const final + { + const int domain_size = context.attributes()->domain_size(context.domain()); + + FieldEvaluator evaluator(context, &mask); + + GArray<> output(*type_, domain_size); + VArray src_selection = VArray::ForSingle(true, domain_size); + /* The selection mask is not required for the mesh. */ + if (context.type() == GEO_COMPONENT_TYPE_CURVE) { + evaluator.add(selection_field_); + } + evaluator.add_with_destination(value_field_, output.as_mutable_span()); + + evaluator.evaluate(); + + if (context.type() == GEO_COMPONENT_TYPE_CURVE) { + src_selection = evaluator.get_evaluated(0); + } + + /* The smoothing function does not work with a graph less than 2x. */ + if (domain_size < 2) { + return GVArray::ForGArray(std::move(output)); + } + + /* If all points of this curve is out of selection, can skip this computing. */ + if (src_selection.is_single() && !src_selection.get_internal_single()) { + return GVArray::ForGArray(std::move(output)); + } + + GArray buffer = output; + + auto clamp_fn = std::make_unique>( + __func__, + [](float factor) { return math::clamp(factor, 0.0f, 1.0f); }, + fn::CustomMF_presets::AllSpanOrSingle()); + Field factor_field_clamped( + FieldOperation::Create(std::move(clamp_fn), {std::move(factor_field_)}), 0); + Array factors(domain_size); + + FieldEvaluator mask_evaluator(context, &mask); + mask_evaluator.add(count_field_); + mask_evaluator.add_with_destination(factor_field_clamped, factors.as_mutable_span()); + mask_evaluator.set_selection(selection_field_); + mask_evaluator.evaluate(); + const VArray src_count = mask_evaluator.get_evaluated(0); + const IndexMask evaluated_mask = mask_evaluator.get_evaluated_selection_as_mask(); + + /* With 0 iterations, there is no effect. */ + if (src_count.is_single() && !src_count.get_internal_single()) { + return GVArray::ForGArray(std::move(output)); + } + + SmoothCore smooth{factors.as_span(), + std::move(src_selection), + std::move(src_count), + output.as_mutable_span(), + buffer.as_mutable_span(), + *type_}; + + switch (context.type()) { + case GEO_COMPONENT_TYPE_MESH: + if (ELEM(context.domain(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) { + if (const Mesh *mesh = context.mesh()) { + smooth_mesh(*mesh, domain_size, context.domain(), evaluated_mask, std::move(smooth)); + } + } + break; + case GEO_COMPONENT_TYPE_CURVE: + if (context.domain() == ATTR_DOMAIN_POINT) { + const bke::CurvesGeometry &curves = *context.curves(); + smooth_curves(curves, std::move(smooth)); + } + break; + default: + break; + } + + return GVArray::ForGArray(std::move(output)); + } + + uint64_t hash() const override + { + return get_default_hash_4(selection_field_, count_field_, factor_field_, value_field_); + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + if (const SmoothField *other_smooth = dynamic_cast(&other)) { + return selection_field_ == other_smooth->selection_field_ && + count_field_ == other_smooth->count_field_ && + factor_field_ == other_smooth->factor_field_ && + value_field_ == other_smooth->value_field_; + } + return false; + } +}; + +static StringRefNull identifier_suffix(eCustomDataType data_type) +{ + switch (data_type) { + case CD_PROP_BOOL: + return "Bool"; + case CD_PROP_FLOAT: + return "Float"; + case CD_PROP_INT32: + return "Int"; + case CD_PROP_COLOR: + return "Color"; + case CD_PROP_FLOAT3: + return "Vector"; + default: + BLI_assert_unreachable(); + return ""; + } +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + const eCustomDataType data_type = static_cast(params.node().custom1); + + Field select_field = params.extract_input>("Selection"); + Field count_field = params.extract_input>("Iterations"); + Field factor_field = params.extract_input>("Factor"); + + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + static const std::string identifier = "Value_" + identifier_suffix(data_type); + Field value_field = params.extract_input>(identifier); + Field output_field{std::make_shared(std::move(select_field), + std::move(count_field), + std::move(factor_field), + std::move(value_field))}; + params.set_output(identifier, std::move(output_field)); + }); +} + +} // namespace blender::nodes::node_geo_smooth_attribute_cc + +void register_node_type_geo_smooth_attribute() +{ + namespace file_ns = blender::nodes::node_geo_smooth_attribute_cc; + + static bNodeType ntype; + geo_node_type_base(&ntype, GEO_NODE_SMOOTH_ATTRIBUTE, "Smooth Attribute", NODE_CLASS_ATTRIBUTE); + ntype.declare = file_ns::node_declare; + ntype.initfunc = file_ns::node_init; + ntype.updatefunc = file_ns::node_update; + ntype.draw_buttons = file_ns::node_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +}