├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── addon_updater.py ├── addon_updater_ops.py ├── helper.py ├── nodes ├── _base │ ├── node_base.py │ ├── node_deletion.py │ ├── node_input.py │ ├── node_modifier.py │ ├── node_operator.py │ ├── node_selection.py │ ├── node_setting.py │ └── node_transform.py ├── arrays │ ├── ScAddArray.py │ ├── ScAddElement.py │ ├── ScClearArray.py │ ├── ScCountElement.py │ ├── ScGetElement.py │ ├── ScMakeArray.py │ ├── ScPopElement.py │ ├── ScRemoveElement.py │ ├── ScReverseArray.py │ └── ScSearchElement.py ├── component_operators │ ├── ScAddEdgeFace.py │ ├── ScAverageNormals.py │ ├── ScBeautifyFill.py │ ├── ScBevel.py │ ├── ScBisect.py │ ├── ScBridgeEdgeLoops.py │ ├── ScConnectVertices.py │ ├── ScConvexHull.py │ ├── ScDecimate.py │ ├── ScDuplicateComponent.py │ ├── ScExtrude.py │ ├── ScExtrudeEdges.py │ ├── ScExtrudeFaces.py │ ├── ScExtrudeRegion.py │ ├── ScExtrudeVertices.py │ ├── ScFillEdgeLoop.py │ ├── ScFillGrid.py │ ├── ScFillHoles.py │ ├── ScFlatten.py │ ├── ScFlipNormals.py │ ├── ScHideComponents.py │ ├── ScInset.py │ ├── ScIntersect.py │ ├── ScIntersectBoolean.py │ ├── ScLoopCut.py │ ├── ScMakeNormalsConsistent.py │ ├── ScMarkComponent.py │ ├── ScMaterial.py │ ├── ScMergeComponents.py │ ├── ScMergeNormals.py │ ├── ScOffsetEdgeLoops.py │ ├── ScPointNormals.py │ ├── ScPoke.py │ ├── ScQuadrangulate.py │ ├── ScRemoveDoubles.py │ ├── ScRip.py │ ├── ScRipEdge.py │ ├── ScRotateEdge.py │ ├── ScScrew.py │ ├── ScSeparate.py │ ├── ScSolidify.py │ ├── ScSpin.py │ ├── ScSplit.py │ ├── ScSubdivide.py │ ├── ScSubdivideEdgeRing.py │ ├── ScSymmetrize.py │ ├── ScSymmetrySnap.py │ ├── ScTriangulate.py │ ├── ScUnhideComponents.py │ ├── ScUnsubdivide.py │ ├── ScUvProject.py │ ├── ScUvSmartProject.py │ ├── ScUvUnwrap.py │ ├── ScVertexGroup.py │ └── ScWireframe.py ├── constants │ ├── ScBool.py │ ├── ScNumber.py │ ├── ScSelectionType.py │ ├── ScString.py │ ├── ScTextBlock.py │ └── ScVector.py ├── curves │ ├── ScConvertToCurve.py │ ├── ScConvertToMesh.py │ ├── ScCurveGeometry.py │ ├── ScCurveShape.py │ ├── ScCurveSpline.py │ ├── ScCustomCurve.py │ ├── ScImportSvg.py │ └── ScText.py ├── deletion │ ├── ScDeleteComponents.py │ ├── ScDeleteEdgeLoop.py │ ├── ScDeleteLoose.py │ ├── ScDissolve.py │ ├── ScDissolveDegenerate.py │ ├── ScDissolveEdges.py │ ├── ScDissolveFaces.py │ ├── ScDissolveLimited.py │ ├── ScDissolveVertices.py │ └── ScEdgeCollapse.py ├── flow_control │ ├── ScBeginForEachComponentLoop.py │ ├── ScBeginForEachLoop.py │ ├── ScBeginForLoop.py │ ├── ScBranch.py │ ├── ScEndForEachComponentLoop.py │ ├── ScEndForEachLoop.py │ └── ScEndForLoop.py ├── inputs │ ├── ScAddCircle.py │ ├── ScAddCone.py │ ├── ScAddCube.py │ ├── ScAddCylinder.py │ ├── ScAddGrid.py │ ├── ScAddIcoSphere.py │ ├── ScAddMonkey.py │ ├── ScAddPlane.py │ ├── ScAddTorus.py │ ├── ScAddUvSphere.py │ ├── ScCreateCircle.py │ ├── ScCreateCone.py │ ├── ScCreateCube.py │ ├── ScCreateCylinder.py │ ├── ScCreateGrid.py │ ├── ScCreateIcoSphere.py │ ├── ScCreateMonkey.py │ ├── ScCreateObject.py │ ├── ScCreatePlane.py │ ├── ScCreateTorus.py │ ├── ScCreateUvSphere.py │ ├── ScCustomObject.py │ ├── ScEmpty.py │ ├── ScImportFbx.py │ ├── ScReceiveFromSverchok.py │ └── ScSingleVertex.py ├── modifiers │ ├── ScArrayMod.py │ ├── ScBevelMod.py │ ├── ScBooleanMod.py │ ├── ScBuildMod.py │ ├── ScCastMod.py │ ├── ScCorrectiveSmoothnessMod.py │ ├── ScCurveMod.py │ ├── ScDecimateMod.py │ ├── ScDisplaceMod.py │ ├── ScEdgeSplitMod.py │ ├── ScHookMod.py │ ├── ScLaplacianSmoothMod.py │ ├── ScLatticeMod.py │ ├── ScMirrorMod.py │ ├── ScRemeshMod.py │ ├── ScScrewMod.py │ ├── ScShrinkwrapMod.py │ ├── ScSimpleDeformMod.py │ ├── ScSkinMod.py │ ├── ScSmoothMod.py │ ├── ScSolidifyMod.py │ ├── ScSubsurfMod.py │ ├── ScTriangulateMod.py │ ├── ScWaveMod.py │ ├── ScWeightedNormalMod.py │ ├── ScWeldMod.py │ └── ScWireframeMod.py ├── noise │ ├── ScCell.py │ ├── ScCellVector.py │ ├── ScFractal.py │ ├── ScHeteroTerrain.py │ ├── ScHybridMultiFractal.py │ ├── ScMultiFractal.py │ ├── ScNoise.py │ ├── ScNoiseVector.py │ ├── ScRidgedMultiFractal.py │ ├── ScTurbulence.py │ ├── ScTurbulenceVector.py │ ├── ScVariableLacunarity.py │ └── ScVoronoi.py ├── object_operators │ ├── ScClearParent.py │ ├── ScDrawMode.py │ ├── ScDuplicateObject.py │ ├── ScExportFbx.py │ ├── ScFindNearest.py │ ├── ScGetChildren.py │ ├── ScGetParent.py │ ├── ScInstancing.py │ ├── ScMakeLinks.py │ ├── ScMergeObjects.py │ ├── ScOrigin.py │ ├── ScOverlap.py │ ├── ScParent.py │ ├── ScQuadriFlowRemesh.py │ ├── ScRaycastObject.py │ ├── ScScatter.py │ ├── ScSetDimensions.py │ ├── ScSetName.py │ ├── ScShading.py │ └── ScVoxelRemesh.py ├── selection │ ├── ScSelectAll.py │ ├── ScSelectAlternateFaces.py │ ├── ScSelectAxis.py │ ├── ScSelectByIndex.py │ ├── ScSelectByIndexArray.py │ ├── ScSelectByLocation.py │ ├── ScSelectByMaterial.py │ ├── ScSelectByNormal.py │ ├── ScSelectByVertexGroup.py │ ├── ScSelectFaceBySides.py │ ├── ScSelectInteriorFaces.py │ ├── ScSelectLess.py │ ├── ScSelectLinked.py │ ├── ScSelectLinkedFacesFlat.py │ ├── ScSelectLinkedPick.py │ ├── ScSelectLoop.py │ ├── ScSelectLoopRegion.py │ ├── ScSelectLoose.py │ ├── ScSelectManually.py │ ├── ScSelectMirror.py │ ├── ScSelectMore.py │ ├── ScSelectMultiLoop.py │ ├── ScSelectNextItem.py │ ├── ScSelectNonManifold.py │ ├── ScSelectNth.py │ ├── ScSelectPrevItem.py │ ├── ScSelectRandom.py │ ├── ScSelectRegionBoundary.py │ ├── ScSelectSharpEdges.py │ ├── ScSelectShortestPath.py │ ├── ScSelectShortestPathPick.py │ ├── ScSelectSimilar.py │ ├── ScSelectSimilarRegion.py │ ├── ScSelectUngrouped.py │ └── ScSelectVerticesByConnections.py ├── settings │ ├── ScCursorTransform.py │ ├── ScPivotPoint.py │ ├── ScProportionalEditing.py │ ├── ScSetSelectionMode.py │ ├── ScSnap.py │ └── ScTransformOrientation.py ├── transform │ ├── ScApplyTransform.py │ ├── ScCopyTransform.py │ ├── ScCreateOrientation.py │ ├── ScLocalTransform.py │ ├── ScRandomizeTransform.py │ ├── ScRandomizeVertices.py │ ├── ScToSphere.py │ ├── ScWarp.py │ └── ScWorldTransform.py └── utilities │ ├── ScAppendString.py │ ├── ScBooleanOp.py │ ├── ScBreakVector.py │ ├── ScClamp.py │ ├── ScComparisonOp.py │ ├── ScComponentInfo.py │ ├── ScCustomPythonScript.py │ ├── ScEvaluateAs.py │ ├── ScGetVariable.py │ ├── ScMapRange.py │ ├── ScMaterialParameter.py │ ├── ScMathsOp.py │ ├── ScNodeGroup.py │ ├── ScObjectInfo.py │ ├── ScPrint.py │ ├── ScRaycastScene.py │ ├── ScSceneInfo.py │ ├── ScSendToSverchok.py │ ├── ScSetVariable.py │ ├── ScTrigoOp.py │ └── ScVectorOp.py ├── operators ├── ScClearPreview.py ├── ScEditGroup.py ├── ScExecuteNode.py ├── ScGroupNodes.py └── ScSaveSelection.py ├── sockets ├── ScNodeSocketArray.py ├── ScNodeSocketArrayPlaceholder.py ├── ScNodeSocketBool.py ├── ScNodeSocketCurve.py ├── ScNodeSocketInfo.py ├── ScNodeSocketInterfaceArray.py ├── ScNodeSocketInterfaceBool.py ├── ScNodeSocketInterfaceCurve.py ├── ScNodeSocketInterfaceNumber.py ├── ScNodeSocketInterfaceObject.py ├── ScNodeSocketInterfaceSelectionType.py ├── ScNodeSocketInterfaceString.py ├── ScNodeSocketInterfaceUniversal.py ├── ScNodeSocketInterfaceVector.py ├── ScNodeSocketNumber.py ├── ScNodeSocketObject.py ├── ScNodeSocketSelectionType.py ├── ScNodeSocketString.py ├── ScNodeSocketUniversal.py ├── ScNodeSocketVector.py └── _base │ ├── interface_base.py │ └── socket_base.py ├── sorcar.png ├── tree ├── ScNodeCategory.py └── ScNodeTree.py └── ui ├── ScNodeGroupPanel.py ├── ScTreePropertiesPanel.py ├── ScUtilitiesPanel.py └── _base └── panel_base.py /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. Windows] 28 | - Blender Version [e.g. 2.80] 29 | - Sorcar Version [e.g. 3.1.0] 30 | 31 | **Additional context** 32 | Add any other context about the problem or your proposed solution here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[REQUEST]" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .vscode/ 3 | experimental/ 4 | sorcar_updater/ 5 | .idea/ 6 | venv/ 7 | -------------------------------------------------------------------------------- /nodes/_base/node_deletion.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from .._base.node_base import ScNode 4 | from ...helper import focus_on_object 5 | 6 | class ScDeletionNode(ScNode): 7 | def init(self, context): 8 | self.node_executable = True 9 | super().init(context) 10 | self.inputs.new("ScNodeSocketObject", "Object") 11 | self.outputs.new("ScNodeSocketObject", "Object") 12 | 13 | def error_condition(self): 14 | return ( 15 | self.inputs["Object"].default_value == None 16 | ) 17 | 18 | def pre_execute(self): 19 | focus_on_object(self.inputs["Object"].default_value, True) 20 | 21 | def post_execute(self): 22 | return {"Object": self.inputs["Object"].default_value} -------------------------------------------------------------------------------- /nodes/_base/node_input.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import PointerProperty, StringProperty, BoolProperty 4 | from .._base.node_base import ScNode 5 | from ...helper import focus_on_object, remove_object 6 | 7 | class ScInputNode(ScNode): 8 | in_name: StringProperty(default="Object", update=ScNode.update_value) 9 | out_mesh: PointerProperty(type=bpy.types.Object) 10 | 11 | def init(self, context): 12 | self.node_executable = True 13 | super().init(context) 14 | self.inputs.new("ScNodeSocketString", "Name").init("in_name") 15 | self.outputs.new("ScNodeSocketObject", "Object") 16 | 17 | def error_condition(self): 18 | return ( 19 | self.inputs["Name"].default_value == "" 20 | ) 21 | 22 | def pre_execute(self): 23 | if (bpy.ops.object.mode_set.poll()): 24 | bpy.ops.object.mode_set(mode="OBJECT") 25 | 26 | def post_execute(self): 27 | out = {} 28 | self.out_mesh = bpy.context.active_object 29 | self.out_mesh.name = self.inputs["Name"].default_value 30 | if (self.out_mesh.data): 31 | self.out_mesh.data.name = self.out_mesh.name 32 | out["Object"] = self.out_mesh 33 | self.id_data.register_object(self.out_mesh) 34 | return out 35 | 36 | def free(self): 37 | self.id_data.unregister_object(self.out_mesh) -------------------------------------------------------------------------------- /nodes/_base/node_modifier.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty 4 | from .._base.node_base import ScNode 5 | from ...helper import focus_on_object 6 | 7 | class ScModifierNode(ScNode): 8 | prop_mod_type: StringProperty() 9 | prop_mod_name: StringProperty() 10 | 11 | def init(self, context): 12 | self.node_executable = True 13 | super().init(context) 14 | self.inputs.new("ScNodeSocketObject", "Object") 15 | self.outputs.new("ScNodeSocketObject", "Object") 16 | 17 | def error_condition(self): 18 | return ( 19 | self.inputs["Object"].default_value == None 20 | ) 21 | 22 | def pre_execute(self): 23 | focus_on_object(self.inputs["Object"].default_value) 24 | bpy.ops.object.modifier_add(type=self.prop_mod_type) 25 | self.prop_mod_name = bpy.context.object.modifiers[-1].name 26 | 27 | def post_execute(self): 28 | bpy.ops.object.modifier_apply(apply_as='DATA', modifier=self.prop_mod_name) 29 | return {"Object": self.inputs["Object"].default_value} -------------------------------------------------------------------------------- /nodes/_base/node_selection.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from ...helper import focus_on_object 7 | 8 | class ScSelectionNode(ScNode): 9 | 10 | in_selection_type: EnumProperty(name="Mode", items=[("VERT", "Vertices", "", "VERTEXSEL", 1), ("EDGE", "Edges", "", "EDGESEL", 2), ("FACE", "Faces", "", "FACESEL", 4)], default=set(), options={"ENUM_FLAG"}, update=ScNode.update_value) 11 | 12 | def init(self, context): 13 | self.node_executable = True 14 | super().init(context) 15 | self.inputs.new("ScNodeSocketObject", "Object") 16 | self.inputs.new("ScNodeSocketSelectionType", "Selection Type").init("in_selection_type") 17 | self.outputs.new("ScNodeSocketObject", "Object") 18 | 19 | def error_condition(self): 20 | return ( 21 | self.inputs["Object"].default_value == None 22 | ) 23 | 24 | def pre_execute(self): 25 | focus_on_object(self.inputs["Object"].default_value, True) 26 | if len(self.inputs["Selection Type"].default_value) != 0: 27 | bpy.context.tool_settings.mesh_select_mode = ["VERT" in self.inputs["Selection Type"].default_value, "EDGE" in self.inputs["Selection Type"].default_value, "FACE" in self.inputs["Selection Type"].default_value] 28 | 29 | def post_execute(self): 30 | return {"Object": self.inputs["Object"].default_value} -------------------------------------------------------------------------------- /nodes/_base/node_setting.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | 6 | class ScSettingNode(ScNode): 7 | def init(self, context): 8 | self.node_executable = False 9 | super().init(context) 10 | self.inputs.new("ScNodeSocketUniversal", "In") 11 | self.outputs.new("ScNodeSocketUniversal", "Out") 12 | 13 | def error_condition(self): 14 | return ( 15 | self.inputs["In"].default_value == None 16 | ) 17 | 18 | def post_execute(self): 19 | return {"Out": self.inputs["In"].default_value} -------------------------------------------------------------------------------- /nodes/_base/node_transform.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from ...helper import focus_on_object 7 | 8 | class ScTransformNode(ScNode): 9 | in_edit: BoolProperty(update=ScNode.update_value) 10 | 11 | def init(self, context): 12 | self.node_executable = True 13 | super().init(context) 14 | self.inputs.new("ScNodeSocketObject", "Object") 15 | self.inputs.new("ScNodeSocketBool", "Edit Mode").init("in_edit", True) 16 | self.outputs.new("ScNodeSocketObject", "Object") 17 | 18 | def error_condition(self): 19 | return ( 20 | self.inputs["Object"].default_value == None 21 | ) 22 | 23 | def pre_execute(self): 24 | focus_on_object(self.inputs["Object"].default_value, self.inputs["Edit Mode"].default_value) 25 | 26 | def post_execute(self): 27 | return {"Object": self.inputs["Object"].default_value} -------------------------------------------------------------------------------- /nodes/arrays/ScAddArray.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import math 3 | 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScAddArray(Node, ScNode): 8 | bl_idname = "ScAddArray" 9 | bl_label = "Add Array" 10 | 11 | def init(self, context): 12 | super().init(context) 13 | self.inputs.new("ScNodeSocketArray", "Array") 14 | self.inputs.new("ScNodeSocketArray", "Secondary Array") 15 | self.outputs.new("ScNodeSocketArray", "New Array") 16 | 17 | def post_execute(self): 18 | out = {} 19 | arr = eval(self.inputs["Array"].default_value) 20 | arr.extend(eval(self.inputs["Secondary Array"].default_value)) 21 | out["New Array"] = repr(arr) 22 | return out -------------------------------------------------------------------------------- /nodes/arrays/ScAddElement.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import math 3 | 4 | from bpy.props import IntProperty, BoolProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | 8 | class ScAddElement(Node, ScNode): 9 | bl_idname = "ScAddElement" 10 | bl_label = "Add Element" 11 | 12 | in_use_index: BoolProperty(update=ScNode.update_value) 13 | in_index: IntProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketArray", "Array") 18 | self.inputs.new("ScNodeSocketUniversal", "Element") 19 | self.inputs.new("ScNodeSocketBool", "Use Index").init("in_use_index") 20 | self.inputs.new("ScNodeSocketNumber", "Index").init("in_index") 21 | self.outputs.new("ScNodeSocketArray", "New Array") 22 | 23 | def post_execute(self): 24 | out = {} 25 | arr = eval(self.inputs["Array"].default_value) 26 | if (self.inputs["Use Index"].default_value): 27 | arr.insert(int(self.inputs["Index"].default_value), self.inputs["Element"].default_value) 28 | else: 29 | arr.append(self.inputs["Element"].default_value) 30 | out["New Array"] = repr(arr) 31 | return out -------------------------------------------------------------------------------- /nodes/arrays/ScClearArray.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import math 3 | 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScClearArray(Node, ScNode): 8 | bl_idname = "ScClearArray" 9 | bl_label = "Clear Array" 10 | 11 | def init(self, context): 12 | super().init(context) 13 | self.inputs.new("ScNodeSocketArray", "Array") 14 | self.outputs.new("ScNodeSocketArray", "Empty Array") 15 | 16 | def post_execute(self): 17 | out = {} 18 | arr = eval(self.inputs["Array"].default_value) 19 | arr.clear() 20 | out["Empty Array"] = repr(arr) 21 | return out -------------------------------------------------------------------------------- /nodes/arrays/ScCountElement.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import math 3 | 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScCountElement(Node, ScNode): 8 | bl_idname = "ScCountElement" 9 | bl_label = "Count Element" 10 | 11 | def init(self, context): 12 | super().init(context) 13 | self.inputs.new("ScNodeSocketArray", "Array") 14 | self.inputs.new("ScNodeSocketUniversal", "Element") 15 | self.outputs.new("ScNodeSocketNumber", "Value") 16 | 17 | def post_execute(self): 18 | out = {} 19 | out["Value"] = eval(self.inputs["Array"].default_value).count(self.inputs["Element"].default_value) 20 | return out -------------------------------------------------------------------------------- /nodes/arrays/ScGetElement.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScGetElement(Node, ScNode): 8 | bl_idname = "ScGetElement" 9 | bl_label = "Get Element" 10 | 11 | in_index: IntProperty(update=ScNode.update_value) 12 | 13 | def init(self, context): 14 | super().init(context) 15 | self.inputs.new("ScNodeSocketArray", "Array") 16 | self.inputs.new("ScNodeSocketNumber", "Index").init("in_index", True) 17 | self.outputs.new("ScNodeSocketUniversal", "Element") 18 | 19 | def post_execute(self): 20 | out = {} 21 | try: 22 | out["Element"] = repr(eval(self.inputs["Array"].default_value)[int(self.inputs["Index"].default_value)]) 23 | except: 24 | out["Element"] = None 25 | return out -------------------------------------------------------------------------------- /nodes/arrays/ScMakeArray.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import math 3 | 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScMakeArray(Node, ScNode): 8 | bl_idname = "ScMakeArray" 9 | bl_label = "Make Array" 10 | 11 | def init(self, context): 12 | super().init(context) 13 | self.inputs.new("ScNodeSocketArrayPlaceholder", "...") 14 | self.outputs.new("ScNodeSocketArray", "Array") 15 | 16 | def init_in(self, forced): 17 | for i in self.inputs: 18 | if (not i.bl_rna.name == "ScNodeSocketArrayPlaceholder"): 19 | if (i.is_linked): 20 | if (not i.execute(forced)): 21 | return False 22 | else: 23 | self.inputs.remove(i) 24 | return True 25 | 26 | def post_execute(self): 27 | arr = [] 28 | for i in self.inputs: 29 | if (not i.bl_rna.name == "ScNodeSocketArrayPlaceholder"): 30 | if (i.bl_rna.name == "ScNodeSocketVector"): 31 | arr.append(list(i.default_value)) 32 | else: 33 | arr.append(i.default_value) 34 | return {"Array": repr(arr)} -------------------------------------------------------------------------------- /nodes/arrays/ScPopElement.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import math 3 | 4 | from bpy.props import IntProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | 8 | class ScPopElement(Node, ScNode): 9 | bl_idname = "ScPopElement" 10 | bl_label = "Pop Element" 11 | 12 | in_index: IntProperty(default=-1, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketArray", "Array") 17 | self.inputs.new("ScNodeSocketNumber", "Index").init("in_index") 18 | self.outputs.new("ScNodeSocketArray", "New Array") 19 | self.outputs.new("ScNodeSocketUniversal", "Element") 20 | 21 | def post_execute(self): 22 | out = {} 23 | arr = eval(self.inputs["Array"].default_value) 24 | try: 25 | elem = arr.pop(int(self.inputs["Index"].default_value)) 26 | except: 27 | elem = None 28 | out["New Array"] = repr(arr) 29 | out["Element"] = repr(elem) 30 | return out -------------------------------------------------------------------------------- /nodes/arrays/ScRemoveElement.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import math 3 | 4 | from bpy.props import IntProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | 8 | class ScRemoveElement(Node, ScNode): 9 | bl_idname = "ScRemoveElement" 10 | bl_label = "Remove Element" 11 | 12 | def init(self, context): 13 | super().init(context) 14 | self.inputs.new("ScNodeSocketArray", "Array") 15 | self.inputs.new("ScNodeSocketUniversal", "Element") 16 | self.outputs.new("ScNodeSocketArray", "New Array") 17 | 18 | def post_execute(self): 19 | out = {} 20 | arr = eval(self.inputs["Array"].default_value) 21 | try: 22 | arr.remove(self.inputs["Element"].default_value) 23 | except: 24 | pass 25 | out["New Array"] = repr(arr) 26 | return out -------------------------------------------------------------------------------- /nodes/arrays/ScReverseArray.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import math 3 | 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScReverseArray(Node, ScNode): 8 | bl_idname = "ScReverseArray" 9 | bl_label = "Reverse Array" 10 | 11 | def init(self, context): 12 | super().init(context) 13 | self.inputs.new("ScNodeSocketArray", "Array") 14 | self.outputs.new("ScNodeSocketArray", "New Array") 15 | 16 | def post_execute(self): 17 | out = {} 18 | arr = eval(self.inputs["Array"].default_value) 19 | arr.reverse() 20 | out["New Array"] = repr(arr) 21 | return out -------------------------------------------------------------------------------- /nodes/arrays/ScSearchElement.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import math 3 | 4 | from bpy.props import BoolProperty, IntProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | 8 | class ScSearchElement(Node, ScNode): 9 | bl_idname = "ScSearchElement" 10 | bl_label = "Search Element" 11 | 12 | in_range: BoolProperty(update=ScNode.update_value) 13 | in_start: IntProperty(update=ScNode.update_value) 14 | in_end: IntProperty(default=10, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketArray", "Array") 19 | self.inputs.new("ScNodeSocketUniversal", "Element") 20 | self.inputs.new("ScNodeSocketBool", "Use Range").init("in_range") 21 | self.inputs.new("ScNodeSocketNumber", "Start Index").init("in_start") 22 | self.inputs.new("ScNodeSocketNumber", "End Index").init("in_end") 23 | self.outputs.new("ScNodeSocketNumber", "Index") 24 | 25 | def post_execute(self): 26 | out = {} 27 | try: 28 | if (self.inputs["Use Range"].default_value): 29 | index = eval(self.inputs["Array"].default_value).index(self.inputs["Element"].default_value, int(self.inputs["Start Index"].default_value), int(self.inputs["End Index"].default_value)) 30 | else: 31 | index = eval(self.inputs["Array"].default_value).index(self.inputs["Element"].default_value) 32 | except: 33 | index = -1 34 | out["Index"] = index 35 | return out -------------------------------------------------------------------------------- /nodes/component_operators/ScAddEdgeFace.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | from .._base.node_operator import ScEditOperatorNode 6 | 7 | class ScAddEdgeFace(Node, ScEditOperatorNode): 8 | bl_idname = "ScAddEdgeFace" 9 | bl_label = "Add Edge/Face" 10 | 11 | def functionality(self): 12 | bpy.ops.mesh.edge_face_add() -------------------------------------------------------------------------------- /nodes/component_operators/ScAverageNormals.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScAverageNormals(Node, ScEditOperatorNode): 9 | bl_idname = "ScAverageNormals" 10 | bl_label = "Average Normals" 11 | 12 | in_average_type: EnumProperty(items=[('CUSTOM_NORMAL', 'Custom Normal', ''), ('FACE_AREA', 'Face Area', ''), ('CORNER_ANGLE', 'Corner Angle', '')], default='CUSTOM_NORMAL', update=ScNode.update_value) 13 | in_weight: FloatProperty(default=50.0, min=1.0, max=100.0, update=ScNode.update_value) 14 | in_threshold: FloatProperty(default=0.01, min=0.0, max=10.0, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketString", "Type").init("in_average_type", True) 19 | self.inputs.new("ScNodeSocketNumber", "Weight").init("in_weight") 20 | self.inputs.new("ScNodeSocketNumber", "Threshold").init("in_threshold") 21 | 22 | def error_condition(self): 23 | return( 24 | super().error_condition() 25 | or (not self.inputs["Type"].default_value in ['CUSTOM_NORMAL', 'FACE_AREA', 'CORNER_ANGLE']) 26 | or (self.inputs["Weight"].default_value < 1.0 or self.inputs["Weight"].default_value > 100.0) 27 | or (self.inputs["Threshold"].default_value < 0.0 or self.inputs["Threshold"].default_value > 10.0) 28 | ) 29 | 30 | def functionality(self): 31 | bpy.ops.mesh.average_normals( 32 | average_type = self.inputs["Type"].default_value, 33 | weight = self.inputs["Weight"].default_value, 34 | threshold = self.inputs["Threshold"].default_value 35 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScBeautifyFill.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScBeautifyFill(Node, ScEditOperatorNode): 9 | bl_idname = "ScBeautifyFill" 10 | bl_label = "Beautify Fill" 11 | 12 | in_angle_limit: FloatProperty(default=3.14159, min=0.0, max=3.14159, unit="ROTATION", update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketNumber", "Angle Limit").init("in_angle_limit", True) 17 | 18 | def error_condition(self): 19 | return( 20 | super().error_condition() 21 | or (self.inputs["Angle Limit"].default_value < 0 or self.inputs["Angle Limit"].default_value > 3.14159) 22 | ) 23 | 24 | def functionality(self): 25 | bpy.ops.mesh.beautify_fill( 26 | angle_limit = self.inputs["Angle Limit"].default_value 27 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScConnectVertices.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScConnectVertices(Node, ScEditOperatorNode): 9 | bl_idname = "ScConnectVertices" 10 | bl_label = "Connect Vertices" 11 | 12 | in_type: EnumProperty(items=[('SIMPLE', 'Simple', ''), ('CONCAVE', 'Concave', ''), ('NONPLANAR', 'Non-Planar', '')], default='SIMPLE', update=ScNode.update_value) 13 | in_angle_limit: FloatProperty(default=0.0872665, min=0.0, max=3.14159, unit="ROTATION", update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketString", "Type").init("in_type", True) 18 | self.inputs.new("ScNodeSocketNumber", "Angle Limit").init("in_angle_limit") 19 | 20 | def error_condition(self): 21 | return( 22 | super().error_condition() 23 | or (not self.inputs["Type"].default_value in ['SIMPLE', 'CONCAVE', 'NONPLANAR']) 24 | or (self.inputs["Angle Limit"].default_value < 0.0 or self.inputs["Angle Limit"].default_value > 3.14159) 25 | ) 26 | 27 | def functionality(self): 28 | if (self.inputs["Type"].default_value == 'SIMPLE'): 29 | bpy.ops.mesh.vert_connect() 30 | elif (self.inputs["Type"].default_value == 'CONCAVE'): 31 | bpy.ops.mesh.vert_connect_concave() 32 | else: 33 | bpy.ops.mesh.vert_connect_nonplanar( 34 | angle_limit = self.inputs["Angle Limit"].default_value 35 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScDuplicateComponent.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatVectorProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | from ...helper import get_override 8 | 9 | class ScDuplicateComponent(Node, ScEditOperatorNode): 10 | bl_idname = "ScDuplicateComponent" 11 | bl_label = "Duplicate Component" 12 | 13 | in_move_offset: FloatVectorProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketVector", "Move Offset").init("in_move_offset", True) 18 | 19 | def functionality(self): 20 | bpy.ops.mesh.duplicate_move( 21 | get_override(self.inputs["Object"].default_value, True), 22 | TRANSFORM_OT_translate = { 23 | "value": self.inputs["Move Offset"].default_value 24 | } 25 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScExtrude.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty, FloatVectorProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | from ...helper import get_override 8 | 9 | class ScExtrude(Node, ScEditOperatorNode): 10 | bl_idname = "ScExtrude" 11 | bl_label = "Extrude" 12 | 13 | in_value: FloatVectorProperty(update=ScNode.update_value) 14 | in_use_normal_flip: BoolProperty(update=ScNode.update_value) 15 | in_mirror: BoolProperty(update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketVector", "Value").init("in_value", True) 20 | self.inputs.new("ScNodeSocketBool", "Flip Normals").init("in_use_normal_flip") 21 | self.inputs.new("ScNodeSocketBool", "Mirror Editing").init("in_mirror") 22 | 23 | def functionality(self): 24 | bpy.ops.mesh.extrude_context_move( 25 | get_override(self.inputs["Object"].default_value, True), 26 | MESH_OT_extrude_context = { 27 | "use_normal_flip": self.inputs["Flip Normals"].default_value, 28 | "mirror": self.inputs["Mirror Editing"].default_value 29 | }, 30 | TRANSFORM_OT_translate = { 31 | "value": self.inputs["Value"].default_value 32 | } 33 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScExtrudeEdges.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty, FloatVectorProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | from ...helper import get_override 8 | 9 | class ScExtrudeEdges(Node, ScEditOperatorNode): 10 | bl_idname = "ScExtrudeEdges" 11 | bl_label = "Extrude Edges (Individually)" 12 | 13 | in_value: FloatVectorProperty(update=ScNode.update_value) 14 | in_use_normal_flip: BoolProperty(update=ScNode.update_value) 15 | in_mirror: BoolProperty(update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketVector", "Value").init("in_value", True) 20 | self.inputs.new("ScNodeSocketBool", "Flip Normals").init("in_use_normal_flip") 21 | self.inputs.new("ScNodeSocketBool", "Mirror Editing").init("in_mirror") 22 | 23 | def functionality(self): 24 | bpy.ops.mesh.extrude_edges_move( 25 | get_override(self.inputs["Object"].default_value, True), 26 | MESH_OT_extrude_edges_indiv = { 27 | "use_normal_flip": self.inputs["Flip Normals"].default_value, 28 | "mirror": self.inputs["Mirror Editing"].default_value 29 | }, 30 | TRANSFORM_OT_translate = { 31 | "value": self.inputs["Value"].default_value 32 | } 33 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScExtrudeFaces.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | from ...helper import get_override 8 | 9 | class ScExtrudeFaces(Node, ScEditOperatorNode): 10 | bl_idname = "ScExtrudeFaces" 11 | bl_label = "Extrude Faces (Individually)" 12 | 13 | in_value: FloatProperty(update=ScNode.update_value) 14 | in_use_normal_flip: BoolProperty(update=ScNode.update_value) 15 | in_mirror: BoolProperty(update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketNumber", "Value").init("in_value", True) 20 | self.inputs.new("ScNodeSocketBool", "Mirror Editing").init("in_mirror") 21 | 22 | def functionality(self): 23 | bpy.ops.mesh.extrude_faces_move( 24 | get_override(self.inputs["Object"].default_value, True), 25 | MESH_OT_extrude_faces_indiv = { 26 | "mirror": self.inputs["Mirror Editing"].default_value 27 | }, 28 | TRANSFORM_OT_shrink_fatten = { 29 | "value": self.inputs["Value"].default_value 30 | } 31 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScExtrudeVertices.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatVectorProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | from ...helper import get_override 8 | 9 | class ScExtrudeVertices(Node, ScEditOperatorNode): 10 | bl_idname = "ScExtrudeVertices" 11 | bl_label = "Extrude Vertices (Individually)" 12 | 13 | in_value: FloatVectorProperty(update=ScNode.update_value) 14 | in_use_normal_flip: BoolProperty(update=ScNode.update_value) 15 | in_mirror: BoolProperty(update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketVector", "Value").init("in_value", True) 20 | self.inputs.new("ScNodeSocketBool", "Mirror Editing").init("in_mirror") 21 | 22 | def functionality(self): 23 | bpy.ops.mesh.extrude_vertices_move( 24 | get_override(self.inputs["Object"].default_value, True), 25 | MESH_OT_extrude_verts_indiv = { 26 | "mirror": self.inputs["Mirror Editing"].default_value 27 | }, 28 | TRANSFORM_OT_translate = { 29 | "value": self.inputs["Value"].default_value 30 | } 31 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScFillEdgeLoop.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScFillEdgeLoop(Node, ScEditOperatorNode): 9 | bl_idname = "ScFillEdgeLoop" 10 | bl_label = "Fill Edge Loop" 11 | 12 | in_use_beauty: BoolProperty(default=True, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Beauty").init("in_use_beauty", True) 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.fill( 20 | use_beauty = self.inputs["Beauty"].default_value 21 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScFillGrid.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty, IntProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScFillGrid(Node, ScEditOperatorNode): 9 | bl_idname = "ScFillGrid" 10 | bl_label = "Fill Grid" 11 | 12 | in_span: IntProperty(default=1, min=1, max=1000, update=ScNode.update_value) 13 | in_offset: IntProperty(default=0, min=-1000, max=1000, update=ScNode.update_value) 14 | in_interp: BoolProperty(update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketNumber", "Span").init("in_span", True) 19 | self.inputs.new("ScNodeSocketNumber", "Offset").init("in_offset", True) 20 | self.inputs.new("ScNodeSocketBool", "Simple Blending").init("in_interp") 21 | 22 | def error_condition(self): 23 | return ( 24 | super().error_condition() 25 | or (int(self.inputs["Span"].default_value) < 1 or int(self.inputs["Span"].default_value) > 1000) 26 | or (int(self.inputs["Offset"].default_value) < -1000 or int(self.inputs["Offset"].default_value) > 1000) 27 | ) 28 | 29 | def functionality(self): 30 | bpy.ops.mesh.fill_grid( 31 | span = int(self.inputs["Span"].default_value), 32 | offset = int(self.inputs["Offset"].default_value), 33 | use_interp_simple = self.inputs["Simple Blending"].default_value 34 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScFillHoles.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScFillHoles(Node, ScEditOperatorNode): 9 | bl_idname = "ScFillHoles" 10 | bl_label = "Fill Holes (by Sides)" 11 | 12 | in_sides: IntProperty(default=4, min=0, max=1000, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketNumber", "Sides").init("in_sides", True) 17 | 18 | def error_condition(self): 19 | return ( 20 | super().error_condition() 21 | or (int(self.inputs["Sides"].default_value) < 0 or int(self.inputs["Sides"].default_value) > 1000) 22 | ) 23 | 24 | def functionality(self): 25 | bpy.ops.mesh.fill_holes( 26 | sides = int(self.inputs["Sides"].default_value) 27 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScFlipNormals.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | from .._base.node_operator import ScEditOperatorNode 6 | 7 | class ScFlipNormals(Node, ScEditOperatorNode): 8 | bl_idname = "ScFlipNormals" 9 | bl_label = "Flip Normals" 10 | 11 | def functionality(self): 12 | bpy.ops.mesh.flip_normals() -------------------------------------------------------------------------------- /nodes/component_operators/ScHideComponents.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScHideComponents(Node, ScEditOperatorNode): 9 | bl_idname = "ScHideComponents" 10 | bl_label = "Hide Components" 11 | 12 | in_unselected: BoolProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Unselected").init("in_unselected") 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.hide( 20 | unselected = self.inputs["Unselected"].default_value 21 | ) 22 | -------------------------------------------------------------------------------- /nodes/component_operators/ScIntersect.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScIntersect(Node, ScEditOperatorNode): 9 | bl_idname = "ScIntersect" 10 | bl_label = "Intersect" 11 | 12 | in_mode: EnumProperty(items=[('SELECT', 'Self Intersect', ''), ('SELECT_UNSELECT', 'Selected/Unselected', '')], default='SELECT_UNSELECT', update=ScNode.update_value) 13 | in_separate_mode: EnumProperty(items=[('ALL', 'All', ''), ('CUT', 'Cut', ''), ('NONE', 'Merge', '')], default='CUT', update=ScNode.update_value) 14 | in_threshold: FloatProperty(default=0.000001, min=0.0, max=0.01, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketString", "Source").init("in_mode", True) 19 | self.inputs.new("ScNodeSocketString", "Separate Mode").init("in_separate_mode", True) 20 | self.inputs.new("ScNodeSocketNumber", "Threshold").init("in_threshold") 21 | 22 | def error_condition(self): 23 | return( 24 | super().error_condition() 25 | or (not self.inputs["Source"].default_value in ['SELECT', 'SELECT_UNSELECT']) 26 | or (not self.inputs["Separate Mode"].default_value in ['ALL', 'CUT', 'NONE']) 27 | or (self.inputs["Threshold"].default_value < 0.0 or self.inputs["Threshold"].default_value > 0.01) 28 | ) 29 | 30 | def functionality(self): 31 | bpy.ops.mesh.intersect( 32 | mode = self.inputs["Source"].default_value, 33 | separate_mode = self.inputs["Separate Mode"].default_value, 34 | threshold = self.inputs["Threshold"].default_value 35 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScIntersectBoolean.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, EnumProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScIntersectBoolean(Node, ScEditOperatorNode): 9 | bl_idname = "ScIntersectBoolean" 10 | bl_label = "Intersect Boolean" 11 | 12 | in_operation: EnumProperty(items=[('INTERSECT', 'Intersect', ''), ('UNION', 'Union', ''), ('DIFFERENCE', 'Difference', '')], default='DIFFERENCE', update=ScNode.update_value) 13 | in_use_swap: BoolProperty(update=ScNode.update_value) 14 | in_threshold: FloatProperty(default=0.000001, min=0.0, max=0.01, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketString", "Operation").init("in_operation", True) 19 | self.inputs.new("ScNodeSocketBool", "Swap").init("in_use_swap") 20 | self.inputs.new("ScNodeSocketNumber", "Threshold").init("in_threshold") 21 | 22 | def error_condition(self): 23 | return( 24 | super().error_condition() 25 | or (not self.inputs["Operation"].default_value in ['INTERSECT', 'UNION', 'DIFFERENCE']) 26 | or (self.inputs["Threshold"].default_value < 0.0 or self.inputs["Threshold"].default_value > 0.01) 27 | ) 28 | 29 | def functionality(self): 30 | bpy.ops.mesh.intersect_boolean( 31 | operation = self.inputs["Operation"].default_value, 32 | use_swap = self.inputs["Swap"].default_value, 33 | threshold = self.inputs["Threshold"].default_value 34 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScMakeNormalsConsistent.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScMakeNormalsConsistent(Node, ScEditOperatorNode): 9 | bl_idname = "ScMakeNormalsConsistent" 10 | bl_label = "Make Normals Consistent" 11 | 12 | in_inside: BoolProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketNumber", "Inside").init("in_inside", True) 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.normals_make_consistent( 20 | inside = self.inputs["Inside"].default_value 21 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScMaterial.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import PointerProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | from ...helper import get_override 8 | 9 | class ScMaterial(Node, ScEditOperatorNode): 10 | bl_idname = "ScMaterial" 11 | bl_label = "Material" 12 | 13 | prop_mat: PointerProperty(name="Material", type=bpy.types.Material, update=ScNode.update_value) 14 | 15 | def draw_buttons(self, context, layout): 16 | super().draw_buttons(context, layout) 17 | layout.prop(self, "prop_mat") 18 | 19 | def error_condition(self): 20 | return( 21 | super().error_condition() 22 | or self.prop_mat == None 23 | ) 24 | 25 | def pre_execute(self): 26 | super().pre_execute() 27 | slot = self.inputs["Object"].default_value.material_slots.find(self.prop_mat.name) 28 | if (slot == -1): 29 | bpy.ops.object.material_slot_add() 30 | self.inputs["Object"].default_value.active_material = self.prop_mat 31 | else: 32 | self.inputs["Object"].default_value.active_material_index = slot 33 | 34 | def functionality(self): 35 | bpy.ops.object.material_slot_assign() -------------------------------------------------------------------------------- /nodes/component_operators/ScMergeComponents.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScMergeComponents(Node, ScEditOperatorNode): 9 | bl_idname = "ScMergeComponents" 10 | bl_label = "Merge Components" 11 | 12 | in_type: EnumProperty(items=[('FIRST', 'First', ''), ('LAST', 'Last', ''), ('CENTER', 'Center', ''), ('CURSOR', 'Cursor', ''), ('COLLAPSE', 'Collapse', '')], default='CENTER', update=ScNode.update_value) 13 | in_uvs: BoolProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketString", "Type").init("in_type", True) 18 | self.inputs.new("ScNodeSocketBool", "UVs").init("in_uvs") 19 | 20 | def error_condition(self): 21 | return( 22 | super().error_condition() 23 | or (not self.inputs["Type"].default_value in ['FIRST', 'LAST', 'CENTER', 'CURSOR', 'COLLAPSE']) 24 | ) 25 | 26 | def functionality(self): 27 | bpy.ops.mesh.merge( 28 | type = self.inputs["Type"].default_value, 29 | uvs = self.inputs["UVs"].default_value 30 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScMergeNormals.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | from .._base.node_operator import ScEditOperatorNode 6 | 7 | class ScMergeNormals(Node, ScEditOperatorNode): 8 | bl_idname = "ScMergeNormals" 9 | bl_label = "Merge Normals" 10 | 11 | def functionality(self): 12 | bpy.ops.mesh.merge_normals() -------------------------------------------------------------------------------- /nodes/component_operators/ScOffsetEdgeLoops.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | from ...helper import get_override 8 | 9 | class ScOffsetEdgeLoops(Node, ScEditOperatorNode): 10 | bl_idname = "ScOffsetEdgeLoops" 11 | bl_label = "Offset Edge Loops" 12 | 13 | in_factor: FloatProperty(default=0.523187, min=-1.0, max=1.0, update=ScNode.update_value) 14 | in_cap: BoolProperty(update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketNumber", "Factor").init("in_factor", True) 19 | self.inputs.new("ScNodeSocketBool", "Cap Endpoint").init("in_cap") 20 | 21 | def error_condition(self): 22 | return( 23 | super().error_condition() 24 | or (self.inputs["Factor"].default_value < -1.0 or self.inputs["Factor"].default_value > 1.0) 25 | ) 26 | 27 | def functionality(self): 28 | bpy.ops.mesh.offset_edge_loops_slide( 29 | get_override(self.inputs["Object"].default_value, True), 30 | MESH_OT_offset_edge_loops = { 31 | "use_cap_endpoint": self.inputs["Cap Endpoint"].default_value 32 | }, 33 | TRANSFORM_OT_edge_slide = { 34 | "value": self.inputs["Factor"].default_value 35 | } 36 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScPointNormals.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty, FloatVectorProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScPointNormals(Node, ScEditOperatorNode): 9 | bl_idname = "ScPointNormals" 10 | bl_label = "Point Normals" 11 | 12 | in_target_location: FloatVectorProperty(update=ScNode.update_value) 13 | in_invert: BoolProperty(update=ScNode.update_value) 14 | in_align: BoolProperty(update=ScNode.update_value) 15 | in_spherize: BoolProperty(update=ScNode.update_value) 16 | in_spherize_strength: FloatProperty(default=0.1, min=0.0, max=1.0, update=ScNode.update_value) 17 | 18 | def init(self, context): 19 | super().init(context) 20 | self.inputs.new("ScNodeSocketVector", "Target").init("in_target_location", True) 21 | self.inputs.new("ScNodeSocketBool", "Invert").init("in_invert", True) 22 | self.inputs.new("ScNodeSocketBool", "Align").init("in_align") 23 | self.inputs.new("ScNodeSocketBool", "Spherize").init("in_spherize") 24 | self.inputs.new("ScNodeSocketNumber", "Spherize Strength").init("in_spherize_strength") 25 | 26 | def error_condition(self): 27 | return( 28 | super().error_condition() 29 | or (self.inputs["Spherize Strength"].default_value < 0.0 or self.inputs["Spherize Strength"].default_value > 1.0) 30 | ) 31 | 32 | def functionality(self): 33 | bpy.ops.mesh.point_normals( 34 | target_location = self.inputs["Target"].default_value, 35 | invert = self.inputs["Invert"].default_value, 36 | align = self.inputs["Align"].default_value, 37 | spherize = self.inputs["Spherize"].default_value, 38 | spherize_strength = self.inputs["Spherize Strength"].default_value 39 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScPoke.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty, EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScPoke(Node, ScEditOperatorNode): 9 | bl_idname = "ScPoke" 10 | bl_label = "Poke" 11 | 12 | in_offset: FloatProperty(default=0.0, min=-1000.0, max=1000.0, update=ScNode.update_value) 13 | in_use_relative_offset: BoolProperty(update=ScNode.update_value) 14 | in_center_mode: EnumProperty(items=[("MEDIAN_WEIGHTED", "Median Weighted", ""), ("MEDIAN", "Median", ""), ("BOUNDS", "Bounds", "")], default="MEDIAN_WEIGHTED", update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketNumber", "Poke Offset").init("in_offset", True) 19 | self.inputs.new("ScNodeSocketBool", "Relative Offset").init("in_use_relative_offset") 20 | self.inputs.new("ScNodeSocketString", "Poke Center").init("in_center_mode") 21 | 22 | def error_condition(self): 23 | return( 24 | super().error_condition() 25 | or (self.inputs["Poke Offset"].default_value < -1000 or self.inputs["Poke Offset"].default_value > 1000) 26 | or (not self.inputs["Poke Center"].default_value in ['MEDIAN_WEIGHTED', 'MEDIAN', 'BOUNDS']) 27 | ) 28 | 29 | def functionality(self): 30 | bpy.ops.mesh.poke( 31 | offset = self.inputs["Poke Offset"].default_value, 32 | use_relative_offset = self.inputs["Relative Offset"].default_value, 33 | center_mode = self.inputs["Poke Center"].default_value 34 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScRemoveDoubles.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScRemoveDoubles(Node, ScEditOperatorNode): 9 | bl_idname = "ScRemoveDoubles" 10 | bl_label = "Remove Doubles" 11 | 12 | in_threshold: FloatProperty(default=0.0001, min=0.000001, max=50.0, update=ScNode.update_value) 13 | in_unselected: BoolProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketNumber", "Threshold").init("in_threshold", True) 18 | self.inputs.new("ScNodeSocketBool", "Unselected").init("in_unselected") 19 | 20 | def error_condition(self): 21 | return( 22 | super().error_condition() 23 | or (self.inputs["Threshold"].default_value < 0.000001 or self.inputs["Threshold"].default_value > 50) 24 | ) 25 | 26 | def functionality(self): 27 | bpy.ops.mesh.remove_doubles( 28 | threshold = self.inputs["Threshold"].default_value, 29 | use_unselected = self.inputs["Unselected"].default_value 30 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScRip.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty, FloatVectorProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | from ...helper import get_override 8 | 9 | class ScRip(Node, ScEditOperatorNode): 10 | bl_idname = "ScRip" 11 | bl_label = "Rip" 12 | 13 | in_value: FloatVectorProperty(update=ScNode.update_value) 14 | in_mirror: BoolProperty(update=ScNode.update_value) 15 | in_fill: BoolProperty(update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketVector", "Value").init("in_value", True) 20 | self.inputs.new("ScNodeSocketBool", "Mirror Editing").init("in_mirror") 21 | self.inputs.new("ScNodeSocketBool", "Fill").init("in_fill") 22 | 23 | def functionality(self): 24 | bpy.ops.mesh.rip_move( 25 | get_override(self.inputs["Object"].default_value, True), 26 | MESH_OT_rip = { 27 | "mirror": self.inputs["Mirror Editing"].default_value, 28 | "use_fill": self.inputs["Fill"].default_value 29 | }, 30 | TRANSFORM_OT_translate = { 31 | "value": self.inputs["Value"].default_value 32 | } 33 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScRipEdge.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty, FloatVectorProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | from ...helper import get_override 8 | 9 | class ScRipEdge(Node, ScEditOperatorNode): 10 | bl_idname = "ScRipEdge" 11 | bl_label = "Rip Edge" 12 | 13 | in_value: FloatVectorProperty(update=ScNode.update_value) 14 | in_mirror: BoolProperty(update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketVector", "Value").init("in_value", True) 19 | self.inputs.new("ScNodeSocketBool", "Mirror Editing").init("in_mirror") 20 | 21 | def functionality(self): 22 | bpy.ops.mesh.rip_edge_move( 23 | get_override(self.inputs["Object"].default_value, True), 24 | MESH_OT_rip_edge = { 25 | "mirror": self.inputs["Mirror Editing"].default_value 26 | }, 27 | TRANSFORM_OT_translate = { 28 | "value": self.inputs["Value"].default_value 29 | } 30 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScRotateEdge.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScRotateEdge(Node, ScEditOperatorNode): 9 | bl_idname = "ScRotateEdge" 10 | bl_label = "Rotate Edge" 11 | 12 | in_use_ccw: BoolProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Counter Clockwise").init("in_use_ccw", True) 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.edge_rotate( 20 | use_ccw = self.inputs["Counter Clockwise"].default_value 21 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScScrew.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty, FloatVectorProperty 4 | from bpy.types import Node 5 | from mathutils import Vector 6 | from .._base.node_base import ScNode 7 | from .._base.node_operator import ScEditOperatorNode 8 | 9 | class ScScrew(Node, ScEditOperatorNode): 10 | bl_idname = "ScScrew" 11 | bl_label = "Screw" 12 | 13 | in_steps: IntProperty(default=9, min=1, max=100000, update=ScNode.update_value) 14 | in_turns: IntProperty(default=1, min=1, max=100000, update=ScNode.update_value) 15 | in_center: FloatVectorProperty(update=ScNode.update_value) 16 | in_axis: FloatVectorProperty(default=(1.0, 0.0, 0.0), min=-1.0, max=1.0, update=ScNode.update_value) 17 | 18 | def init(self, context): 19 | super().init(context) 20 | self.inputs.new("ScNodeSocketNumber", "Steps").init("in_steps", True) 21 | self.inputs.new("ScNodeSocketNumber", "Turns").init("in_turns", True) 22 | self.inputs.new("ScNodeSocketVector", "Center").init("in_center", True) 23 | self.inputs.new("ScNodeSocketVector", "Axis").init("in_axis", True) 24 | 25 | def error_condition(self): 26 | return( 27 | super().error_condition() 28 | or (int(self.inputs["Steps"].default_value) < 1 or int(self.inputs["Steps"].default_value) > 100000) 29 | or (int(self.inputs["Turns"].default_value) < 1 or int(self.inputs["Turns"].default_value) > 100000) 30 | or Vector(self.inputs["Axis"].default_value).magnitude == 0 31 | ) 32 | 33 | def functionality(self): 34 | bpy.ops.mesh.screw( 35 | steps = int(self.inputs["Steps"].default_value), 36 | turns = int(self.inputs["Turns"].default_value), 37 | center = self.inputs["Center"].default_value, 38 | axis = self.inputs["Axis"].default_value 39 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScSolidify.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScSolidify(Node, ScEditOperatorNode): 9 | bl_idname = "ScSolidify" 10 | bl_label = "Solidify" 11 | 12 | in_thickness: FloatProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketNumber", "Thickness").init("in_thickness", True) 17 | 18 | def error_condition(self): 19 | return( 20 | super().error_condition() 21 | or (self.inputs["Thickness"].default_value < -10000.0 or self.inputs["Thickness"].default_value > 10000.0) 22 | ) 23 | 24 | def functionality(self): 25 | bpy.ops.mesh.solidify( 26 | thickness = self.inputs["Thickness"].default_value 27 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScSplit.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScSplit(Node, ScEditOperatorNode): 9 | bl_idname = "ScSplit" 10 | bl_label = "Split" 11 | 12 | in_type: EnumProperty(items=[('REGION', 'Region', ''), ('INDIVIDUAL', 'Individual', ''), ('EDGE', 'Loose Edges', ''), ('NORMAL', 'Normals', '')], default='REGION', update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketString", "Type").init("in_type", True) 17 | 18 | def error_condition(self): 19 | return ( 20 | super().error_condition() 21 | or (not self.inputs["Type"].default_value in ['REGION', 'INDIVIDUAL', 'EDGE', 'NORMAL']) 22 | ) 23 | 24 | def functionality(self): 25 | if (self.inputs["Type"].default_value == 'REGION'): 26 | bpy.ops.mesh.split() 27 | elif (self.inputs["Type"].default_value == 'INDIVIDUAL'): 28 | bpy.ops.mesh.edge_split() 29 | elif (self.inputs["Type"].default_value == 'EDGE'): 30 | bpy.ops.mesh.face_split_by_edges() 31 | elif (self.inputs["Type"].default_value == 'NORMAL'): 32 | bpy.ops.mesh.split_normals() -------------------------------------------------------------------------------- /nodes/component_operators/ScSymmetrize.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScSymmetrize(Node, ScEditOperatorNode): 9 | bl_idname = "ScSymmetrize" 10 | bl_label = "Symmetrize" 11 | 12 | in_direction: EnumProperty(items=[("NEGATIVE_X", "-X to +X", ""), ("POSITIVE_X", "+X to -X", ""), ("NEGATIVE_Y", "-Y to +Y", ""), ("POSITIVE_Y", "+Y to -Y", ""), ("NEGATIVE_Z", "-Z to +Z", ""), ("POSITIVE_Z", "+Z to -Z", "")], default="NEGATIVE_X", update=ScNode.update_value) 13 | in_threshold: FloatProperty(default=0.0001, min=0.0, max=10.0, update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketString", "Direction").init("in_direction", True) 18 | self.inputs.new("ScNodeSocketNumber", "Threshold").init("in_threshold") 19 | 20 | def error_condition(self): 21 | return( 22 | super().error_condition() 23 | or (not self.inputs["Direction"].default_value in ['NEGATIVE_X', 'POSITIVE_X', 'NEGATIVE_Y', 'POSITIVE_Y', 'NEGATIVE_Z', 'POSITIVE_Z']) 24 | or (self.inputs["Threshold"].default_value < 0.0 or self.inputs["Threshold"].default_value > 10.0) 25 | ) 26 | 27 | def functionality(self): 28 | bpy.ops.mesh.symmetrize( 29 | direction = self.inputs["Direction"].default_value, 30 | threshold = self.inputs["Threshold"].default_value 31 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScTriangulate.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScTriangulate(Node, ScEditOperatorNode): 9 | bl_idname = "ScTriangulate" 10 | bl_label = "Triangulate" 11 | 12 | in_quad: EnumProperty(items=[("BEAUTY", "Beauty", ""), ("FIXED", "Fixed", ""), ("FIXED_ALTERNATE", "Fixed Alternate", ""), ("SHORTEST_DIAGONAL", "Shortest Diagonal", "")], default="BEAUTY", update=ScNode.update_value) 13 | in_ngon: EnumProperty(items=[("BEAUTY", "Beauty", ""), ("CLIP", "Clip", "")], default="BEAUTY", update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketString", "Quad Method").init("in_quad", True) 18 | self.inputs.new("ScNodeSocketString", "Polygon Method").init("in_ngon", True) 19 | 20 | def error_condition(self): 21 | return( 22 | super().error_condition() 23 | or (not self.inputs["Quad Method"].default_value in ['BEAUTY', 'FIXED', 'FIXED_ALTERNATE', 'SHORTEST_DIAGONAL']) 24 | or (not self.inputs["Polygon Method"].default_value in ['BEAUTY', 'CLIP']) 25 | ) 26 | 27 | def functionality(self): 28 | bpy.ops.mesh.quads_convert_to_tris( 29 | quad_method = self.inputs["Quad Method"].default_value, 30 | ngon_method = self.inputs["Polygon Method"].default_value 31 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScUnhideComponents.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScUnhideComponents(Node, ScEditOperatorNode): 9 | bl_idname = "ScUnhideComponents" 10 | bl_label = "Unhide Components" 11 | 12 | in_select: BoolProperty(default=True, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Select").init("in_select") 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.reveal( 20 | select = self.inputs["Select"].default_value 21 | ) 22 | -------------------------------------------------------------------------------- /nodes/component_operators/ScUnsubdivide.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScUnsubdivide(Node, ScEditOperatorNode): 9 | bl_idname = "ScUnsubdivide" 10 | bl_label = "Unsubdivide" 11 | 12 | in_iterations: IntProperty(default=2, min=1, max=1000, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketNumber", "Iterations").init("in_iterations", True) 17 | 18 | def error_condition(self): 19 | return( 20 | super().error_condition() 21 | or (int(self.inputs["Iterations"].default_value) < 1 or int(self.inputs["Iterations"].default_value) > 1000) 22 | ) 23 | 24 | def functionality(self): 25 | bpy.ops.mesh.unsubdivide( 26 | iterations = int(self.inputs["Iterations"].default_value) 27 | ) -------------------------------------------------------------------------------- /nodes/component_operators/ScVertexGroup.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScVertexGroup(Node, ScEditOperatorNode): 9 | bl_idname = "ScVertexGroup" 10 | bl_label = "Vertex Group" 11 | 12 | in_vg: StringProperty(default="Group", update=ScNode.update_value) 13 | in_assign: BoolProperty(default=True, update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketString", "Name").init("in_vg", True) 18 | self.inputs.new("ScNodeSocketBool", "Assign").init("in_assign") 19 | 20 | def error_condition(self): 21 | return( 22 | super().error_condition() 23 | or self.inputs["Name"].default_value == "" 24 | ) 25 | 26 | def pre_execute(self): 27 | super().pre_execute() 28 | name = self.inputs["Name"].default_value 29 | slot = self.inputs["Object"].default_value.vertex_groups.find(name) 30 | if (slot == -1): 31 | bpy.ops.object.vertex_group_add() 32 | self.inputs["Object"].default_value.vertex_groups.active.name = name 33 | else: 34 | self.inputs["Object"].default_value.vertex_groups.active_index = slot 35 | 36 | def functionality(self): 37 | if (self.inputs["Assign"].default_value): 38 | bpy.ops.object.vertex_group_assign() 39 | else: 40 | bpy.ops.object.vertex_group_remove_from() -------------------------------------------------------------------------------- /nodes/constants/ScBool.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | 4 | from bpy.props import BoolProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | 8 | class ScBool(Node, ScNode): 9 | bl_idname = "ScBool" 10 | bl_label = "Bool" 11 | 12 | prop_bool: BoolProperty(name="Bool", update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.outputs.new("ScNodeSocketBool", "Value") 17 | 18 | def draw_buttons(self, context, layout): 19 | super().draw_buttons(context, layout) 20 | layout.prop(self, "prop_bool") 21 | 22 | def post_execute(self): 23 | return {"Value": self.prop_bool} -------------------------------------------------------------------------------- /nodes/constants/ScSelectionType.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | 4 | from bpy.props import BoolVectorProperty, EnumProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | 8 | class ScSelectionType(Node, ScNode): 9 | bl_idname = "ScSelectionType" 10 | bl_label = "Selection Type" 11 | 12 | prop_type: EnumProperty(name="Mode", items=[("VERT", "Vertices", "", "VERTEXSEL", 1), ("EDGE", "Edges", "", "EDGESEL", 2), ("FACE", "Faces", "", "FACESEL", 4)], default={"VERT"}, options={"ENUM_FLAG"}, update=ScNode.update_value) 13 | def init(self, context): 14 | super().init(context) 15 | self.outputs.new("ScNodeSocketSelectionType", "Value") 16 | 17 | def draw_buttons(self, context, layout): 18 | super().draw_buttons(context, layout) 19 | layout.column().prop(self, "prop_type") 20 | 21 | def post_execute(self): 22 | return {"Value": self.prop_type} -------------------------------------------------------------------------------- /nodes/constants/ScString.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScString(Node, ScNode): 8 | bl_idname = "ScString" 9 | bl_label = "String" 10 | 11 | prop_string: StringProperty(name="String", update=ScNode.update_value) 12 | 13 | def init(self, context): 14 | super().init(context) 15 | self.outputs.new("ScNodeSocketString", "Value") 16 | 17 | def draw_buttons(self, context, layout): 18 | super().draw_buttons(context, layout) 19 | layout.prop(self, "prop_string") 20 | 21 | def post_execute(self): 22 | return {"Value": self.prop_string} -------------------------------------------------------------------------------- /nodes/constants/ScTextBlock.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import PointerProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScTextBlock(Node, ScNode): 8 | bl_idname = "ScTextBlock" 9 | bl_label = "Text Block" 10 | 11 | prop_text: PointerProperty(name="Text", type=bpy.types.Text, update=ScNode.update_value) 12 | 13 | def init(self, context): 14 | super().init(context) 15 | self.outputs.new("ScNodeSocketString", "Value") 16 | 17 | def error_condition(self): 18 | return self.prop_text == None 19 | 20 | def draw_buttons(self, context, layout): 21 | super().draw_buttons(context, layout) 22 | layout.prop(self, "prop_text") 23 | if (not self.prop_text == None): 24 | col = layout.column() 25 | for l in self.prop_text.lines: 26 | col.label(text=l.body) 27 | 28 | def post_execute(self): 29 | return {"Value": self.prop_text.as_string()} -------------------------------------------------------------------------------- /nodes/curves/ScConvertToCurve.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import os 3 | 4 | from bpy.props import PointerProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | from ...helper import focus_on_object 8 | 9 | class ScConvertToCurve(Node, ScNode): 10 | bl_idname = "ScConvertToCurve" 11 | bl_label = "Convert to Curve" 12 | 13 | prop_mesh: PointerProperty(type=bpy.types.Mesh) 14 | 15 | def init(self, context): 16 | self.node_executable = True 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketObject", "Object") 19 | self.outputs.new("ScNodeSocketCurve", "Curve") 20 | 21 | def pre_execute(self): 22 | focus_on_object(self.inputs["Object"].default_value) 23 | self.prop_mesh = self.inputs["Object"].default_value.data 24 | 25 | def functionality(self): 26 | bpy.ops.object.convert( 27 | target = "CURVE", 28 | keep_original = False 29 | ) 30 | 31 | def post_execute(self): 32 | bpy.context.active_object.data.name = bpy.context.active_object.name 33 | bpy.data.meshes.remove(self.prop_mesh) 34 | return {"Curve": bpy.context.active_object} -------------------------------------------------------------------------------- /nodes/curves/ScConvertToMesh.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import os 3 | 4 | from bpy.props import PointerProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | from ...helper import focus_on_object 8 | 9 | class ScConvertToMesh(Node, ScNode): 10 | bl_idname = "ScConvertToMesh" 11 | bl_label = "Convert to Mesh" 12 | 13 | prop_curve: PointerProperty(type=bpy.types.Curve) 14 | 15 | def init(self, context): 16 | self.node_executable = True 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketCurve", "Curve") 19 | self.outputs.new("ScNodeSocketObject", "Object") 20 | 21 | def pre_execute(self): 22 | focus_on_object(self.inputs["Curve"].default_value) 23 | self.prop_curve = self.inputs["Curve"].default_value.data 24 | 25 | def functionality(self): 26 | bpy.ops.object.convert( 27 | target = "MESH", 28 | keep_original = False 29 | ) 30 | 31 | def post_execute(self): 32 | bpy.context.active_object.data.name = bpy.context.active_object.name 33 | bpy.data.curves.remove(self.prop_curve) 34 | return {"Object": bpy.context.active_object} -------------------------------------------------------------------------------- /nodes/deletion/ScDeleteComponents.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_deletion import ScDeletionNode 7 | 8 | class ScDeleteComponents(Node, ScDeletionNode): 9 | bl_idname = "ScDeleteComponents" 10 | bl_label = "Delete Components" 11 | 12 | in_type: EnumProperty(items=[("VERT", "Vertices", ""), ("EDGE", "Edges", ""), ("FACE", "Faces", ""), ("EDGE_FACE", "Edges And Faces", ""), ("ONLY_FACE", "Only Faces", "")], default="VERT", update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketString", "Type").init("in_type", True) 17 | 18 | def error_condition(self): 19 | return ( 20 | super().error_condition() 21 | or (not self.inputs["Type"].default_value in ['VERT', 'EDGE', 'FACE', 'EDGE_FACE', 'ONLY_FACE']) 22 | ) 23 | 24 | def functionality(self): 25 | bpy.ops.mesh.delete( 26 | type = self.inputs["Type"].default_value 27 | ) -------------------------------------------------------------------------------- /nodes/deletion/ScDeleteEdgeLoop.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_deletion import ScDeletionNode 7 | 8 | class ScDeleteEdgeLoop(Node, ScDeletionNode): 9 | bl_idname = "ScDeleteEdgeLoop" 10 | bl_label = "Delete Edge Loop" 11 | 12 | in_split: BoolProperty(default=True, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Face Split").init("in_split") 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.delete_edgeloop( 20 | use_face_split = self.inputs["Face Split"].default_value 21 | ) -------------------------------------------------------------------------------- /nodes/deletion/ScDeleteLoose.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_deletion import ScDeletionNode 7 | 8 | class ScDeleteLoose(Node, ScDeletionNode): 9 | bl_idname = "ScDeleteLoose" 10 | bl_label = "Delete Loose" 11 | 12 | in_vert: BoolProperty(default=True, update=ScNode.update_value) 13 | in_edge: BoolProperty(default=True, update=ScNode.update_value) 14 | in_face: BoolProperty(update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketBool", "Vertices").init("in_vert") 19 | self.inputs.new("ScNodeSocketBool", "Edges").init("in_edge") 20 | self.inputs.new("ScNodeSocketBool", "Faces").init("in_face") 21 | 22 | def functionality(self): 23 | bpy.ops.mesh.delete_loose( 24 | use_verts = self.inputs["Vertices"].default_value, 25 | use_edges = self.inputs["Edges"].default_value, 26 | use_faces = self.inputs["Faces"].default_value 27 | ) -------------------------------------------------------------------------------- /nodes/deletion/ScDissolve.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_deletion import ScDeletionNode 7 | 8 | class ScDissolve(Node, ScDeletionNode): 9 | bl_idname = "ScDissolve" 10 | bl_label = "Dissolve" 11 | 12 | in_split: BoolProperty(update=ScNode.update_value) 13 | in_boundary: BoolProperty(update=ScNode.update_value) 14 | in_verts: BoolProperty(update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketBool", "Dissolve Vertices").init("in_verts") 19 | self.inputs.new("ScNodeSocketBool", "Face Split").init("in_split") 20 | self.inputs.new("ScNodeSocketBool", "Tear Boundary").init("in_boundary") 21 | 22 | def functionality(self): 23 | bpy.ops.mesh.dissolve_mode( 24 | use_verts = self.inputs["Dissolve Vertices"].default_value, 25 | use_face_split = self.inputs["Face Split"].default_value, 26 | use_boundary_tear = self.inputs["Tear Boundary"].default_value 27 | ) -------------------------------------------------------------------------------- /nodes/deletion/ScDissolveDegenerate.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_deletion import ScDeletionNode 7 | 8 | class ScDissolveDegenerate(Node, ScDeletionNode): 9 | bl_idname = "ScDissolveDegenerate" 10 | bl_label = "Dissolve Degenerate" 11 | 12 | in_threshold: FloatProperty(default=0.0001, min=0.000001, max=50.0, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketNumber", "Threshold").init("in_threshold", True) 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.dissolve_degenerate( 20 | threshold = self.inputs["Threshold"].default_value 21 | ) -------------------------------------------------------------------------------- /nodes/deletion/ScDissolveEdges.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_deletion import ScDeletionNode 7 | 8 | class ScDissolveEdges(Node, ScDeletionNode): 9 | bl_idname = "ScDissolveEdges" 10 | bl_label = "Dissolve Edges" 11 | 12 | in_verts: BoolProperty(default=True, update=ScNode.update_value) 13 | in_split: BoolProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketBool", "Dissolve Vertices").init("in_verts", True) 18 | self.inputs.new("ScNodeSocketBool", "Face Split").init("in_split") 19 | 20 | def functionality(self): 21 | bpy.ops.mesh.dissolve_edges( 22 | use_verts = self.inputs["Dissolve Vertices"].default_value, 23 | use_face_split = self.inputs["Face Split"].default_value 24 | ) -------------------------------------------------------------------------------- /nodes/deletion/ScDissolveFaces.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_deletion import ScDeletionNode 7 | 8 | class ScDissolveFaces(Node, ScDeletionNode): 9 | bl_idname = "ScDissolveFaces" 10 | bl_label = "Dissolve Faces" 11 | 12 | in_verts: BoolProperty(default=True, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Dissolve Vertices").init("in_verts", True) 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.dissolve_faces( 20 | use_verts = self.inputs["Dissolve Vertices"].default_value, 21 | ) -------------------------------------------------------------------------------- /nodes/deletion/ScDissolveLimited.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty, BoolProperty, FloatProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_deletion import ScDeletionNode 7 | 8 | class ScDissolveLimited(Node, ScDeletionNode): 9 | bl_idname = "ScDissolveLimited" 10 | bl_label = "Dissolve Limited" 11 | 12 | prop_delimit: EnumProperty(items=[('NORMAL', 'Normal', "", 2), ('MATERIAL', 'Material', "", 4), ('SEAM', 'Seam', "", 8), ('SHARP', 'Sharp', "", 16), ('UV', 'UV', "", 32)], default={'NORMAL'}, options={"ENUM_FLAG"}, update=ScNode.update_value) 13 | in_angle: FloatProperty(default=0.0872665, min=0, max=3.14159, unit="ROTATION", update=ScNode.update_value) 14 | in_boundary: BoolProperty(update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketNumber", "Max Angle").init("in_angle", True) 19 | self.inputs.new("ScNodeSocketBool", "All Boundaries").init("in_boundary") 20 | 21 | def draw_buttons(self, context, layout): 22 | super().draw_buttons(context, layout) 23 | layout.prop(self, "prop_delimit") 24 | 25 | def error_condition(self): 26 | return ( 27 | super().error_condition() 28 | or (self.inputs["Max Angle"].default_value < 0 or self.inputs["Max Angle"].default_value > 3.14159) 29 | ) 30 | 31 | def functionality(self): 32 | bpy.ops.mesh.dissolve_limited( 33 | angle_limit = self.inputs["Max Angle"].default_value, 34 | use_dissolve_boundaries = self.inputs["All Boundaries"].default_value, 35 | delimit = self.prop_delimit 36 | ) -------------------------------------------------------------------------------- /nodes/deletion/ScDissolveVertices.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_deletion import ScDeletionNode 7 | 8 | class ScDissolveVertices(Node, ScDeletionNode): 9 | bl_idname = "ScDissolveVertices" 10 | bl_label = "Dissolve Vertices" 11 | 12 | in_split: BoolProperty(update=ScNode.update_value) 13 | in_boundary: BoolProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketBool", "Face Split").init("in_split") 18 | self.inputs.new("ScNodeSocketBool", "Tear Boundary").init("in_boundary") 19 | 20 | def functionality(self): 21 | bpy.ops.mesh.dissolve_verts( 22 | use_face_split = self.inputs["Face Split"].default_value, 23 | use_boundary_tear = self.inputs["Tear Boundary"].default_value 24 | ) -------------------------------------------------------------------------------- /nodes/deletion/ScEdgeCollapse.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_deletion import ScDeletionNode 7 | 8 | class ScEdgeCollapse(Node, ScDeletionNode): 9 | bl_idname = "ScEdgeCollapse" 10 | bl_label = "Collapse Edge" 11 | 12 | def functionality(self): 13 | bpy.ops.mesh.edge_collapse() -------------------------------------------------------------------------------- /nodes/flow_control/ScBeginForEachLoop.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty, IntProperty, StringProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScBeginForEachLoop(Node, ScNode): 8 | bl_idname = "ScBeginForEachLoop" 9 | bl_label = "Begin For-Each Loop" 10 | 11 | prop_locked: BoolProperty() 12 | out_element: StringProperty() 13 | out_index: IntProperty() 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketUniversal", "In") 18 | self.outputs.new("ScNodeSocketInfo", "End For-Each Loop") 19 | self.outputs.new("ScNodeSocketUniversal", "Out") 20 | self.outputs.new("ScNodeSocketUniversal", "Element") 21 | self.outputs.new("ScNodeSocketNumber", "Index") 22 | 23 | def execute(self, forced=False): 24 | if (self.prop_locked): 25 | self.outputs["Element"].default_value = self.out_element 26 | self.outputs["Index"].default_value = self.out_index 27 | self.set_color() 28 | return True 29 | else: 30 | self.prop_locked = True 31 | self.out_index = 0 32 | return super().execute(forced) 33 | 34 | def post_execute(self): 35 | out = {} 36 | out["Out"] = self.inputs["In"].default_value 37 | out["Index"] = self.out_index 38 | return out -------------------------------------------------------------------------------- /nodes/flow_control/ScBeginForLoop.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty, IntProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScBeginForLoop(Node, ScNode): 8 | bl_idname = "ScBeginForLoop" 9 | bl_label = "Begin For Loop" 10 | 11 | prop_locked: BoolProperty() 12 | out_counter: IntProperty() 13 | 14 | def reset(self, execute): 15 | if (execute): 16 | self.prop_locked = False 17 | super().reset(execute) 18 | 19 | def init(self, context): 20 | super().init(context) 21 | self.inputs.new("ScNodeSocketUniversal", "In") 22 | self.outputs.new("ScNodeSocketInfo", "End For Loop") 23 | self.outputs.new("ScNodeSocketUniversal", "Out") 24 | self.outputs.new("ScNodeSocketNumber", "Counter") 25 | 26 | def execute(self, forced=False): 27 | if (self.prop_locked): 28 | self.outputs["Counter"].default_value = self.out_counter 29 | self.set_color() 30 | return True 31 | else: 32 | self.prop_locked = True 33 | self.out_counter = 0 34 | return super().execute(forced) 35 | 36 | def post_execute(self): 37 | out = {} 38 | out["Out"] = self.inputs["In"].default_value 39 | out["Counter"] = self.out_counter 40 | return out -------------------------------------------------------------------------------- /nodes/flow_control/ScBranch.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScBranch(Node, ScNode): 8 | bl_idname = "ScBranch" 9 | bl_label = "Branch (If-Else)" 10 | 11 | in_condition: BoolProperty(update=ScNode.update_value) 12 | 13 | def init(self, context): 14 | super().init(context) 15 | self.inputs.new("ScNodeSocketUniversal", "True") 16 | self.inputs.new("ScNodeSocketUniversal", "False") 17 | self.inputs.new("ScNodeSocketBool", "Condition").init("in_condition", True) 18 | self.outputs.new("ScNodeSocketUniversal", "Value") 19 | 20 | def init_in(self, forced): 21 | if (self.inputs["Condition"].execute(forced)): 22 | if (self.inputs["Condition"].default_value): 23 | return self.inputs["True"].execute(forced) 24 | else: 25 | return self.inputs["False"].execute(forced) 26 | return False 27 | 28 | def post_execute(self): 29 | if (self.inputs["Condition"].default_value): 30 | return {"Value": self.inputs["True"].default_value} 31 | else: 32 | return {"Value": self.inputs["False"].default_value} -------------------------------------------------------------------------------- /nodes/flow_control/ScEndForEachLoop.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScEndForEachLoop(Node, ScNode): 8 | bl_idname = "ScEndForEachLoop" 9 | bl_label = "End For-Each Loop" 10 | 11 | in_iterations: IntProperty(default=5, min=1, update=ScNode.update_value) 12 | 13 | def init(self, context): 14 | self.node_executable = True 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketInfo", "Begin For-Each Loop") 17 | self.inputs.new("ScNodeSocketUniversal", "In") 18 | self.inputs.new("ScNodeSocketArray", "Array") 19 | self.outputs.new("ScNodeSocketUniversal", "Out") 20 | 21 | def init_in(self, forced): 22 | return ( 23 | self.inputs["Begin For-Each Loop"].is_linked 24 | and self.inputs["Begin For-Each Loop"].links[0].from_node.execute(forced) 25 | and self.inputs["Array"].execute(forced) 26 | ) 27 | 28 | def error_condition(self): 29 | return ( 30 | len(eval(self.inputs["Array"].default_value)) == 0 31 | ) 32 | 33 | def functionality(self): 34 | for i in eval(self.inputs["Array"].default_value): 35 | self.inputs["Begin For-Each Loop"].links[0].from_node.out_index += 1 36 | self.inputs["Begin For-Each Loop"].links[0].from_node.out_element = repr(i) 37 | self.inputs["In"].execute(True) 38 | self.inputs["Begin For-Each Loop"].links[0].from_node.prop_locked = False 39 | 40 | def post_execute(self): 41 | out = {} 42 | out["Out"] = self.inputs["In"].default_value 43 | return out -------------------------------------------------------------------------------- /nodes/flow_control/ScEndForLoop.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScEndForLoop(Node, ScNode): 8 | bl_idname = "ScEndForLoop" 9 | bl_label = "End For Loop" 10 | 11 | in_iterations: IntProperty(default=5, min=1, update=ScNode.update_value) 12 | 13 | def init(self, context): 14 | self.node_executable = True 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketInfo", "Begin For Loop") 17 | self.inputs.new("ScNodeSocketUniversal", "In") 18 | self.inputs.new("ScNodeSocketNumber", "Iterations").init("in_iterations", True) 19 | self.outputs.new("ScNodeSocketUniversal", "Out") 20 | 21 | def init_in(self, forced): 22 | return ( 23 | self.inputs["Begin For Loop"].is_linked 24 | and self.inputs["Begin For Loop"].links[0].from_node.execute(forced) 25 | and self.inputs["Iterations"].execute(forced) 26 | ) 27 | 28 | def error_condition(self): 29 | return ( 30 | int(self.inputs["Iterations"].default_value) < 1 31 | ) 32 | 33 | def functionality(self): 34 | for i in range (0, int(self.inputs["Iterations"].default_value)): 35 | self.inputs["Begin For Loop"].links[0].from_node.out_counter += 1 36 | self.inputs["In"].execute(True) 37 | self.inputs["Begin For Loop"].links[0].from_node.prop_locked = False 38 | 39 | def post_execute(self): 40 | out = {} 41 | out["Out"] = self.inputs["In"].default_value 42 | return out -------------------------------------------------------------------------------- /nodes/inputs/ScAddCircle.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty, IntProperty, FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScAddCircle(Node, ScEditOperatorNode): 9 | bl_idname = "ScAddCircle" 10 | bl_label = "Add Circle" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_type: EnumProperty(items=[("NOTHING", "Nothing", ""), ("NGON", "Ngon", ""), ("TRIFAN", "Triangle Fan", "")], default="NOTHING", update=ScNode.update_value) 14 | in_vertices: IntProperty(default=32, min=3, max=10000000, update=ScNode.update_value) 15 | in_radius: FloatProperty(default=1.0, min=0.0, update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 20 | self.inputs.new("ScNodeSocketString", "Fill Type").init("in_type") 21 | self.inputs.new("ScNodeSocketNumber", "Vertices").init("in_vertices", True) 22 | self.inputs.new("ScNodeSocketNumber", "Radius").init("in_radius", True) 23 | 24 | def error_condition(self): 25 | return ( 26 | super().error_condition() 27 | or (not self.inputs["Fill Type"].default_value in ['NOTHING', 'NGON', 'TRIFAN']) 28 | or self.inputs["Vertices"].default_value < 3 29 | or self.inputs["Radius"].default_value < 0 30 | ) 31 | 32 | def functionality(self): 33 | bpy.ops.mesh.primitive_circle_add( 34 | vertices = int(self.inputs["Vertices"].default_value), 35 | radius = self.inputs["Radius"].default_value, 36 | fill_type = self.inputs["Fill Type"].default_value, 37 | calc_uvs = self.inputs["Generate UVs"].default_value 38 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScAddCube.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScAddCube(Node, ScEditOperatorNode): 9 | bl_idname = "ScAddCube" 10 | bl_label = "Add Cube" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_size: FloatProperty(default=2.0, min=0.0, update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 18 | self.inputs.new("ScNodeSocketNumber", "Size").init("in_size", True) 19 | 20 | def error_condition(self): 21 | return ( 22 | super().error_condition() 23 | or self.inputs["Size"].default_value <= 0 24 | ) 25 | 26 | def functionality(self): 27 | bpy.ops.mesh.primitive_cube_add( 28 | size = self.inputs["Size"].default_value, 29 | calc_uvs = self.inputs["Generate UVs"].default_value 30 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScAddGrid.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty, FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScAddGrid(Node, ScEditOperatorNode): 9 | bl_idname = "ScAddGrid" 10 | bl_label = "Add Grid" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_x: IntProperty(default=10, min=2, max=10000000, update=ScNode.update_value) 14 | in_y: IntProperty(default=10, min=2, max=10000000, update=ScNode.update_value) 15 | in_size: FloatProperty(default=2.0, min=0.0, update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 20 | self.inputs.new("ScNodeSocketNumber", "X Subdivisions").init("in_x", True) 21 | self.inputs.new("ScNodeSocketNumber", "Y Subdivisions").init("in_y", True) 22 | self.inputs.new("ScNodeSocketNumber", "Size").init("in_size", True) 23 | 24 | def error_condition(self): 25 | return ( 26 | super().error_condition() 27 | or (self.inputs["X Subdivisions"].default_value < 2 or self.inputs["X Subdivisions"].default_value > 10000000) 28 | or (self.inputs["Y Subdivisions"].default_value < 2 or self.inputs["Y Subdivisions"].default_value > 10000000) 29 | or self.inputs["Size"].default_value <= 0 30 | ) 31 | 32 | def functionality(self): 33 | bpy.ops.mesh.primitive_grid_add( 34 | x_subdivisions = int(self.inputs["X Subdivisions"].default_value), 35 | y_subdivisions = int(self.inputs["Y Subdivisions"].default_value), 36 | size = self.inputs["Size"].default_value, 37 | calc_uvs = self.inputs["Generate UVs"].default_value 38 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScAddIcoSphere.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty, FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScAddIcoSphere(Node, ScEditOperatorNode): 9 | bl_idname = "ScAddIcoSphere" 10 | bl_label = "Add Ico Sphere" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_subdivision: IntProperty(default=2, min=1, max=10, update=ScNode.update_value) 14 | in_radius: FloatProperty(default=1.0, min=0.0, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 19 | self.inputs.new("ScNodeSocketNumber", "Subdivisions").init("in_subdivision", True) 20 | self.inputs.new("ScNodeSocketNumber", "Radius").init("in_radius", True) 21 | 22 | def error_condition(self): 23 | return ( 24 | super().error_condition() 25 | or (self.inputs["Subdivisions"].default_value < 1 or self.inputs["Subdivisions"].default_value > 10) 26 | or self.inputs["Radius"].default_value < 0 27 | ) 28 | 29 | def functionality(self): 30 | bpy.ops.mesh.primitive_ico_sphere_add( 31 | subdivisions = int(self.inputs["Subdivisions"].default_value), 32 | radius = self.inputs["Radius"].default_value, 33 | calc_uvs = self.inputs["Generate UVs"].default_value 34 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScAddMonkey.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScAddMonkey(Node, ScEditOperatorNode): 9 | bl_idname = "ScAddMonkey" 10 | bl_label = "Add Monkey (Suzanne)" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_size: FloatProperty(default=2.0, min=0.0, update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 18 | self.inputs.new("ScNodeSocketNumber", "Size").init("in_size", True) 19 | 20 | def error_condition(self): 21 | return ( 22 | super().error_condition() 23 | or self.inputs["Size"].default_value <= 0 24 | ) 25 | 26 | def functionality(self): 27 | bpy.ops.mesh.primitive_monkey_add( 28 | size = self.inputs["Size"].default_value, 29 | calc_uvs = self.inputs["Generate UVs"].default_value 30 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScAddPlane.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScAddPlane(Node, ScEditOperatorNode): 9 | bl_idname = "ScAddPlane" 10 | bl_label = "Add Plane" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_size: FloatProperty(default=2.0, min=0.0, update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 18 | self.inputs.new("ScNodeSocketNumber", "Size").init("in_size", True) 19 | 20 | def error_condition(self): 21 | return ( 22 | super().error_condition() 23 | or self.inputs["Size"].default_value <= 0 24 | ) 25 | 26 | def functionality(self): 27 | bpy.ops.mesh.primitive_plane_add( 28 | size = self.inputs["Size"].default_value, 29 | calc_uvs = self.inputs["Generate UVs"].default_value 30 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScAddUvSphere.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty, FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScAddUvSphere(Node, ScEditOperatorNode): 9 | bl_idname = "ScAddUvSphere" 10 | bl_label = "Add UV Sphere" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_segment: IntProperty(default=32, min=3, max=10000000, update=ScNode.update_value) 14 | in_ring: IntProperty(default=16, min=3, max=10000000, update=ScNode.update_value) 15 | in_radius: FloatProperty(default=1.0, min=0.0, update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 20 | self.inputs.new("ScNodeSocketNumber", "Segments").init("in_segment", True) 21 | self.inputs.new("ScNodeSocketNumber", "Rings").init("in_ring", True) 22 | self.inputs.new("ScNodeSocketNumber", "Radius").init("in_radius", True) 23 | 24 | def error_condition(self): 25 | return ( 26 | super().error_condition() 27 | or (self.inputs["Segments"].default_value < 3 or self.inputs["Segments"].default_value > 10000000) 28 | or (self.inputs["Rings"].default_value < 3 or self.inputs["Rings"].default_value > 10000000) 29 | or self.inputs["Radius"].default_value < 0 30 | ) 31 | 32 | def functionality(self): 33 | bpy.ops.mesh.primitive_uv_sphere_add( 34 | segments = int(self.inputs["Segments"].default_value), 35 | ring_count = int(self.inputs["Rings"].default_value), 36 | radius = self.inputs["Radius"].default_value, 37 | calc_uvs = self.inputs["Generate UVs"].default_value 38 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScCreateCircle.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty, IntProperty, FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_input import ScInputNode 7 | 8 | class ScCreateCircle(Node, ScInputNode): 9 | bl_idname = "ScCreateCircle" 10 | bl_label = "Create Circle" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_type: EnumProperty(items=[("NOTHING", "Nothing", ""), ("NGON", "Ngon", ""), ("TRIFAN", "Triangle Fan", "")], default="NOTHING", update=ScNode.update_value) 14 | in_vertices: IntProperty(default=32, min=3, max=10000000, update=ScNode.update_value) 15 | in_radius: FloatProperty(default=1.0, min=0.0, update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 20 | self.inputs.new("ScNodeSocketString", "Fill Type").init("in_type") 21 | self.inputs.new("ScNodeSocketNumber", "Vertices").init("in_vertices", True) 22 | self.inputs.new("ScNodeSocketNumber", "Radius").init("in_radius", True) 23 | 24 | def error_condition(self): 25 | return ( 26 | super().error_condition() 27 | or (not self.inputs["Fill Type"].default_value in ['NOTHING', 'NGON', 'TRIFAN']) 28 | or self.inputs["Vertices"].default_value < 3 29 | or self.inputs["Radius"].default_value < 0 30 | ) 31 | 32 | def functionality(self): 33 | bpy.ops.mesh.primitive_circle_add( 34 | vertices = int(self.inputs["Vertices"].default_value), 35 | radius = self.inputs["Radius"].default_value, 36 | fill_type = self.inputs["Fill Type"].default_value, 37 | calc_uvs = self.inputs["Generate UVs"].default_value 38 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScCreateCube.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_input import ScInputNode 7 | 8 | class ScCreateCube(Node, ScInputNode): 9 | bl_idname = "ScCreateCube" 10 | bl_label = "Create Cube" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_size: FloatProperty(default=2.0, min=0.0, update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 18 | self.inputs.new("ScNodeSocketNumber", "Size").init("in_size", True) 19 | 20 | def error_condition(self): 21 | return ( 22 | super().error_condition() 23 | or self.inputs["Size"].default_value <= 0 24 | ) 25 | 26 | def functionality(self): 27 | bpy.ops.mesh.primitive_cube_add( 28 | size = self.inputs["Size"].default_value, 29 | calc_uvs = self.inputs["Generate UVs"].default_value 30 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScCreateGrid.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty, FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_input import ScInputNode 7 | 8 | class ScCreateGrid(Node, ScInputNode): 9 | bl_idname = "ScCreateGrid" 10 | bl_label = "Create Grid" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_x: IntProperty(default=10, min=2, max=10000000, update=ScNode.update_value) 14 | in_y: IntProperty(default=10, min=2, max=10000000, update=ScNode.update_value) 15 | in_size: FloatProperty(default=2.0, min=0.0, update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 20 | self.inputs.new("ScNodeSocketNumber", "X Subdivisions").init("in_x", True) 21 | self.inputs.new("ScNodeSocketNumber", "Y Subdivisions").init("in_y", True) 22 | self.inputs.new("ScNodeSocketNumber", "Size").init("in_size", True) 23 | 24 | def error_condition(self): 25 | return ( 26 | super().error_condition() 27 | or (self.inputs["X Subdivisions"].default_value < 2 or self.inputs["X Subdivisions"].default_value > 10000000) 28 | or (self.inputs["Y Subdivisions"].default_value < 2 or self.inputs["Y Subdivisions"].default_value > 10000000) 29 | or self.inputs["Size"].default_value <= 0 30 | ) 31 | 32 | def functionality(self): 33 | bpy.ops.mesh.primitive_grid_add( 34 | x_subdivisions = int(self.inputs["X Subdivisions"].default_value), 35 | y_subdivisions = int(self.inputs["Y Subdivisions"].default_value), 36 | size = self.inputs["Size"].default_value, 37 | calc_uvs = self.inputs["Generate UVs"].default_value 38 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScCreateIcoSphere.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty, FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_input import ScInputNode 7 | 8 | class ScCreateIcoSphere(Node, ScInputNode): 9 | bl_idname = "ScCreateIcoSphere" 10 | bl_label = "Create Ico Sphere" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_subdivision: IntProperty(default=2, min=1, max=10, update=ScNode.update_value) 14 | in_radius: FloatProperty(default=1.0, min=0.0, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 19 | self.inputs.new("ScNodeSocketNumber", "Subdivisions").init("in_subdivision", True) 20 | self.inputs.new("ScNodeSocketNumber", "Radius").init("in_radius", True) 21 | 22 | def error_condition(self): 23 | return ( 24 | super().error_condition() 25 | or (self.inputs["Subdivisions"].default_value < 1 or self.inputs["Subdivisions"].default_value > 10) 26 | or self.inputs["Radius"].default_value < 0 27 | ) 28 | 29 | def functionality(self): 30 | bpy.ops.mesh.primitive_ico_sphere_add( 31 | subdivisions = int(self.inputs["Subdivisions"].default_value), 32 | radius = self.inputs["Radius"].default_value, 33 | calc_uvs = self.inputs["Generate UVs"].default_value 34 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScCreateMonkey.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_input import ScInputNode 7 | 8 | class ScCreateMonkey(Node, ScInputNode): 9 | bl_idname = "ScCreateMonkey" 10 | bl_label = "Create Monkey (Suzanne)" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_size: FloatProperty(default=2.0, min=0.0, update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 18 | self.inputs.new("ScNodeSocketNumber", "Size").init("in_size", True) 19 | 20 | def error_condition(self): 21 | return ( 22 | super().error_condition() 23 | or self.inputs["Size"].default_value <= 0 24 | ) 25 | 26 | def functionality(self): 27 | bpy.ops.mesh.primitive_monkey_add( 28 | size = self.inputs["Size"].default_value, 29 | calc_uvs = self.inputs["Generate UVs"].default_value 30 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScCreateObject.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | from .._base.node_input import ScInputNode 6 | 7 | class ScCreateObject(Node, ScInputNode): 8 | bl_idname = "ScCreateObject" 9 | bl_label = "Create Object" 10 | 11 | def init(self, context): 12 | super().init(context) 13 | self.inputs.new("ScNodeSocketArray", "Vertices") 14 | self.inputs.new("ScNodeSocketArray", "Edges") 15 | self.inputs.new("ScNodeSocketArray", "Faces") 16 | 17 | def functionality(self): 18 | bpy.ops.object.add( 19 | type = "MESH", 20 | align = "CURSOR" 21 | ) 22 | bpy.context.active_object.data.from_pydata(eval(self.inputs["Vertices"].default_value), eval(self.inputs["Edges"].default_value), eval(self.inputs["Faces"].default_value)) -------------------------------------------------------------------------------- /nodes/inputs/ScCreatePlane.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_input import ScInputNode 7 | 8 | class ScCreatePlane(Node, ScInputNode): 9 | bl_idname = "ScCreatePlane" 10 | bl_label = "Create Plane" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_size: FloatProperty(default=2.0, min=0.0, update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 18 | self.inputs.new("ScNodeSocketNumber", "Size").init("in_size", True) 19 | 20 | def error_condition(self): 21 | return ( 22 | super().error_condition() 23 | or self.inputs["Size"].default_value <= 0 24 | ) 25 | 26 | def functionality(self): 27 | bpy.ops.mesh.primitive_plane_add( 28 | size = self.inputs["Size"].default_value, 29 | calc_uvs = self.inputs["Generate UVs"].default_value 30 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScCreateUvSphere.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty, FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_input import ScInputNode 7 | 8 | class ScCreateUvSphere(Node, ScInputNode): 9 | bl_idname = "ScCreateUvSphere" 10 | bl_label = "Create UV Sphere" 11 | 12 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 13 | in_segment: IntProperty(default=32, min=3, max=10000000, update=ScNode.update_value) 14 | in_ring: IntProperty(default=16, min=3, max=10000000, update=ScNode.update_value) 15 | in_radius: FloatProperty(default=1.0, min=0.0, update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 20 | self.inputs.new("ScNodeSocketNumber", "Segments").init("in_segment", True) 21 | self.inputs.new("ScNodeSocketNumber", "Rings").init("in_ring", True) 22 | self.inputs.new("ScNodeSocketNumber", "Radius").init("in_radius", True) 23 | 24 | def error_condition(self): 25 | return ( 26 | super().error_condition() 27 | or (self.inputs["Segments"].default_value < 3 or self.inputs["Segments"].default_value > 10000000) 28 | or (self.inputs["Rings"].default_value < 3 or self.inputs["Rings"].default_value > 10000000) 29 | or self.inputs["Radius"].default_value < 0 30 | ) 31 | 32 | def functionality(self): 33 | bpy.ops.mesh.primitive_uv_sphere_add( 34 | segments = int(self.inputs["Segments"].default_value), 35 | ring_count = int(self.inputs["Rings"].default_value), 36 | radius = self.inputs["Radius"].default_value, 37 | calc_uvs = self.inputs["Generate UVs"].default_value 38 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScCustomObject.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import PointerProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_input import ScInputNode 7 | from ...helper import focus_on_object, remove_object, sc_poll_mesh, apply_all_modifiers 8 | 9 | class ScCustomObject(Node, ScInputNode): 10 | bl_idname = "ScCustomObject" 11 | bl_label = "Custom Object" 12 | 13 | in_obj: PointerProperty(type=bpy.types.Object, poll=sc_poll_mesh, update=ScNode.update_value) 14 | in_hide: BoolProperty(default=True, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketObject", "Object").init("in_obj", True) 19 | self.inputs.new("ScNodeSocketBool", "Hide Original").init("in_hide") 20 | 21 | def error_condition(self): 22 | return ( 23 | super().error_condition() 24 | or self.inputs["Object"].default_value == None 25 | ) 26 | 27 | def pre_execute(self): 28 | self.inputs["Object"].default_value.hide_set(False) 29 | focus_on_object(self.inputs["Object"].default_value) 30 | 31 | def functionality(self): 32 | bpy.ops.object.duplicate() 33 | 34 | def post_execute(self): 35 | out = super().post_execute() 36 | apply_all_modifiers(self.out_mesh) 37 | self.inputs["Object"].default_value.hide_set(self.inputs["Hide Original"].default_value) 38 | return out 39 | 40 | def free(self): 41 | super().free() 42 | if (self.inputs["Object"].default_value): 43 | self.inputs["Object"].default_value.hide_set(False) -------------------------------------------------------------------------------- /nodes/inputs/ScEmpty.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_input import ScInputNode 7 | 8 | class ScEmpty(Node, ScInputNode): 9 | bl_idname = "ScEmpty" 10 | bl_label = "Empty" 11 | 12 | in_type: EnumProperty(items=[('PLAIN_AXES', 'Plain Axes', ''), ('ARROWS', 'Arrows', ''), ('SINGLE_ARROW', 'Single Arrow', ''), ('CIRCLE', 'Circle', ''), ('CUBE', 'Cube', ''), ('SPHERE', 'Sphere', ''), ('CONE', 'Cone', ''), ('IMAGE', 'Image', '')], default='PLAIN_AXES', update=ScNode.update_value) 13 | in_radius: FloatProperty(default=1.0, min=0.0, update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketString", "Type").init("in_type", True) 18 | self.inputs.new("ScNodeSocketNumber", "Radius").init("in_radius") 19 | 20 | def error_condition(self): 21 | return ( 22 | super().error_condition() 23 | or (not self.inputs["Type"].default_value in ['PLAIN_AXES', 'ARROWS', 'SINGLE_ARROW', 'CIRCLE', 'CUBE', 'SPHERE', 'CONE', 'IMAGE']) 24 | or self.inputs["Radius"].default_value <= 0 25 | ) 26 | 27 | def functionality(self): 28 | bpy.ops.object.empty_add( 29 | type = self.inputs["Type"].default_value, 30 | radius = self.inputs["Radius"].default_value 31 | ) -------------------------------------------------------------------------------- /nodes/inputs/ScImportFbx.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import os 3 | 4 | from bpy.props import StringProperty, BoolProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | from .._base.node_input import ScInputNode 8 | 9 | class ScImportFbx(Node, ScInputNode): 10 | bl_idname = "ScImportFbx" 11 | bl_label = "Import FBX" 12 | 13 | in_file: StringProperty(subtype='FILE_PATH', update=ScNode.update_value) 14 | in_uv: BoolProperty(default=True, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketString", "File").init("in_file", True) 19 | self.inputs.new("ScNodeSocketBool", "Generate UVs").init("in_uv") 20 | 21 | def error_condition(self): 22 | return ( 23 | super().error_condition() 24 | or self.inputs["File"].default_value == "" 25 | ) 26 | 27 | def functionality(self): 28 | bpy.ops.import_scene.fbx( 29 | filepath = bpy.path.abspath(self.inputs["File"].default_value), 30 | use_custom_normals = self.inputs["Generate UVs"].default_value 31 | ) 32 | 33 | def post_execute(self): 34 | bpy.context.view_layer.objects.active = bpy.context.selected_objects[0] 35 | return super().post_execute() -------------------------------------------------------------------------------- /nodes/inputs/ScSingleVertex.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_input import ScInputNode 7 | 8 | 9 | class ScSingleVertex(Node, ScInputNode): 10 | bl_idname = "ScSingleVertex" 11 | bl_label = "Single Vertex" 12 | 13 | in_show_name: BoolProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketBool", "Show Name").init("in_show_name", True) 18 | 19 | def functionality(self): 20 | m = bpy.data.meshes.new(self.inputs["Name"].default_value) 21 | obj = bpy.data.objects.new(self.inputs["Name"].default_value, m) 22 | obj.location = bpy.context.scene.cursor.location 23 | m.vertices.add(1) 24 | m.update() 25 | obj.show_name = self.inputs["Show Name"].default_value 26 | bpy.context.collection.objects.link(obj) 27 | bpy.context.view_layer.objects.active = obj 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /nodes/modifiers/ScEdgeSplitMod.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_modifier import ScModifierNode 7 | 8 | class ScEdgeSplitMod(Node, ScModifierNode): 9 | bl_idname = "ScEdgeSplitMod" 10 | bl_label = "Edge Split Modifier" 11 | 12 | in_split_angle: FloatProperty(default=0.523599, min=0.0, max=3.14159, unit="ROTATION", update=ScNode.update_value) 13 | in_use_edge_angle: BoolProperty(default=True, update=ScNode.update_value) 14 | in_use_edge_sharp: BoolProperty(default=True, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.prop_mod_type = "EDGE_SPLIT" 19 | self.inputs.new("ScNodeSocketNumber", "Split Angle").init("in_split_angle", True) 20 | self.inputs.new("ScNodeSocketNumber", "Edge Angle").init("in_use_edge_angle") 21 | self.inputs.new("ScNodeSocketNumber", "Sharp Edges").init("in_use_edge_sharp") 22 | 23 | def error_condition(self): 24 | return ( 25 | super().error_condition() 26 | or (self.inputs["Split Angle"].default_value < 0 or self.inputs["Split Angle"].default_value > 3.14159) 27 | ) 28 | 29 | def functionality(self): 30 | bpy.context.object.modifiers[self.prop_mod_name].split_angle = self.inputs["Split Angle"].default_value 31 | bpy.context.object.modifiers[self.prop_mod_name].use_edge_angle = self.inputs["Edge Angle"].default_value 32 | bpy.context.object.modifiers[self.prop_mod_name].use_edge_sharp = self.inputs["Sharp Edges"].default_value -------------------------------------------------------------------------------- /nodes/modifiers/ScLatticeMod.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, PointerProperty, StringProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_modifier import ScModifierNode 7 | from ...helper import sc_poll_lattice 8 | 9 | class ScLatticeMod(Node, ScModifierNode): 10 | bl_idname = "ScLatticeMod" 11 | bl_label = "Lattice Modifier" 12 | 13 | prop_vertex_group: StringProperty(update=ScNode.update_value) 14 | in_strength: FloatProperty(default=1.0, soft_min=0.0, soft_max=1.0, update=ScNode.update_value) 15 | in_lattice: PointerProperty(type=bpy.types.Object, poll=sc_poll_lattice, update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.prop_mod_type = "LATTICE" 20 | self.inputs.new("ScNodeSocketObject", "Lattice").init("in_lattice", True) 21 | self.inputs.new("ScNodeSocketNumber", "Strength").init("in_strength") 22 | 23 | def draw_buttons(self, context, layout): 24 | super().draw_buttons(context, layout) 25 | if (not self.inputs["Object"].default_value == None): 26 | layout.prop_search(self, "prop_vertex_group", self.inputs["Object"].default_value, "vertex_groups", text="Vertex Group") 27 | 28 | def error_condition(self): 29 | return ( 30 | super().error_condition() 31 | or self.inputs["Lattice"].default_value == None 32 | ) 33 | 34 | def functionality(self): 35 | bpy.context.object.modifiers[self.prop_mod_name].vertex_group = self.prop_vertex_group 36 | bpy.context.object.modifiers[self.prop_mod_name].object = self.inputs["Lattice"].default_value 37 | bpy.context.object.modifiers[self.prop_mod_name].strength = self.inputs["Strength"].default_value -------------------------------------------------------------------------------- /nodes/modifiers/ScWeldMod.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, IntProperty, StringProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_modifier import ScModifierNode 7 | 8 | class ScWeldMod(Node, ScModifierNode): 9 | bl_idname = "ScWeldMod" 10 | bl_label = "Weld Modifier" 11 | 12 | prop_vertex_group: StringProperty(update=ScNode.update_value) 13 | in_distance: FloatProperty(default=0.001, min=0.0, soft_max=1.0, update=ScNode.update_value) 14 | in_limit: IntProperty(default=1, min=0, soft_max=10000, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.prop_mod_type = "WELD" 19 | self.inputs.new("ScNodeSocketNumber", "Distance").init("in_distance", True) 20 | self.inputs.new("ScNodeSocketNumber", "Duplicate Limit").init("in_limit", True) 21 | 22 | def draw_buttons(self, context, layout): 23 | super().draw_buttons(context, layout) 24 | if (not self.inputs["Object"].default_value == None): 25 | layout.prop_search(self, "prop_vertex_group", self.inputs["Object"].default_value, "vertex_groups", text="Vertex Group") 26 | 27 | def error_condition(self): 28 | return ( 29 | super().error_condition() 30 | or self.inputs["Distance"].default_value < 0.0 31 | or int(self.inputs["Duplicate Limit"].default_value) < 0 32 | ) 33 | 34 | def functionality(self): 35 | bpy.context.object.modifiers[self.prop_mod_name].vertex_group = self.prop_vertex_group 36 | bpy.context.object.modifiers[self.prop_mod_name].merge_threshold = self.inputs["Distance"].default_value 37 | bpy.context.object.modifiers[self.prop_mod_name].max_interactions = int(self.inputs["Duplicate Limit"].default_value) -------------------------------------------------------------------------------- /nodes/noise/ScCell.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | 4 | from bpy.props import FloatVectorProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | 8 | class ScCell(Node, ScNode): 9 | bl_idname = "ScCell" 10 | bl_label = "Cell" 11 | 12 | in_position: FloatVectorProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketVector", "Position").init("in_position", True) 17 | self.outputs.new("ScNodeSocketNumber", "Value") 18 | 19 | def post_execute(self): 20 | out = {} 21 | out["Value"] = mathutils.noise.cell(self.inputs["Position"].default_value) 22 | return out -------------------------------------------------------------------------------- /nodes/noise/ScCellVector.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | 4 | from bpy.props import FloatVectorProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | 8 | class ScCellVector(Node, ScNode): 9 | bl_idname = "ScCellVector" 10 | bl_label = "Cell (Vector)" 11 | 12 | in_position: FloatVectorProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketVector", "Position").init("in_position", True) 17 | self.outputs.new("ScNodeSocketVector", "Value") 18 | 19 | def post_execute(self): 20 | out = {} 21 | out["Value"] = mathutils.noise.cell_vector(self.inputs["Position"].default_value) 22 | return out -------------------------------------------------------------------------------- /nodes/noise/ScNoise.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | 4 | from bpy.props import FloatVectorProperty, EnumProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | 8 | class ScNoise(Node, ScNode): 9 | bl_idname = "ScNoise" 10 | bl_label = "Noise" 11 | 12 | in_position: FloatVectorProperty(update=ScNode.update_value) 13 | in_noise_basis: EnumProperty(items=[('BLENDER', 'Blender', ''), ('PERLIN_ORIGINAL', 'Perlin (Original)', ''), ('PERLIN_NEW', 'Perlin (New)', ''), ('VORONOI_F1', 'Voronoi (F1)', ''), ('VORONOI_F2', 'Voronoi (F2)', ''), ('VORONOI_F3', 'Voronoi (F3)', ''), ('VORONOI_F4', 'Voronoi (F4)', ''), ('VORONOI_F2F1', 'Voronoi (F2F1)', ''), ('VORONOI_CRACKLE', 'Voronoi (Crackle)', ''), ('CELLNOISE', 'Cellnoise', '')], default='PERLIN_ORIGINAL', update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketVector", "Position").init("in_position", True) 18 | self.inputs.new("ScNodeSocketString", "Noise Basis").init("in_noise_basis", True) 19 | self.outputs.new("ScNodeSocketNumber", "Value") 20 | 21 | def error_condition(self): 22 | return ( 23 | super().error_condition() 24 | or (not self.inputs["Noise Basis"].default_value in ['BLENDER', 'PERLIN_ORIGINAL', 'PERLIN_NEW', 'VORONOI_F1', 'VORONOI_F2', 'VORONOI_F3', 'VORONOI_F4', 'VORONOI_F2F1', 'VORONOI_CRACKLE', 'CELLNOISE']) 25 | ) 26 | 27 | def post_execute(self): 28 | out = {} 29 | out["Value"] = mathutils.noise.noise( 30 | self.inputs["Position"].default_value, 31 | noise_basis = self.inputs["Noise Basis"].default_value 32 | ) 33 | return out -------------------------------------------------------------------------------- /nodes/noise/ScNoiseVector.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | 4 | from bpy.props import FloatVectorProperty, EnumProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | 8 | class ScNoiseVector(Node, ScNode): 9 | bl_idname = "ScNoiseVector" 10 | bl_label = "Noise (Vector)" 11 | 12 | in_position: FloatVectorProperty(update=ScNode.update_value) 13 | in_noise_basis: EnumProperty(items=[('BLENDER', 'Blender', ''), ('PERLIN_ORIGINAL', 'Perlin (Original)', ''), ('PERLIN_NEW', 'Perlin (New)', ''), ('VORONOI_F1', 'Voronoi (F1)', ''), ('VORONOI_F2', 'Voronoi (F2)', ''), ('VORONOI_F3', 'Voronoi (F3)', ''), ('VORONOI_F4', 'Voronoi (F4)', ''), ('VORONOI_F2F1', 'Voronoi (F2F1)', ''), ('VORONOI_CRACKLE', 'Voronoi (Crackle)', ''), ('CELLNOISE', 'Cellnoise', '')], default='PERLIN_ORIGINAL', update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketVector", "Position").init("in_position", True) 18 | self.inputs.new("ScNodeSocketString", "Noise Basis").init("in_noise_basis", True) 19 | self.outputs.new("ScNodeSocketVector", "Value") 20 | 21 | def error_condition(self): 22 | return ( 23 | super().error_condition() 24 | or (not self.inputs["Noise Basis"].default_value in ['BLENDER', 'PERLIN_ORIGINAL', 'PERLIN_NEW', 'VORONOI_F1', 'VORONOI_F2', 'VORONOI_F3', 'VORONOI_F4', 'VORONOI_F2F1', 'VORONOI_CRACKLE', 'CELLNOISE']) 25 | ) 26 | 27 | def post_execute(self): 28 | out = {} 29 | out["Value"] = mathutils.noise.noise_vector( 30 | self.inputs["Position"].default_value, 31 | noise_basis = self.inputs["Noise Basis"].default_value 32 | ) 33 | return out -------------------------------------------------------------------------------- /nodes/object_operators/ScClearParent.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | 8 | class ScClearParent(Node, ScObjectOperatorNode): 9 | bl_idname = "ScClearParent" 10 | bl_label = "Clear Parent" 11 | 12 | ops_type: EnumProperty(items=[('CLEAR', 'Normal', ''), ('CLEAR_KEEP_TRANSFORM', 'Keep Transform', ''), ('CLEAR_INVERSE', 'Clear Inverse', '')], default='CLEAR', update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketString", "Type").init("ops_type", True) 17 | 18 | def error_condition(self): 19 | return ( 20 | super().error_condition() 21 | or (not self.inputs["Type"].default_value in ['CLEAR', 'CLEAR_KEEP_TRANSFORM', 'CLEAR_INVERSE']) 22 | ) 23 | 24 | def functionality(self): 25 | bpy.ops.object.parent_clear( 26 | type = self.inputs["Type"].default_value 27 | ) 28 | -------------------------------------------------------------------------------- /nodes/object_operators/ScDuplicateObject.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty, PointerProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | from ...helper import remove_object 8 | 9 | class ScDuplicateObject(Node, ScObjectOperatorNode): 10 | bl_idname = "ScDuplicateObject" 11 | bl_label = "Duplicate Object" 12 | 13 | in_linked: BoolProperty(update=ScNode.update_value) 14 | out_mesh: PointerProperty(type=bpy.types.Object) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketBool", "Linked").init("in_linked") 19 | self.outputs.new("ScNodeSocketObject", "Duplicate Object") 20 | 21 | def functionality(self): 22 | bpy.ops.object.duplicate( 23 | linked = self.inputs["Linked"].default_value 24 | ) 25 | 26 | def post_execute(self): 27 | out = super().post_execute() 28 | self.out_mesh = bpy.context.active_object 29 | out["Duplicate Object"] = self.out_mesh 30 | self.id_data.register_object(self.out_mesh) 31 | return out 32 | 33 | def free(self): 34 | self.id_data.unregister_object(self.out_mesh) -------------------------------------------------------------------------------- /nodes/object_operators/ScExportFbx.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import os 3 | 4 | from bpy.props import StringProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | from .._base.node_operator import ScObjectOperatorNode 8 | 9 | class ScExportFbx(Node, ScObjectOperatorNode): 10 | bl_idname = "ScExportFbx" 11 | bl_label = "Export FBX" 12 | 13 | in_dir: StringProperty(subtype='DIR_PATH', update=ScNode.update_value) 14 | in_filename: StringProperty(default="untitled") 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketString", "Directory").init("in_dir", True) 19 | self.inputs.new("ScNodeSocketString", "File Name").init("in_filename", True) 20 | 21 | def error_condition(self): 22 | return ( 23 | super().error_condition() 24 | or self.inputs["Directory"].default_value == "" 25 | or self.inputs["File Name"].default_value == "" 26 | ) 27 | 28 | def functionality(self): 29 | bpy.ops.export_scene.fbx( 30 | filepath = os.path.join( 31 | bpy.path.abspath(self.inputs["Directory"].default_value), 32 | self.inputs["File Name"].default_value+".fbx" 33 | ), 34 | use_selection = True, 35 | use_tspace = True 36 | ) -------------------------------------------------------------------------------- /nodes/object_operators/ScGetChildren.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | from ...helper import focus_on_object 6 | 7 | class ScGetChildren(Node, ScNode): 8 | bl_idname = "ScGetChildren" 9 | bl_label = "Get Children" 10 | 11 | def init(self, context): 12 | super().init(context) 13 | self.inputs.new("ScNodeSocketObject", "Object") 14 | self.outputs.new("ScNodeSocketArray", "Children") 15 | 16 | def error_condition(self): 17 | return ( 18 | self.inputs["Object"].default_value == None 19 | ) 20 | 21 | def post_execute(self): 22 | return { 23 | "Children": repr(list(self.inputs["Object"].default_value.children)) 24 | } -------------------------------------------------------------------------------- /nodes/object_operators/ScGetParent.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | from ...helper import focus_on_object 6 | 7 | class ScGetParent(Node, ScNode): 8 | bl_idname = "ScGetParent" 9 | bl_label = "Get Parent" 10 | 11 | def init(self, context): 12 | super().init(context) 13 | self.inputs.new("ScNodeSocketObject", "Object") 14 | self.outputs.new("ScNodeSocketObject", "Parent") 15 | 16 | def error_condition(self): 17 | return ( 18 | self.inputs["Object"].default_value == None 19 | ) 20 | 21 | def post_execute(self): 22 | return {"Parent": self.inputs["Object"].default_value.parent} -------------------------------------------------------------------------------- /nodes/object_operators/ScMakeLinks.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | 8 | class ScMakeLinks(Node, ScObjectOperatorNode): 9 | bl_idname = "ScMakeLinks" 10 | bl_label = "Make Links" 11 | 12 | in_type: EnumProperty(items=[("OBDATA", "Object Data", ""), ("MATERIAL", "Material", ""), ("ANIMATION", "Animation", ""), ("GROUPS", "Groups", ""), ("DUPLIGROUP", "Dupligroup", ""), ("MODIFIERS", "Modifiers", ""), ("FONTS", "Fonts", "")], default="OBDATA", update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketString", "Type").init("in_type", True) 17 | self.inputs.new("ScNodeSocketArray", "Objects") 18 | 19 | def error_condition(self): 20 | return( 21 | super().error_condition() 22 | or (not self.inputs["Type"].default_value in ['OBDATA', 'MATERIAL', 'ANIMATION', 'GROUPS', 'DUPLICOLLECTION', 'MODIFIERS', 'FONTS']) 23 | ) 24 | 25 | def pre_execute(self): 26 | super().pre_execute() 27 | for obj in eval(self.inputs["Objects"].default_value): 28 | obj.select_set(True, view_layer=bpy.context.view_layer) 29 | 30 | def functionality(self): 31 | bpy.ops.object.make_links_data( 32 | type = self.inputs["Type"].default_value 33 | ) -------------------------------------------------------------------------------- /nodes/object_operators/ScMergeObjects.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | from ...helper import focus_on_object 8 | 9 | class ScMergeObjects(Node, ScObjectOperatorNode): 10 | bl_idname = "ScMergeObjects" 11 | bl_label = "Merge Objects" 12 | 13 | def init(self, context): 14 | super().init(context) 15 | self.inputs.new("ScNodeSocketArray", "Mesh Array") 16 | 17 | def error_condition(self): 18 | return( 19 | super().error_condition() 20 | or len(eval(self.inputs["Mesh Array"].default_value)) == 0 21 | ) 22 | 23 | def pre_execute(self): 24 | super().pre_execute() 25 | for obj in eval(self.inputs["Mesh Array"].default_value): 26 | obj.select_set(True, view_layer=bpy.context.view_layer) 27 | 28 | def functionality(self): 29 | bpy.ops.object.join() -------------------------------------------------------------------------------- /nodes/object_operators/ScOrigin.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | 8 | class ScOrigin(Node, ScObjectOperatorNode): 9 | bl_idname = "ScOrigin" 10 | bl_label = "Origin" 11 | 12 | in_type: EnumProperty(items=[("GEOMETRY_ORIGIN", "Geometry to Origin", ""), ("ORIGIN_GEOMETRY", "Origin to Geometry", ""), ("ORIGIN_CURSOR", "Origin to 3D Cursor", ""), ("ORIGIN_CENTER_OF_MASS", "Origin to Center of Mass (Surface)", ""), ("ORIGIN_CENTER_OF_VOLUME", "Origin to Center of Mass (Volume)", "")], default="GEOMETRY_ORIGIN", update=ScNode.update_value) 13 | in_center: EnumProperty(items=[("MEDIAN", "Median", ""), ("BOUNDS", "Bounds", "")], default="MEDIAN", update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketString", "Type").init("in_type", True) 18 | self.inputs.new("ScNodeSocketString", "Center").init("in_center") 19 | 20 | def error_condition(self): 21 | return( 22 | super().error_condition() 23 | or (not self.inputs["Type"].default_value in ['GEOMETRY_ORIGIN', 'ORIGIN_GEOMETRY', 'ORIGIN_CURSOR', 'ORIGIN_CENTER_OF_MASS', 'ORIGIN_CENTER_OF_VOLUME']) 24 | or (not self.inputs["Center"].default_value in ['MEDIAN', 'BOUNDS']) 25 | ) 26 | 27 | def functionality(self): 28 | bpy.ops.object.origin_set( 29 | type = self.inputs["Type"].default_value, 30 | center = self.inputs["Center"].default_value 31 | ) -------------------------------------------------------------------------------- /nodes/object_operators/ScOverlap.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | 4 | from bpy.props import PointerProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | from .._base.node_operator import ScObjectOperatorNode 8 | 9 | class ScOverlap(Node, ScObjectOperatorNode): 10 | bl_idname = "ScOverlap" 11 | bl_label = "Overlap" 12 | 13 | in_object: PointerProperty(type=bpy.types.Object, update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketObject", "Secondary Object").init("in_object", True) 18 | self.outputs.new("ScNodeSocketArray", "Primary Indices") 19 | self.outputs.new("ScNodeSocketArray", "Secondary Indices") 20 | 21 | def error_condition(self): 22 | return( 23 | super().error_condition() 24 | or self.inputs["Secondary Object"].default_value == None 25 | ) 26 | 27 | def post_execute(self): 28 | out = super().post_execute() 29 | ret = mathutils.bvhtree.BVHTree().FromObject(self.inputs["Object"].default_value, bpy.context.evaluated_depsgraph_get()).overlap(mathutils.bvhtree.BVHTree().FromObject(self.inputs["Secondary Object"].default_value, bpy.context.evaluated_depsgraph_get())) 30 | out["Primary Indices"] = repr([i[0] for i in ret]) 31 | out["Secondary Indices"] = repr([i[1] for i in ret]) 32 | return out -------------------------------------------------------------------------------- /nodes/object_operators/ScParent.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import PointerProperty, EnumProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | 8 | class ScParent(Node, ScObjectOperatorNode): 9 | bl_idname = "ScParent" 10 | bl_label = "Parent" 11 | 12 | prop_obj: PointerProperty(type=bpy.types.Object, update=ScNode.update_value) 13 | in_ops_type: EnumProperty(items=[('OBJECT', 'Object', ''), ('WITHOUT_INVERSE', 'Object(Without Inverse)', '')], default='OBJECT', update=ScNode.update_value) 14 | in_keep_transform: BoolProperty(update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketObject", "Parent").init("prop_obj", True) 19 | self.inputs.new("ScNodeSocketString", "Type").init("in_ops_type") 20 | self.inputs.new("ScNodeSocketBool", "Keep Transform").init( 21 | "in_keep_transform") 22 | 23 | def error_condition(self): 24 | return ( 25 | super().error_condition() 26 | or self.inputs["Parent"].default_value == None 27 | or (not self.inputs["Type"].default_value in ['OBJECT', 'WITHOUT_INVERSE']) 28 | ) 29 | 30 | def functionality(self): 31 | parent = self.inputs["Parent"].default_value 32 | parent.select_set(state=True) 33 | bpy.context.view_layer.objects.active = parent 34 | 35 | if self.inputs["Type"].default_value == "WITHOUT_INVERSE": 36 | bpy.ops.object.parent_no_inverse_set() 37 | else: 38 | bpy.ops.object.parent_set( 39 | type = 'OBJECT', 40 | keep_transform = self.inputs["Keep Transform"].default_value 41 | ) 42 | -------------------------------------------------------------------------------- /nodes/object_operators/ScRaycastObject.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | 4 | from bpy.props import FloatVectorProperty, FloatProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | from .._base.node_operator import ScObjectOperatorNode 8 | 9 | class ScRaycastObject(Node, ScObjectOperatorNode): 10 | bl_idname = "ScRaycastObject" 11 | bl_label = "Raycast (Object)" 12 | 13 | in_origin: FloatVectorProperty(update=ScNode.update_value) 14 | in_direction: FloatVectorProperty(update=ScNode.update_value) 15 | in_distance: FloatProperty(default=100.0, min=0.0, update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketVector", "Origin").init("in_origin", True) 20 | self.inputs.new("ScNodeSocketVector", "Direction").init("in_direction", True) 21 | self.inputs.new("ScNodeSocketNumber", "Distance").init("in_distance") 22 | self.outputs.new("ScNodeSocketVector", "Location") 23 | self.outputs.new("ScNodeSocketVector", "Normal") 24 | self.outputs.new("ScNodeSocketNumber", "Index") 25 | self.outputs.new("ScNodeSocketNumber", "Distance") 26 | 27 | def error_condition(self): 28 | return( 29 | super().error_condition() 30 | or self.inputs["Distance"].default_value < 0.0 31 | ) 32 | 33 | def post_execute(self): 34 | out = super().post_execute() 35 | ret = mathutils.bvhtree.BVHTree().FromObject(self.inputs["Object"].default_value, bpy.context.evaluated_depsgraph_get()).ray_cast(self.inputs["Origin"].default_value, self.inputs["Direction"].default_value, self.inputs["Distance"].default_value) 36 | out["Location"] = ret[0] 37 | out["Normal"] = ret[1] 38 | out["Index"] = ret[2] 39 | out["Distance"] = ret[3] 40 | return out -------------------------------------------------------------------------------- /nodes/object_operators/ScSetDimensions.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatVectorProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | 8 | class ScSetDimensions(Node, ScObjectOperatorNode): 9 | bl_idname = "ScSetDimensions" 10 | bl_label = "Set Dimensions" 11 | 12 | in_dimensions: FloatVectorProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketVector", "Dimensions").init("in_dimensions", True) 17 | 18 | def functionality(self): 19 | self.inputs["Object"].default_value.dimensions = self.inputs["Dimensions"].default_value -------------------------------------------------------------------------------- /nodes/object_operators/ScSetName.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | 8 | class ScSetName(Node, ScObjectOperatorNode): 9 | bl_idname = "ScSetName" 10 | bl_label = "Set Name" 11 | 12 | in_name: StringProperty(default="Object", update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketString", "Name").init("in_name", True) 17 | 18 | def error_condition(self): 19 | return( 20 | super().error_condition() 21 | or self.inputs["Name"].default_value == "" 22 | ) 23 | 24 | def functionality(self): 25 | self.inputs["Object"].default_value.name = self.inputs["Name"].default_value 26 | if (self.inputs["Object"].default_value.data): 27 | self.inputs["Object"].default_value.data.name = self.inputs["Name"].default_value -------------------------------------------------------------------------------- /nodes/object_operators/ScShading.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, EnumProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | 8 | class ScShading(Node, ScObjectOperatorNode): 9 | bl_idname = "ScShading" 10 | bl_label = "Shading" 11 | 12 | in_shading: EnumProperty(items=[("SMOOTH", "Smooth", ""), ("FLAT", "Flat", "")], default="FLAT", update=ScNode.update_value) 13 | in_auto: BoolProperty(update=ScNode.update_value) 14 | in_angle: FloatProperty(default=0.523599, min=0.0, max=3.14159, unit="ROTATION", update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketString", "Shading").init("in_shading", True) 19 | self.inputs.new("ScNodeSocketBool", "Auto Smooth").init("in_auto") 20 | self.inputs.new("ScNodeSocketNumber", "Angle").init("in_angle") 21 | 22 | def error_condition(self): 23 | return( 24 | super().error_condition() 25 | or (not self.inputs["Shading"].default_value in ['SMOOTH', 'FLAT']) 26 | or (self.inputs["Angle"].default_value < 0.0 or self.inputs["Angle"].default_value > 3.14159) 27 | ) 28 | 29 | def functionality(self): 30 | if (self.inputs["Shading"].default_value == "FLAT"): 31 | bpy.ops.object.shade_flat() 32 | else: 33 | bpy.ops.object.shade_smooth() 34 | self.inputs["Object"].default_value.data.use_auto_smooth = self.inputs["Auto Smooth"].default_value 35 | self.inputs["Object"].default_value.data.auto_smooth_angle = self.inputs["Angle"].default_value -------------------------------------------------------------------------------- /nodes/selection/ScSelectAll.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectAll(Node, ScSelectionNode): 9 | bl_idname = "ScSelectAll" 10 | bl_label = "Select All" 11 | 12 | in_action: EnumProperty(items=[("TOGGLE", "Toggle", ""), ("SELECT", "Select", ""), ("DESELECT", "Deselect", ""), ("INVERT", "Invert", "")], default="TOGGLE", update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketString", "Action").init("in_action", True) 17 | 18 | def error_condition(self): 19 | return( 20 | super().error_condition() 21 | or (not self.inputs["Action"].default_value in ["TOGGLE", "SELECT", "DESELECT", "INVERT"]) 22 | ) 23 | 24 | def functionality(self): 25 | bpy.ops.mesh.select_all( 26 | action = self.inputs["Action"].default_value 27 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectAxis.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty, FloatProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectAxis(Node, ScSelectionNode): 9 | bl_idname = "ScSelectAxis" 10 | bl_label = "Select Axis" 11 | 12 | in_sign: EnumProperty(items=[("POS", "Positive", ""), ("NEG", "Negative", ""), ("ALIGN", "Aligned", "")], default="POS", update=ScNode.update_value) 13 | in_axis: EnumProperty(items=[("X", "X", ""), ("Y", "Y", ""), ("Z", "Z", "")], default="X", update=ScNode.update_value) 14 | in_threshold: FloatProperty(default=0.0001, min=0.000001, max=50, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketString", "Sign").init("in_sign") 19 | self.inputs.new("ScNodeSocketString", "Axis").init("in_axis", True) 20 | self.inputs.new("ScNodeSocketNumber", "Threshold").init("in_threshold") 21 | 22 | def error_condition(self): 23 | return( 24 | super().error_condition() 25 | or (not self.inputs["Sign"].default_value in ['POS', 'NEG', 'ALIGN']) 26 | or (not self.inputs["Axis"].default_value in ['X', 'Y', 'Z']) 27 | or (self.inputs["Threshold"].default_value < 0.000001 or self.inputs["Threshold"].default_value > 50) 28 | ) 29 | 30 | def functionality(self): 31 | bpy.ops.mesh.select_axis( 32 | orientation = bpy.context.scene.transform_orientation_slots[0].type, 33 | sign = self.inputs["Sign"].default_value, 34 | axis = self.inputs["Axis"].default_value, 35 | threshold = self.inputs["Threshold"].default_value 36 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectFaceBySides.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty, IntProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectFaceBySides(Node, ScSelectionNode): 9 | bl_idname = "ScSelectFaceBySides" 10 | bl_label = "Select Face by Sides" 11 | 12 | in_number: IntProperty(default=4, min=3, update=ScNode.update_value) 13 | in_type: EnumProperty(items=[("LESS", "Less", ""), ("EQUAL", "Equal", ""), ("GREATER", "Greater", ""), ("NOTEQUAL", "Not Equal", "")], default="EQUAL", update=ScNode.update_value) 14 | in_extend: BoolProperty(default=True, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketNumber", "Number").init("in_number", True) 19 | self.inputs.new("ScNodeSocketString", "Type").init("in_type") 20 | self.inputs.new("ScNodeSocketBool", "Extend").init("in_extend") 21 | 22 | def error_condition(self): 23 | return( 24 | super().error_condition() 25 | or int(self.inputs["Number"].default_value) < 3 26 | or (not self.inputs["Type"].default_value in ['LESS', 'EQUAL', 'GREATER', 'NOTEQUAL']) 27 | ) 28 | 29 | def functionality(self): 30 | bpy.ops.mesh.select_face_by_sides( 31 | number = int(self.inputs["Number"].default_value), 32 | type = self.inputs["Type"].default_value, 33 | extend = self.inputs["Extend"].default_value 34 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectInteriorFaces.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | from .._base.node_selection import ScSelectionNode 6 | 7 | class ScSelectInteriorFaces(Node, ScSelectionNode): 8 | bl_idname = "ScSelectInteriorFaces" 9 | bl_label = "Select Interior Faces" 10 | 11 | def functionality(self): 12 | bpy.ops.mesh.select_interior_faces() -------------------------------------------------------------------------------- /nodes/selection/ScSelectLess.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectLess(Node, ScSelectionNode): 9 | bl_idname = "ScSelectLess" 10 | bl_label = "Select Less" 11 | 12 | in_step: BoolProperty(default=True, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Face Step").init("in_step", True) 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.select_less( 20 | use_face_step = self.inputs["Face Step"].default_value 21 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectLinked.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectLinked(Node, ScSelectionNode): 9 | bl_idname = "ScSelectLinked" 10 | bl_label = "Select Linked" 11 | 12 | prop_delimit: EnumProperty(items=[("NORMAL", "Normal", "", 2), ("MATERIAL", "Material", "", 4), ("SEAM", "Seam", "", 8), ("SHARP", "Sharp", "", 16), ("UV", "UV", "", 32)], default={"SEAM"}, options={"ENUM_FLAG"}, update=ScNode.update_value) 13 | 14 | def draw_buttons(self, context, layout): 15 | super().draw_buttons(context, layout) 16 | layout.prop(self, "prop_delimit", expand=True) 17 | 18 | def error_condition(self): 19 | return ( 20 | super().error_condition() 21 | or len(self.prop_delimit) == 0 22 | ) 23 | 24 | def functionality(self): 25 | bpy.ops.mesh.select_linked( 26 | delimit = self.prop_delimit 27 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectLinkedFacesFlat.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectLinkedFacesFlat(Node, ScSelectionNode): 9 | bl_idname = "ScSelectLinkedFacesFlat" 10 | bl_label = "Select Linked Faces by Angle" 11 | 12 | in_sharpness: FloatProperty(default=0.523599, min=0.000174533, max=3.14159, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketNumber", "Sharpness").init("in_sharpness", True) 17 | 18 | def error_condition(self): 19 | return( 20 | super().error_condition() 21 | or (self.inputs["Sharpness"].default_value < 0.000174533 or self.inputs["Sharpness"].default_value > 3.14159) 22 | ) 23 | 24 | def functionality(self): 25 | bpy.ops.mesh.select_linked_faces_flat( 26 | sharpness = self.inputs["Sharpness"].default_value 27 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectLinkedPick.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty, BoolProperty, IntProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectLinkedPick(Node, ScSelectionNode): 9 | bl_idname = "ScSelectLinkedPick" 10 | bl_label = "Select Linked Pick" 11 | 12 | prop_delimit: EnumProperty(items=[("NORMAL", "Normal", "", 2), ("MATERIAL", "Material", "", 4), ("SEAM", "Seam", "", 8), ("SHARP", "Sharp", "", 16), ("UV", "UV", "", 32)], default={"SEAM"}, options={"ENUM_FLAG"}, update=ScNode.update_value) 13 | in_deselect: BoolProperty(update=ScNode.update_value) 14 | in_index: IntProperty(default=-1, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketBool", "Deselect").init("in_deselect") 19 | self.inputs.new("ScNodeSocketNumber", "Index").init("in_index", True) 20 | 21 | def draw_buttons(self, context, layout): 22 | super().draw_buttons(context, layout) 23 | layout.prop(self, "prop_delimit", expand=True) 24 | 25 | def error_condition(self): 26 | return ( 27 | super().error_condition() 28 | or len(self.prop_delimit) == 0 29 | or int(self.inputs["Index"].default_value < 0) 30 | ) 31 | 32 | def functionality(self): 33 | bpy.ops.mesh.select_linked_pick( 34 | deselect = self.inputs["Deselect"].default_value, 35 | delimit = self.prop_delimit, 36 | index = self.inputs["Index"].default_value 37 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectLoop.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | from ...helper import get_override 8 | 9 | class ScSelectLoop(Node, ScSelectionNode): 10 | bl_idname = "ScSelectLoop" 11 | bl_label = "Select Loop" 12 | 13 | in_ring: BoolProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketBool", "Ring").init("in_ring", True) 18 | 19 | def functionality(self): 20 | bpy.ops.mesh.loop_multi_select( 21 | ring = self.inputs["Ring"].default_value 22 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectLoopRegion.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectLoopRegion(Node, ScSelectionNode): 9 | bl_idname = "ScSelectLoopRegion" 10 | bl_label = "Select Loop Region" 11 | 12 | in_bigger: BoolProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Select Bigger").init("in_bigger", True) 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.loop_to_region( 20 | select_bigger = self.inputs["Select Bigger"].default_value 21 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectLoose.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectLoose(Node, ScSelectionNode): 9 | bl_idname = "ScSelectLoose" 10 | bl_label = "Select Loose" 11 | 12 | in_extend: BoolProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Extend").init("in_extend", True) 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.select_loose( 20 | extend = self.inputs["Extend"].default_value 21 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectMirror.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectMirror(Node, ScSelectionNode): 9 | bl_idname = "ScSelectMirror" 10 | bl_label = "Select Mirror " 11 | 12 | prop_axis: EnumProperty(items=[("X", "X", "", 2), ("Y", "Y", "", 4), ("Z", "Z", "", 8)], default={"X"}, options={"ENUM_FLAG"}, update=ScNode.update_value) 13 | in_extend: BoolProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketBool", "Extend").init("in_extend") 18 | 19 | def draw_buttons(self, context, layout): 20 | super().draw_buttons(context, layout) 21 | layout.prop(self, "prop_axis", expand=True) 22 | 23 | def error_condition(self): 24 | return( 25 | super().error_condition() 26 | or len(self.prop_axis) == 0 27 | ) 28 | 29 | def functionality(self): 30 | bpy.ops.mesh.select_mirror( 31 | axis = self.prop_axis, 32 | extend = self.inputs["Extend"].default_value 33 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectMore.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectMore(Node, ScSelectionNode): 9 | bl_idname = "ScSelectMore" 10 | bl_label = "Select More" 11 | 12 | in_step: BoolProperty(default=True, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Face Step").init("in_step", True) 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.select_more( 20 | use_face_step = self.inputs["Face Step"].default_value 21 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectMultiLoop.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectMultiLoop(Node, ScSelectionNode): 9 | bl_idname = "ScSelectMultiLoop" 10 | bl_label = "Select Multi-Loop" 11 | 12 | in_ring: BoolProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Select Ring").init("in_ring", True) 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.loop_multi_select( 20 | ring = self.inputs["Select Ring"].default_value 21 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectNextItem.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | from .._base.node_selection import ScSelectionNode 6 | 7 | class ScSelectNextItem(Node, ScSelectionNode): 8 | bl_idname = "ScSelectNextItem" 9 | bl_label = "Select Next Item" 10 | 11 | def functionality(self): 12 | bpy.ops.mesh.select_next_item() -------------------------------------------------------------------------------- /nodes/selection/ScSelectNonManifold.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectNonManifold(Node, ScSelectionNode): 9 | bl_idname = "ScSelectNonManifold" 10 | bl_label = "Select Non-Manifold" 11 | 12 | in_extend: BoolProperty(default=True, update=ScNode.update_value) 13 | in_wire: BoolProperty(default=True, update=ScNode.update_value) 14 | in_boundary: BoolProperty(default=True, update=ScNode.update_value) 15 | in_multi_face: BoolProperty(default=True, update=ScNode.update_value) 16 | in_non_contiguous: BoolProperty(default=True, update=ScNode.update_value) 17 | in_verts: BoolProperty(default=True, update=ScNode.update_value) 18 | 19 | def init(self, context): 20 | super().init(context) 21 | self.inputs.new("ScNodeSocketBool", "Extend").init("in_extend", True) 22 | self.inputs.new("ScNodeSocketBool", "Wire").init("in_wire") 23 | self.inputs.new("ScNodeSocketBool", "Boundaries").init("in_boundary") 24 | self.inputs.new("ScNodeSocketBool", "Multiple Face").init("in_multi_face") 25 | self.inputs.new("ScNodeSocketBool", "Non-Contiguous").init("in_non_contiguous") 26 | self.inputs.new("ScNodeSocketBool", "Vertices").init("in_verts") 27 | 28 | def functionality(self): 29 | bpy.ops.mesh.select_non_manifold( 30 | extend = self.inputs["Extend"].default_value, 31 | use_wire = self.inputs["Wire"].default_value, 32 | use_boundary = self.inputs["Boundaries"].default_value, 33 | use_multi_face = self.inputs["Multiple Face"].default_value, 34 | use_non_contiguous = self.inputs["Non-Contiguous"].default_value, 35 | use_verts = self.inputs["Vertices"].default_value 36 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectNth.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectNth(Node, ScSelectionNode): 9 | bl_idname = "ScSelectNth" 10 | bl_label = "Select Nth (Checker Deselect)" 11 | 12 | in_nth: IntProperty(default=1, min=1, update=ScNode.update_value) 13 | in_skip: IntProperty(default=1, min=1, update=ScNode.update_value) 14 | in_offset: IntProperty(update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketNumber", "Nth Element").init("in_nth", True) 19 | self.inputs.new("ScNodeSocketNumber", "Skip Number").init("in_skip") 20 | self.inputs.new("ScNodeSocketNumber", "Offset").init("in_offset") 21 | 22 | def error_condition(self): 23 | return( 24 | super().error_condition() 25 | or int(self.inputs["Nth Element"].default_value) < 1 26 | or int(self.inputs["Skip Number"].default_value) < 1 27 | ) 28 | 29 | def functionality(self): 30 | bpy.ops.mesh.select_nth( 31 | nth = int(self.inputs["Nth Element"].default_value), 32 | skip = int(self.inputs["Skip Number"].default_value), 33 | offset = int(self.inputs["Offset"].default_value) 34 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectPrevItem.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | from .._base.node_selection import ScSelectionNode 6 | 7 | class ScSelectPrevItem(Node, ScSelectionNode): 8 | bl_idname = "ScSelectPrevItem" 9 | bl_label = "Select Previous Item" 10 | 11 | def functionality(self): 12 | bpy.ops.mesh.select_next_item() -------------------------------------------------------------------------------- /nodes/selection/ScSelectRandom.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty, IntProperty, FloatProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectRandom(Node, ScSelectionNode): 9 | bl_idname = "ScSelectRandom" 10 | bl_label = "Select Random" 11 | 12 | in_percent: FloatProperty(default=50.0, min=0.0, max=100.0, update=ScNode.update_value) 13 | in_seed: IntProperty(default=0, min=0, update=ScNode.update_value) 14 | in_action: EnumProperty(items=[("SELECT", "Select", ""), ("DESELECT", "Deselect", "")], default="SELECT", update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketNumber", "Percent").init("in_percent", True) 19 | self.inputs.new("ScNodeSocketNumber", "Seed").init("in_seed", True) 20 | self.inputs.new("ScNodeSocketString", "Action").init("in_action", True) 21 | 22 | def error_condition(self): 23 | return( 24 | super().error_condition() 25 | or (self.inputs["Percent"].default_value < 0 or self.inputs["Percent"].default_value > 100) 26 | or self.inputs["Seed"].default_value < 0 27 | or (not self.inputs["Action"].default_value in ["SELECT", "DESELECT"]) 28 | ) 29 | 30 | def functionality(self): 31 | bpy.ops.mesh.select_random( 32 | percent = self.inputs["Percent"].default_value, 33 | seed = int(self.inputs["Seed"].default_value), 34 | action = self.inputs["Action"].default_value 35 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectRegionBoundary.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | from .._base.node_selection import ScSelectionNode 6 | 7 | class ScSelectRegionBoundary(Node, ScSelectionNode): 8 | bl_idname = "ScSelectRegionBoundary" 9 | bl_label = "Select Region Boundary" 10 | 11 | def functionality(self): 12 | bpy.ops.mesh.region_to_loop() -------------------------------------------------------------------------------- /nodes/selection/ScSelectSharpEdges.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectSharpEdges(Node, ScSelectionNode): 9 | bl_idname = "ScSelectSharpEdges" 10 | bl_label = "Select Sharp Edges" 11 | 12 | in_sharpness: FloatProperty(default=0.523599, min=0.000174533, max=3.14159, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketNumber", "Sharpness").init("in_sharpness", True) 17 | 18 | def error_condition(self): 19 | return( 20 | super().error_condition() 21 | or (self.inputs["Sharpness"].default_value < 0.000174533 or self.inputs["Sharpness"].default_value > 3.14159) 22 | ) 23 | 24 | def functionality(self): 25 | bpy.ops.mesh.edges_select_sharp( 26 | sharpness = self.inputs["Sharpness"].default_value 27 | ) -------------------------------------------------------------------------------- /nodes/selection/ScSelectSimilarRegion.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Node 4 | from .._base.node_base import ScNode 5 | from .._base.node_selection import ScSelectionNode 6 | 7 | class ScSelectSimilarRegion(Node, ScSelectionNode): 8 | bl_idname = "ScSelectSimilarRegion" 9 | bl_label = "Select Similar Region" 10 | 11 | def functionality(self): 12 | bpy.ops.mesh.select_similar_region() -------------------------------------------------------------------------------- /nodes/selection/ScSelectUngrouped.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_selection import ScSelectionNode 7 | 8 | class ScSelectUngrouped(Node, ScSelectionNode): 9 | bl_idname = "ScSelectUngrouped" 10 | bl_label = "Select Ungrouped" 11 | 12 | in_extend: BoolProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketBool", "Extend").init("in_extend", True) 17 | 18 | def functionality(self): 19 | bpy.ops.mesh.select_ungrouped( 20 | extend = self.inputs["Extend"].default_value 21 | ) -------------------------------------------------------------------------------- /nodes/settings/ScCursorTransform.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatVectorProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_setting import ScSettingNode 7 | 8 | class ScCursorTransform(Node, ScSettingNode): 9 | bl_idname = "ScCursorTransform" 10 | bl_label = "Cursor Transform" 11 | 12 | in_location: FloatVectorProperty(update=ScNode.update_value) 13 | in_rotation: FloatVectorProperty(unit="ROTATION", update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketVector", "Location").init("in_location", True) 18 | self.inputs.new("ScNodeSocketVector", "Rotation").init("in_rotation") 19 | 20 | def functionality(self): 21 | bpy.context.scene.cursor.location = self.inputs["Location"].default_value 22 | bpy.context.scene.cursor.rotation_euler = self.inputs["Rotation"].default_value -------------------------------------------------------------------------------- /nodes/settings/ScPivotPoint.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_setting import ScSettingNode 7 | 8 | class ScPivotPoint(Node, ScSettingNode): 9 | bl_idname = "ScPivotPoint" 10 | bl_label = "Pivot Point" 11 | 12 | in_pivot: EnumProperty(items=[("BOUNDING_BOX_CENTER", "Bound Box Center", ""), ("CURSOR", "Cursor", ""), ("INDIVIDUAL_ORIGINS", "Individual Origins", ""), ("MEDIAN_POINT", "Median Point", ""), ("ACTIVE_ELEMENT", "Active Element", "")], default="MEDIAN_POINT", update=ScNode.update_value) 13 | in_origin: BoolProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketString", "Pivot Point").init("in_pivot", True) 18 | self.inputs.new("ScNodeSocketBool", "Only Origins").init("in_origin") 19 | 20 | def error_condition(self): 21 | return ( 22 | super().error_condition() 23 | or (not self.inputs["Pivot Point"].default_value in ['BOUNDING_BOX_CENTER', 'CURSOR', 'INDIVIDUAL_ORIGINS', 'MEDIAN_POINT', 'ACTIVE_ELEMENT']) 24 | ) 25 | 26 | def functionality(self): 27 | bpy.context.scene.tool_settings.transform_pivot_point = self.inputs["Pivot Point"].default_value 28 | bpy.context.scene.tool_settings.use_transform_pivot_point_align = self.inputs["Only Origins"].default_value -------------------------------------------------------------------------------- /nodes/settings/ScSetSelectionMode.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from ...helper import focus_on_object 7 | 8 | class ScSetSelectionMode(Node, ScNode): 9 | bl_idname = "ScSetSelectionMode" 10 | bl_label = "Set Selection Mode" 11 | 12 | in_selection_type: EnumProperty(name="Mode", items=[("VERT", "Vertices", "", "VERTEXSEL", 1), ("EDGE", "Edges", "", "EDGESEL", 2), ("FACE", "Faces", "", "FACESEL", 4)], default={'VERT'}, options={"ENUM_FLAG"}, update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | self.node_executable = False 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketObject", "Object") 18 | self.inputs.new("ScNodeSocketSelectionType", "Selection Type").init("in_selection_type", True) 19 | self.outputs.new("ScNodeSocketObject", "Object") 20 | 21 | def error_condition(self): 22 | return ( 23 | self.inputs["Object"].default_value == None 24 | or len(self.inputs["Selection Type"].default_value) == 0 25 | ) 26 | 27 | def pre_execute(self): 28 | focus_on_object(self.inputs["Object"].default_value, True) 29 | 30 | def functionality(self): 31 | bpy.context.tool_settings.mesh_select_mode = ["VERT" in self.inputs["Selection Type"].default_value, "EDGE" in self.inputs["Selection Type"].default_value, "FACE" in self.inputs["Selection Type"].default_value] 32 | 33 | def post_execute(self): 34 | return {"Object": self.inputs["Object"].default_value} -------------------------------------------------------------------------------- /nodes/settings/ScTransformOrientation.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_setting import ScSettingNode 7 | 8 | class ScTransformOrientation(Node, ScSettingNode): 9 | bl_idname = "ScTransformOrientation" 10 | bl_label = "Transform Orientation" 11 | 12 | in_orientation: EnumProperty(items=[("GLOBAL", "Global", ""), ("LOCAL", "Local", ""), ("NORMAL", "Normal", ""), ("GIMBAL", "Gimbal", ""), ("CURSOR", "Cursor", "")], default="GLOBAL", update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketString", "Transform Orientation").init("in_orientation", True) 17 | 18 | def functionality(self): 19 | bpy.context.scene.transform_orientation_slots[0].type = self.inputs["Transform Orientation"].default_value -------------------------------------------------------------------------------- /nodes/transform/ScApplyTransform.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | 8 | class ScApplyTransform(Node, ScObjectOperatorNode): 9 | bl_idname = "ScApplyTransform" 10 | bl_label = "Apply Transform" 11 | 12 | in_location: BoolProperty(default=True, update=ScNode.update_value) 13 | in_rotation: BoolProperty(default=True, update=ScNode.update_value) 14 | in_scale: BoolProperty(default=True, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketBool", "Location").init("in_location", True) 19 | self.inputs.new("ScNodeSocketBool", "Rotation").init("in_rotation", True) 20 | self.inputs.new("ScNodeSocketBool", "Scale").init("in_scale", True) 21 | 22 | def functionality(self): 23 | bpy.ops.object.transform_apply( 24 | location = self.inputs["Location"].default_value, 25 | rotation = self.inputs["Rotation"].default_value, 26 | scale = self.inputs["Scale"].default_value 27 | ) -------------------------------------------------------------------------------- /nodes/transform/ScCopyTransform.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty, PointerProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | 8 | class ScCopyTransform(Node, ScObjectOperatorNode): 9 | bl_idname = "ScCopyTransform" 10 | bl_label = "Copy Transform" 11 | 12 | in_location: BoolProperty(default=True, update=ScNode.update_value) 13 | in_rotation: BoolProperty(default=True, update=ScNode.update_value) 14 | in_scale: BoolProperty(default=True, update=ScNode.update_value) 15 | in_obj: PointerProperty(type=bpy.types.Object, update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketObject", "Secondary Object").init("in_obj", True) 20 | self.inputs.new("ScNodeSocketBool", "Location").init("in_location", True) 21 | self.inputs.new("ScNodeSocketBool", "Rotation").init("in_rotation", True) 22 | self.inputs.new("ScNodeSocketBool", "Scale").init("in_scale", True) 23 | 24 | def error_condition(self): 25 | return ( 26 | super().error_condition() 27 | or self.inputs["Secondary Object"].default_value == None 28 | ) 29 | 30 | def functionality(self): 31 | if self.inputs["Location"].default_value: 32 | self.inputs["Object"].default_value.location = self.inputs["Secondary Object"].default_value.location 33 | if self.inputs["Rotation"].default_value: 34 | self.inputs["Object"].default_value.rotation_euler = self.inputs["Secondary Object"].default_value.rotation_euler 35 | if self.inputs["Scale"].default_value: 36 | self.inputs["Object"].default_value.scale = self.inputs["Secondary Object"].default_value.scale -------------------------------------------------------------------------------- /nodes/transform/ScCreateOrientation.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_transform import ScTransformNode 7 | from ...helper import get_override 8 | 9 | class ScCreateOrientation(Node, ScTransformNode): 10 | bl_idname = "ScCreateOrientation" 11 | bl_label = "Create Orientation" 12 | 13 | in_name: StringProperty(default="My Orientation", update=ScNode.update_value) 14 | in_use: BoolProperty(default=True, update=ScNode.update_value) 15 | in_overwrite: BoolProperty(default=True, update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketString", "Name").init("in_name", True) 20 | self.inputs.new("ScNodeSocketBool", "Use").init("in_use") 21 | self.inputs.new("ScNodeSocketBool", "Overwrite").init("in_overwrite") 22 | 23 | def error_condition(self): 24 | return ( 25 | super().error_condition() 26 | or (self.inputs["Name"].default_value == None or self.inputs["Name"].default_value == "") 27 | ) 28 | 29 | def functionality(self): 30 | bpy.ops.transform.create_orientation( 31 | get_override(self.inputs["Object"].default_value, self.inputs["Edit Mode"].default_value), 32 | name = self.inputs["Name"].default_value, 33 | use = self.inputs["Use"].default_value, 34 | overwrite = self.inputs["Overwrite"].default_value 35 | ) -------------------------------------------------------------------------------- /nodes/transform/ScRandomizeVertices.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import IntProperty, FloatProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScRandomizeVertices(Node, ScEditOperatorNode): 9 | bl_idname = "ScRandomizeVertices" 10 | bl_label = "Randomize Vertices" 11 | 12 | in_offset: FloatProperty(update=ScNode.update_value) 13 | in_uniform: FloatProperty(min=0.0, max=1.0, update=ScNode.update_value) 14 | in_normal: FloatProperty(min=0.0, max=1.0, update=ScNode.update_value) 15 | in_seed: IntProperty(min=0, max=10000, update=ScNode.update_value) 16 | 17 | def init(self, context): 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketNumber", "Offset Amount").init("in_offset", True) 20 | self.inputs.new("ScNodeSocketNumber", "Uniform").init("in_uniform") 21 | self.inputs.new("ScNodeSocketNumber", "Normal").init("in_normal") 22 | self.inputs.new("ScNodeSocketNumber", "Random Seed").init("in_seed", True) 23 | 24 | def error_condition(self): 25 | return ( 26 | super().error_condition() 27 | or (self.inputs["Uniform"].default_value < 0 or self.inputs["Uniform"].default_value > 1) 28 | or (self.inputs["Normal"].default_value < 0 or self.inputs["Normal"].default_value > 1) 29 | or (int(self.inputs["Random Seed"].default_value) < 0 or int(self.inputs["Random Seed"].default_value) > 10000) 30 | ) 31 | 32 | def functionality(self): 33 | bpy.ops.transform.vertex_random( 34 | offset = self.inputs["Offset Amount"].default_value, 35 | uniform = self.inputs["Uniform"].default_value, 36 | normal = self.inputs["Normal"].default_value, 37 | seed = int(self.inputs["Random Seed"].default_value) 38 | ) -------------------------------------------------------------------------------- /nodes/transform/ScWarp.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, FloatVectorProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScEditOperatorNode 7 | 8 | class ScWarp(Node, ScEditOperatorNode): 9 | bl_idname = "ScWarp" 10 | bl_label = "Warp" 11 | 12 | in_warp_angle: FloatProperty(default=6.28319, update=ScNode.update_value) 13 | in_offset_angle: FloatProperty(update=ScNode.update_value) 14 | in_min: FloatProperty(default=-1.0, update=ScNode.update_value) 15 | in_max: FloatProperty(default=1.0, update=ScNode.update_value) 16 | in_center: FloatVectorProperty(update=ScNode.update_value) 17 | 18 | def init(self, context): 19 | super().init(context) 20 | self.inputs.new("ScNodeSocketNumber", "Warp Angle").init("in_warp_angle", True) 21 | self.inputs.new("ScNodeSocketNumber", "Offset Angle").init("in_offset_angle", True) 22 | self.inputs.new("ScNodeSocketNumber", "Min").init("in_min") 23 | self.inputs.new("ScNodeSocketNumber", "Max").init("in_max") 24 | self.inputs.new("ScNodeSocketVector", "Center").init("in_center") 25 | 26 | def functionality(self): 27 | bpy.ops.transform.vertex_warp( 28 | warp_angle = self.inputs["Warp Angle"].default_value, 29 | offset_angle = self.inputs["Offset Angle"].default_value, 30 | min = self.inputs["Min"].default_value, 31 | max = self.inputs["Max"].default_value, 32 | center = self.inputs["Center"].default_value 33 | ) -------------------------------------------------------------------------------- /nodes/transform/ScWorldTransform.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatVectorProperty, EnumProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from .._base.node_operator import ScObjectOperatorNode 7 | 8 | class ScWorldTransform(Node, ScObjectOperatorNode): 9 | bl_idname = "ScWorldTransform" 10 | bl_label = "World Transform" 11 | 12 | in_type: EnumProperty(items=[('LOCATION', 'Location', ''), ('ROTATION', 'Rotation', ''), ('SCALE', 'Scale', '')], update=ScNode.update_value) 13 | in_val: FloatVectorProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketString", "Type").init("in_type", True) 18 | self.inputs.new("ScNodeSocketVector", "Value").init("in_val", True) 19 | 20 | def error_condition(self): 21 | return ( 22 | super().error_condition() 23 | or (not self.inputs["Type"].default_value in ['LOCATION', 'ROTATION', 'SCALE']) 24 | ) 25 | 26 | def functionality(self): 27 | if (self.inputs["Type"].default_value == 'LOCATION'): 28 | self.inputs["Object"].default_value.location = self.inputs["Value"].default_value 29 | elif (self.inputs["Type"].default_value == 'ROTATION'): 30 | self.inputs["Object"].default_value.rotation_euler = self.inputs["Value"].default_value 31 | elif (self.inputs["Type"].default_value == 'SCALE'): 32 | self.inputs["Object"].default_value.scale = self.inputs["Value"].default_value -------------------------------------------------------------------------------- /nodes/utilities/ScAppendString.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScAppendString(Node, ScNode): 8 | bl_idname = "ScAppendString" 9 | bl_label = "Append String" 10 | 11 | in_a: StringProperty(update=ScNode.update_value) 12 | in_b: StringProperty(update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketString", "A").init("in_a", True) 17 | self.inputs.new("ScNodeSocketString", "B").init("in_b", True) 18 | self.outputs.new("ScNodeSocketString", "Value") 19 | 20 | def post_execute(self): 21 | out = {} 22 | out["Value"] = self.inputs["A"].default_value + self.inputs["B"].default_value 23 | return out -------------------------------------------------------------------------------- /nodes/utilities/ScBreakVector.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatVectorProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScBreakVector(Node, ScNode): 8 | bl_idname = "ScBreakVector" 9 | bl_label = "Break Vector" 10 | 11 | in_vector: FloatVectorProperty(update=ScNode.update_value) 12 | 13 | def init(self, context): 14 | super().init(context) 15 | self.inputs.new("ScNodeSocketVector", "Vector").init("in_vector", True) 16 | self.outputs.new("ScNodeSocketNumber", "X") 17 | self.outputs.new("ScNodeSocketNumber", "Y") 18 | self.outputs.new("ScNodeSocketNumber", "Z") 19 | 20 | def post_execute(self): 21 | out = {} 22 | out["X"] = self.inputs["Vector"].default_value[0] 23 | out["Y"] = self.inputs["Vector"].default_value[1] 24 | out["Z"] = self.inputs["Vector"].default_value[2] 25 | return out -------------------------------------------------------------------------------- /nodes/utilities/ScClamp.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScClamp(Node, ScNode): 8 | bl_idname = "ScClamp" 9 | bl_label = "Clamp" 10 | 11 | in_x: FloatProperty(update=ScNode.update_value) 12 | in_min: FloatProperty(update=ScNode.update_value) 13 | in_max: FloatProperty(default=1, update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketNumber", "X").init("in_x", True) 18 | self.inputs.new("ScNodeSocketNumber", "Min").init("in_min", True) 19 | self.inputs.new("ScNodeSocketNumber", "Max").init("in_max", True) 20 | self.outputs.new("ScNodeSocketNumber", "Value") 21 | 22 | def error_condition(self): 23 | return ( 24 | self.inputs["Max"].default_value < self.inputs["Min"].default_value 25 | ) 26 | 27 | def post_execute(self): 28 | out = {} 29 | out["Value"] = max(min(self.inputs["Max"].default_value, self.inputs["X"].default_value), self.inputs["Min"].default_value) 30 | return out -------------------------------------------------------------------------------- /nodes/utilities/ScCustomPythonScript.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import math 3 | 4 | from bpy.props import IntProperty, StringProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | from ...helper import print_log 8 | 9 | class ScCustomPythonScript(Node, ScNode): 10 | bl_idname = "ScCustomPythonScript" 11 | bl_label = "Custom Python Script" 12 | 13 | in_script: StringProperty(default="print('Hello')", update=ScNode.update_value) 14 | in_iteration: IntProperty(default=1, min=1, soft_max=50, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | super().init(context) 18 | self.inputs.new("ScNodeSocketUniversal", "In") 19 | self.inputs.new("ScNodeSocketString", "Script").init("in_script", True) 20 | self.inputs.new("ScNodeSocketNumber", "Repeat").init("in_iteration") 21 | self.outputs.new("ScNodeSocketUniversal", "Out") 22 | 23 | def error_condition(self): 24 | return ( 25 | int(self.inputs["Repeat"].default_value) < 1 26 | ) 27 | 28 | def pre_execute(self): 29 | print_log(self.name, None, None, self.inputs["Script"].default_value) 30 | 31 | def functionality(self): 32 | _C = bpy.context 33 | _D = bpy.data 34 | _O = bpy.ops 35 | _S = _C.scene 36 | _N = self 37 | _NT = self.id_data 38 | if not hasattr(_NT, "variables"): 39 | _NT.variables = {} 40 | _VAR = _NT.variables 41 | _IN = self.inputs["In"].default_value 42 | for i in range(0, int(self.inputs["Repeat"].default_value)): 43 | exec(self.inputs["Script"].default_value) 44 | 45 | def post_execute(self): 46 | return {"Out": self.inputs["In"].default_value} -------------------------------------------------------------------------------- /nodes/utilities/ScGetVariable.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import PointerProperty, StringProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScGetVariable(Node, ScNode): 8 | bl_idname = "ScGetVariable" 9 | bl_label = "Get Variable" 10 | 11 | prop_nodetree: PointerProperty(name="NodeTree", type=bpy.types.NodeTree, update=ScNode.update_value) 12 | in_name: StringProperty(default="Var", update=ScNode.update_value) 13 | in_default: StringProperty(default="Value", update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.inputs.new("ScNodeSocketString", "Name").init("in_name", True) 18 | self.inputs.new("ScNodeSocketString", "Default").init("in_default") 19 | self.outputs.new("ScNodeSocketUniversal", "Value") 20 | 21 | def draw_buttons(self, context, layout): 22 | super().draw_buttons(context, layout) 23 | layout.prop(self, "prop_nodetree") 24 | 25 | def error_condition(self): 26 | return ( 27 | self.prop_nodetree == None 28 | or self.inputs["Name"].default_value == "" 29 | ) 30 | 31 | def pre_execute(self): 32 | if not hasattr(self.prop_nodetree, "variables"): 33 | self.prop_nodetree.variables = {} 34 | 35 | def functionality(self): 36 | if (not self.inputs["Name"].default_value in self.prop_nodetree.variables): 37 | self.prop_nodetree.variables[self.inputs["Name"].default_value] = self.inputs["Default"].default_value 38 | 39 | def post_execute(self): 40 | out = {} 41 | out["Value"] = self.prop_nodetree.variables[self.inputs["Name"].default_value] 42 | return out -------------------------------------------------------------------------------- /nodes/utilities/ScPrint.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty, BoolProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | from ...helper import print_log 7 | 8 | class ScPrint(Node, ScNode): 9 | bl_idname = "ScPrint" 10 | bl_label = "Print" 11 | 12 | prop_force: BoolProperty(name="Force Re-evaluate", update=ScNode.update_value) 13 | in_str: StringProperty(update=ScNode.update_value) 14 | 15 | def init(self, context): 16 | super().init(context) 17 | self.node_executable = True 18 | self.inputs.new("ScNodeSocketUniversal", "In") 19 | self.inputs.new("ScNodeSocketString", "String").init("in_str", True) 20 | self.outputs.new("ScNodeSocketUniversal", "Out") 21 | 22 | def draw_buttons(self, context, layout): 23 | super().draw_buttons(context, layout) 24 | layout.prop(self, "prop_force") 25 | 26 | def execute(self, forced=False): 27 | forced = forced or self.prop_force 28 | return super().execute(forced=forced) 29 | 30 | def functionality(self): 31 | print_log(self.name, msg=self.inputs["String"].default_value) 32 | 33 | def post_execute(self): 34 | return {"Out": self.inputs["In"].default_value} -------------------------------------------------------------------------------- /nodes/utilities/ScRaycastScene.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | 4 | from bpy.props import FloatVectorProperty, FloatProperty 5 | from bpy.types import Node 6 | from .._base.node_base import ScNode 7 | 8 | class ScRaycastScene(Node, ScNode): 9 | bl_idname = "ScRaycastScene" 10 | bl_label = "Raycast (Scene)" 11 | 12 | in_origin: FloatVectorProperty(update=ScNode.update_value) 13 | in_direction: FloatVectorProperty(update=ScNode.update_value) 14 | in_distance: FloatProperty(default=100.0, min=0.0, update=ScNode.update_value) 15 | 16 | def init(self, context): 17 | self.node_executable = True 18 | super().init(context) 19 | self.inputs.new("ScNodeSocketVector", "Origin").init("in_origin", True) 20 | self.inputs.new("ScNodeSocketVector", "Direction").init("in_direction", True) 21 | self.inputs.new("ScNodeSocketNumber", "Distance").init("in_distance") 22 | self.outputs.new("ScNodeSocketBool", "Result") 23 | self.outputs.new("ScNodeSocketVector", "Location") 24 | self.outputs.new("ScNodeSocketVector", "Normal") 25 | self.outputs.new("ScNodeSocketNumber", "Index") 26 | self.outputs.new("ScNodeSocketObject", "Object") 27 | 28 | def error_condition(self): 29 | return( 30 | self.inputs["Distance"].default_value < 0.0 31 | ) 32 | 33 | def post_execute(self): 34 | out = {} 35 | ret = bpy.context.scene.ray_cast( 36 | bpy.context.view_layer, 37 | self.inputs["Origin"].default_value, 38 | self.inputs["Direction"].default_value, 39 | distance = self.inputs["Distance"].default_value 40 | ) 41 | out["Result"] = ret[0] 42 | out["Location"] = ret[1] 43 | out["Normal"] = ret[2] 44 | out["Index"] = ret[3] 45 | out["Object"] = ret[4] 46 | return out -------------------------------------------------------------------------------- /nodes/utilities/ScSceneInfo.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import time 3 | 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScSceneInfo(Node, ScNode): 8 | bl_idname = "ScSceneInfo" 9 | bl_label = "Scene Info" 10 | 11 | def init(self, context): 12 | super().init(context) 13 | self.outputs.new("ScNodeSocketNumber", "Start Frame") 14 | self.outputs.new("ScNodeSocketNumber", "Current Frame") 15 | self.outputs.new("ScNodeSocketNumber", "End Frame") 16 | self.outputs.new("ScNodeSocketVector", "Cursor Location") 17 | self.outputs.new("ScNodeSocketVector", "Cursor Rotation") 18 | self.outputs.new("ScNodeSocketObject", "Active Object") 19 | self.outputs.new("ScNodeSocketArray", "Selected Objects") 20 | self.outputs.new("ScNodeSocketArray", "All Objects") 21 | self.outputs.new("ScNodeSocketNumber", "Unit Scale") 22 | self.outputs.new("ScNodeSocketNumber", "System Time") 23 | 24 | def post_execute(self): 25 | c = bpy.context 26 | s = c.scene 27 | out = {} 28 | out["Start Frame"] = s.frame_start 29 | out["Current Frame"] = s.frame_current 30 | out["End Frame"] = s.frame_end 31 | out["Cursor Location"] = s.cursor.location 32 | out["Cursor Rotation"] = s.cursor.rotation_euler 33 | out["Active Object"] = c.object 34 | out["Selected Objects"] = repr(list(c.selected_objects)) 35 | out["All Objects"] = repr(list(s.objects)) 36 | out["Unit Scale"] = s.unit_settings.scale_length 37 | out["System Time"] = time.time() 38 | return out -------------------------------------------------------------------------------- /nodes/utilities/ScSetVariable.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import PointerProperty, StringProperty 4 | from bpy.types import Node 5 | from .._base.node_base import ScNode 6 | 7 | class ScSetVariable(Node, ScNode): 8 | bl_idname = "ScSetVariable" 9 | bl_label = "Set Variable" 10 | 11 | prop_nodetree: PointerProperty(name="NodeTree", type=bpy.types.NodeTree, update=ScNode.update_value) 12 | in_name: StringProperty(default="Var", update=ScNode.update_value) 13 | 14 | def init(self, context): 15 | super().init(context) 16 | self.inputs.new("ScNodeSocketUniversal", "In") 17 | self.inputs.new("ScNodeSocketString", "Name").init("in_name", True) 18 | self.inputs.new("ScNodeSocketUniversal", "Value") 19 | self.outputs.new("ScNodeSocketUniversal", "Out") 20 | self.outputs.new("ScNodeSocketUniversal", "Value") 21 | 22 | def draw_buttons(self, context, layout): 23 | super().draw_buttons(context, layout) 24 | layout.prop(self, "prop_nodetree") 25 | 26 | def error_condition(self): 27 | return ( 28 | self.prop_nodetree == None 29 | or self.inputs["Name"].default_value == "" 30 | ) 31 | 32 | def pre_execute(self): 33 | if not hasattr(self.prop_nodetree, "variables"): 34 | self.prop_nodetree.variables = {} 35 | 36 | def functionality(self): 37 | self.prop_nodetree.variables[self.inputs["Name"].default_value] = self.inputs["Value"].default_value 38 | 39 | def post_execute(self): 40 | out = {} 41 | out["Out"] = self.inputs["In"].default_value 42 | out["Value"] = self.inputs["Value"].default_value 43 | return out -------------------------------------------------------------------------------- /operators/ScClearPreview.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Operator 4 | from ..helper import sc_poll_op 5 | 6 | class ScClearPreview(Operator): 7 | """Clear the preview node""" 8 | bl_idname = "sorcar.clear_preview" 9 | bl_label = "Clear Preview" 10 | 11 | @classmethod 12 | def poll(cls, context): 13 | return sc_poll_op(context) 14 | 15 | def execute(self, context): 16 | curr_tree = context.space_data.edit_tree 17 | curr_tree.node = None 18 | curr_tree.execute_node() 19 | return {"FINISHED"} -------------------------------------------------------------------------------- /operators/ScEditGroup.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Operator 4 | from ..helper import sc_poll_op 5 | 6 | class ScEditGroup(Operator): 7 | """Edit the group referenced by the active node (or exit the current node-group)""" 8 | bl_idname = "sorcar.edit_group" 9 | bl_label = "Edit Group" 10 | 11 | @classmethod 12 | def poll(cls, context): 13 | return ( 14 | sc_poll_op(context) 15 | ) 16 | 17 | def execute(self, context): 18 | space = context.space_data 19 | path = space.path 20 | node = path[-1].node_tree.nodes.active 21 | 22 | if hasattr(node, "node_tree"): 23 | if (node.node_tree): 24 | path.append(node.node_tree, node=node) 25 | return {"FINISHED"} 26 | elif len(path) > 1: 27 | path.pop() 28 | return {"CANCELLED"} -------------------------------------------------------------------------------- /operators/ScExecuteNode.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Operator 4 | from ..helper import sc_poll_op 5 | 6 | class ScExecuteNode(Operator): 7 | """Execute the selected node (re-evaluates the nodetree)""" 8 | bl_idname = "sorcar.execute_node" 9 | bl_label = "Execute Node" 10 | 11 | @classmethod 12 | def poll(cls, context): 13 | return sc_poll_op(context) 14 | 15 | def execute(self, context): 16 | curr_tree = context.space_data.edit_tree 17 | if (curr_tree.nodes.active): 18 | curr_tree.node = curr_tree.nodes.active.name 19 | curr_tree.execute_node() 20 | return {"FINISHED"} 21 | return {"CANCELLED"} -------------------------------------------------------------------------------- /operators/ScSaveSelection.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Operator 4 | from ..helper import sc_poll_op 5 | 6 | class ScSaveSelection(Operator): 7 | """Save the components of the mesh currently selected""" 8 | bl_idname = "sorcar.save_selection" 9 | bl_label = "Save Selection" 10 | 11 | @classmethod 12 | def poll(cls, context): 13 | return sc_poll_op(context) 14 | 15 | def execute(self, context): 16 | context.space_data.edit_tree.nodes.active.save_selection() 17 | return {"FINISHED"} -------------------------------------------------------------------------------- /sockets/ScNodeSocketArray.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty 4 | from bpy.types import NodeSocket 5 | from ._base.socket_base import ScNodeSocket 6 | from ..nodes._base.node_base import ScNode 7 | 8 | class ScNodeSocketArray(NodeSocket, ScNodeSocket): 9 | bl_idname = "ScNodeSocketArray" 10 | bl_label = "Array" 11 | color = (0.0, 0.0, 1.0, 1.0) 12 | 13 | default_value: StringProperty(default="[]") 14 | default_value_update: StringProperty(default="[]", update=ScNode.update_value) 15 | default_type: StringProperty(default="ARRAY") 16 | 17 | def get_label(self): 18 | arr = [] 19 | arr_len = 0 20 | try: 21 | arr = eval(self.default_value) 22 | arr_len = len(arr) 23 | except: 24 | arr_len = self.default_value.count(',') + 1 25 | return str(arr_len) 26 | 27 | def draw(self, context, layout, node, text): 28 | if (self.is_output or self.is_linked): 29 | layout.label(text=text + " [" + self.get_label() + "]") 30 | else: 31 | layout.label(text=text) -------------------------------------------------------------------------------- /sockets/ScNodeSocketArrayPlaceholder.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty 4 | from bpy.types import NodeSocket 5 | from ._base.socket_base import ScNodeSocket 6 | 7 | class ScNodeSocketArrayPlaceholder(NodeSocket): 8 | bl_idname = "ScNodeSocketArrayPlaceholder" 9 | bl_label = "Array Placeholder" 10 | 11 | def draw_color(self, context, node): 12 | return (0.0, 0.0, 0.0, 0.0) 13 | 14 | def draw(self, context, layout, node, text): 15 | layout.label(text="---") -------------------------------------------------------------------------------- /sockets/ScNodeSocketBool.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty, StringProperty 4 | from bpy.types import NodeSocket 5 | from ._base.socket_base import ScNodeSocket 6 | from ..nodes._base.node_base import ScNode 7 | 8 | class ScNodeSocketBool(NodeSocket, ScNodeSocket): 9 | bl_idname = "ScNodeSocketBool" 10 | bl_label = "Bool" 11 | color = (1.0, 0.0, 0.0, 1.0) 12 | 13 | default_value: BoolProperty() 14 | default_value_update: BoolProperty(update=ScNode.update_value) 15 | default_type: StringProperty(default="BOOL") -------------------------------------------------------------------------------- /sockets/ScNodeSocketCurve.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import PointerProperty, StringProperty 4 | from bpy.types import NodeSocket 5 | from ._base.socket_base import ScNodeSocket 6 | from ..nodes._base.node_base import ScNode 7 | 8 | class ScNodeSocketCurve(NodeSocket, ScNodeSocket): 9 | bl_idname = "ScNodeSocketCurve" 10 | bl_label = "Curve" 11 | color = (0.0, 0.0, 1.0, 1.0) 12 | 13 | default_value: PointerProperty(type=bpy.types.Object) 14 | default_value_update: PointerProperty(type=bpy.types.Object, update=ScNode.update_value) 15 | default_type: StringProperty(default="CURVE") 16 | 17 | def get_label(self): 18 | if (self.default_value): 19 | return self.default_value.name 20 | else: 21 | return "-" -------------------------------------------------------------------------------- /sockets/ScNodeSocketInfo.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import NodeSocket 4 | 5 | class ScNodeSocketInfo(NodeSocket): 6 | bl_idname = "ScNodeSocketInfo" 7 | bl_label = "Info Socket" 8 | 9 | def draw_color(self, context, node): 10 | return (1.0, 0.5, 0.5, 1.0) 11 | 12 | def draw(self, context, layout, node, text): 13 | layout.label(text=text) -------------------------------------------------------------------------------- /sockets/ScNodeSocketInterfaceArray.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty 4 | from bpy.types import NodeSocketInterface 5 | from ._base.interface_base import ScNodeSocketInterface 6 | 7 | class ScNodeSocketInterfaceArray(NodeSocketInterface, ScNodeSocketInterface): 8 | bl_idname = "ScNodeSocketInterfaceArray" 9 | bl_label = "Array" 10 | bl_socket_idname = "ScNodeSocketArray" 11 | 12 | color = (0.0, 0.0, 1.0, 1.0) 13 | default_value: StringProperty(name="Default Array", default="[]") -------------------------------------------------------------------------------- /sockets/ScNodeSocketInterfaceBool.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | from bpy.types import NodeSocketInterface 5 | from ._base.interface_base import ScNodeSocketInterface 6 | 7 | class ScNodeSocketInterfaceBool(NodeSocketInterface, ScNodeSocketInterface): 8 | bl_idname = "ScNodeSocketInterfaceBool" 9 | bl_label = "Bool" 10 | bl_socket_idname = "ScNodeSocketBool" 11 | 12 | color = (1.0, 0.0, 0.0, 1.0) 13 | default_value: BoolProperty(name="Default Value") -------------------------------------------------------------------------------- /sockets/ScNodeSocketInterfaceCurve.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import PointerProperty 4 | from bpy.types import NodeSocketInterface 5 | from ._base.interface_base import ScNodeSocketInterface 6 | 7 | class ScNodeSocketInterfaceCurve(NodeSocketInterface, ScNodeSocketInterface): 8 | bl_idname = "ScNodeSocketInterfaceCurve" 9 | bl_label = "Curve" 10 | bl_socket_idname = "ScNodeSocketCurve" 11 | 12 | color = (0.0, 0.0, 1.0, 1.0) 13 | default_value: PointerProperty(name="Default Curve", type=bpy.types.Object) -------------------------------------------------------------------------------- /sockets/ScNodeSocketInterfaceNumber.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty 4 | from bpy.types import NodeSocketInterface 5 | from ._base.interface_base import ScNodeSocketInterface 6 | 7 | class ScNodeSocketInterfaceNumber(NodeSocketInterface, ScNodeSocketInterface): 8 | bl_idname = "ScNodeSocketInterfaceNumber" 9 | bl_label = "Number" 10 | bl_socket_idname = "ScNodeSocketNumber" 11 | 12 | color = (0.0, 1.0, 0.0, 1.0) 13 | default_value: FloatProperty(name="Default Value") -------------------------------------------------------------------------------- /sockets/ScNodeSocketInterfaceObject.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import PointerProperty 4 | from bpy.types import NodeSocketInterface 5 | from ._base.interface_base import ScNodeSocketInterface 6 | 7 | class ScNodeSocketInterfaceObject(NodeSocketInterface, ScNodeSocketInterface): 8 | bl_idname = "ScNodeSocketInterfaceObject" 9 | bl_label = "Object" 10 | bl_socket_idname = "ScNodeSocketObject" 11 | 12 | color = (1.0, 1.0, 1.0, 1.0) 13 | default_value: PointerProperty(name="Default Object", type=bpy.types.Object) -------------------------------------------------------------------------------- /sockets/ScNodeSocketInterfaceSelectionType.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import EnumProperty 4 | from bpy.types import NodeSocketInterface 5 | from ._base.interface_base import ScNodeSocketInterface 6 | 7 | class ScNodeSocketInterfaceSelectionType(NodeSocketInterface, ScNodeSocketInterface): 8 | bl_idname = "ScNodeSocketInterfaceSelectionType" 9 | bl_label = "Selection Type" 10 | bl_socket_idname = "ScNodeSocketSelectionType" 11 | 12 | color = (0.3, 0.6, 0.9, 1.0) 13 | default_value: EnumProperty(name="Default Mode", items=[("VERT", "Vertices", "", "VERTEXSEL", 1), ("EDGE", "Edges", "", "EDGESEL", 2), ("FACE", "Faces", "", "FACESEL", 4)], options={"ENUM_FLAG"}) -------------------------------------------------------------------------------- /sockets/ScNodeSocketInterfaceString.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty 4 | from bpy.types import NodeSocketInterface 5 | from ._base.interface_base import ScNodeSocketInterface 6 | 7 | class ScNodeSocketInterfaceString(NodeSocketInterface, ScNodeSocketInterface): 8 | bl_idname = "ScNodeSocketInterfaceString" 9 | bl_label = "String" 10 | bl_socket_idname = "ScNodeSocketString" 11 | 12 | color = (1.0, 0.0, 1.0, 1.0) 13 | default_value: StringProperty(name="Default String") -------------------------------------------------------------------------------- /sockets/ScNodeSocketInterfaceUniversal.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty 4 | from bpy.types import NodeSocketInterface 5 | from ._base.interface_base import ScNodeSocketInterface 6 | 7 | class ScNodeSocketInterfaceUniversal(NodeSocketInterface, ScNodeSocketInterface): 8 | bl_idname = "ScNodeSocketInterfaceUniversal" 9 | bl_label = "Universal" 10 | bl_socket_idname = "ScNodeSocketUniversal" 11 | 12 | color = (0.0, 0.0, 0.0, 0.0) 13 | default_value: StringProperty(name="Default Universal") -------------------------------------------------------------------------------- /sockets/ScNodeSocketInterfaceVector.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatVectorProperty 4 | from bpy.types import NodeSocketInterface 5 | from ._base.interface_base import ScNodeSocketInterface 6 | 7 | class ScNodeSocketInterfaceVector(NodeSocketInterface, ScNodeSocketInterface): 8 | bl_idname = "ScNodeSocketInterfaceVector" 9 | bl_label = "Vector" 10 | bl_socket_idname = "ScNodeSocketVector" 11 | 12 | color = (1.0, 1.0, 0.0, 1.0) 13 | default_value: FloatVectorProperty(name="Default Vector") -------------------------------------------------------------------------------- /sockets/ScNodeSocketNumber.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatProperty, StringProperty 4 | from bpy.types import NodeSocket 5 | from ._base.socket_base import ScNodeSocket 6 | from ..nodes._base.node_base import ScNode 7 | 8 | class ScNodeSocketNumber(NodeSocket, ScNodeSocket): 9 | bl_idname = "ScNodeSocketNumber" 10 | bl_label = "Number" 11 | color = (0.0, 1.0, 0.0, 1.0) 12 | 13 | default_value: FloatProperty() 14 | default_value_update: FloatProperty(update=ScNode.update_value) 15 | default_type: StringProperty(default="NUMBER") 16 | 17 | def get_label(self): 18 | return str(round(self.default_value, 2)) -------------------------------------------------------------------------------- /sockets/ScNodeSocketObject.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import PointerProperty, StringProperty 4 | from bpy.types import NodeSocket 5 | from ._base.socket_base import ScNodeSocket 6 | from ..nodes._base.node_base import ScNode 7 | 8 | class ScNodeSocketObject(NodeSocket, ScNodeSocket): 9 | bl_idname = "ScNodeSocketObject" 10 | bl_label = "Object" 11 | color = (1.0, 1.0, 1.0, 1.0) 12 | 13 | default_value: PointerProperty(type=bpy.types.Object) 14 | default_value_update: PointerProperty(type=bpy.types.Object, update=ScNode.update_value) 15 | default_type: StringProperty(default="OBJECT") 16 | 17 | def get_label(self): 18 | if (self.default_value): 19 | return self.default_value.name 20 | else: 21 | return "-" -------------------------------------------------------------------------------- /sockets/ScNodeSocketSelectionType.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty, EnumProperty 4 | from bpy.types import NodeSocket 5 | from ._base.socket_base import ScNodeSocket 6 | from ..nodes._base.node_base import ScNode 7 | from ..helper import selection_type_to_string 8 | 9 | class ScNodeSocketSelectionType(NodeSocket, ScNodeSocket): 10 | bl_idname = "ScNodeSocketSelectionType" 11 | bl_label = "Selection Type" 12 | color = (0.3, 0.6, 0.9, 1.0) 13 | 14 | default_value: EnumProperty(name="Mode", items=[("VERT", "Vertices", "", "VERTEXSEL", 1), ("EDGE", "Edges", "", "EDGESEL", 2), ("FACE", "Faces", "", "FACESEL", 4)], options={"ENUM_FLAG"}) 15 | default_value_update: EnumProperty(name="Mode", items=[("VERT", "Vertices", "", "VERTEXSEL", 1), ("EDGE", "Edges", "", "EDGESEL", 2), ("FACE", "Faces", "", "FACESEL", 4)], options={"ENUM_FLAG"}, update=ScNode.update_value) 16 | default_type: StringProperty(default="SELECTION_TYPE") 17 | 18 | def get_label(self): 19 | return selection_type_to_string(self.default_value) 20 | 21 | def draw_layout(self, context, layout, node, prop, text): 22 | row = layout.row(align = True) 23 | row.label(text=text) 24 | row.prop(node, prop, icon_only = True) -------------------------------------------------------------------------------- /sockets/ScNodeSocketString.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty 4 | from bpy.types import NodeSocket 5 | from ._base.socket_base import ScNodeSocket 6 | from ..nodes._base.node_base import ScNode 7 | 8 | class ScNodeSocketString(NodeSocket, ScNodeSocket): 9 | bl_idname = "ScNodeSocketString" 10 | bl_label = "String" 11 | color = (1.0, 0.0, 1.0, 1.0) 12 | 13 | default_value: StringProperty() 14 | default_value_update: StringProperty(update=ScNode.update_value) 15 | default_type: StringProperty(default="STRING") -------------------------------------------------------------------------------- /sockets/ScNodeSocketUniversal.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import StringProperty 4 | from bpy.types import NodeSocket 5 | from ._base.socket_base import ScNodeSocket 6 | from ..nodes._base.node_base import ScNode 7 | 8 | class ScNodeSocketUniversal(NodeSocket, ScNodeSocket): 9 | bl_idname = "ScNodeSocketUniversal" 10 | bl_label = "Universal" 11 | color = (0.0, 0.0, 0.0, 0.0) 12 | 13 | default_value: StringProperty() 14 | default_value_update: StringProperty(update=ScNode.update_value) 15 | default_type: StringProperty(default="STRING") -------------------------------------------------------------------------------- /sockets/ScNodeSocketVector.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import FloatVectorProperty, StringProperty 4 | from bpy.types import NodeSocket 5 | from ._base.socket_base import ScNodeSocket 6 | from ..nodes._base.node_base import ScNode 7 | 8 | class ScNodeSocketVector(NodeSocket, ScNodeSocket): 9 | bl_idname = "ScNodeSocketVector" 10 | bl_label = "Vector" 11 | color = (1.0, 1.0, 0.0, 1.0) 12 | 13 | default_value: FloatVectorProperty() 14 | default_value_update: FloatVectorProperty(update=ScNode.update_value) 15 | default_type: StringProperty(default="VECTOR") 16 | 17 | def get_label(self): 18 | return str(round(self.default_value[0], 1)) + ", " + str(round(self.default_value[1], 1)) + ", " + str(round(self.default_value[2], 1)) 19 | 20 | def draw_layout(self, context, layout, node, prop, text): 21 | layout.column().prop(node, prop, text=text) -------------------------------------------------------------------------------- /sockets/_base/interface_base.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.props import BoolProperty 4 | 5 | class ScNodeSocketInterface: 6 | show_prop: BoolProperty(name="Show Property", default=True) 7 | 8 | def draw(self, context, layout): 9 | if (not self.is_output): 10 | layout.prop(self, "show_prop") 11 | # layout.prop(self, "default_value") 12 | 13 | def draw_color(self, context): 14 | return self.color -------------------------------------------------------------------------------- /sorcar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aachman98/Sorcar/650cb6585c3f8a92af029ae7f5c2d7453e9459ef/sorcar.png -------------------------------------------------------------------------------- /tree/ScNodeCategory.py: -------------------------------------------------------------------------------- 1 | import nodeitems_utils 2 | 3 | from nodeitems_utils import NodeCategory 4 | 5 | class ScNodeCategory(NodeCategory): 6 | @classmethod 7 | def poll(self, context): 8 | return context.space_data.tree_type == "ScNodeTree" -------------------------------------------------------------------------------- /ui/ScNodeGroupPanel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Panel 4 | from ._base.panel_base import ScPanel 5 | 6 | class ScNodeGroupPanel(Panel, ScPanel): 7 | bl_label = "Node Groups" 8 | bl_idname = "NODE_PT_sc_node_group" 9 | bl_order = 2 10 | 11 | def draw(self, context): 12 | layout = self.layout 13 | layout.operator("sorcar.group_nodes", text="Create Group", icon='GROUP') 14 | layout.operator("sorcar.edit_group", text="Edit Group", icon='MENU_PANEL') -------------------------------------------------------------------------------- /ui/ScTreePropertiesPanel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Panel 4 | from ._base.panel_base import ScPanel 5 | 6 | class ScTreePropertiesPanel(Panel, ScPanel): 7 | bl_label = "Properties" 8 | bl_idname = "NODE_PT_sc_tree_properties" 9 | bl_order = 0 10 | 11 | def draw(self, context): 12 | layout = self.layout 13 | nt = context.space_data.node_tree 14 | layout.label(text="Preview node: " + str(nt.node), icon='NODE') 15 | layout.prop(nt, "prop_realtime") 16 | layout.prop(nt, "prop_clear_vars") -------------------------------------------------------------------------------- /ui/ScUtilitiesPanel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from bpy.types import Panel 4 | from ._base.panel_base import ScPanel 5 | 6 | class ScUtilitiesPanel(Panel, ScPanel): 7 | bl_label = "Utilities" 8 | bl_idname = "NODE_PT_sc_utilities" 9 | bl_order = 1 10 | 11 | def draw(self, context): 12 | layout = self.layout 13 | layout.operator("sorcar.execute_node") 14 | layout.operator("sorcar.clear_preview") 15 | layout.separator() 16 | layout.operator("node.join", text="Frame (Comment)", icon='SEQ_STRIP_META') -------------------------------------------------------------------------------- /ui/_base/panel_base.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | from ...helper import sc_poll_op 4 | 5 | class ScPanel(): 6 | bl_space_type = 'NODE_EDITOR' 7 | bl_region_type = 'UI' 8 | bl_category = "Sorcar" 9 | 10 | @classmethod 11 | def poll(self, context): 12 | return sc_poll_op(context) --------------------------------------------------------------------------------