nodebpy 0.1.1__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nodebpy/builder.py +770 -306
- nodebpy/nodes/__init__.py +623 -9
- nodebpy/nodes/attribute.py +174 -273
- nodebpy/nodes/color.py +76 -0
- nodebpy/nodes/converter.py +4518 -0
- nodebpy/nodes/experimental.py +314 -0
- nodebpy/nodes/geometry.py +3665 -5250
- nodebpy/nodes/grid.py +1228 -0
- nodebpy/nodes/group.py +20 -0
- nodebpy/nodes/input.py +1571 -254
- nodebpy/nodes/interface.py +400 -0
- nodebpy/nodes/mesh.py +0 -1391
- nodebpy/nodes/texture.py +70 -0
- nodebpy/nodes/types.py +319 -6
- nodebpy/nodes/vector.py +0 -0
- nodebpy/nodes/zone.py +442 -0
- nodebpy/screenshot.py +2 -1
- nodebpy/sockets.py +12 -12
- {nodebpy-0.1.1.dist-info → nodebpy-0.2.0.dist-info}/METADATA +4 -4
- nodebpy-0.2.0.dist-info/RECORD +25 -0
- nodebpy/nodes/curve.py +0 -2006
- nodebpy/nodes/manually_specified.py +0 -1382
- nodebpy/nodes/utilities.py +0 -2344
- nodebpy-0.1.1.dist-info/RECORD +0 -19
- {nodebpy-0.1.1.dist-info → nodebpy-0.2.0.dist-info}/WHEEL +0 -0
- {nodebpy-0.1.1.dist-info → nodebpy-0.2.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,4518 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
import bpy
|
|
4
|
+
from bpy.types import NodeSocket
|
|
5
|
+
|
|
6
|
+
from ..builder import NodeBuilder, SocketLinker
|
|
7
|
+
from . import types
|
|
8
|
+
from .types import (
|
|
9
|
+
LINKABLE,
|
|
10
|
+
SOCKET_TYPES,
|
|
11
|
+
TYPE_INPUT_ALL,
|
|
12
|
+
TYPE_INPUT_BOOLEAN,
|
|
13
|
+
TYPE_INPUT_COLOR,
|
|
14
|
+
TYPE_INPUT_INT,
|
|
15
|
+
TYPE_INPUT_MATRIX,
|
|
16
|
+
TYPE_INPUT_MENU,
|
|
17
|
+
TYPE_INPUT_ROTATION,
|
|
18
|
+
TYPE_INPUT_STRING,
|
|
19
|
+
TYPE_INPUT_VALUE,
|
|
20
|
+
TYPE_INPUT_VECTOR,
|
|
21
|
+
_AccumulateFieldDataTypes,
|
|
22
|
+
_AttributeDomains,
|
|
23
|
+
_EvaluateAtIndexDataTypes,
|
|
24
|
+
_IntegerMathOperations,
|
|
25
|
+
_is_default_value,
|
|
26
|
+
_MixColorBlendTypes,
|
|
27
|
+
_MixDataTypes,
|
|
28
|
+
_RandomValueDataTypes,
|
|
29
|
+
_VectorMathOperations,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class AlignRotationToVector(NodeBuilder):
|
|
34
|
+
"""Orient a rotation along the given direction"""
|
|
35
|
+
|
|
36
|
+
name = "FunctionNodeAlignRotationToVector"
|
|
37
|
+
node: bpy.types.FunctionNodeAlignRotationToVector
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
rotation: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0),
|
|
42
|
+
factor: TYPE_INPUT_VALUE = 1.0,
|
|
43
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 1.0),
|
|
44
|
+
axis: Literal["X", "Y", "Z"] = "Z",
|
|
45
|
+
pivot_axis: Literal["AUTO", "X", "Y", "Z"] = "AUTO",
|
|
46
|
+
**kwargs,
|
|
47
|
+
):
|
|
48
|
+
super().__init__()
|
|
49
|
+
key_args = {"Rotation": rotation, "Factor": factor, "Vector": vector}
|
|
50
|
+
key_args.update(kwargs)
|
|
51
|
+
self.axis = axis
|
|
52
|
+
self.pivot_axis = pivot_axis
|
|
53
|
+
self._establish_links(**key_args)
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def i_rotation(self) -> SocketLinker:
|
|
57
|
+
"""Input socket: Rotation"""
|
|
58
|
+
return self._input("Rotation")
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def i_factor(self) -> SocketLinker:
|
|
62
|
+
"""Input socket: Factor"""
|
|
63
|
+
return self._input("Factor")
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def i_vector(self) -> SocketLinker:
|
|
67
|
+
"""Input socket: Vector"""
|
|
68
|
+
return self._input("Vector")
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def o_rotation(self) -> SocketLinker:
|
|
72
|
+
"""Output socket: Rotation"""
|
|
73
|
+
return self._output("Rotation")
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def axis(self) -> Literal["X", "Y", "Z"]:
|
|
77
|
+
return self.node.axis
|
|
78
|
+
|
|
79
|
+
@axis.setter
|
|
80
|
+
def axis(self, value: Literal["X", "Y", "Z"]):
|
|
81
|
+
self.node.axis = value
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def pivot_axis(self) -> Literal["AUTO", "X", "Y", "Z"]:
|
|
85
|
+
return self.node.pivot_axis
|
|
86
|
+
|
|
87
|
+
@pivot_axis.setter
|
|
88
|
+
def pivot_axis(self, value: Literal["AUTO", "X", "Y", "Z"]):
|
|
89
|
+
self.node.pivot_axis = value
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class AxesToRotation(NodeBuilder):
|
|
93
|
+
"""Create a rotation from a primary and (ideally orthogonal) secondary axis"""
|
|
94
|
+
|
|
95
|
+
name = "FunctionNodeAxesToRotation"
|
|
96
|
+
node: bpy.types.FunctionNodeAxesToRotation
|
|
97
|
+
|
|
98
|
+
def __init__(
|
|
99
|
+
self,
|
|
100
|
+
primary_axis_vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 1.0),
|
|
101
|
+
secondary_axis_vector: TYPE_INPUT_VECTOR = (1.0, 0.0, 0.0),
|
|
102
|
+
primary_axis: Literal["X", "Y", "Z"] = "Z",
|
|
103
|
+
secondary_axis: Literal["X", "Y", "Z"] = "X",
|
|
104
|
+
**kwargs,
|
|
105
|
+
):
|
|
106
|
+
super().__init__()
|
|
107
|
+
key_args = {
|
|
108
|
+
"Primary Axis": primary_axis_vector,
|
|
109
|
+
"Secondary Axis": secondary_axis_vector,
|
|
110
|
+
}
|
|
111
|
+
key_args.update(kwargs)
|
|
112
|
+
self.primary_axis = primary_axis
|
|
113
|
+
self.secondary_axis = secondary_axis
|
|
114
|
+
self._establish_links(**key_args)
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def i_primary_axis(self) -> SocketLinker:
|
|
118
|
+
"""Input socket: Primary Axis"""
|
|
119
|
+
return self._input("Primary Axis")
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def i_secondary_axis(self) -> SocketLinker:
|
|
123
|
+
"""Input socket: Secondary Axis"""
|
|
124
|
+
return self._input("Secondary Axis")
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def o_rotation(self) -> SocketLinker:
|
|
128
|
+
"""Output socket: Rotation"""
|
|
129
|
+
return self._output("Rotation")
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def primary_axis(self) -> Literal["X", "Y", "Z"]:
|
|
133
|
+
return self.node.primary_axis
|
|
134
|
+
|
|
135
|
+
@primary_axis.setter
|
|
136
|
+
def primary_axis(self, value: Literal["X", "Y", "Z"]):
|
|
137
|
+
self.node.primary_axis = value
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def secondary_axis(self) -> Literal["X", "Y", "Z"]:
|
|
141
|
+
return self.node.secondary_axis
|
|
142
|
+
|
|
143
|
+
@secondary_axis.setter
|
|
144
|
+
def secondary_axis(self, value: Literal["X", "Y", "Z"]):
|
|
145
|
+
self.node.secondary_axis = value
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class AxisAngleToRotation(NodeBuilder):
|
|
149
|
+
"""Build a rotation from an axis and a rotation around that axis"""
|
|
150
|
+
|
|
151
|
+
name = "FunctionNodeAxisAngleToRotation"
|
|
152
|
+
node: bpy.types.FunctionNodeAxisAngleToRotation
|
|
153
|
+
|
|
154
|
+
def __init__(
|
|
155
|
+
self,
|
|
156
|
+
axis: TYPE_INPUT_VECTOR = (0.0, 0.0, 1.0),
|
|
157
|
+
angle: TYPE_INPUT_VALUE = 0.0,
|
|
158
|
+
**kwargs,
|
|
159
|
+
):
|
|
160
|
+
super().__init__()
|
|
161
|
+
key_args = {"Axis": axis, "Angle": angle}
|
|
162
|
+
key_args.update(kwargs)
|
|
163
|
+
|
|
164
|
+
self._establish_links(**key_args)
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def i_axis(self) -> SocketLinker:
|
|
168
|
+
"""Input socket: Axis"""
|
|
169
|
+
return self._input("Axis")
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def i_angle(self) -> SocketLinker:
|
|
173
|
+
"""Input socket: Angle"""
|
|
174
|
+
return self._input("Angle")
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def o_rotation(self) -> SocketLinker:
|
|
178
|
+
"""Output socket: Rotation"""
|
|
179
|
+
return self._output("Rotation")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class BitMath(NodeBuilder):
|
|
183
|
+
"""Perform bitwise operations on 32-bit integers"""
|
|
184
|
+
|
|
185
|
+
name = "FunctionNodeBitMath"
|
|
186
|
+
node: bpy.types.FunctionNodeBitMath
|
|
187
|
+
|
|
188
|
+
def __init__(
|
|
189
|
+
self,
|
|
190
|
+
a: TYPE_INPUT_INT = 0,
|
|
191
|
+
b: TYPE_INPUT_INT = 0,
|
|
192
|
+
operation: Literal["AND", "OR", "XOR", "NOT", "SHIFT", "ROTATE"] = "AND",
|
|
193
|
+
**kwargs,
|
|
194
|
+
):
|
|
195
|
+
super().__init__()
|
|
196
|
+
key_args = {"A": a, "B": b}
|
|
197
|
+
key_args.update(kwargs)
|
|
198
|
+
self.operation = operation
|
|
199
|
+
self._establish_links(**key_args)
|
|
200
|
+
|
|
201
|
+
@classmethod
|
|
202
|
+
def l_and(cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0) -> "BitMath":
|
|
203
|
+
"""Create Bit Math with operation 'And'."""
|
|
204
|
+
return cls(operation="AND", A=a, B=b)
|
|
205
|
+
|
|
206
|
+
@classmethod
|
|
207
|
+
def l_or(cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0) -> "BitMath":
|
|
208
|
+
"""Create Bit Math with operation 'Or'."""
|
|
209
|
+
return cls(operation="OR", A=a, B=b)
|
|
210
|
+
|
|
211
|
+
@classmethod
|
|
212
|
+
def l_exclusive_or(cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0) -> "BitMath":
|
|
213
|
+
"""Create Bit Math with operation 'XOR'."""
|
|
214
|
+
return cls(operation="XOR", A=a, B=b)
|
|
215
|
+
|
|
216
|
+
@classmethod
|
|
217
|
+
def l_not(cls, a: TYPE_INPUT_INT = 0) -> "BitMath":
|
|
218
|
+
"""Create Bit Math with operation 'Not'."""
|
|
219
|
+
return cls(operation="NOT", A=a)
|
|
220
|
+
|
|
221
|
+
@classmethod
|
|
222
|
+
def shift(cls, a: TYPE_INPUT_INT = 0, shift: TYPE_INPUT_INT = 0) -> "BitMath":
|
|
223
|
+
"""Create Bit Math with operation 'Shift'."""
|
|
224
|
+
return cls(operation="SHIFT", A=a, B=shift)
|
|
225
|
+
|
|
226
|
+
@classmethod
|
|
227
|
+
def rotate(cls, a: TYPE_INPUT_INT = 0, shift: TYPE_INPUT_INT = 0) -> "BitMath":
|
|
228
|
+
"""Create Bit Math with operation 'Rotate'."""
|
|
229
|
+
return cls(operation="ROTATE", A=a, B=shift)
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def i_a(self) -> SocketLinker:
|
|
233
|
+
"""Input socket: A"""
|
|
234
|
+
return self._input("A")
|
|
235
|
+
|
|
236
|
+
@property
|
|
237
|
+
def i_b(self) -> SocketLinker:
|
|
238
|
+
"""Input socket: B"""
|
|
239
|
+
return self._input("B")
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def o_value(self) -> SocketLinker:
|
|
243
|
+
"""Output socket: Value"""
|
|
244
|
+
return self._output("Value")
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def operation(self) -> Literal["AND", "OR", "XOR", "NOT", "SHIFT", "ROTATE"]:
|
|
248
|
+
return self.node.operation
|
|
249
|
+
|
|
250
|
+
@operation.setter
|
|
251
|
+
def operation(self, value: Literal["AND", "OR", "XOR", "NOT", "SHIFT", "ROTATE"]):
|
|
252
|
+
self.node.operation = value
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class CombineColor(NodeBuilder):
|
|
256
|
+
"""Combine four channels into a single color, based on a particular color model"""
|
|
257
|
+
|
|
258
|
+
name = "FunctionNodeCombineColor"
|
|
259
|
+
node: bpy.types.FunctionNodeCombineColor
|
|
260
|
+
|
|
261
|
+
def __init__(
|
|
262
|
+
self,
|
|
263
|
+
red: TYPE_INPUT_VALUE = 0.0,
|
|
264
|
+
green: TYPE_INPUT_VALUE = 0.0,
|
|
265
|
+
blue: TYPE_INPUT_VALUE = 0.0,
|
|
266
|
+
alpha: TYPE_INPUT_VALUE = 1.0,
|
|
267
|
+
mode: Literal["RGB", "HSV", "HSL"] = "RGB",
|
|
268
|
+
):
|
|
269
|
+
super().__init__()
|
|
270
|
+
key_args = {"Red": red, "Green": green, "Blue": blue, "Alpha": alpha}
|
|
271
|
+
self.mode = mode
|
|
272
|
+
self._establish_links(**key_args)
|
|
273
|
+
|
|
274
|
+
@classmethod
|
|
275
|
+
def rgb(
|
|
276
|
+
cls,
|
|
277
|
+
red: TYPE_INPUT_VALUE = 0.0,
|
|
278
|
+
green: TYPE_INPUT_VALUE = 0.0,
|
|
279
|
+
blue: TYPE_INPUT_VALUE = 0.0,
|
|
280
|
+
alpha: TYPE_INPUT_VALUE = 1.0,
|
|
281
|
+
):
|
|
282
|
+
return cls(red=red, green=green, blue=blue, alpha=alpha, mode="RGB")
|
|
283
|
+
|
|
284
|
+
@classmethod
|
|
285
|
+
def hsv(
|
|
286
|
+
cls,
|
|
287
|
+
hue: TYPE_INPUT_VALUE = 0.0,
|
|
288
|
+
saturation: TYPE_INPUT_VALUE = 0.0,
|
|
289
|
+
value: TYPE_INPUT_VALUE = 0.0,
|
|
290
|
+
alpha: TYPE_INPUT_VALUE = 1.0,
|
|
291
|
+
):
|
|
292
|
+
return cls(red=hue, green=saturation, blue=value, alpha=alpha, mode="HSV")
|
|
293
|
+
|
|
294
|
+
@classmethod
|
|
295
|
+
def hsl(
|
|
296
|
+
cls,
|
|
297
|
+
hue: TYPE_INPUT_VALUE = 0.0,
|
|
298
|
+
saturation: TYPE_INPUT_VALUE = 0.0,
|
|
299
|
+
lightness: TYPE_INPUT_VALUE = 0.0,
|
|
300
|
+
alpha: TYPE_INPUT_VALUE = 1.0,
|
|
301
|
+
):
|
|
302
|
+
return cls(red=hue, green=saturation, blue=lightness, alpha=alpha, mode="HSL")
|
|
303
|
+
|
|
304
|
+
@property
|
|
305
|
+
def i_red(self) -> SocketLinker:
|
|
306
|
+
"""Input socket: Red"""
|
|
307
|
+
return self._input("Red")
|
|
308
|
+
|
|
309
|
+
@property
|
|
310
|
+
def i_green(self) -> SocketLinker:
|
|
311
|
+
"""Input socket: Green"""
|
|
312
|
+
return self._input("Green")
|
|
313
|
+
|
|
314
|
+
@property
|
|
315
|
+
def i_blue(self) -> SocketLinker:
|
|
316
|
+
"""Input socket: Blue"""
|
|
317
|
+
return self._input("Blue")
|
|
318
|
+
|
|
319
|
+
@property
|
|
320
|
+
def i_alpha(self) -> SocketLinker:
|
|
321
|
+
"""Input socket: Alpha"""
|
|
322
|
+
return self._input("Alpha")
|
|
323
|
+
|
|
324
|
+
@property
|
|
325
|
+
def o_color(self) -> SocketLinker:
|
|
326
|
+
"""Output socket: Color"""
|
|
327
|
+
return self._output("Color")
|
|
328
|
+
|
|
329
|
+
@property
|
|
330
|
+
def mode(self) -> Literal["RGB", "HSV", "HSL"]:
|
|
331
|
+
return self.node.mode
|
|
332
|
+
|
|
333
|
+
@mode.setter
|
|
334
|
+
def mode(self, value: Literal["RGB", "HSV", "HSL"]):
|
|
335
|
+
self.node.mode = value
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
class CombineMatrix(NodeBuilder):
|
|
339
|
+
"""Construct a 4x4 matrix from its individual values"""
|
|
340
|
+
|
|
341
|
+
name = "FunctionNodeCombineMatrix"
|
|
342
|
+
node: bpy.types.FunctionNodeCombineMatrix
|
|
343
|
+
|
|
344
|
+
def __init__(
|
|
345
|
+
self,
|
|
346
|
+
column_1_row_1: TYPE_INPUT_VALUE = 1.0,
|
|
347
|
+
column_1_row_2: TYPE_INPUT_VALUE = 0.0,
|
|
348
|
+
column_1_row_3: TYPE_INPUT_VALUE = 0.0,
|
|
349
|
+
column_1_row_4: TYPE_INPUT_VALUE = 0.0,
|
|
350
|
+
column_2_row_1: TYPE_INPUT_VALUE = 0.0,
|
|
351
|
+
column_2_row_2: TYPE_INPUT_VALUE = 1.0,
|
|
352
|
+
column_2_row_3: TYPE_INPUT_VALUE = 0.0,
|
|
353
|
+
column_2_row_4: TYPE_INPUT_VALUE = 0.0,
|
|
354
|
+
column_3_row_1: TYPE_INPUT_VALUE = 0.0,
|
|
355
|
+
column_3_row_2: TYPE_INPUT_VALUE = 0.0,
|
|
356
|
+
column_3_row_3: TYPE_INPUT_VALUE = 1.0,
|
|
357
|
+
column_3_row_4: TYPE_INPUT_VALUE = 0.0,
|
|
358
|
+
column_4_row_1: TYPE_INPUT_VALUE = 0.0,
|
|
359
|
+
column_4_row_2: TYPE_INPUT_VALUE = 0.0,
|
|
360
|
+
column_4_row_3: TYPE_INPUT_VALUE = 0.0,
|
|
361
|
+
column_4_row_4: TYPE_INPUT_VALUE = 1.0,
|
|
362
|
+
**kwargs,
|
|
363
|
+
):
|
|
364
|
+
super().__init__()
|
|
365
|
+
key_args = {
|
|
366
|
+
"Column 1 Row 1": column_1_row_1,
|
|
367
|
+
"Column 1 Row 2": column_1_row_2,
|
|
368
|
+
"Column 1 Row 3": column_1_row_3,
|
|
369
|
+
"Column 1 Row 4": column_1_row_4,
|
|
370
|
+
"Column 2 Row 1": column_2_row_1,
|
|
371
|
+
"Column 2 Row 2": column_2_row_2,
|
|
372
|
+
"Column 2 Row 3": column_2_row_3,
|
|
373
|
+
"Column 2 Row 4": column_2_row_4,
|
|
374
|
+
"Column 3 Row 1": column_3_row_1,
|
|
375
|
+
"Column 3 Row 2": column_3_row_2,
|
|
376
|
+
"Column 3 Row 3": column_3_row_3,
|
|
377
|
+
"Column 3 Row 4": column_3_row_4,
|
|
378
|
+
"Column 4 Row 1": column_4_row_1,
|
|
379
|
+
"Column 4 Row 2": column_4_row_2,
|
|
380
|
+
"Column 4 Row 3": column_4_row_3,
|
|
381
|
+
"Column 4 Row 4": column_4_row_4,
|
|
382
|
+
}
|
|
383
|
+
key_args.update(kwargs)
|
|
384
|
+
|
|
385
|
+
self._establish_links(**key_args)
|
|
386
|
+
|
|
387
|
+
@property
|
|
388
|
+
def i_column_1_row_1(self) -> SocketLinker:
|
|
389
|
+
"""Input socket: Column 1 Row 1"""
|
|
390
|
+
return self._input("Column 1 Row 1")
|
|
391
|
+
|
|
392
|
+
@property
|
|
393
|
+
def i_column_1_row_2(self) -> SocketLinker:
|
|
394
|
+
"""Input socket: Column 1 Row 2"""
|
|
395
|
+
return self._input("Column 1 Row 2")
|
|
396
|
+
|
|
397
|
+
@property
|
|
398
|
+
def i_column_1_row_3(self) -> SocketLinker:
|
|
399
|
+
"""Input socket: Column 1 Row 3"""
|
|
400
|
+
return self._input("Column 1 Row 3")
|
|
401
|
+
|
|
402
|
+
@property
|
|
403
|
+
def i_column_1_row_4(self) -> SocketLinker:
|
|
404
|
+
"""Input socket: Column 1 Row 4"""
|
|
405
|
+
return self._input("Column 1 Row 4")
|
|
406
|
+
|
|
407
|
+
@property
|
|
408
|
+
def i_column_2_row_1(self) -> SocketLinker:
|
|
409
|
+
"""Input socket: Column 2 Row 1"""
|
|
410
|
+
return self._input("Column 2 Row 1")
|
|
411
|
+
|
|
412
|
+
@property
|
|
413
|
+
def i_column_2_row_2(self) -> SocketLinker:
|
|
414
|
+
"""Input socket: Column 2 Row 2"""
|
|
415
|
+
return self._input("Column 2 Row 2")
|
|
416
|
+
|
|
417
|
+
@property
|
|
418
|
+
def i_column_2_row_3(self) -> SocketLinker:
|
|
419
|
+
"""Input socket: Column 2 Row 3"""
|
|
420
|
+
return self._input("Column 2 Row 3")
|
|
421
|
+
|
|
422
|
+
@property
|
|
423
|
+
def i_column_2_row_4(self) -> SocketLinker:
|
|
424
|
+
"""Input socket: Column 2 Row 4"""
|
|
425
|
+
return self._input("Column 2 Row 4")
|
|
426
|
+
|
|
427
|
+
@property
|
|
428
|
+
def i_column_3_row_1(self) -> SocketLinker:
|
|
429
|
+
"""Input socket: Column 3 Row 1"""
|
|
430
|
+
return self._input("Column 3 Row 1")
|
|
431
|
+
|
|
432
|
+
@property
|
|
433
|
+
def i_column_3_row_2(self) -> SocketLinker:
|
|
434
|
+
"""Input socket: Column 3 Row 2"""
|
|
435
|
+
return self._input("Column 3 Row 2")
|
|
436
|
+
|
|
437
|
+
@property
|
|
438
|
+
def i_column_3_row_3(self) -> SocketLinker:
|
|
439
|
+
"""Input socket: Column 3 Row 3"""
|
|
440
|
+
return self._input("Column 3 Row 3")
|
|
441
|
+
|
|
442
|
+
@property
|
|
443
|
+
def i_column_3_row_4(self) -> SocketLinker:
|
|
444
|
+
"""Input socket: Column 3 Row 4"""
|
|
445
|
+
return self._input("Column 3 Row 4")
|
|
446
|
+
|
|
447
|
+
@property
|
|
448
|
+
def i_column_4_row_1(self) -> SocketLinker:
|
|
449
|
+
"""Input socket: Column 4 Row 1"""
|
|
450
|
+
return self._input("Column 4 Row 1")
|
|
451
|
+
|
|
452
|
+
@property
|
|
453
|
+
def i_column_4_row_2(self) -> SocketLinker:
|
|
454
|
+
"""Input socket: Column 4 Row 2"""
|
|
455
|
+
return self._input("Column 4 Row 2")
|
|
456
|
+
|
|
457
|
+
@property
|
|
458
|
+
def i_column_4_row_3(self) -> SocketLinker:
|
|
459
|
+
"""Input socket: Column 4 Row 3"""
|
|
460
|
+
return self._input("Column 4 Row 3")
|
|
461
|
+
|
|
462
|
+
@property
|
|
463
|
+
def i_column_4_row_4(self) -> SocketLinker:
|
|
464
|
+
"""Input socket: Column 4 Row 4"""
|
|
465
|
+
return self._input("Column 4 Row 4")
|
|
466
|
+
|
|
467
|
+
@property
|
|
468
|
+
def o_matrix(self) -> SocketLinker:
|
|
469
|
+
"""Output socket: Matrix"""
|
|
470
|
+
return self._output("Matrix")
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
class CombineTransform(NodeBuilder):
|
|
474
|
+
"""Combine a translation vector, a rotation, and a scale vector into a transformation matrix"""
|
|
475
|
+
|
|
476
|
+
name = "FunctionNodeCombineTransform"
|
|
477
|
+
node: bpy.types.FunctionNodeCombineTransform
|
|
478
|
+
|
|
479
|
+
def __init__(
|
|
480
|
+
self,
|
|
481
|
+
translation: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
482
|
+
rotation: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0),
|
|
483
|
+
scale: TYPE_INPUT_VECTOR = (1.0, 1.0, 1.0),
|
|
484
|
+
**kwargs,
|
|
485
|
+
):
|
|
486
|
+
super().__init__()
|
|
487
|
+
key_args = {"Translation": translation, "Rotation": rotation, "Scale": scale}
|
|
488
|
+
key_args.update(kwargs)
|
|
489
|
+
|
|
490
|
+
self._establish_links(**key_args)
|
|
491
|
+
|
|
492
|
+
@property
|
|
493
|
+
def i_translation(self) -> SocketLinker:
|
|
494
|
+
"""Input socket: Translation"""
|
|
495
|
+
return self._input("Translation")
|
|
496
|
+
|
|
497
|
+
@property
|
|
498
|
+
def i_rotation(self) -> SocketLinker:
|
|
499
|
+
"""Input socket: Rotation"""
|
|
500
|
+
return self._input("Rotation")
|
|
501
|
+
|
|
502
|
+
@property
|
|
503
|
+
def i_scale(self) -> SocketLinker:
|
|
504
|
+
"""Input socket: Scale"""
|
|
505
|
+
return self._input("Scale")
|
|
506
|
+
|
|
507
|
+
@property
|
|
508
|
+
def o_transform(self) -> SocketLinker:
|
|
509
|
+
"""Output socket: Transform"""
|
|
510
|
+
return self._output("Transform")
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
_CompareOperations = Literal[
|
|
514
|
+
"LESS_THAN",
|
|
515
|
+
"LESS_EQUAL",
|
|
516
|
+
"GREATER_THAN",
|
|
517
|
+
"GREATER_EQUAL",
|
|
518
|
+
"EQUAL",
|
|
519
|
+
"NOT_EQUAL",
|
|
520
|
+
"BRIGHTER",
|
|
521
|
+
"DARKER",
|
|
522
|
+
]
|
|
523
|
+
|
|
524
|
+
_CompareDataTypes = Literal[
|
|
525
|
+
"FLOAT",
|
|
526
|
+
"INT",
|
|
527
|
+
"VECTOR",
|
|
528
|
+
"RGBA",
|
|
529
|
+
"ROTATION",
|
|
530
|
+
"STRING",
|
|
531
|
+
]
|
|
532
|
+
|
|
533
|
+
_CompareVectorModes = Literal[
|
|
534
|
+
"ELEMENT", "LENGTH", "AVERAGE", "DOT_PRODUCT", "DIRECTION"
|
|
535
|
+
]
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def _compare_operation_method(operation: _CompareOperations):
|
|
539
|
+
"""Create a factory for Compare with a specific operation"""
|
|
540
|
+
|
|
541
|
+
class CompareOperationFactory:
|
|
542
|
+
@staticmethod
|
|
543
|
+
def float(
|
|
544
|
+
a: TYPE_INPUT_VALUE = 0.0,
|
|
545
|
+
b: TYPE_INPUT_VALUE = 0.0,
|
|
546
|
+
*,
|
|
547
|
+
epsilon: TYPE_INPUT_VALUE = 0.0001,
|
|
548
|
+
) -> "Compare":
|
|
549
|
+
return Compare.float(operation=operation, a=a, b=b, epsilon=epsilon)
|
|
550
|
+
|
|
551
|
+
@staticmethod
|
|
552
|
+
def integer(a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0) -> "Compare":
|
|
553
|
+
return Compare.integer(operation=operation, a=a, b=b)
|
|
554
|
+
|
|
555
|
+
@staticmethod
|
|
556
|
+
def vector(
|
|
557
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
558
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
559
|
+
*,
|
|
560
|
+
mode: _CompareVectorModes = "ELEMENT",
|
|
561
|
+
c: TYPE_INPUT_VALUE = None,
|
|
562
|
+
angle: TYPE_INPUT_VALUE = None,
|
|
563
|
+
epsilon: TYPE_INPUT_VALUE = None,
|
|
564
|
+
) -> "Compare":
|
|
565
|
+
return Compare.vector(
|
|
566
|
+
operation=operation,
|
|
567
|
+
a=a,
|
|
568
|
+
b=b,
|
|
569
|
+
mode=mode,
|
|
570
|
+
c=c,
|
|
571
|
+
angle=angle,
|
|
572
|
+
epsilon=epsilon,
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
@staticmethod
|
|
576
|
+
def color(
|
|
577
|
+
a: TYPE_INPUT_COLOR = None,
|
|
578
|
+
b: TYPE_INPUT_COLOR = None,
|
|
579
|
+
epsilon: TYPE_INPUT_VALUE = None,
|
|
580
|
+
) -> "Compare":
|
|
581
|
+
return Compare.color(operation=operation, a=a, b=b, epsilon=epsilon)
|
|
582
|
+
|
|
583
|
+
@staticmethod
|
|
584
|
+
def string(a: TYPE_INPUT_STRING = "", b: TYPE_INPUT_STRING = "") -> "Compare":
|
|
585
|
+
return Compare.string(operation=operation, a=a, b=b)
|
|
586
|
+
|
|
587
|
+
return CompareOperationFactory()
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
class Compare(NodeBuilder):
|
|
591
|
+
"""Perform a comparison operation on the two given inputs"""
|
|
592
|
+
|
|
593
|
+
name = "FunctionNodeCompare"
|
|
594
|
+
node: bpy.types.FunctionNodeCompare
|
|
595
|
+
|
|
596
|
+
less_than = _compare_operation_method("LESS_THAN")
|
|
597
|
+
less_equal = _compare_operation_method("LESS_EQUAL")
|
|
598
|
+
greater_than = _compare_operation_method("GREATER_THAN")
|
|
599
|
+
greater_equal = _compare_operation_method("GREATER_EQUAL")
|
|
600
|
+
equal = _compare_operation_method("EQUAL")
|
|
601
|
+
not_equal = _compare_operation_method("NOT_EQUAL")
|
|
602
|
+
brighter = _compare_operation_method("BRIGHTER")
|
|
603
|
+
darker = _compare_operation_method("DARKER")
|
|
604
|
+
|
|
605
|
+
def __init__(
|
|
606
|
+
self,
|
|
607
|
+
operation: _CompareOperations = "GREATER_THAN",
|
|
608
|
+
data_type: _CompareDataTypes = "FLOAT",
|
|
609
|
+
**kwargs,
|
|
610
|
+
):
|
|
611
|
+
super().__init__()
|
|
612
|
+
self.operation = operation
|
|
613
|
+
self.data_type = data_type
|
|
614
|
+
if self.data_type == "VECTOR":
|
|
615
|
+
self.mode = kwargs["mode"]
|
|
616
|
+
self._establish_links(**kwargs)
|
|
617
|
+
|
|
618
|
+
@classmethod
|
|
619
|
+
def float(
|
|
620
|
+
cls,
|
|
621
|
+
a: TYPE_INPUT_VALUE = 0.0,
|
|
622
|
+
b: TYPE_INPUT_VALUE = 0.0,
|
|
623
|
+
operation: _CompareOperations = "LESS_THAN",
|
|
624
|
+
*,
|
|
625
|
+
epsilon: TYPE_INPUT_VALUE = 0.0001,
|
|
626
|
+
):
|
|
627
|
+
kwargs = {"operation": operation, "data_type": "FLOAT", "A": a, "B": b}
|
|
628
|
+
if operation in ("EQUAL", "NOT_EQUAL"):
|
|
629
|
+
kwargs["Epsilon"] = epsilon
|
|
630
|
+
return cls(**kwargs)
|
|
631
|
+
|
|
632
|
+
@classmethod
|
|
633
|
+
def integer(
|
|
634
|
+
cls,
|
|
635
|
+
a: TYPE_INPUT_INT = 0,
|
|
636
|
+
b: TYPE_INPUT_INT = 0,
|
|
637
|
+
operation: _CompareOperations = "LESS_THAN",
|
|
638
|
+
) -> "Compare":
|
|
639
|
+
return cls(operation=operation, data_type="INT", A_INT=a, B_INT=b)
|
|
640
|
+
|
|
641
|
+
@classmethod
|
|
642
|
+
def vector(
|
|
643
|
+
cls,
|
|
644
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
645
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
646
|
+
operation: _CompareOperations = "LESS_THAN",
|
|
647
|
+
*,
|
|
648
|
+
mode: _CompareVectorModes = "ELEMENT",
|
|
649
|
+
c: TYPE_INPUT_VALUE = None,
|
|
650
|
+
angle: TYPE_INPUT_VALUE = None,
|
|
651
|
+
epsilon: TYPE_INPUT_VALUE = None,
|
|
652
|
+
) -> "Compare":
|
|
653
|
+
kwargs = {
|
|
654
|
+
"operation": operation,
|
|
655
|
+
"data_type": "VECTOR",
|
|
656
|
+
"mode": mode,
|
|
657
|
+
"A_VEC3": a,
|
|
658
|
+
"B_VEC3": b,
|
|
659
|
+
}
|
|
660
|
+
if operation in ("EQUAL", "NOT_EQUAL"):
|
|
661
|
+
kwargs["Epsilon"] = epsilon
|
|
662
|
+
|
|
663
|
+
match mode:
|
|
664
|
+
case "DIRECTION":
|
|
665
|
+
kwargs["Angle"] = angle
|
|
666
|
+
case "DOT_PRODUCT":
|
|
667
|
+
kwargs["C"] = c
|
|
668
|
+
case _:
|
|
669
|
+
pass
|
|
670
|
+
|
|
671
|
+
return cls(**kwargs)
|
|
672
|
+
|
|
673
|
+
@classmethod
|
|
674
|
+
def color(
|
|
675
|
+
cls,
|
|
676
|
+
a: TYPE_INPUT_COLOR = None,
|
|
677
|
+
b: TYPE_INPUT_COLOR = None,
|
|
678
|
+
operation: _CompareOperations = "EQUAL",
|
|
679
|
+
*,
|
|
680
|
+
epsilon: TYPE_INPUT_VALUE = None,
|
|
681
|
+
) -> "Compare":
|
|
682
|
+
"""Create Compare with operation 'Color'."""
|
|
683
|
+
kwargs = {
|
|
684
|
+
"operation": operation,
|
|
685
|
+
"data_type": "RGBA",
|
|
686
|
+
"A_COL": a,
|
|
687
|
+
"B_COL": b,
|
|
688
|
+
}
|
|
689
|
+
if operation in ("EQUAL", "NOT_EQUAL"):
|
|
690
|
+
kwargs["Epsilon"] = epsilon
|
|
691
|
+
return cls(**kwargs)
|
|
692
|
+
|
|
693
|
+
@classmethod
|
|
694
|
+
def string(
|
|
695
|
+
cls,
|
|
696
|
+
a,
|
|
697
|
+
b,
|
|
698
|
+
) -> "Compare":
|
|
699
|
+
"""Create Compare with operation 'String'."""
|
|
700
|
+
return cls(mode="STRING", A_STR=a, B_STR=b)
|
|
701
|
+
|
|
702
|
+
def _suffix(self) -> str:
|
|
703
|
+
suffix_lookup = {
|
|
704
|
+
"FLOAT": "",
|
|
705
|
+
"INT": "_INT",
|
|
706
|
+
"VECTOR": "_VEC",
|
|
707
|
+
"RGBA": "_COL",
|
|
708
|
+
"STRING": "_STR",
|
|
709
|
+
}
|
|
710
|
+
return suffix_lookup[self.data_type]
|
|
711
|
+
|
|
712
|
+
@property
|
|
713
|
+
def i_a(self) -> SocketLinker:
|
|
714
|
+
"""Input socket: A"""
|
|
715
|
+
return self._input(f"A{self._suffix()}")
|
|
716
|
+
|
|
717
|
+
@property
|
|
718
|
+
def i_b(self) -> SocketLinker:
|
|
719
|
+
"""Input socket: B"""
|
|
720
|
+
return self._input(f"B{self._suffix()}")
|
|
721
|
+
|
|
722
|
+
@property
|
|
723
|
+
def o_result(self) -> SocketLinker:
|
|
724
|
+
"""Output socket: Result"""
|
|
725
|
+
return self._output("Result")
|
|
726
|
+
|
|
727
|
+
@property
|
|
728
|
+
def operation(
|
|
729
|
+
self,
|
|
730
|
+
) -> _CompareOperations:
|
|
731
|
+
return self.node.operation
|
|
732
|
+
|
|
733
|
+
@operation.setter
|
|
734
|
+
def operation(
|
|
735
|
+
self,
|
|
736
|
+
value: _CompareOperations,
|
|
737
|
+
):
|
|
738
|
+
self.node.operation = value
|
|
739
|
+
|
|
740
|
+
@property
|
|
741
|
+
def data_type(
|
|
742
|
+
self,
|
|
743
|
+
) -> _CompareDataTypes:
|
|
744
|
+
return self.node.data_type # type: ignore
|
|
745
|
+
|
|
746
|
+
@data_type.setter
|
|
747
|
+
def data_type(
|
|
748
|
+
self,
|
|
749
|
+
value: _CompareDataTypes,
|
|
750
|
+
):
|
|
751
|
+
self.node.data_type = value
|
|
752
|
+
|
|
753
|
+
@property
|
|
754
|
+
def mode(
|
|
755
|
+
self,
|
|
756
|
+
) -> _CompareVectorModes:
|
|
757
|
+
return self.node.mode
|
|
758
|
+
|
|
759
|
+
@mode.setter
|
|
760
|
+
def mode(
|
|
761
|
+
self,
|
|
762
|
+
value: _CompareVectorModes,
|
|
763
|
+
):
|
|
764
|
+
self.node.mode = value
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
class EulerToRotation(NodeBuilder):
|
|
768
|
+
"""Build a rotation from separate angles around each axis"""
|
|
769
|
+
|
|
770
|
+
name = "FunctionNodeEulerToRotation"
|
|
771
|
+
node: bpy.types.FunctionNodeEulerToRotation
|
|
772
|
+
|
|
773
|
+
def __init__(self, euler: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0)):
|
|
774
|
+
super().__init__()
|
|
775
|
+
key_args = {"Euler": euler}
|
|
776
|
+
self._establish_links(**key_args)
|
|
777
|
+
|
|
778
|
+
@property
|
|
779
|
+
def i_euler(self) -> SocketLinker:
|
|
780
|
+
"""Input socket: Euler"""
|
|
781
|
+
return self._input("Euler")
|
|
782
|
+
|
|
783
|
+
@property
|
|
784
|
+
def o_rotation(self) -> SocketLinker:
|
|
785
|
+
"""Output socket: Rotation"""
|
|
786
|
+
return self._output("Rotation")
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
class FindInString(NodeBuilder):
|
|
790
|
+
"""Find the number of times a given string occurs in another string and the position of the first match"""
|
|
791
|
+
|
|
792
|
+
name = "FunctionNodeFindInString"
|
|
793
|
+
node: bpy.types.FunctionNodeFindInString
|
|
794
|
+
|
|
795
|
+
def __init__(
|
|
796
|
+
self,
|
|
797
|
+
string: TYPE_INPUT_STRING = "",
|
|
798
|
+
search: TYPE_INPUT_STRING = "",
|
|
799
|
+
):
|
|
800
|
+
super().__init__()
|
|
801
|
+
key_args = {"String": string, "Search": search}
|
|
802
|
+
|
|
803
|
+
self._establish_links(**key_args)
|
|
804
|
+
|
|
805
|
+
@property
|
|
806
|
+
def i_string(self) -> SocketLinker:
|
|
807
|
+
"""Input socket: String"""
|
|
808
|
+
return self._input("String")
|
|
809
|
+
|
|
810
|
+
@property
|
|
811
|
+
def i_search(self) -> SocketLinker:
|
|
812
|
+
"""Input socket: Search"""
|
|
813
|
+
return self._input("Search")
|
|
814
|
+
|
|
815
|
+
@property
|
|
816
|
+
def o_first_found(self) -> SocketLinker:
|
|
817
|
+
"""Output socket: First Found"""
|
|
818
|
+
return self._output("First Found")
|
|
819
|
+
|
|
820
|
+
@property
|
|
821
|
+
def o_count(self) -> SocketLinker:
|
|
822
|
+
"""Output socket: Count"""
|
|
823
|
+
return self._output("Count")
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
class FloatToInteger(NodeBuilder):
|
|
827
|
+
"""Convert the given floating-point number to an integer, with a choice of methods"""
|
|
828
|
+
|
|
829
|
+
name = "FunctionNodeFloatToInt"
|
|
830
|
+
node: bpy.types.FunctionNodeFloatToInt
|
|
831
|
+
|
|
832
|
+
def __init__(
|
|
833
|
+
self,
|
|
834
|
+
float: TYPE_INPUT_VALUE = 0.0,
|
|
835
|
+
rounding_mode: Literal["ROUND", "FLOOR", "CEILING", "TRUNCATE"] = "ROUND",
|
|
836
|
+
):
|
|
837
|
+
super().__init__()
|
|
838
|
+
key_args = {"Float": float}
|
|
839
|
+
self.rounding_mode = rounding_mode
|
|
840
|
+
self._establish_links(**key_args)
|
|
841
|
+
|
|
842
|
+
@property
|
|
843
|
+
def i_float(self) -> SocketLinker:
|
|
844
|
+
"""Input socket: Float"""
|
|
845
|
+
return self._input("Float")
|
|
846
|
+
|
|
847
|
+
@property
|
|
848
|
+
def o_integer(self) -> SocketLinker:
|
|
849
|
+
"""Output socket: Integer"""
|
|
850
|
+
return self._output("Integer")
|
|
851
|
+
|
|
852
|
+
@property
|
|
853
|
+
def rounding_mode(self) -> Literal["ROUND", "FLOOR", "CEILING", "TRUNCATE"]:
|
|
854
|
+
return self.node.rounding_mode
|
|
855
|
+
|
|
856
|
+
@rounding_mode.setter
|
|
857
|
+
def rounding_mode(self, value: Literal["ROUND", "FLOOR", "CEILING", "TRUNCATE"]):
|
|
858
|
+
self.node.rounding_mode = value
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
class FormatString(NodeBuilder):
|
|
862
|
+
"""Insert values into a string using a Python and path template compatible formatting syntax"""
|
|
863
|
+
|
|
864
|
+
name = "FunctionNodeFormatString"
|
|
865
|
+
node: bpy.types.FunctionNodeFormatString
|
|
866
|
+
_socket_data_types = ("VALUE", "INT", "STRING")
|
|
867
|
+
|
|
868
|
+
def __init__(
|
|
869
|
+
self,
|
|
870
|
+
*args,
|
|
871
|
+
format: TYPE_INPUT_STRING = "",
|
|
872
|
+
**kwargs,
|
|
873
|
+
):
|
|
874
|
+
super().__init__()
|
|
875
|
+
key_args = {"Format": format}
|
|
876
|
+
key_args.update(self._add_inputs(*args, **kwargs)) # type: ignore
|
|
877
|
+
self._establish_links(**key_args)
|
|
878
|
+
|
|
879
|
+
def _add_socket( # type: ignore
|
|
880
|
+
self,
|
|
881
|
+
name: str,
|
|
882
|
+
type: Literal["FLOAT", "INT", "STRING"] = "FLOAT",
|
|
883
|
+
default_value: float | int | str | None = None,
|
|
884
|
+
):
|
|
885
|
+
item = self.node.format_items.new(socket_type=type, name=name)
|
|
886
|
+
if default_value is not None:
|
|
887
|
+
try:
|
|
888
|
+
self.node.inputs[item.name].default_value = default_value # type: ignore
|
|
889
|
+
except TypeError as e:
|
|
890
|
+
raise ValueError(
|
|
891
|
+
f"Invalid default value for {type}: {default_value}"
|
|
892
|
+
) from e
|
|
893
|
+
return self.node.inputs[item.name]
|
|
894
|
+
|
|
895
|
+
@property
|
|
896
|
+
def i_format(self) -> SocketLinker:
|
|
897
|
+
"""Input socket: Format"""
|
|
898
|
+
return self._input("Format")
|
|
899
|
+
|
|
900
|
+
@property
|
|
901
|
+
def i_input_socket(self) -> SocketLinker:
|
|
902
|
+
"""Input socket:"""
|
|
903
|
+
return self._input("__extend__")
|
|
904
|
+
|
|
905
|
+
@property
|
|
906
|
+
def items(self) -> dict[str, SocketLinker]:
|
|
907
|
+
"""Input sockets:"""
|
|
908
|
+
return {socket.name: self._input(socket.name) for socket in self.node.inputs}
|
|
909
|
+
|
|
910
|
+
@property
|
|
911
|
+
def o_string(self) -> SocketLinker:
|
|
912
|
+
"""Output socket: String"""
|
|
913
|
+
return self._output("String")
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
_HashValueDataTypes = Literal[
|
|
917
|
+
"FLOAT",
|
|
918
|
+
"INT",
|
|
919
|
+
"VECTOR",
|
|
920
|
+
"RGBA",
|
|
921
|
+
"ROTATION",
|
|
922
|
+
"MATRIX",
|
|
923
|
+
"STRING",
|
|
924
|
+
]
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
class HashValue(NodeBuilder):
|
|
928
|
+
"""Generate a randomized integer using the given input value as a seed"""
|
|
929
|
+
|
|
930
|
+
name = "FunctionNodeHashValue"
|
|
931
|
+
node: bpy.types.FunctionNodeHashValue
|
|
932
|
+
|
|
933
|
+
def __init__(
|
|
934
|
+
self,
|
|
935
|
+
value: TYPE_INPUT_VALUE
|
|
936
|
+
| TYPE_INPUT_INT
|
|
937
|
+
| TYPE_INPUT_VECTOR
|
|
938
|
+
| TYPE_INPUT_STRING
|
|
939
|
+
| TYPE_INPUT_COLOR
|
|
940
|
+
| TYPE_INPUT_ROTATION
|
|
941
|
+
| TYPE_INPUT_MATRIX
|
|
942
|
+
| TYPE_INPUT_STRING = None,
|
|
943
|
+
seed: TYPE_INPUT_INT = 0,
|
|
944
|
+
*,
|
|
945
|
+
data_type: _HashValueDataTypes = "INT",
|
|
946
|
+
):
|
|
947
|
+
super().__init__()
|
|
948
|
+
key_args = {"Value": value, "Seed": seed}
|
|
949
|
+
self.data_type = data_type
|
|
950
|
+
self._establish_links(**key_args)
|
|
951
|
+
|
|
952
|
+
@classmethod
|
|
953
|
+
def float(cls, value: TYPE_INPUT_VALUE = None, seed: TYPE_INPUT_INT = 0):
|
|
954
|
+
return cls(value, seed, "FLOAT")
|
|
955
|
+
|
|
956
|
+
@classmethod
|
|
957
|
+
def integer(cls, value: TYPE_INPUT_INT = None, seed: TYPE_INPUT_INT = 0):
|
|
958
|
+
return cls(value, seed, "INT")
|
|
959
|
+
|
|
960
|
+
@classmethod
|
|
961
|
+
def vector(cls, value: TYPE_INPUT_VECTOR = None, seed: TYPE_INPUT_INT = 0):
|
|
962
|
+
return cls(value, seed, "VECTOR")
|
|
963
|
+
|
|
964
|
+
@classmethod
|
|
965
|
+
def string(cls, value: TYPE_INPUT_STRING = None, seed: TYPE_INPUT_INT = 0):
|
|
966
|
+
return cls(value, seed, "STRING")
|
|
967
|
+
|
|
968
|
+
@classmethod
|
|
969
|
+
def color(cls, value: TYPE_INPUT_COLOR = None, seed: TYPE_INPUT_INT = 0):
|
|
970
|
+
return cls(value, seed, "RGBA")
|
|
971
|
+
|
|
972
|
+
@property
|
|
973
|
+
def i_value(self) -> SocketLinker:
|
|
974
|
+
"""Input socket: Value"""
|
|
975
|
+
return self._input("Value")
|
|
976
|
+
|
|
977
|
+
@property
|
|
978
|
+
def i_seed(self) -> SocketLinker:
|
|
979
|
+
"""Input socket: Seed"""
|
|
980
|
+
return self._input("Seed")
|
|
981
|
+
|
|
982
|
+
@property
|
|
983
|
+
def o_hash(self) -> SocketLinker:
|
|
984
|
+
"""Output socket: Hash"""
|
|
985
|
+
return self._output("Hash")
|
|
986
|
+
|
|
987
|
+
@property
|
|
988
|
+
def data_type(
|
|
989
|
+
self,
|
|
990
|
+
) -> _HashValueDataTypes:
|
|
991
|
+
return self.node.data_type # type: ignore
|
|
992
|
+
|
|
993
|
+
@data_type.setter
|
|
994
|
+
def data_type(
|
|
995
|
+
self,
|
|
996
|
+
value: _HashValueDataTypes,
|
|
997
|
+
):
|
|
998
|
+
self.node.data_type = value
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
class Math(NodeBuilder):
|
|
1002
|
+
"""Perform math operations"""
|
|
1003
|
+
|
|
1004
|
+
name = "ShaderNodeMath"
|
|
1005
|
+
node: bpy.types.ShaderNodeMath # type: ignore
|
|
1006
|
+
|
|
1007
|
+
def __init__(
|
|
1008
|
+
self,
|
|
1009
|
+
operation: types.NodeMathItems = "ADD",
|
|
1010
|
+
use_clamp: bool = False,
|
|
1011
|
+
**kwargs,
|
|
1012
|
+
):
|
|
1013
|
+
super().__init__()
|
|
1014
|
+
self.operation = operation
|
|
1015
|
+
self.use_clamp = use_clamp
|
|
1016
|
+
self._establish_links(**kwargs)
|
|
1017
|
+
|
|
1018
|
+
@property
|
|
1019
|
+
def operation(self) -> types.NodeMathItems:
|
|
1020
|
+
return self.node.operation
|
|
1021
|
+
|
|
1022
|
+
@operation.setter
|
|
1023
|
+
def operation(self, value: types.NodeMathItems):
|
|
1024
|
+
self.node.operation = value
|
|
1025
|
+
|
|
1026
|
+
@property
|
|
1027
|
+
def use_clamp(self) -> bool:
|
|
1028
|
+
return self.node.use_clamp
|
|
1029
|
+
|
|
1030
|
+
@use_clamp.setter
|
|
1031
|
+
def use_clamp(self, value: bool):
|
|
1032
|
+
self.node.use_clamp = value
|
|
1033
|
+
|
|
1034
|
+
@property
|
|
1035
|
+
def o_value(self) -> SocketLinker:
|
|
1036
|
+
return self._output("Value") # type: ignore
|
|
1037
|
+
|
|
1038
|
+
@property
|
|
1039
|
+
def i_value(self) -> SocketLinker:
|
|
1040
|
+
return self._input("Value")
|
|
1041
|
+
|
|
1042
|
+
@property
|
|
1043
|
+
def i_value_001(self) -> SocketLinker:
|
|
1044
|
+
return self._input("Value_001")
|
|
1045
|
+
|
|
1046
|
+
@property
|
|
1047
|
+
def i_value_002(self) -> SocketLinker:
|
|
1048
|
+
return self._input("Value_002")
|
|
1049
|
+
|
|
1050
|
+
@classmethod
|
|
1051
|
+
def add(
|
|
1052
|
+
cls,
|
|
1053
|
+
a: float | LINKABLE = 0.5,
|
|
1054
|
+
b: float | LINKABLE = 0.5,
|
|
1055
|
+
) -> "Math":
|
|
1056
|
+
"""Create Math with operation of `a + b`."""
|
|
1057
|
+
return cls(operation="ADD", Value=a, Value_001=b)
|
|
1058
|
+
|
|
1059
|
+
@classmethod
|
|
1060
|
+
def subtract(
|
|
1061
|
+
cls,
|
|
1062
|
+
a: float | LINKABLE = 0.5,
|
|
1063
|
+
b: float | LINKABLE = 0.5,
|
|
1064
|
+
) -> "Math":
|
|
1065
|
+
"""Create Math with operation of `a - b`."""
|
|
1066
|
+
return cls(operation="SUBTRACT", Value=a, Value_001=b)
|
|
1067
|
+
|
|
1068
|
+
@classmethod
|
|
1069
|
+
def multiply(
|
|
1070
|
+
cls,
|
|
1071
|
+
a: float | LINKABLE = 0.5,
|
|
1072
|
+
b: float | LINKABLE = 0.5,
|
|
1073
|
+
) -> "Math":
|
|
1074
|
+
"""Create Math with operation of `a * b`."""
|
|
1075
|
+
return cls(operation="MULTIPLY", Value=a, Value_001=b)
|
|
1076
|
+
|
|
1077
|
+
@classmethod
|
|
1078
|
+
def divide(
|
|
1079
|
+
cls,
|
|
1080
|
+
a: float | LINKABLE = 0.5,
|
|
1081
|
+
b: float | LINKABLE = 0.5,
|
|
1082
|
+
) -> "Math":
|
|
1083
|
+
"""Create Math with operation of `a / b`."""
|
|
1084
|
+
return cls(operation="DIVIDE", Value=a, Value_001=b)
|
|
1085
|
+
|
|
1086
|
+
@classmethod
|
|
1087
|
+
def multiply_add(
|
|
1088
|
+
cls,
|
|
1089
|
+
a: float | LINKABLE = 0.5,
|
|
1090
|
+
b: float | LINKABLE = 0.5,
|
|
1091
|
+
c: float | LINKABLE = 0.5,
|
|
1092
|
+
) -> "Math":
|
|
1093
|
+
"""Create Math with operation `a * b + c`."""
|
|
1094
|
+
return cls(operation="MULTIPLY_ADD", Value=a, Value_001=b, Value_002=c)
|
|
1095
|
+
|
|
1096
|
+
@classmethod
|
|
1097
|
+
def power(
|
|
1098
|
+
cls,
|
|
1099
|
+
base: float | LINKABLE = 0.5,
|
|
1100
|
+
exponent: float | LINKABLE = 0.5,
|
|
1101
|
+
) -> "Math":
|
|
1102
|
+
"""Create Math with operation `base ** exponent`."""
|
|
1103
|
+
return cls(operation="POWER", Value=base, Value_001=exponent)
|
|
1104
|
+
|
|
1105
|
+
@classmethod
|
|
1106
|
+
def logarithm(
|
|
1107
|
+
cls,
|
|
1108
|
+
value: float | LINKABLE = 0.5,
|
|
1109
|
+
base: float | LINKABLE = 0.5,
|
|
1110
|
+
) -> "Math":
|
|
1111
|
+
"""Create Math with operation `log(value, base)`."""
|
|
1112
|
+
return cls(operation="LOGARITHM", Value=value, Value_001=base)
|
|
1113
|
+
|
|
1114
|
+
@classmethod
|
|
1115
|
+
def sqrt(
|
|
1116
|
+
cls,
|
|
1117
|
+
value: float | LINKABLE = 0.5,
|
|
1118
|
+
) -> "Math":
|
|
1119
|
+
"""Create Math with operation `sqrt(value)`."""
|
|
1120
|
+
return cls(operation="SQRT", Value=value)
|
|
1121
|
+
|
|
1122
|
+
@classmethod
|
|
1123
|
+
def inverse_sqrt(
|
|
1124
|
+
cls,
|
|
1125
|
+
value: float | LINKABLE = 0.5,
|
|
1126
|
+
) -> "Math":
|
|
1127
|
+
"""Create Math with operation `inverse_sqrt(value)`."""
|
|
1128
|
+
return cls(operation="INVERSE_SQRT", Value=value)
|
|
1129
|
+
|
|
1130
|
+
@classmethod
|
|
1131
|
+
def absolute(
|
|
1132
|
+
cls,
|
|
1133
|
+
value: float | LINKABLE = 0.5,
|
|
1134
|
+
) -> "Math":
|
|
1135
|
+
"""Create Math with operation `abs(value)`."""
|
|
1136
|
+
return cls(operation="ABSOLUTE", Value=value)
|
|
1137
|
+
|
|
1138
|
+
@classmethod
|
|
1139
|
+
def exponent(
|
|
1140
|
+
cls,
|
|
1141
|
+
value: float | LINKABLE = 0.5,
|
|
1142
|
+
) -> "Math":
|
|
1143
|
+
"""Create Math with operation `exp(value)`."""
|
|
1144
|
+
return cls(operation="EXPONENT", Value=value)
|
|
1145
|
+
|
|
1146
|
+
@classmethod
|
|
1147
|
+
def minimum(
|
|
1148
|
+
cls,
|
|
1149
|
+
a: float | LINKABLE = 0.5,
|
|
1150
|
+
b: float | LINKABLE = 0.5,
|
|
1151
|
+
) -> "Math":
|
|
1152
|
+
"""Create Math with operation `min(a, b)`."""
|
|
1153
|
+
return cls(operation="MINIMUM", Value=a, Value_001=b)
|
|
1154
|
+
|
|
1155
|
+
@classmethod
|
|
1156
|
+
def maximum(
|
|
1157
|
+
cls,
|
|
1158
|
+
a: float | LINKABLE = 0.5,
|
|
1159
|
+
b: float | LINKABLE = 0.5,
|
|
1160
|
+
) -> "Math":
|
|
1161
|
+
"""Create Math with operation `max(a, b)`."""
|
|
1162
|
+
return cls(operation="MAXIMUM", Value=a, Value_001=b)
|
|
1163
|
+
|
|
1164
|
+
@classmethod
|
|
1165
|
+
def less_than(
|
|
1166
|
+
cls,
|
|
1167
|
+
value: float | LINKABLE = 0.5,
|
|
1168
|
+
threshold: float | LINKABLE = 0.5,
|
|
1169
|
+
) -> "Math":
|
|
1170
|
+
"""Create Math with operation `value < threshold` returning 1 or 0."""
|
|
1171
|
+
return cls(operation="LESS_THAN", Value=value, Value_001=threshold)
|
|
1172
|
+
|
|
1173
|
+
@classmethod
|
|
1174
|
+
def greater_than(
|
|
1175
|
+
cls,
|
|
1176
|
+
value: float | LINKABLE = 0.5,
|
|
1177
|
+
threshold: float | LINKABLE = 0.5,
|
|
1178
|
+
) -> "Math":
|
|
1179
|
+
"""Create Math with operation `value > threshold` returning 1 or 0."""
|
|
1180
|
+
return cls(operation="GREATER_THAN", Value=value, Value_001=threshold)
|
|
1181
|
+
|
|
1182
|
+
@classmethod
|
|
1183
|
+
def sign(
|
|
1184
|
+
cls,
|
|
1185
|
+
value: float | LINKABLE = 0.5,
|
|
1186
|
+
) -> "Math":
|
|
1187
|
+
"""Create Math with operation `sign(value)` returning -1, 0, or 1."""
|
|
1188
|
+
return cls(operation="SIGN", Value=value)
|
|
1189
|
+
|
|
1190
|
+
@classmethod
|
|
1191
|
+
def compare(
|
|
1192
|
+
cls,
|
|
1193
|
+
a: float | LINKABLE = 0.5,
|
|
1194
|
+
b: float | LINKABLE = 0.5,
|
|
1195
|
+
epsilon: float | LINKABLE = 0.5,
|
|
1196
|
+
) -> "Math":
|
|
1197
|
+
"""Create Math with operation `compare(a, b, epsilon)` returning -1, 0, or 1."""
|
|
1198
|
+
return cls(operation="COMPARE", Value=a, Value_001=b, Value_002=epsilon)
|
|
1199
|
+
|
|
1200
|
+
@classmethod
|
|
1201
|
+
def smooth_min(
|
|
1202
|
+
cls,
|
|
1203
|
+
a: float | LINKABLE = 0.5,
|
|
1204
|
+
b: float | LINKABLE = 0.5,
|
|
1205
|
+
distance: float | LINKABLE = 0.5,
|
|
1206
|
+
) -> "Math":
|
|
1207
|
+
"""Create Math with operation `smooth_min(a, b, distance)`."""
|
|
1208
|
+
return cls(operation="SMOOTH_MIN", Value=a, Value_001=b, Value_002=distance)
|
|
1209
|
+
|
|
1210
|
+
@classmethod
|
|
1211
|
+
def smooth_max_(
|
|
1212
|
+
cls,
|
|
1213
|
+
a: float | LINKABLE = 0.5,
|
|
1214
|
+
b: float | LINKABLE = 0.5,
|
|
1215
|
+
distance: float | LINKABLE = 0.5,
|
|
1216
|
+
) -> "Math":
|
|
1217
|
+
"""Create Math with operation `smooth_max(a, b, distance)`."""
|
|
1218
|
+
return cls(operation="SMOOTH_MAX", Value=a, Value_001=b, Value_002=distance)
|
|
1219
|
+
|
|
1220
|
+
@classmethod
|
|
1221
|
+
def round(
|
|
1222
|
+
cls,
|
|
1223
|
+
value: float | LINKABLE = 0.5,
|
|
1224
|
+
) -> "Math":
|
|
1225
|
+
"""Round A to the nearest integer. Round up if 0.5 or greater."""
|
|
1226
|
+
return cls(operation="ROUND", Value=value)
|
|
1227
|
+
|
|
1228
|
+
@classmethod
|
|
1229
|
+
def floor(
|
|
1230
|
+
cls,
|
|
1231
|
+
value: float | LINKABLE = 0.5,
|
|
1232
|
+
) -> "Math":
|
|
1233
|
+
"""The largest integer smaller than or equal to `value`"""
|
|
1234
|
+
return cls(operation="FLOOR", Value=value)
|
|
1235
|
+
|
|
1236
|
+
@classmethod
|
|
1237
|
+
def ceil(
|
|
1238
|
+
cls,
|
|
1239
|
+
value: float | LINKABLE = 0.5,
|
|
1240
|
+
) -> "Math":
|
|
1241
|
+
"""The smallest integer greater than or equal to `value`"""
|
|
1242
|
+
return cls(operation="CEIL", Value=value)
|
|
1243
|
+
|
|
1244
|
+
@classmethod
|
|
1245
|
+
def truncate(
|
|
1246
|
+
cls,
|
|
1247
|
+
value: float | LINKABLE = 0.5,
|
|
1248
|
+
) -> "Math":
|
|
1249
|
+
"""The integer part of `value` removing the fractional part"""
|
|
1250
|
+
return cls(operation="TRUNC", Value=value)
|
|
1251
|
+
|
|
1252
|
+
@classmethod
|
|
1253
|
+
def fraction(
|
|
1254
|
+
cls,
|
|
1255
|
+
value: float | LINKABLE = 0.5,
|
|
1256
|
+
) -> "Math":
|
|
1257
|
+
"""The fractional part of `value`"""
|
|
1258
|
+
return cls(operation="FRACT", Value=value)
|
|
1259
|
+
|
|
1260
|
+
@classmethod
|
|
1261
|
+
def truncated_modulo(
|
|
1262
|
+
cls,
|
|
1263
|
+
a: float | LINKABLE = 0.5,
|
|
1264
|
+
b: float | LINKABLE = 0.5,
|
|
1265
|
+
) -> "Math":
|
|
1266
|
+
"""The remained of truncated division using fmod(a, b)"""
|
|
1267
|
+
return cls(operation="MODULO", Value=a, Value_001=b)
|
|
1268
|
+
|
|
1269
|
+
@classmethod
|
|
1270
|
+
def floored_modulo(
|
|
1271
|
+
cls,
|
|
1272
|
+
a: float | LINKABLE = 0.5,
|
|
1273
|
+
b: float | LINKABLE = 0.5,
|
|
1274
|
+
) -> "Math":
|
|
1275
|
+
"""The remained of floored division"""
|
|
1276
|
+
return cls(operation="FLOORED_MODULO", Value=a, Value_001=b)
|
|
1277
|
+
|
|
1278
|
+
@classmethod
|
|
1279
|
+
def wrap(
|
|
1280
|
+
cls,
|
|
1281
|
+
value: float | LINKABLE = 0.5,
|
|
1282
|
+
max: float | LINKABLE = 0.5,
|
|
1283
|
+
min: float | LINKABLE = 0.5,
|
|
1284
|
+
) -> "Math":
|
|
1285
|
+
"""Wrap value to range, wrap(value, max, min)"""
|
|
1286
|
+
return cls(operation="WRAP", Value=value, Value_001=max, Value_002=min)
|
|
1287
|
+
|
|
1288
|
+
@classmethod
|
|
1289
|
+
def snap(
|
|
1290
|
+
cls,
|
|
1291
|
+
value: float | LINKABLE = 0.5,
|
|
1292
|
+
increment: float | LINKABLE = 0.5,
|
|
1293
|
+
) -> "Math":
|
|
1294
|
+
"""Snap to increment of `snap(value, increment)`"""
|
|
1295
|
+
return cls(operation="SNAP", Value=value, Value_001=increment)
|
|
1296
|
+
|
|
1297
|
+
@classmethod
|
|
1298
|
+
def ping_pong(
|
|
1299
|
+
cls,
|
|
1300
|
+
value: float | LINKABLE = 0.5,
|
|
1301
|
+
scale: float | LINKABLE = 0.5,
|
|
1302
|
+
) -> "Math":
|
|
1303
|
+
"""Wraps a value and reverses every other cycle"""
|
|
1304
|
+
return cls(operation="PINGPONG", Value=value, Value_001=scale)
|
|
1305
|
+
|
|
1306
|
+
@classmethod
|
|
1307
|
+
def sin(
|
|
1308
|
+
cls,
|
|
1309
|
+
value: float | LINKABLE = 0.5,
|
|
1310
|
+
) -> "Math":
|
|
1311
|
+
"""Create Math with operation 'sin(value)'."""
|
|
1312
|
+
return cls(operation="SINE", Value=value)
|
|
1313
|
+
|
|
1314
|
+
@classmethod
|
|
1315
|
+
def cos(
|
|
1316
|
+
cls,
|
|
1317
|
+
value: float | LINKABLE = 0.5,
|
|
1318
|
+
) -> "Math":
|
|
1319
|
+
"""Create Math with operation 'cos(value)'."""
|
|
1320
|
+
return cls(operation="COSINE", Value=value)
|
|
1321
|
+
|
|
1322
|
+
@classmethod
|
|
1323
|
+
def tan(
|
|
1324
|
+
cls,
|
|
1325
|
+
value: float | LINKABLE = 0.5,
|
|
1326
|
+
) -> "Math":
|
|
1327
|
+
"""Create Math with operation 'tan(value)'."""
|
|
1328
|
+
return cls(operation="TANGENT", Value=value)
|
|
1329
|
+
|
|
1330
|
+
@classmethod
|
|
1331
|
+
def arcsin(
|
|
1332
|
+
cls,
|
|
1333
|
+
value: float | LINKABLE = 0.5,
|
|
1334
|
+
) -> "Math":
|
|
1335
|
+
"""Create Math with operation `arcsin(value)`."""
|
|
1336
|
+
return cls(operation="ARCSINE", Value=value)
|
|
1337
|
+
|
|
1338
|
+
@classmethod
|
|
1339
|
+
def arccos(
|
|
1340
|
+
cls,
|
|
1341
|
+
value: float | LINKABLE = 0.5,
|
|
1342
|
+
) -> "Math":
|
|
1343
|
+
"""Create Math with operation 'arccos(value)'."""
|
|
1344
|
+
return cls(operation="ARCCOSINE", Value=value)
|
|
1345
|
+
|
|
1346
|
+
@classmethod
|
|
1347
|
+
def arctan(
|
|
1348
|
+
cls,
|
|
1349
|
+
value: float | LINKABLE = 0.5,
|
|
1350
|
+
) -> "Math":
|
|
1351
|
+
"""Create Math with operation 'arctan(value)'."""
|
|
1352
|
+
return cls(operation="ARCTANGENT", Value=value)
|
|
1353
|
+
|
|
1354
|
+
@classmethod
|
|
1355
|
+
def arctan2(
|
|
1356
|
+
cls,
|
|
1357
|
+
a: float | LINKABLE = 0.5,
|
|
1358
|
+
b: float | LINKABLE = 0.5,
|
|
1359
|
+
) -> "Math":
|
|
1360
|
+
"""Create Math with operation 'arctan(a / b)'."""
|
|
1361
|
+
return cls(operation="ARCTAN2", Value=a, Value_001=b)
|
|
1362
|
+
|
|
1363
|
+
@classmethod
|
|
1364
|
+
def sinh(
|
|
1365
|
+
cls,
|
|
1366
|
+
value: float | LINKABLE = 0.5,
|
|
1367
|
+
) -> "Math":
|
|
1368
|
+
"""Create Math with operation `sinh(value)`."""
|
|
1369
|
+
return cls(operation="SINH", Value=value)
|
|
1370
|
+
|
|
1371
|
+
@classmethod
|
|
1372
|
+
def cosh(
|
|
1373
|
+
cls,
|
|
1374
|
+
value: float | LINKABLE = 0.5,
|
|
1375
|
+
) -> "Math":
|
|
1376
|
+
"""Create Math with operation `cosh(value)`."""
|
|
1377
|
+
return cls(operation="COSH", Value=value)
|
|
1378
|
+
|
|
1379
|
+
@classmethod
|
|
1380
|
+
def tanh(
|
|
1381
|
+
cls,
|
|
1382
|
+
value: float | LINKABLE = 0.5,
|
|
1383
|
+
) -> "Math":
|
|
1384
|
+
"""Create Math with operation `tanh(value)`."""
|
|
1385
|
+
return cls(operation="TANH", Value=value)
|
|
1386
|
+
|
|
1387
|
+
@classmethod
|
|
1388
|
+
def radians(
|
|
1389
|
+
cls,
|
|
1390
|
+
degrees: float | LINKABLE = 0.5,
|
|
1391
|
+
) -> "Math":
|
|
1392
|
+
"""Create Math with operation `radians(degrees)`."""
|
|
1393
|
+
return cls(operation="RADIANS", Value=degrees)
|
|
1394
|
+
|
|
1395
|
+
@classmethod
|
|
1396
|
+
def degrees(
|
|
1397
|
+
cls,
|
|
1398
|
+
radians: float | LINKABLE = 0.5,
|
|
1399
|
+
) -> "Math":
|
|
1400
|
+
"""Create Math with operation 'To Degrees'."""
|
|
1401
|
+
return cls(operation="DEGREES", Value=radians)
|
|
1402
|
+
|
|
1403
|
+
|
|
1404
|
+
class BooleanMath(NodeBuilder):
|
|
1405
|
+
"""Boolean Math node"""
|
|
1406
|
+
|
|
1407
|
+
name = "FunctionNodeBooleanMath"
|
|
1408
|
+
node: bpy.types.FunctionNodeBooleanMath
|
|
1409
|
+
|
|
1410
|
+
def __init__(self, operation: types.NodeBooleanMathItems = "AND", **kwargs):
|
|
1411
|
+
super().__init__()
|
|
1412
|
+
self.operator = operation
|
|
1413
|
+
self._establish_links(**kwargs)
|
|
1414
|
+
|
|
1415
|
+
@property
|
|
1416
|
+
def operation(self) -> types.NodeBooleanMathItems:
|
|
1417
|
+
return self.node.operation
|
|
1418
|
+
|
|
1419
|
+
@operation.setter
|
|
1420
|
+
def operation(self, value: types.NodeBooleanMathItems):
|
|
1421
|
+
self.node.operation = value
|
|
1422
|
+
|
|
1423
|
+
@property
|
|
1424
|
+
def i_boolean(self) -> SocketLinker:
|
|
1425
|
+
return self._input("Boolean") # type: ignore
|
|
1426
|
+
|
|
1427
|
+
@property
|
|
1428
|
+
def i_boolean_001(self) -> SocketLinker:
|
|
1429
|
+
return self._input("Boolean_001") # type: ignore
|
|
1430
|
+
|
|
1431
|
+
@property
|
|
1432
|
+
def o_boolean(self) -> SocketLinker:
|
|
1433
|
+
return self._output("Boolean") # type: ignore
|
|
1434
|
+
|
|
1435
|
+
@classmethod
|
|
1436
|
+
def l_and(
|
|
1437
|
+
cls,
|
|
1438
|
+
boolean: TYPE_INPUT_BOOLEAN = False,
|
|
1439
|
+
boolean_001: TYPE_INPUT_BOOLEAN = False,
|
|
1440
|
+
) -> "BooleanMath":
|
|
1441
|
+
"""Create Boolean Math with operation 'AND'."""
|
|
1442
|
+
return cls(operation="AND", Boolean=boolean, Boolean_001=boolean_001)
|
|
1443
|
+
|
|
1444
|
+
@classmethod
|
|
1445
|
+
def l_or(
|
|
1446
|
+
cls,
|
|
1447
|
+
boolean: TYPE_INPUT_BOOLEAN = False,
|
|
1448
|
+
boolean_001: TYPE_INPUT_BOOLEAN = False,
|
|
1449
|
+
) -> "BooleanMath":
|
|
1450
|
+
"""Create Boolean Math with operation 'OR'."""
|
|
1451
|
+
return cls(operation="OR", Boolean=boolean, Boolean_001=boolean_001)
|
|
1452
|
+
|
|
1453
|
+
@classmethod
|
|
1454
|
+
def l_not(cls, boolean: TYPE_INPUT_BOOLEAN = False) -> "BooleanMath":
|
|
1455
|
+
"""Create Boolean Math with operation 'NOT'."""
|
|
1456
|
+
return cls(operation="NOT", Boolean=boolean)
|
|
1457
|
+
|
|
1458
|
+
@classmethod
|
|
1459
|
+
def l_not_and(
|
|
1460
|
+
cls,
|
|
1461
|
+
boolean: TYPE_INPUT_BOOLEAN = False,
|
|
1462
|
+
boolean_001: TYPE_INPUT_BOOLEAN = False,
|
|
1463
|
+
) -> "BooleanMath":
|
|
1464
|
+
"""Create Boolean Math with operation 'NAND'."""
|
|
1465
|
+
return cls(operation="NAND", Boolean=boolean, Boolean_001=boolean_001)
|
|
1466
|
+
|
|
1467
|
+
@classmethod
|
|
1468
|
+
def l_nor(
|
|
1469
|
+
cls,
|
|
1470
|
+
boolean: TYPE_INPUT_BOOLEAN = False,
|
|
1471
|
+
boolean_001: TYPE_INPUT_BOOLEAN = False,
|
|
1472
|
+
) -> "BooleanMath":
|
|
1473
|
+
"""Create Boolean Math with operation 'NOR'."""
|
|
1474
|
+
return cls(operation="NOR", Boolean=boolean, Boolean_001=boolean_001)
|
|
1475
|
+
|
|
1476
|
+
@classmethod
|
|
1477
|
+
def l_equal(
|
|
1478
|
+
cls,
|
|
1479
|
+
boolean: TYPE_INPUT_BOOLEAN = False,
|
|
1480
|
+
boolean_001: TYPE_INPUT_BOOLEAN = False,
|
|
1481
|
+
) -> "BooleanMath":
|
|
1482
|
+
"""Create Boolean Math with operation 'XNOR'."""
|
|
1483
|
+
return cls(operation="XNOR", Boolean=boolean, Boolean_001=boolean_001)
|
|
1484
|
+
|
|
1485
|
+
@classmethod
|
|
1486
|
+
def l_not_equal(
|
|
1487
|
+
cls,
|
|
1488
|
+
boolean: TYPE_INPUT_BOOLEAN = False,
|
|
1489
|
+
boolean_001: TYPE_INPUT_BOOLEAN = False,
|
|
1490
|
+
) -> "BooleanMath":
|
|
1491
|
+
"""Create Boolean Math with operation 'XOR'."""
|
|
1492
|
+
return cls(operation="XOR", Boolean=boolean, Boolean_001=boolean_001)
|
|
1493
|
+
|
|
1494
|
+
@classmethod
|
|
1495
|
+
def l_imply(
|
|
1496
|
+
cls,
|
|
1497
|
+
boolean: TYPE_INPUT_BOOLEAN = False,
|
|
1498
|
+
boolean_001: TYPE_INPUT_BOOLEAN = False,
|
|
1499
|
+
) -> "BooleanMath":
|
|
1500
|
+
"""Create Boolean Math with operation 'IMPLY'."""
|
|
1501
|
+
return cls(operation="IMPLY", Boolean=boolean, Boolean_001=boolean_001)
|
|
1502
|
+
|
|
1503
|
+
@classmethod
|
|
1504
|
+
def l_subtract(
|
|
1505
|
+
cls,
|
|
1506
|
+
boolean: TYPE_INPUT_BOOLEAN = False,
|
|
1507
|
+
boolean_001: TYPE_INPUT_BOOLEAN = False,
|
|
1508
|
+
) -> "BooleanMath":
|
|
1509
|
+
"""Create Boolean Math with operation 'NIMPLY'."""
|
|
1510
|
+
return cls(operation="NIMPLY", Boolean=boolean, Boolean_001=boolean_001)
|
|
1511
|
+
|
|
1512
|
+
|
|
1513
|
+
class VectorMath(NodeBuilder):
|
|
1514
|
+
"""Perform vector math operation"""
|
|
1515
|
+
|
|
1516
|
+
name = "ShaderNodeVectorMath"
|
|
1517
|
+
node: bpy.types.ShaderNodeVectorMath
|
|
1518
|
+
|
|
1519
|
+
def __init__(
|
|
1520
|
+
self,
|
|
1521
|
+
operation: _VectorMathOperations = "ADD",
|
|
1522
|
+
**kwargs,
|
|
1523
|
+
):
|
|
1524
|
+
super().__init__()
|
|
1525
|
+
self.operation = operation
|
|
1526
|
+
self._establish_links(**kwargs)
|
|
1527
|
+
|
|
1528
|
+
@property
|
|
1529
|
+
def i_vector(self) -> SocketLinker:
|
|
1530
|
+
"""Input socket: Vector"""
|
|
1531
|
+
return self._input("Vector")
|
|
1532
|
+
|
|
1533
|
+
@property
|
|
1534
|
+
def i_vector_001(self) -> SocketLinker:
|
|
1535
|
+
"""Input socket: Vector"""
|
|
1536
|
+
return self._input("Vector_001")
|
|
1537
|
+
|
|
1538
|
+
@property
|
|
1539
|
+
def o_vector(self) -> SocketLinker:
|
|
1540
|
+
"""Output socket: Vector"""
|
|
1541
|
+
if self.operation in {"DOT_PRODUCT", "DISTANCE", "LENGTH"}:
|
|
1542
|
+
raise RuntimeError(
|
|
1543
|
+
f"Output 'Vector' is not available for operation '{self.operation}'"
|
|
1544
|
+
)
|
|
1545
|
+
return self._output("Vector")
|
|
1546
|
+
|
|
1547
|
+
@property
|
|
1548
|
+
def o_value(self) -> SocketLinker:
|
|
1549
|
+
"""Output socket: Value"""
|
|
1550
|
+
assert self.operation in {"DOT_PRODUCT", "DISTANCE", "LENGTH"}
|
|
1551
|
+
return self._output("Value")
|
|
1552
|
+
|
|
1553
|
+
@property
|
|
1554
|
+
def _default_output_socket(self) -> bpy.types.NodeSocket:
|
|
1555
|
+
match self.operation:
|
|
1556
|
+
case "DOT_PRODUCT" | "DISTANCE" | "LENGTH":
|
|
1557
|
+
return self.o_value.socket
|
|
1558
|
+
case _:
|
|
1559
|
+
return self.o_vector.socket
|
|
1560
|
+
|
|
1561
|
+
@property
|
|
1562
|
+
def operation(
|
|
1563
|
+
self,
|
|
1564
|
+
) -> _VectorMathOperations:
|
|
1565
|
+
return self.node.operation
|
|
1566
|
+
|
|
1567
|
+
@operation.setter
|
|
1568
|
+
def operation(
|
|
1569
|
+
self,
|
|
1570
|
+
value: _VectorMathOperations,
|
|
1571
|
+
):
|
|
1572
|
+
self.node.operation = value
|
|
1573
|
+
|
|
1574
|
+
@classmethod
|
|
1575
|
+
def add(
|
|
1576
|
+
cls,
|
|
1577
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1578
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1579
|
+
) -> "VectorMath":
|
|
1580
|
+
"""Create Vector Math with operation `a + b`."""
|
|
1581
|
+
return cls(operation="ADD", Vector=a, Vector_001=b)
|
|
1582
|
+
|
|
1583
|
+
@classmethod
|
|
1584
|
+
def subtract(
|
|
1585
|
+
cls,
|
|
1586
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1587
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1588
|
+
) -> "VectorMath":
|
|
1589
|
+
"""Create Vector Math with operation `a - b`."""
|
|
1590
|
+
return cls(operation="SUBTRACT", Vector=a, Vector_001=b)
|
|
1591
|
+
|
|
1592
|
+
@classmethod
|
|
1593
|
+
def multiply(
|
|
1594
|
+
cls,
|
|
1595
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1596
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1597
|
+
) -> "VectorMath":
|
|
1598
|
+
"""Create Vector Math with operation `a * b` element-wise."""
|
|
1599
|
+
return cls(operation="MULTIPLY", Vector=a, Vector_001=b)
|
|
1600
|
+
|
|
1601
|
+
@classmethod
|
|
1602
|
+
def divide(
|
|
1603
|
+
cls,
|
|
1604
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1605
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1606
|
+
) -> "VectorMath":
|
|
1607
|
+
"""Create Vector Math with operation 'Divide'."""
|
|
1608
|
+
return cls(operation="DIVIDE", Vector=a, Vector_001=b)
|
|
1609
|
+
|
|
1610
|
+
@classmethod
|
|
1611
|
+
def multiply_add(
|
|
1612
|
+
cls,
|
|
1613
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1614
|
+
multiplier: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1615
|
+
addend: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1616
|
+
) -> "VectorMath":
|
|
1617
|
+
"""Create Vector Math with operation 'Multiply Add'."""
|
|
1618
|
+
return cls(
|
|
1619
|
+
operation="MULTIPLY_ADD",
|
|
1620
|
+
Vector=vector,
|
|
1621
|
+
Vector_001=multiplier,
|
|
1622
|
+
Vector_002=addend,
|
|
1623
|
+
)
|
|
1624
|
+
|
|
1625
|
+
@classmethod
|
|
1626
|
+
def cross_product(
|
|
1627
|
+
cls,
|
|
1628
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1629
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1630
|
+
) -> "VectorMath":
|
|
1631
|
+
"""Create Vector Math with operation 'Cross Product'."""
|
|
1632
|
+
return cls(operation="CROSS_PRODUCT", Vector=a, Vector_001=b)
|
|
1633
|
+
|
|
1634
|
+
@classmethod
|
|
1635
|
+
def project(
|
|
1636
|
+
cls,
|
|
1637
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1638
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1639
|
+
) -> "VectorMath":
|
|
1640
|
+
"""Project A onto B."""
|
|
1641
|
+
return cls(operation="PROJECT", Vector=a, Vector_001=b)
|
|
1642
|
+
|
|
1643
|
+
@classmethod
|
|
1644
|
+
def reflect(
|
|
1645
|
+
cls,
|
|
1646
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1647
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1648
|
+
) -> "VectorMath":
|
|
1649
|
+
"""Reflect A around the normal B. B does not need to be normalized."""
|
|
1650
|
+
return cls(operation="REFLECT", Vector=a, Vector_001=b)
|
|
1651
|
+
|
|
1652
|
+
@classmethod
|
|
1653
|
+
def refract(
|
|
1654
|
+
cls,
|
|
1655
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1656
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1657
|
+
ior: LINKABLE | float = 1.0,
|
|
1658
|
+
) -> "VectorMath":
|
|
1659
|
+
"""For a given incident vector and surface normal (b) with an index of refraction (ior), return the refraction vector"""
|
|
1660
|
+
return cls(operation="REFRACT", Vector=a, Vector_001=b, Scale=ior)
|
|
1661
|
+
|
|
1662
|
+
@classmethod
|
|
1663
|
+
def face_forward(
|
|
1664
|
+
cls,
|
|
1665
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1666
|
+
incidence: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1667
|
+
reference: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1668
|
+
) -> "VectorMath":
|
|
1669
|
+
"""Orients a vector to face away from a surface (incidence) defined by it's normal (reference)"""
|
|
1670
|
+
return cls(
|
|
1671
|
+
operation="FACEFORWARD",
|
|
1672
|
+
Vector=vector,
|
|
1673
|
+
Vector_001=incidence,
|
|
1674
|
+
Vector_002=reference,
|
|
1675
|
+
)
|
|
1676
|
+
|
|
1677
|
+
@classmethod
|
|
1678
|
+
def dot_product(
|
|
1679
|
+
cls,
|
|
1680
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1681
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1682
|
+
) -> "VectorMath":
|
|
1683
|
+
"""Create Vector Math with operation 'Dot Product'."""
|
|
1684
|
+
return cls(operation="DOT_PRODUCT", Vector=a, Vector_001=b)
|
|
1685
|
+
|
|
1686
|
+
@classmethod
|
|
1687
|
+
def distance(
|
|
1688
|
+
cls,
|
|
1689
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1690
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1691
|
+
) -> "VectorMath":
|
|
1692
|
+
"""Create Vector Math with operation 'Distance'."""
|
|
1693
|
+
return cls(operation="DISTANCE", Vector=a, Vector_001=b)
|
|
1694
|
+
|
|
1695
|
+
@classmethod
|
|
1696
|
+
def length(
|
|
1697
|
+
cls,
|
|
1698
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1699
|
+
) -> "VectorMath":
|
|
1700
|
+
"""Create Vector Math with operation 'Length'."""
|
|
1701
|
+
return cls(operation="LENGTH", Vector=vector)
|
|
1702
|
+
|
|
1703
|
+
@classmethod
|
|
1704
|
+
def scale(
|
|
1705
|
+
cls,
|
|
1706
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1707
|
+
scale: LINKABLE | float = 1.0,
|
|
1708
|
+
) -> "VectorMath":
|
|
1709
|
+
"""Create Vector Math with operation 'Scale'."""
|
|
1710
|
+
return cls(operation="SCALE", Vector=vector, Scale=scale)
|
|
1711
|
+
|
|
1712
|
+
@classmethod
|
|
1713
|
+
def normalize(
|
|
1714
|
+
cls,
|
|
1715
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1716
|
+
) -> "VectorMath":
|
|
1717
|
+
"""Create Vector Math with operation 'Normalize'."""
|
|
1718
|
+
return cls(operation="NORMALIZE", Vector=vector)
|
|
1719
|
+
|
|
1720
|
+
@classmethod
|
|
1721
|
+
def absolute(
|
|
1722
|
+
cls,
|
|
1723
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1724
|
+
) -> "VectorMath":
|
|
1725
|
+
"""Create Vector Math with operation 'Absolute'."""
|
|
1726
|
+
return cls(operation="ABSOLUTE", Vector=vector)
|
|
1727
|
+
|
|
1728
|
+
@classmethod
|
|
1729
|
+
def power(
|
|
1730
|
+
cls,
|
|
1731
|
+
base: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1732
|
+
exponent: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1733
|
+
) -> "VectorMath":
|
|
1734
|
+
"""Create Vector Math with operation 'Power'."""
|
|
1735
|
+
return cls(operation="POWER", Vector=base, Vector_001=exponent)
|
|
1736
|
+
|
|
1737
|
+
@classmethod
|
|
1738
|
+
def sign(
|
|
1739
|
+
cls,
|
|
1740
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1741
|
+
) -> "VectorMath":
|
|
1742
|
+
"""Create Vector Math with operation 'Sign'."""
|
|
1743
|
+
return cls(operation="SIGN", Vector=vector)
|
|
1744
|
+
|
|
1745
|
+
@classmethod
|
|
1746
|
+
def minimum(
|
|
1747
|
+
cls,
|
|
1748
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1749
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1750
|
+
) -> "VectorMath":
|
|
1751
|
+
"""Create Vector Math with operation 'Minimum'."""
|
|
1752
|
+
return cls(operation="MINIMUM", Vector=a, Vector_001=b)
|
|
1753
|
+
|
|
1754
|
+
@classmethod
|
|
1755
|
+
def maximum(
|
|
1756
|
+
cls,
|
|
1757
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1758
|
+
b: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1759
|
+
) -> "VectorMath":
|
|
1760
|
+
"""Create Vector Math with operation 'Maximum'."""
|
|
1761
|
+
return cls(operation="MAXIMUM", Vector=a, Vector_001=b)
|
|
1762
|
+
|
|
1763
|
+
@classmethod
|
|
1764
|
+
def floor(
|
|
1765
|
+
cls,
|
|
1766
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1767
|
+
) -> "VectorMath":
|
|
1768
|
+
"""Create Vector Math with operation 'Floor'."""
|
|
1769
|
+
return cls(operation="FLOOR", Vector=vector)
|
|
1770
|
+
|
|
1771
|
+
@classmethod
|
|
1772
|
+
def ceil(
|
|
1773
|
+
cls,
|
|
1774
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1775
|
+
) -> "VectorMath":
|
|
1776
|
+
"""Create Vector Math with operation 'Ceil'."""
|
|
1777
|
+
return cls(operation="CEIL", Vector=vector)
|
|
1778
|
+
|
|
1779
|
+
@classmethod
|
|
1780
|
+
def fraction(
|
|
1781
|
+
cls,
|
|
1782
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1783
|
+
) -> "VectorMath":
|
|
1784
|
+
"""Create Vector Math with operation 'Fraction'."""
|
|
1785
|
+
return cls(operation="FRACTION", Vector=vector)
|
|
1786
|
+
|
|
1787
|
+
@classmethod
|
|
1788
|
+
def modulo(
|
|
1789
|
+
cls,
|
|
1790
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1791
|
+
) -> "VectorMath":
|
|
1792
|
+
"""Create Vector Math with operation 'Modulo'."""
|
|
1793
|
+
return cls(operation="MODULO", Vector=vector)
|
|
1794
|
+
|
|
1795
|
+
@classmethod
|
|
1796
|
+
def wrap(
|
|
1797
|
+
cls,
|
|
1798
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1799
|
+
min: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1800
|
+
max: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1801
|
+
) -> "VectorMath":
|
|
1802
|
+
"""Create Vector Math with operation 'Wrap'."""
|
|
1803
|
+
return cls(operation="WRAP", Vector=vector, Vector_001=min, Vector_002=max)
|
|
1804
|
+
|
|
1805
|
+
@classmethod
|
|
1806
|
+
def snap(
|
|
1807
|
+
cls,
|
|
1808
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1809
|
+
increment: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1810
|
+
) -> "VectorMath":
|
|
1811
|
+
"""Create Vector Math with operation 'Snap'."""
|
|
1812
|
+
return cls(operation="SNAP", Vector=vector, Vector_001=increment)
|
|
1813
|
+
|
|
1814
|
+
@classmethod
|
|
1815
|
+
def sin(
|
|
1816
|
+
cls,
|
|
1817
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1818
|
+
) -> "VectorMath":
|
|
1819
|
+
"""Create Vector Math with operation 'Sine'."""
|
|
1820
|
+
return cls(operation="SINE", Vector=vector)
|
|
1821
|
+
|
|
1822
|
+
@classmethod
|
|
1823
|
+
def cos(
|
|
1824
|
+
cls,
|
|
1825
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1826
|
+
) -> "VectorMath":
|
|
1827
|
+
"""Create Vector Math with operation 'Cosine'."""
|
|
1828
|
+
return cls(operation="COSINE", Vector=vector)
|
|
1829
|
+
|
|
1830
|
+
@classmethod
|
|
1831
|
+
def tan(
|
|
1832
|
+
cls,
|
|
1833
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1834
|
+
) -> "VectorMath":
|
|
1835
|
+
"""Create Vector Math with operation 'Tangent'."""
|
|
1836
|
+
return cls(operation="TANGENT", Vector=vector)
|
|
1837
|
+
|
|
1838
|
+
|
|
1839
|
+
class RandomValue(NodeBuilder):
|
|
1840
|
+
"""Random Value node"""
|
|
1841
|
+
|
|
1842
|
+
name = "FunctionNodeRandomValue"
|
|
1843
|
+
node: bpy.types.FunctionNodeRandomValue
|
|
1844
|
+
_default_input_id = "ID"
|
|
1845
|
+
|
|
1846
|
+
def __init__(
|
|
1847
|
+
self,
|
|
1848
|
+
id: TYPE_INPUT_INT = None,
|
|
1849
|
+
seed: TYPE_INPUT_INT = 0,
|
|
1850
|
+
*,
|
|
1851
|
+
data_type: _RandomValueDataTypes = "FLOAT",
|
|
1852
|
+
**kwargs,
|
|
1853
|
+
):
|
|
1854
|
+
super().__init__()
|
|
1855
|
+
self.node.data_type = data_type
|
|
1856
|
+
key_args = {
|
|
1857
|
+
"ID": id,
|
|
1858
|
+
"Seed": seed,
|
|
1859
|
+
}
|
|
1860
|
+
key_args.update(kwargs)
|
|
1861
|
+
self._establish_links(**key_args)
|
|
1862
|
+
|
|
1863
|
+
@property
|
|
1864
|
+
def data_type(self) -> _RandomValueDataTypes:
|
|
1865
|
+
return self.node.data_type # type: ignore
|
|
1866
|
+
|
|
1867
|
+
@data_type.setter
|
|
1868
|
+
def data_type(self, value: _RandomValueDataTypes):
|
|
1869
|
+
self.node.data_type = value
|
|
1870
|
+
|
|
1871
|
+
@property
|
|
1872
|
+
def o_value(self) -> SocketLinker:
|
|
1873
|
+
"""Output socket: Value"""
|
|
1874
|
+
match self.data_type:
|
|
1875
|
+
case "FLOAT":
|
|
1876
|
+
return self._output("Value_001")
|
|
1877
|
+
case "INT":
|
|
1878
|
+
return self._output("Value_002")
|
|
1879
|
+
case "BOOLEAN":
|
|
1880
|
+
return self._output("Value_003")
|
|
1881
|
+
case "FLOAT_VECTOR":
|
|
1882
|
+
return self._output("Value")
|
|
1883
|
+
|
|
1884
|
+
def i_min(self) -> SocketLinker:
|
|
1885
|
+
"""Input socket: Minimum"""
|
|
1886
|
+
match self.data_type:
|
|
1887
|
+
case "FLOAT":
|
|
1888
|
+
return self._input("Min_001")
|
|
1889
|
+
case "INT":
|
|
1890
|
+
return self._input("Min_002")
|
|
1891
|
+
case "BOOLEAN":
|
|
1892
|
+
raise ValueError(
|
|
1893
|
+
"Boolean data type does not support minimum value, use 'Probability'"
|
|
1894
|
+
)
|
|
1895
|
+
case "FLOAT_VECTOR":
|
|
1896
|
+
return self._input("Min")
|
|
1897
|
+
|
|
1898
|
+
def i_max(self) -> SocketLinker:
|
|
1899
|
+
"""Input socket: Maximum"""
|
|
1900
|
+
match self.data_type:
|
|
1901
|
+
case "FLOAT":
|
|
1902
|
+
return self._input("Max_001")
|
|
1903
|
+
case "INT":
|
|
1904
|
+
return self._input("Max_002")
|
|
1905
|
+
case "BOOLEAN":
|
|
1906
|
+
raise ValueError(
|
|
1907
|
+
"Boolean data type does not support maximum value, use 'Probability'"
|
|
1908
|
+
)
|
|
1909
|
+
case "FLOAT_VECTOR":
|
|
1910
|
+
return self._input("Max")
|
|
1911
|
+
|
|
1912
|
+
def i_probability(self) -> SocketLinker:
|
|
1913
|
+
"""Input socket: Probability"""
|
|
1914
|
+
if self.data_type != "BOOLEAN":
|
|
1915
|
+
raise ValueError(
|
|
1916
|
+
f"Probability socket is only supported for boolean data types, not for data type: {self.data_type}"
|
|
1917
|
+
)
|
|
1918
|
+
|
|
1919
|
+
return self._input("Probability")
|
|
1920
|
+
|
|
1921
|
+
@classmethod
|
|
1922
|
+
def float(
|
|
1923
|
+
cls,
|
|
1924
|
+
min: TYPE_INPUT_VALUE = 0.0,
|
|
1925
|
+
max: TYPE_INPUT_VALUE = 1.0,
|
|
1926
|
+
id: TYPE_INPUT_INT = None,
|
|
1927
|
+
seed: int | LINKABLE = 1,
|
|
1928
|
+
) -> NodeBuilder:
|
|
1929
|
+
buidler = cls(Min_001=min, Max_001=max, id=id, seed=seed, data_type="FLOAT")
|
|
1930
|
+
buidler._default_output_id = "Value_001"
|
|
1931
|
+
return buidler
|
|
1932
|
+
|
|
1933
|
+
@classmethod
|
|
1934
|
+
def integer(
|
|
1935
|
+
cls,
|
|
1936
|
+
min: TYPE_INPUT_INT = 0,
|
|
1937
|
+
max: TYPE_INPUT_INT = 1,
|
|
1938
|
+
id: TYPE_INPUT_INT = None,
|
|
1939
|
+
seed: TYPE_INPUT_INT = 1,
|
|
1940
|
+
) -> NodeBuilder:
|
|
1941
|
+
buidler = cls(Min_002=min, Max_002=max, id=id, seed=seed, data_type="INT")
|
|
1942
|
+
buidler._default_output_id = "Value_002"
|
|
1943
|
+
return buidler
|
|
1944
|
+
|
|
1945
|
+
@classmethod
|
|
1946
|
+
def boolean(
|
|
1947
|
+
cls,
|
|
1948
|
+
probability: TYPE_INPUT_VALUE = 0.5,
|
|
1949
|
+
id: TYPE_INPUT_INT = None,
|
|
1950
|
+
seed: TYPE_INPUT_INT = 1,
|
|
1951
|
+
) -> NodeBuilder:
|
|
1952
|
+
builder = cls(Probability=probability, id=id, seed=seed, data_type="BOOLEAN")
|
|
1953
|
+
builder._default_output_id = "Value_003"
|
|
1954
|
+
return builder
|
|
1955
|
+
|
|
1956
|
+
@classmethod
|
|
1957
|
+
def vector(
|
|
1958
|
+
cls,
|
|
1959
|
+
min: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
1960
|
+
max: TYPE_INPUT_VECTOR = (1.0, 1.0, 1.0),
|
|
1961
|
+
id: TYPE_INPUT_INT = None,
|
|
1962
|
+
seed: TYPE_INPUT_INT = 1,
|
|
1963
|
+
) -> NodeBuilder:
|
|
1964
|
+
builder = cls(Min=min, Max=max, id=id, seed=seed, data_type="FLOAT_VECTOR")
|
|
1965
|
+
builder._default_output_id = "Value"
|
|
1966
|
+
return builder
|
|
1967
|
+
|
|
1968
|
+
|
|
1969
|
+
class SeparateXYZ(NodeBuilder):
|
|
1970
|
+
"""Split a vector into its X, Y, and Z components"""
|
|
1971
|
+
|
|
1972
|
+
name = "ShaderNodeSeparateXYZ"
|
|
1973
|
+
node: bpy.types.ShaderNodeSeparateXYZ # type: ignore
|
|
1974
|
+
|
|
1975
|
+
def __init__(self, vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0)):
|
|
1976
|
+
super().__init__()
|
|
1977
|
+
self._establish_links(**{"Vector": vector})
|
|
1978
|
+
|
|
1979
|
+
@property
|
|
1980
|
+
def i_vector(self) -> SocketLinker:
|
|
1981
|
+
"""Input socket: Vector"""
|
|
1982
|
+
return self._input("Vector")
|
|
1983
|
+
|
|
1984
|
+
@property
|
|
1985
|
+
def o_x(self) -> SocketLinker:
|
|
1986
|
+
"""Output socket: X"""
|
|
1987
|
+
return self._output("X")
|
|
1988
|
+
|
|
1989
|
+
@property
|
|
1990
|
+
def o_y(self) -> SocketLinker:
|
|
1991
|
+
"""Output socket: Y"""
|
|
1992
|
+
return self._output("Y")
|
|
1993
|
+
|
|
1994
|
+
@property
|
|
1995
|
+
def o_z(self) -> SocketLinker:
|
|
1996
|
+
"""Output socket: Z"""
|
|
1997
|
+
return self._output("Z")
|
|
1998
|
+
|
|
1999
|
+
|
|
2000
|
+
class CombineXYZ(NodeBuilder):
|
|
2001
|
+
"""Create a vector from X, Y, and Z components"""
|
|
2002
|
+
|
|
2003
|
+
name = "ShaderNodeCombineXYZ"
|
|
2004
|
+
node: bpy.types.ShaderNodeCombineXYZ # type: ignore
|
|
2005
|
+
|
|
2006
|
+
def __init__(
|
|
2007
|
+
self,
|
|
2008
|
+
x: TYPE_INPUT_VALUE = 0.0,
|
|
2009
|
+
y: TYPE_INPUT_VALUE = 0.0,
|
|
2010
|
+
z: TYPE_INPUT_VALUE = 0.0,
|
|
2011
|
+
):
|
|
2012
|
+
super().__init__()
|
|
2013
|
+
self._establish_links(**{"X": x, "Y": y, "Z": z})
|
|
2014
|
+
|
|
2015
|
+
@property
|
|
2016
|
+
def o_vector(self) -> SocketLinker:
|
|
2017
|
+
"""Output socket: Vector"""
|
|
2018
|
+
return self._output("Vector")
|
|
2019
|
+
|
|
2020
|
+
@property
|
|
2021
|
+
def i_x(self) -> SocketLinker:
|
|
2022
|
+
"""Input socket: X"""
|
|
2023
|
+
return self._input("X")
|
|
2024
|
+
|
|
2025
|
+
@property
|
|
2026
|
+
def i_y(self) -> SocketLinker:
|
|
2027
|
+
"""Input socket: Y"""
|
|
2028
|
+
return self._input("Y")
|
|
2029
|
+
|
|
2030
|
+
@property
|
|
2031
|
+
def i_z(self) -> SocketLinker:
|
|
2032
|
+
"""Input socket: Z"""
|
|
2033
|
+
return self._input("Z")
|
|
2034
|
+
|
|
2035
|
+
|
|
2036
|
+
class Mix(NodeBuilder):
|
|
2037
|
+
"""Mix values by a factor"""
|
|
2038
|
+
|
|
2039
|
+
name = "ShaderNodeMix"
|
|
2040
|
+
node: bpy.types.ShaderNodeMix # type: ignore
|
|
2041
|
+
|
|
2042
|
+
def __init__(
|
|
2043
|
+
self,
|
|
2044
|
+
data_type: _MixDataTypes = "FLOAT",
|
|
2045
|
+
**kwargs,
|
|
2046
|
+
):
|
|
2047
|
+
super().__init__()
|
|
2048
|
+
self._default_input_id = f"A_{data_type.title()}"
|
|
2049
|
+
self._default_output_id = f"Result_{data_type.title()}"
|
|
2050
|
+
self.node.data_type = "RGBA" if data_type == "COLOR" else data_type
|
|
2051
|
+
key_args = {}
|
|
2052
|
+
key_args.update(kwargs)
|
|
2053
|
+
self._establish_links(**key_args)
|
|
2054
|
+
|
|
2055
|
+
@property
|
|
2056
|
+
def data_type(self) -> str:
|
|
2057
|
+
return self.node.data_type
|
|
2058
|
+
|
|
2059
|
+
@data_type.setter
|
|
2060
|
+
def data_type(self, value: _MixDataTypes):
|
|
2061
|
+
self.node.data_type = value # type: ignore
|
|
2062
|
+
|
|
2063
|
+
@property
|
|
2064
|
+
def factor_mode(self) -> Literal["UNIFORM", "NON_UNIFORM"]:
|
|
2065
|
+
return self.node.factor_mode
|
|
2066
|
+
|
|
2067
|
+
@factor_mode.setter
|
|
2068
|
+
def factor_mode(self, value: Literal["NON_UNIFORM", "UNIFORM"]):
|
|
2069
|
+
self.node.factor_mode = value
|
|
2070
|
+
|
|
2071
|
+
@property
|
|
2072
|
+
def o_result(self) -> SocketLinker:
|
|
2073
|
+
"""Output socket: Result"""
|
|
2074
|
+
return SocketLinker(self._default_output_socket)
|
|
2075
|
+
|
|
2076
|
+
@property
|
|
2077
|
+
def i_factor(self) -> SocketLinker:
|
|
2078
|
+
"""Input socket: Factor"""
|
|
2079
|
+
match self.data_type:
|
|
2080
|
+
case "FLOAT":
|
|
2081
|
+
name = "Factor_Float"
|
|
2082
|
+
case "VECTOR":
|
|
2083
|
+
name = (
|
|
2084
|
+
"Factor_Float" if self.factor_mode == "UNIFORM" else "Factor_Vector"
|
|
2085
|
+
)
|
|
2086
|
+
case "RGBA":
|
|
2087
|
+
name = "Factor_Color"
|
|
2088
|
+
case "ROTATION":
|
|
2089
|
+
name = "Factor_Rotation"
|
|
2090
|
+
case _:
|
|
2091
|
+
raise ValueError(f"Unsupported data type: {self.data_type}")
|
|
2092
|
+
|
|
2093
|
+
idx = self._input_idx(name)
|
|
2094
|
+
return SocketLinker(self.node.inputs[idx])
|
|
2095
|
+
|
|
2096
|
+
@property
|
|
2097
|
+
def i_value_a(self) -> SocketLinker:
|
|
2098
|
+
"""Input socket: Value A"""
|
|
2099
|
+
type_name = "Color" if self.data_type == "RGBA" else self.data_type
|
|
2100
|
+
name = f"A_{type_name}"
|
|
2101
|
+
idx = self._input_idx(name)
|
|
2102
|
+
return SocketLinker(self.node.inputs[idx])
|
|
2103
|
+
|
|
2104
|
+
@property
|
|
2105
|
+
def i_value_b(self) -> SocketLinker:
|
|
2106
|
+
"""Input socket: Value B"""
|
|
2107
|
+
type_name = "Color" if self.data_type == "RGBA" else self.data_type
|
|
2108
|
+
name = f"B_{type_name}"
|
|
2109
|
+
idx = self._input_idx(name)
|
|
2110
|
+
return SocketLinker(self.node.inputs[idx])
|
|
2111
|
+
|
|
2112
|
+
@classmethod
|
|
2113
|
+
def float(
|
|
2114
|
+
cls,
|
|
2115
|
+
factor: TYPE_INPUT_VALUE = 0.5,
|
|
2116
|
+
a: TYPE_INPUT_VALUE = 0.0,
|
|
2117
|
+
b: TYPE_INPUT_VALUE = 0.0,
|
|
2118
|
+
clamp_factor: bool = True,
|
|
2119
|
+
) -> "Mix":
|
|
2120
|
+
builder = cls(
|
|
2121
|
+
Factor_Float=factor,
|
|
2122
|
+
A_Float=a,
|
|
2123
|
+
B_Float=b,
|
|
2124
|
+
data_type="COLOR",
|
|
2125
|
+
)
|
|
2126
|
+
builder.node.clamp_factor = clamp_factor
|
|
2127
|
+
return builder
|
|
2128
|
+
|
|
2129
|
+
@classmethod
|
|
2130
|
+
def vector(
|
|
2131
|
+
cls,
|
|
2132
|
+
factor: TYPE_INPUT_VALUE = 0.5,
|
|
2133
|
+
a: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
2134
|
+
b: TYPE_INPUT_VECTOR = (1.0, 1.0, 1.0),
|
|
2135
|
+
clamp_factor: bool = True,
|
|
2136
|
+
factor_mode: Literal["UNIFORM", "NON_UNIFORM"] = "UNIFORM",
|
|
2137
|
+
) -> "Mix":
|
|
2138
|
+
match factor_mode:
|
|
2139
|
+
case "UNIFORM":
|
|
2140
|
+
builder = cls(
|
|
2141
|
+
Factor_Float=factor,
|
|
2142
|
+
A_Vector=a,
|
|
2143
|
+
B_Vector=b,
|
|
2144
|
+
data_type="VECTOR",
|
|
2145
|
+
)
|
|
2146
|
+
case "NON_UNIFORM":
|
|
2147
|
+
builder = cls(
|
|
2148
|
+
Factor_Vector=factor,
|
|
2149
|
+
A_Vector=a,
|
|
2150
|
+
B_Vector=b,
|
|
2151
|
+
data_type="VECTOR",
|
|
2152
|
+
)
|
|
2153
|
+
|
|
2154
|
+
builder.node.clamp_factor = clamp_factor
|
|
2155
|
+
return builder
|
|
2156
|
+
|
|
2157
|
+
@classmethod
|
|
2158
|
+
def color(
|
|
2159
|
+
cls,
|
|
2160
|
+
factor: TYPE_INPUT_VALUE = 0.5,
|
|
2161
|
+
a: TYPE_INPUT_COLOR = (0.0, 0.0, 0.0, 0.0),
|
|
2162
|
+
b: TYPE_INPUT_COLOR = (1.0, 1.0, 1.0, 1.0),
|
|
2163
|
+
blend_type: _MixColorBlendTypes = "ADD",
|
|
2164
|
+
clamp_factor: bool = True,
|
|
2165
|
+
clamp_result: bool = True,
|
|
2166
|
+
) -> "Mix":
|
|
2167
|
+
builder = cls(
|
|
2168
|
+
Factor_Float=factor,
|
|
2169
|
+
A_Color=a,
|
|
2170
|
+
B_Color=b,
|
|
2171
|
+
data_type="COLOR",
|
|
2172
|
+
)
|
|
2173
|
+
builder.node.blend_type = blend_type
|
|
2174
|
+
builder.node.clamp_factor = clamp_factor
|
|
2175
|
+
builder.node.clamp_result = clamp_result
|
|
2176
|
+
return builder
|
|
2177
|
+
|
|
2178
|
+
@classmethod
|
|
2179
|
+
def rotation(
|
|
2180
|
+
cls,
|
|
2181
|
+
a: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0),
|
|
2182
|
+
b: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0),
|
|
2183
|
+
factor: TYPE_INPUT_VALUE = 0.5,
|
|
2184
|
+
clamp_factor: bool = True,
|
|
2185
|
+
) -> "Mix":
|
|
2186
|
+
builder = cls(
|
|
2187
|
+
Factor_Float=factor,
|
|
2188
|
+
A_Rotation=a,
|
|
2189
|
+
B_Rotation=b,
|
|
2190
|
+
data_type="ROTATION",
|
|
2191
|
+
)
|
|
2192
|
+
builder.node.clamp_factor = clamp_factor
|
|
2193
|
+
return builder
|
|
2194
|
+
|
|
2195
|
+
|
|
2196
|
+
def _accumlate_field_factory(domain: _AttributeDomains):
|
|
2197
|
+
"""Create a factory for AccumulateField with a specific data type"""
|
|
2198
|
+
|
|
2199
|
+
class EvaluateAtIndexDomainFactory:
|
|
2200
|
+
@staticmethod
|
|
2201
|
+
def float(
|
|
2202
|
+
value: TYPE_INPUT_VALUE = None, index: TYPE_INPUT_INT = 0
|
|
2203
|
+
) -> "AccumulateField":
|
|
2204
|
+
return AccumulateField(value, index, domain=domain, data_type="FLOAT")
|
|
2205
|
+
|
|
2206
|
+
@staticmethod
|
|
2207
|
+
def integer(
|
|
2208
|
+
value: TYPE_INPUT_INT = None, index: TYPE_INPUT_INT = 0
|
|
2209
|
+
) -> "AccumulateField":
|
|
2210
|
+
return AccumulateField(value, index, domain=domain, data_type="INT")
|
|
2211
|
+
|
|
2212
|
+
@staticmethod
|
|
2213
|
+
def vector(
|
|
2214
|
+
value: TYPE_INPUT_VECTOR = None, index: TYPE_INPUT_INT = 0
|
|
2215
|
+
) -> "AccumulateField":
|
|
2216
|
+
return AccumulateField(
|
|
2217
|
+
value, index, domain=domain, data_type="FLOAT_VECTOR"
|
|
2218
|
+
)
|
|
2219
|
+
|
|
2220
|
+
@staticmethod
|
|
2221
|
+
def transform(
|
|
2222
|
+
value: TYPE_INPUT_MATRIX = None, index: TYPE_INPUT_INT = 0
|
|
2223
|
+
) -> "AccumulateField":
|
|
2224
|
+
return AccumulateField(value, index, domain=domain, data_type="TRANSFORM")
|
|
2225
|
+
|
|
2226
|
+
return EvaluateAtIndexDomainFactory()
|
|
2227
|
+
|
|
2228
|
+
|
|
2229
|
+
class AccumulateField(NodeBuilder):
|
|
2230
|
+
"""Add the values of an evaluated field together and output the running total for each element"""
|
|
2231
|
+
|
|
2232
|
+
name = "GeometryNodeAccumulateField"
|
|
2233
|
+
node: bpy.types.GeometryNodeAccumulateField
|
|
2234
|
+
|
|
2235
|
+
point = _accumlate_field_factory("POINT")
|
|
2236
|
+
edge = _accumlate_field_factory("EDGE")
|
|
2237
|
+
face = _accumlate_field_factory("FACE")
|
|
2238
|
+
corner = _accumlate_field_factory("CORNER")
|
|
2239
|
+
spline = _accumlate_field_factory("SPLINE")
|
|
2240
|
+
instance = _accumlate_field_factory("INSTANCE")
|
|
2241
|
+
layer = _accumlate_field_factory("LAYER")
|
|
2242
|
+
|
|
2243
|
+
def __init__(
|
|
2244
|
+
self,
|
|
2245
|
+
value: TYPE_INPUT_VALUE
|
|
2246
|
+
| TYPE_INPUT_INT
|
|
2247
|
+
| TYPE_INPUT_VECTOR
|
|
2248
|
+
| TYPE_INPUT_MATRIX = 1.0,
|
|
2249
|
+
group_index: TYPE_INPUT_INT = 0,
|
|
2250
|
+
*,
|
|
2251
|
+
data_type: _AccumulateFieldDataTypes = "FLOAT",
|
|
2252
|
+
domain: _AttributeDomains = "POINT",
|
|
2253
|
+
**kwargs,
|
|
2254
|
+
):
|
|
2255
|
+
super().__init__()
|
|
2256
|
+
key_args = {"Value": value, "Group Index": group_index}
|
|
2257
|
+
key_args.update(kwargs)
|
|
2258
|
+
self.data_type = data_type
|
|
2259
|
+
self.domain = domain
|
|
2260
|
+
self._establish_links(**key_args)
|
|
2261
|
+
|
|
2262
|
+
@property
|
|
2263
|
+
def i_value(self) -> SocketLinker:
|
|
2264
|
+
"""Input socket: Value"""
|
|
2265
|
+
return self._input("Value")
|
|
2266
|
+
|
|
2267
|
+
@property
|
|
2268
|
+
def i_group_id(self) -> SocketLinker:
|
|
2269
|
+
"""Input socket: Group ID"""
|
|
2270
|
+
return self._input("Group Index")
|
|
2271
|
+
|
|
2272
|
+
@property
|
|
2273
|
+
def o_leading(self) -> SocketLinker:
|
|
2274
|
+
"""Output socket: Leading"""
|
|
2275
|
+
return self._output("Leading")
|
|
2276
|
+
|
|
2277
|
+
@property
|
|
2278
|
+
def o_trailing(self) -> SocketLinker:
|
|
2279
|
+
"""Output socket: Trailing"""
|
|
2280
|
+
return self._output("Trailing")
|
|
2281
|
+
|
|
2282
|
+
@property
|
|
2283
|
+
def o_total(self) -> SocketLinker:
|
|
2284
|
+
"""Output socket: Total"""
|
|
2285
|
+
return self._output("Total")
|
|
2286
|
+
|
|
2287
|
+
@property
|
|
2288
|
+
def data_type(self) -> _AccumulateFieldDataTypes:
|
|
2289
|
+
return self.node.data_type
|
|
2290
|
+
|
|
2291
|
+
@data_type.setter
|
|
2292
|
+
def data_type(self, value: _AccumulateFieldDataTypes):
|
|
2293
|
+
self.node.data_type = value
|
|
2294
|
+
|
|
2295
|
+
@property
|
|
2296
|
+
def domain(
|
|
2297
|
+
self,
|
|
2298
|
+
) -> _AttributeDomains:
|
|
2299
|
+
return self.node.domain
|
|
2300
|
+
|
|
2301
|
+
@domain.setter
|
|
2302
|
+
def domain(
|
|
2303
|
+
self,
|
|
2304
|
+
value: _AttributeDomains,
|
|
2305
|
+
):
|
|
2306
|
+
self.node.domain = value
|
|
2307
|
+
|
|
2308
|
+
|
|
2309
|
+
def _evaluate_at_index_factory(domain: _AttributeDomains):
|
|
2310
|
+
"""Create a factory for AccumulateField with a specific data type"""
|
|
2311
|
+
|
|
2312
|
+
class EvaluateAtIndexDomainFactory:
|
|
2313
|
+
@staticmethod
|
|
2314
|
+
def float(value: TYPE_INPUT_VALUE = None, index: TYPE_INPUT_INT = 0):
|
|
2315
|
+
return EvaluateAtIndex(value, index, domain=domain, data_type="FLOAT")
|
|
2316
|
+
|
|
2317
|
+
@staticmethod
|
|
2318
|
+
def integer(value: TYPE_INPUT_INT = None, index: TYPE_INPUT_INT = 0):
|
|
2319
|
+
return EvaluateAtIndex(value, index, domain=domain, data_type="INT")
|
|
2320
|
+
|
|
2321
|
+
@staticmethod
|
|
2322
|
+
def boolean(value: TYPE_INPUT_BOOLEAN = None, index: TYPE_INPUT_INT = 0):
|
|
2323
|
+
return EvaluateAtIndex(value, index, domain=domain, data_type="BOOLEAN")
|
|
2324
|
+
|
|
2325
|
+
@staticmethod
|
|
2326
|
+
def vector(value: TYPE_INPUT_VECTOR = None, index: TYPE_INPUT_INT = 0):
|
|
2327
|
+
return EvaluateAtIndex(
|
|
2328
|
+
value, index, domain=domain, data_type="FLOAT_VECTOR"
|
|
2329
|
+
)
|
|
2330
|
+
|
|
2331
|
+
@staticmethod
|
|
2332
|
+
def rotation(value: TYPE_INPUT_ROTATION = None, index: TYPE_INPUT_INT = 0):
|
|
2333
|
+
return EvaluateAtIndex(value, index, domain=domain, data_type="QUATERNION")
|
|
2334
|
+
|
|
2335
|
+
@staticmethod
|
|
2336
|
+
def transform(value: TYPE_INPUT_MATRIX = None, index: TYPE_INPUT_INT = 0):
|
|
2337
|
+
return EvaluateAtIndex(value, index, domain=domain, data_type="TRANSFORM")
|
|
2338
|
+
|
|
2339
|
+
return EvaluateAtIndexDomainFactory()
|
|
2340
|
+
|
|
2341
|
+
|
|
2342
|
+
class EvaluateAtIndex(NodeBuilder):
|
|
2343
|
+
"""Retrieve data of other elements in the context's geometry"""
|
|
2344
|
+
|
|
2345
|
+
name = "GeometryNodeFieldAtIndex"
|
|
2346
|
+
node: bpy.types.GeometryNodeFieldAtIndex
|
|
2347
|
+
|
|
2348
|
+
point = _evaluate_at_index_factory("POINT")
|
|
2349
|
+
edge = _evaluate_at_index_factory("EDGE")
|
|
2350
|
+
face = _evaluate_at_index_factory("FACE")
|
|
2351
|
+
corner = _evaluate_at_index_factory("CORNER")
|
|
2352
|
+
spline = _evaluate_at_index_factory("SPLINE")
|
|
2353
|
+
instance = _evaluate_at_index_factory("INSTANCE")
|
|
2354
|
+
layer = _evaluate_at_index_factory("LAYER")
|
|
2355
|
+
|
|
2356
|
+
def __init__(
|
|
2357
|
+
self,
|
|
2358
|
+
value: LINKABLE = None,
|
|
2359
|
+
index: TYPE_INPUT_INT = 0,
|
|
2360
|
+
*,
|
|
2361
|
+
domain: _AttributeDomains = "POINT",
|
|
2362
|
+
data_type: _EvaluateAtIndexDataTypes = "FLOAT",
|
|
2363
|
+
**kwargs,
|
|
2364
|
+
):
|
|
2365
|
+
super().__init__()
|
|
2366
|
+
key_args = {"Value": value, "Index": index}
|
|
2367
|
+
key_args.update(kwargs)
|
|
2368
|
+
self.domain = domain
|
|
2369
|
+
self.data_type = data_type
|
|
2370
|
+
self._establish_links(**key_args)
|
|
2371
|
+
|
|
2372
|
+
@property
|
|
2373
|
+
def i_value(self) -> SocketLinker:
|
|
2374
|
+
"""Input socket: Value"""
|
|
2375
|
+
return self._input("Value")
|
|
2376
|
+
|
|
2377
|
+
@property
|
|
2378
|
+
def i_index(self) -> SocketLinker:
|
|
2379
|
+
"""Input socket: Index"""
|
|
2380
|
+
return self._input("Index")
|
|
2381
|
+
|
|
2382
|
+
@property
|
|
2383
|
+
def o_value(self) -> SocketLinker:
|
|
2384
|
+
"""Output socket: Value"""
|
|
2385
|
+
return self._output("Value")
|
|
2386
|
+
|
|
2387
|
+
@property
|
|
2388
|
+
def domain(
|
|
2389
|
+
self,
|
|
2390
|
+
) -> _AttributeDomains:
|
|
2391
|
+
return self.node.domain
|
|
2392
|
+
|
|
2393
|
+
@domain.setter
|
|
2394
|
+
def domain(
|
|
2395
|
+
self,
|
|
2396
|
+
value: _AttributeDomains,
|
|
2397
|
+
):
|
|
2398
|
+
self.node.domain = value
|
|
2399
|
+
|
|
2400
|
+
@property
|
|
2401
|
+
def data_type(
|
|
2402
|
+
self,
|
|
2403
|
+
) -> _EvaluateAtIndexDataTypes:
|
|
2404
|
+
return self.node.data_type
|
|
2405
|
+
|
|
2406
|
+
@data_type.setter
|
|
2407
|
+
def data_type(
|
|
2408
|
+
self,
|
|
2409
|
+
value: _EvaluateAtIndexDataTypes,
|
|
2410
|
+
):
|
|
2411
|
+
self.node.data_type = value
|
|
2412
|
+
|
|
2413
|
+
|
|
2414
|
+
def _field_average_factory(domain: _AttributeDomains):
|
|
2415
|
+
"""Create a factory for FieldVariance with a specific data type"""
|
|
2416
|
+
|
|
2417
|
+
class FieldAverageDomainFactory:
|
|
2418
|
+
@staticmethod
|
|
2419
|
+
def float(
|
|
2420
|
+
value: TYPE_INPUT_VALUE = 1.0,
|
|
2421
|
+
group_index: TYPE_INPUT_INT = 0,
|
|
2422
|
+
) -> "FieldAverage":
|
|
2423
|
+
"""Create FieldAverage for the "FLOAT" data type"""
|
|
2424
|
+
return FieldAverage(value, group_index, data_type="FLOAT", domain=domain)
|
|
2425
|
+
|
|
2426
|
+
@staticmethod
|
|
2427
|
+
def vector(
|
|
2428
|
+
value: TYPE_INPUT_VECTOR = (1.0, 1.0, 1.0),
|
|
2429
|
+
group_index: TYPE_INPUT_INT = 0,
|
|
2430
|
+
) -> "FieldAverage":
|
|
2431
|
+
"""Create FieldAverage on for the "FLOAT_VECTOR" data type"""
|
|
2432
|
+
return FieldAverage(
|
|
2433
|
+
value, group_index, data_type="FLOAT_VECTOR", domain=domain
|
|
2434
|
+
)
|
|
2435
|
+
|
|
2436
|
+
return FieldAverageDomainFactory()
|
|
2437
|
+
|
|
2438
|
+
|
|
2439
|
+
class FieldAverage(NodeBuilder):
|
|
2440
|
+
"""Calculate the mean and median of a given field"""
|
|
2441
|
+
|
|
2442
|
+
name = "GeometryNodeFieldAverage"
|
|
2443
|
+
node: bpy.types.GeometryNodeFieldAverage
|
|
2444
|
+
|
|
2445
|
+
point = _field_average_factory("POINT")
|
|
2446
|
+
edge = _field_average_factory("EDGE")
|
|
2447
|
+
face = _field_average_factory("FACE")
|
|
2448
|
+
corner = _field_average_factory("CORNER")
|
|
2449
|
+
spline = _field_average_factory("SPLINE")
|
|
2450
|
+
instance = _field_average_factory("INSTANCE")
|
|
2451
|
+
layer = _field_average_factory("LAYER")
|
|
2452
|
+
|
|
2453
|
+
def __init__(
|
|
2454
|
+
self,
|
|
2455
|
+
value: LINKABLE = None,
|
|
2456
|
+
group_index: TYPE_INPUT_VALUE | TYPE_INPUT_VECTOR = 0,
|
|
2457
|
+
*,
|
|
2458
|
+
data_type: Literal["FLOAT", "FLOAT_VECTOR"] = "FLOAT",
|
|
2459
|
+
domain: _AttributeDomains = "POINT",
|
|
2460
|
+
):
|
|
2461
|
+
super().__init__()
|
|
2462
|
+
key_args = {"Value": value, "Group Index": group_index}
|
|
2463
|
+
self.data_type = data_type
|
|
2464
|
+
self.domain = domain
|
|
2465
|
+
self._establish_links(**key_args)
|
|
2466
|
+
|
|
2467
|
+
@property
|
|
2468
|
+
def i_value(self) -> SocketLinker:
|
|
2469
|
+
"""Input socket: Value"""
|
|
2470
|
+
return self._input("Value")
|
|
2471
|
+
|
|
2472
|
+
@property
|
|
2473
|
+
def i_group_id(self) -> SocketLinker:
|
|
2474
|
+
"""Input socket: Group ID"""
|
|
2475
|
+
return self._input("Group Index")
|
|
2476
|
+
|
|
2477
|
+
@property
|
|
2478
|
+
def o_mean(self) -> SocketLinker:
|
|
2479
|
+
"""Output socket: Mean"""
|
|
2480
|
+
return self._output("Mean")
|
|
2481
|
+
|
|
2482
|
+
@property
|
|
2483
|
+
def o_median(self) -> SocketLinker:
|
|
2484
|
+
"""Output socket: Median"""
|
|
2485
|
+
return self._output("Median")
|
|
2486
|
+
|
|
2487
|
+
@property
|
|
2488
|
+
def data_type(self) -> Literal["FLOAT", "FLOAT_VECTOR"]:
|
|
2489
|
+
return self.node.data_type
|
|
2490
|
+
|
|
2491
|
+
@data_type.setter
|
|
2492
|
+
def data_type(self, value: Literal["FLOAT", "FLOAT_VECTOR"]):
|
|
2493
|
+
self.node.data_type = value
|
|
2494
|
+
|
|
2495
|
+
@property
|
|
2496
|
+
def domain(
|
|
2497
|
+
self,
|
|
2498
|
+
) -> _AttributeDomains:
|
|
2499
|
+
return self.node.domain
|
|
2500
|
+
|
|
2501
|
+
@domain.setter
|
|
2502
|
+
def domain(
|
|
2503
|
+
self,
|
|
2504
|
+
value: _AttributeDomains,
|
|
2505
|
+
):
|
|
2506
|
+
self.node.domain = value
|
|
2507
|
+
|
|
2508
|
+
|
|
2509
|
+
def _field_min_and_max_factory(domain: _AttributeDomains):
|
|
2510
|
+
"""Create a factory for AccumulateField with a specific data type"""
|
|
2511
|
+
|
|
2512
|
+
class FieldMinMaxDataTypeFactory:
|
|
2513
|
+
@staticmethod
|
|
2514
|
+
def float(
|
|
2515
|
+
value: TYPE_INPUT_VALUE = 1.0,
|
|
2516
|
+
group_index: TYPE_INPUT_INT = 0,
|
|
2517
|
+
) -> "FieldMinMax":
|
|
2518
|
+
"""Create FieldMinMax for the "FLOAT" data type"""
|
|
2519
|
+
return FieldMinMax(value, group_index, data_type="FLOAT", domain=domain)
|
|
2520
|
+
|
|
2521
|
+
@staticmethod
|
|
2522
|
+
def integer(
|
|
2523
|
+
value: TYPE_INPUT_INT = 1,
|
|
2524
|
+
group_index: TYPE_INPUT_INT = 0,
|
|
2525
|
+
) -> "FieldMinMax":
|
|
2526
|
+
"""Create FieldMinMax for the "INT" data type"""
|
|
2527
|
+
return FieldMinMax(value, group_index, data_type="INT", domain=domain)
|
|
2528
|
+
|
|
2529
|
+
@staticmethod
|
|
2530
|
+
def vector(
|
|
2531
|
+
value: TYPE_INPUT_VECTOR = (1.0, 1.0, 1.0),
|
|
2532
|
+
group_index: TYPE_INPUT_INT = 0,
|
|
2533
|
+
) -> "FieldMinMax":
|
|
2534
|
+
"""Create FieldMinMax on for the "FLOAT_VECTOR" data type"""
|
|
2535
|
+
return FieldMinMax(
|
|
2536
|
+
value, group_index, data_type="FLOAT_VECTOR", domain=domain
|
|
2537
|
+
)
|
|
2538
|
+
|
|
2539
|
+
return FieldMinMaxDataTypeFactory()
|
|
2540
|
+
|
|
2541
|
+
|
|
2542
|
+
class FieldMinMax(NodeBuilder):
|
|
2543
|
+
"""Calculate the minimum and maximum of a given field"""
|
|
2544
|
+
|
|
2545
|
+
name = "GeometryNodeFieldMinAndMax"
|
|
2546
|
+
node: bpy.types.GeometryNodeFieldMinAndMax
|
|
2547
|
+
|
|
2548
|
+
point = _field_min_and_max_factory("POINT")
|
|
2549
|
+
edge = _field_min_and_max_factory("EDGE")
|
|
2550
|
+
face = _field_min_and_max_factory("FACE")
|
|
2551
|
+
corner = _field_min_and_max_factory("CORNER")
|
|
2552
|
+
spline = _field_min_and_max_factory("SPLINE")
|
|
2553
|
+
instance = _field_min_and_max_factory("INSTANCE")
|
|
2554
|
+
layer = _field_min_and_max_factory("LAYER")
|
|
2555
|
+
|
|
2556
|
+
def __init__(
|
|
2557
|
+
self,
|
|
2558
|
+
value: TYPE_INPUT_VALUE | TYPE_INPUT_VECTOR | TYPE_INPUT_INT = 1.0,
|
|
2559
|
+
group_index: TYPE_INPUT_INT = 0,
|
|
2560
|
+
*,
|
|
2561
|
+
data_type: Literal["FLOAT", "INT", "FLOAT_VECTOR"] = "FLOAT",
|
|
2562
|
+
domain: _AttributeDomains = "POINT",
|
|
2563
|
+
):
|
|
2564
|
+
super().__init__()
|
|
2565
|
+
key_args = {"Value": value, "Group Index": group_index}
|
|
2566
|
+
self.data_type = data_type
|
|
2567
|
+
self.domain = domain
|
|
2568
|
+
self._establish_links(**key_args)
|
|
2569
|
+
|
|
2570
|
+
@property
|
|
2571
|
+
def i_value(self) -> SocketLinker:
|
|
2572
|
+
"""Input socket: Value"""
|
|
2573
|
+
return self._input("Value")
|
|
2574
|
+
|
|
2575
|
+
@property
|
|
2576
|
+
def i_group_id(self) -> SocketLinker:
|
|
2577
|
+
"""Input socket: Group ID"""
|
|
2578
|
+
return self._input("Group Index")
|
|
2579
|
+
|
|
2580
|
+
@property
|
|
2581
|
+
def o_min(self) -> SocketLinker:
|
|
2582
|
+
"""Output socket: Min"""
|
|
2583
|
+
return self._output("Min")
|
|
2584
|
+
|
|
2585
|
+
@property
|
|
2586
|
+
def o_max(self) -> SocketLinker:
|
|
2587
|
+
"""Output socket: Max"""
|
|
2588
|
+
return self._output("Max")
|
|
2589
|
+
|
|
2590
|
+
@property
|
|
2591
|
+
def data_type(self) -> Literal["FLOAT", "INT", "FLOAT_VECTOR"]:
|
|
2592
|
+
return self.node.data_type
|
|
2593
|
+
|
|
2594
|
+
@data_type.setter
|
|
2595
|
+
def data_type(self, value: Literal["FLOAT", "INT", "FLOAT_VECTOR"]):
|
|
2596
|
+
self.node.data_type = value
|
|
2597
|
+
|
|
2598
|
+
@property
|
|
2599
|
+
def domain(
|
|
2600
|
+
self,
|
|
2601
|
+
) -> _AttributeDomains:
|
|
2602
|
+
return self.node.domain
|
|
2603
|
+
|
|
2604
|
+
@domain.setter
|
|
2605
|
+
def domain(
|
|
2606
|
+
self,
|
|
2607
|
+
value: _AttributeDomains,
|
|
2608
|
+
):
|
|
2609
|
+
self.node.domain = value
|
|
2610
|
+
|
|
2611
|
+
|
|
2612
|
+
def _evaluate_on_domain_factory(domain: _AttributeDomains):
|
|
2613
|
+
"""Create a factory for AccumulateField with a specific data type"""
|
|
2614
|
+
|
|
2615
|
+
class EvaluateOnDomainDomainFactory:
|
|
2616
|
+
@staticmethod
|
|
2617
|
+
def float(value: TYPE_INPUT_VALUE = None):
|
|
2618
|
+
return EvaluateOnDomain(value, domain=domain, data_type="FLOAT")
|
|
2619
|
+
|
|
2620
|
+
@staticmethod
|
|
2621
|
+
def integer(value: TYPE_INPUT_INT = None):
|
|
2622
|
+
return EvaluateOnDomain(value, domain=domain, data_type="INT")
|
|
2623
|
+
|
|
2624
|
+
@staticmethod
|
|
2625
|
+
def boolean(value: TYPE_INPUT_BOOLEAN = None, index: TYPE_INPUT_INT = 0):
|
|
2626
|
+
return EvaluateOnDomain(value, index, domain=domain, data_type="BOOLEAN")
|
|
2627
|
+
|
|
2628
|
+
@staticmethod
|
|
2629
|
+
def vector(value: TYPE_INPUT_VECTOR = None):
|
|
2630
|
+
return EvaluateOnDomain(value, domain=domain, data_type="FLOAT_VECTOR")
|
|
2631
|
+
|
|
2632
|
+
@staticmethod
|
|
2633
|
+
def rotation(value: TYPE_INPUT_ROTATION = None):
|
|
2634
|
+
return EvaluateOnDomain(value, domain=domain, data_type="QUATERNION")
|
|
2635
|
+
|
|
2636
|
+
@staticmethod
|
|
2637
|
+
def transform(value: TYPE_INPUT_MATRIX = None):
|
|
2638
|
+
return EvaluateOnDomain(value, domain=domain, data_type="TRANSFORM")
|
|
2639
|
+
|
|
2640
|
+
return EvaluateOnDomainDomainFactory()
|
|
2641
|
+
|
|
2642
|
+
|
|
2643
|
+
class EvaluateOnDomain(NodeBuilder):
|
|
2644
|
+
"""Retrieve values from a field on a different domain besides the domain from the context"""
|
|
2645
|
+
|
|
2646
|
+
name = "GeometryNodeFieldOnDomain"
|
|
2647
|
+
node: bpy.types.GeometryNodeFieldOnDomain
|
|
2648
|
+
|
|
2649
|
+
point = _field_min_and_max_factory("POINT")
|
|
2650
|
+
edge = _field_min_and_max_factory("EDGE")
|
|
2651
|
+
face = _field_min_and_max_factory("FACE")
|
|
2652
|
+
corner = _field_min_and_max_factory("CORNER")
|
|
2653
|
+
spline = _field_min_and_max_factory("SPLINE")
|
|
2654
|
+
instance = _field_min_and_max_factory("INSTANCE")
|
|
2655
|
+
layer = _field_min_and_max_factory("LAYER")
|
|
2656
|
+
|
|
2657
|
+
def __init__(
|
|
2658
|
+
self,
|
|
2659
|
+
value: LINKABLE = None,
|
|
2660
|
+
*,
|
|
2661
|
+
domain: _AttributeDomains = "POINT",
|
|
2662
|
+
data_type: _EvaluateAtIndexDataTypes = "FLOAT",
|
|
2663
|
+
):
|
|
2664
|
+
super().__init__()
|
|
2665
|
+
key_args = {"Value": value}
|
|
2666
|
+
self.domain = domain
|
|
2667
|
+
self.data_type = data_type
|
|
2668
|
+
self._establish_links(**key_args)
|
|
2669
|
+
|
|
2670
|
+
@property
|
|
2671
|
+
def i_value(self) -> SocketLinker:
|
|
2672
|
+
"""Input socket: Value"""
|
|
2673
|
+
return self._input("Value")
|
|
2674
|
+
|
|
2675
|
+
@property
|
|
2676
|
+
def o_value(self) -> SocketLinker:
|
|
2677
|
+
"""Output socket: Value"""
|
|
2678
|
+
return self._output("Value")
|
|
2679
|
+
|
|
2680
|
+
@property
|
|
2681
|
+
def domain(
|
|
2682
|
+
self,
|
|
2683
|
+
) -> _AttributeDomains:
|
|
2684
|
+
return self.node.domain
|
|
2685
|
+
|
|
2686
|
+
@domain.setter
|
|
2687
|
+
def domain(
|
|
2688
|
+
self,
|
|
2689
|
+
value: _AttributeDomains,
|
|
2690
|
+
):
|
|
2691
|
+
self.node.domain = value
|
|
2692
|
+
|
|
2693
|
+
@property
|
|
2694
|
+
def data_type(
|
|
2695
|
+
self,
|
|
2696
|
+
) -> _EvaluateAtIndexDataTypes:
|
|
2697
|
+
return self.node.data_type
|
|
2698
|
+
|
|
2699
|
+
@data_type.setter
|
|
2700
|
+
def data_type(
|
|
2701
|
+
self,
|
|
2702
|
+
value: _EvaluateAtIndexDataTypes,
|
|
2703
|
+
):
|
|
2704
|
+
self.node.data_type = value
|
|
2705
|
+
|
|
2706
|
+
|
|
2707
|
+
def _field_variance_factory(domain: _AttributeDomains):
|
|
2708
|
+
"""Create a factory for FieldVariance with a specific data type"""
|
|
2709
|
+
|
|
2710
|
+
class FieldVarianceDomainFactory:
|
|
2711
|
+
@staticmethod
|
|
2712
|
+
def float(
|
|
2713
|
+
value: TYPE_INPUT_VALUE = 1.0,
|
|
2714
|
+
group_index: TYPE_INPUT_INT = 0,
|
|
2715
|
+
) -> "FieldVariance":
|
|
2716
|
+
"""Create FieldVariance for the "FLOAT" data type"""
|
|
2717
|
+
return FieldVariance(value, group_index, data_type="FLOAT", domain=domain)
|
|
2718
|
+
|
|
2719
|
+
@staticmethod
|
|
2720
|
+
def vector(
|
|
2721
|
+
value: TYPE_INPUT_VECTOR = (1.0, 1.0, 1.0),
|
|
2722
|
+
group_index: TYPE_INPUT_INT = 0,
|
|
2723
|
+
) -> "FieldVariance":
|
|
2724
|
+
"""Create FieldVariance on for the "FLOAT_VECTOR" data type"""
|
|
2725
|
+
return FieldVariance(
|
|
2726
|
+
value, group_index, data_type="FLOAT_VECTOR", domain=domain
|
|
2727
|
+
)
|
|
2728
|
+
|
|
2729
|
+
return FieldVarianceDomainFactory()
|
|
2730
|
+
|
|
2731
|
+
|
|
2732
|
+
class FieldVariance(NodeBuilder):
|
|
2733
|
+
"""Calculate the standard deviation and variance of a given field"""
|
|
2734
|
+
|
|
2735
|
+
name = "GeometryNodeFieldVariance"
|
|
2736
|
+
node: bpy.types.GeometryNodeFieldVariance
|
|
2737
|
+
|
|
2738
|
+
point = _field_variance_factory("POINT")
|
|
2739
|
+
edge = _field_variance_factory("EDGE")
|
|
2740
|
+
face = _field_variance_factory("FACE")
|
|
2741
|
+
corner = _field_variance_factory("CORNER")
|
|
2742
|
+
spline = _field_variance_factory("SPLINE")
|
|
2743
|
+
instance = _field_variance_factory("INSTANCE")
|
|
2744
|
+
layer = _field_variance_factory("LAYER")
|
|
2745
|
+
|
|
2746
|
+
def __init__(
|
|
2747
|
+
self,
|
|
2748
|
+
value: TYPE_INPUT_VALUE | TYPE_INPUT_VECTOR = None,
|
|
2749
|
+
group_index: TYPE_INPUT_INT = None,
|
|
2750
|
+
*,
|
|
2751
|
+
data_type: Literal["FLOAT", "FLOAT_VECTOR"] = "FLOAT",
|
|
2752
|
+
domain: _AttributeDomains = "POINT",
|
|
2753
|
+
):
|
|
2754
|
+
super().__init__()
|
|
2755
|
+
key_args = {"Value": value, "Group Index": group_index}
|
|
2756
|
+
self.data_type = data_type
|
|
2757
|
+
self.domain = domain
|
|
2758
|
+
self._establish_links(**key_args)
|
|
2759
|
+
|
|
2760
|
+
@property
|
|
2761
|
+
def i_value(self) -> SocketLinker:
|
|
2762
|
+
"""Input socket: Value"""
|
|
2763
|
+
return self._input("Value")
|
|
2764
|
+
|
|
2765
|
+
@property
|
|
2766
|
+
def i_group_id(self) -> SocketLinker:
|
|
2767
|
+
"""Input socket: Group ID"""
|
|
2768
|
+
return self._input("Group Index")
|
|
2769
|
+
|
|
2770
|
+
@property
|
|
2771
|
+
def o_standard_deviation(self) -> SocketLinker:
|
|
2772
|
+
"""Output socket: Standard Deviation"""
|
|
2773
|
+
return self._output("Standard Deviation")
|
|
2774
|
+
|
|
2775
|
+
@property
|
|
2776
|
+
def o_variance(self) -> SocketLinker:
|
|
2777
|
+
"""Output socket: Variance"""
|
|
2778
|
+
return self._output("Variance")
|
|
2779
|
+
|
|
2780
|
+
@property
|
|
2781
|
+
def data_type(self) -> Literal["FLOAT", "FLOAT_VECTOR"]:
|
|
2782
|
+
return self.node.data_type
|
|
2783
|
+
|
|
2784
|
+
@data_type.setter
|
|
2785
|
+
def data_type(self, value: Literal["FLOAT", "FLOAT_VECTOR"]):
|
|
2786
|
+
self.node.data_type = value
|
|
2787
|
+
|
|
2788
|
+
@property
|
|
2789
|
+
def domain(
|
|
2790
|
+
self,
|
|
2791
|
+
) -> _AttributeDomains:
|
|
2792
|
+
return self.node.domain
|
|
2793
|
+
|
|
2794
|
+
@domain.setter
|
|
2795
|
+
def domain(
|
|
2796
|
+
self,
|
|
2797
|
+
value: _AttributeDomains,
|
|
2798
|
+
):
|
|
2799
|
+
self.node.domain = value
|
|
2800
|
+
|
|
2801
|
+
|
|
2802
|
+
class IndexOfNearest(NodeBuilder):
|
|
2803
|
+
"""Find the nearest element in a group. Similar to the "Sample Nearest" node"""
|
|
2804
|
+
|
|
2805
|
+
name = "GeometryNodeIndexOfNearest"
|
|
2806
|
+
node: bpy.types.GeometryNodeIndexOfNearest
|
|
2807
|
+
|
|
2808
|
+
def __init__(
|
|
2809
|
+
self, position: TYPE_INPUT_VECTOR = None, group_id: TYPE_INPUT_INT = None
|
|
2810
|
+
):
|
|
2811
|
+
super().__init__()
|
|
2812
|
+
key_args = {"Position": position, "Group ID": group_id}
|
|
2813
|
+
self._establish_links(**key_args)
|
|
2814
|
+
|
|
2815
|
+
@property
|
|
2816
|
+
def i_position(self) -> SocketLinker:
|
|
2817
|
+
"""Input socket: Position"""
|
|
2818
|
+
return self._input("Position")
|
|
2819
|
+
|
|
2820
|
+
@property
|
|
2821
|
+
def i_group_id(self) -> SocketLinker:
|
|
2822
|
+
"""Input socket: Group ID"""
|
|
2823
|
+
return self._input("Group ID")
|
|
2824
|
+
|
|
2825
|
+
@property
|
|
2826
|
+
def o_index(self) -> SocketLinker:
|
|
2827
|
+
"""Output socket: Index"""
|
|
2828
|
+
return self._output("Index")
|
|
2829
|
+
|
|
2830
|
+
@property
|
|
2831
|
+
def o_has_neighbor(self) -> SocketLinker:
|
|
2832
|
+
"""Output socket: Has Neighbor"""
|
|
2833
|
+
return self._output("Has Neighbor")
|
|
2834
|
+
|
|
2835
|
+
|
|
2836
|
+
class JoinStrings(NodeBuilder):
|
|
2837
|
+
"""Combine any number of input strings"""
|
|
2838
|
+
|
|
2839
|
+
name = "GeometryNodeStringJoin"
|
|
2840
|
+
node: bpy.types.GeometryNodeStringJoin
|
|
2841
|
+
|
|
2842
|
+
def __init__(self, *args: LINKABLE, delimiter: TYPE_INPUT_STRING = ""):
|
|
2843
|
+
super().__init__()
|
|
2844
|
+
|
|
2845
|
+
self._establish_links(Delimiter=delimiter)
|
|
2846
|
+
for arg in args:
|
|
2847
|
+
self._link_from(arg, "Strings")
|
|
2848
|
+
|
|
2849
|
+
@property
|
|
2850
|
+
def i_delimiter(self) -> SocketLinker:
|
|
2851
|
+
"""Input socket: Delimiter"""
|
|
2852
|
+
return self._input("Delimiter")
|
|
2853
|
+
|
|
2854
|
+
@property
|
|
2855
|
+
def i_strings(self) -> SocketLinker:
|
|
2856
|
+
"""Input socket: Strings"""
|
|
2857
|
+
return self._input("Strings")
|
|
2858
|
+
|
|
2859
|
+
@property
|
|
2860
|
+
def o_string(self) -> SocketLinker:
|
|
2861
|
+
"""Output socket: String"""
|
|
2862
|
+
return self._output("String")
|
|
2863
|
+
|
|
2864
|
+
|
|
2865
|
+
def _switch_data_type_method(input_type: SOCKET_TYPES):
|
|
2866
|
+
@classmethod
|
|
2867
|
+
def method(
|
|
2868
|
+
cls, switch: TYPE_INPUT_BOOLEAN, false: LINKABLE, true: LINKABLE
|
|
2869
|
+
) -> "Switch":
|
|
2870
|
+
"""Create a NamedAttribute with specific data type."""
|
|
2871
|
+
return cls(switch=switch, false=false, true=true, input_type=input_type)
|
|
2872
|
+
|
|
2873
|
+
return method
|
|
2874
|
+
|
|
2875
|
+
|
|
2876
|
+
class Switch(NodeBuilder):
|
|
2877
|
+
"""Switch between two inputs"""
|
|
2878
|
+
|
|
2879
|
+
name = "GeometryNodeSwitch"
|
|
2880
|
+
node: bpy.types.GeometryNodeSwitch
|
|
2881
|
+
|
|
2882
|
+
float = _switch_data_type_method("FLOAT")
|
|
2883
|
+
integer = _switch_data_type_method("INT")
|
|
2884
|
+
boolean = _switch_data_type_method("BOOLEAN")
|
|
2885
|
+
vector = _switch_data_type_method("VECTOR")
|
|
2886
|
+
rgba = _switch_data_type_method("RGBA")
|
|
2887
|
+
rotation = _switch_data_type_method("ROTATION")
|
|
2888
|
+
matrix = _switch_data_type_method("MATRIX")
|
|
2889
|
+
string = _switch_data_type_method("STRING")
|
|
2890
|
+
menu = _switch_data_type_method("MENU")
|
|
2891
|
+
object = _switch_data_type_method("OBJECT")
|
|
2892
|
+
geometry = _switch_data_type_method("GEOMETRY")
|
|
2893
|
+
collection = _switch_data_type_method("COLLECTION")
|
|
2894
|
+
image = _switch_data_type_method("IMAGE")
|
|
2895
|
+
material = _switch_data_type_method("MATERIAL")
|
|
2896
|
+
bundle = _switch_data_type_method("BUNDLE")
|
|
2897
|
+
closure = _switch_data_type_method("CLOSURE")
|
|
2898
|
+
|
|
2899
|
+
def __init__(
|
|
2900
|
+
self,
|
|
2901
|
+
switch: TYPE_INPUT_BOOLEAN = False,
|
|
2902
|
+
false: LINKABLE = None,
|
|
2903
|
+
true: LINKABLE = None,
|
|
2904
|
+
*,
|
|
2905
|
+
input_type: SOCKET_TYPES = "GEOMETRY",
|
|
2906
|
+
):
|
|
2907
|
+
super().__init__()
|
|
2908
|
+
self.input_type = input_type
|
|
2909
|
+
key_args = {"Switch": switch, "False": false, "True": true}
|
|
2910
|
+
self._establish_links(**key_args)
|
|
2911
|
+
|
|
2912
|
+
@property
|
|
2913
|
+
def i_switch(self) -> SocketLinker:
|
|
2914
|
+
"""Input socket: Switch"""
|
|
2915
|
+
return self._input("Switch")
|
|
2916
|
+
|
|
2917
|
+
@property
|
|
2918
|
+
def i_false(self) -> SocketLinker:
|
|
2919
|
+
"""Input socket: False"""
|
|
2920
|
+
return self._input("False")
|
|
2921
|
+
|
|
2922
|
+
@property
|
|
2923
|
+
def i_true(self) -> SocketLinker:
|
|
2924
|
+
"""Input socket: True"""
|
|
2925
|
+
return self._input("True")
|
|
2926
|
+
|
|
2927
|
+
@property
|
|
2928
|
+
def o_output(self) -> SocketLinker:
|
|
2929
|
+
"""Output socket: Output"""
|
|
2930
|
+
return self._output("Output")
|
|
2931
|
+
|
|
2932
|
+
@property
|
|
2933
|
+
def input_type(
|
|
2934
|
+
self,
|
|
2935
|
+
) -> SOCKET_TYPES:
|
|
2936
|
+
return self.node.input_type # type: ignore
|
|
2937
|
+
|
|
2938
|
+
@input_type.setter
|
|
2939
|
+
def input_type(
|
|
2940
|
+
self,
|
|
2941
|
+
value: SOCKET_TYPES,
|
|
2942
|
+
):
|
|
2943
|
+
self.node.input_type = value
|
|
2944
|
+
|
|
2945
|
+
|
|
2946
|
+
class PackUVIslands(NodeBuilder):
|
|
2947
|
+
"""Scale islands of a UV map and move them so they fill the UV space as much as possible"""
|
|
2948
|
+
|
|
2949
|
+
name = "GeometryNodeUVPackIslands"
|
|
2950
|
+
node: bpy.types.GeometryNodeUVPackIslands
|
|
2951
|
+
|
|
2952
|
+
def __init__(
|
|
2953
|
+
self,
|
|
2954
|
+
uv: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
2955
|
+
selection: TYPE_INPUT_BOOLEAN = True,
|
|
2956
|
+
margin: TYPE_INPUT_VALUE = 0.001,
|
|
2957
|
+
rotate: TYPE_INPUT_BOOLEAN = True,
|
|
2958
|
+
method: Literal["Bounding Box", "Convex Hull", "Exact Shape"] = "Bounding Box",
|
|
2959
|
+
):
|
|
2960
|
+
super().__init__()
|
|
2961
|
+
key_args = {
|
|
2962
|
+
"UV": uv,
|
|
2963
|
+
"Selection": selection,
|
|
2964
|
+
"Margin": margin,
|
|
2965
|
+
"Rotate": rotate,
|
|
2966
|
+
"Method": method,
|
|
2967
|
+
}
|
|
2968
|
+
self._establish_links(**key_args)
|
|
2969
|
+
|
|
2970
|
+
@property
|
|
2971
|
+
def i_uv(self) -> SocketLinker:
|
|
2972
|
+
"""Input socket: UV"""
|
|
2973
|
+
return self._input("UV")
|
|
2974
|
+
|
|
2975
|
+
@property
|
|
2976
|
+
def i_selection(self) -> SocketLinker:
|
|
2977
|
+
"""Input socket: Selection"""
|
|
2978
|
+
return self._input("Selection")
|
|
2979
|
+
|
|
2980
|
+
@property
|
|
2981
|
+
def i_margin(self) -> SocketLinker:
|
|
2982
|
+
"""Input socket: Margin"""
|
|
2983
|
+
return self._input("Margin")
|
|
2984
|
+
|
|
2985
|
+
@property
|
|
2986
|
+
def i_rotate(self) -> SocketLinker:
|
|
2987
|
+
"""Input socket: Rotate"""
|
|
2988
|
+
return self._input("Rotate")
|
|
2989
|
+
|
|
2990
|
+
@property
|
|
2991
|
+
def i_method(self) -> SocketLinker:
|
|
2992
|
+
"""Input socket: Method"""
|
|
2993
|
+
return self._input("Method")
|
|
2994
|
+
|
|
2995
|
+
@property
|
|
2996
|
+
def o_uv(self) -> SocketLinker:
|
|
2997
|
+
"""Output socket: UV"""
|
|
2998
|
+
return self._output("UV")
|
|
2999
|
+
|
|
3000
|
+
|
|
3001
|
+
class UVUnwrap(NodeBuilder):
|
|
3002
|
+
"""Generate a UV map based on seam edges"""
|
|
3003
|
+
|
|
3004
|
+
name = "GeometryNodeUVUnwrap"
|
|
3005
|
+
node: bpy.types.GeometryNodeUVUnwrap
|
|
3006
|
+
|
|
3007
|
+
def __init__(
|
|
3008
|
+
self,
|
|
3009
|
+
selection: TYPE_INPUT_BOOLEAN = True,
|
|
3010
|
+
seam: TYPE_INPUT_BOOLEAN = False,
|
|
3011
|
+
margin: TYPE_INPUT_VALUE = 0.001,
|
|
3012
|
+
fill_holes: TYPE_INPUT_BOOLEAN = True,
|
|
3013
|
+
method: Literal["Angle Based", "Conformal"] = "Angle Based",
|
|
3014
|
+
):
|
|
3015
|
+
super().__init__()
|
|
3016
|
+
key_args = {
|
|
3017
|
+
"Selection": selection,
|
|
3018
|
+
"Seam": seam,
|
|
3019
|
+
"Margin": margin,
|
|
3020
|
+
"Fill Holes": fill_holes,
|
|
3021
|
+
"Method": method,
|
|
3022
|
+
}
|
|
3023
|
+
self._establish_links(**key_args)
|
|
3024
|
+
|
|
3025
|
+
@property
|
|
3026
|
+
def i_selection(self) -> SocketLinker:
|
|
3027
|
+
"""Input socket: Selection"""
|
|
3028
|
+
return self._input("Selection")
|
|
3029
|
+
|
|
3030
|
+
@property
|
|
3031
|
+
def i_seam(self) -> SocketLinker:
|
|
3032
|
+
"""Input socket: Seam"""
|
|
3033
|
+
return self._input("Seam")
|
|
3034
|
+
|
|
3035
|
+
@property
|
|
3036
|
+
def i_margin(self) -> SocketLinker:
|
|
3037
|
+
"""Input socket: Margin"""
|
|
3038
|
+
return self._input("Margin")
|
|
3039
|
+
|
|
3040
|
+
@property
|
|
3041
|
+
def i_fill_holes(self) -> SocketLinker:
|
|
3042
|
+
"""Input socket: Fill Holes"""
|
|
3043
|
+
return self._input("Fill Holes")
|
|
3044
|
+
|
|
3045
|
+
@property
|
|
3046
|
+
def i_method(self) -> SocketLinker:
|
|
3047
|
+
"""Input socket: Method"""
|
|
3048
|
+
return self._input("Method")
|
|
3049
|
+
|
|
3050
|
+
@property
|
|
3051
|
+
def o_uv(self) -> SocketLinker:
|
|
3052
|
+
"""Output socket: UV"""
|
|
3053
|
+
return self._output("UV")
|
|
3054
|
+
|
|
3055
|
+
|
|
3056
|
+
class FloatCurve(NodeBuilder):
|
|
3057
|
+
"""Map an input float to a curve and outputs a float value"""
|
|
3058
|
+
|
|
3059
|
+
# TODO: add support for custom curves
|
|
3060
|
+
|
|
3061
|
+
name = "ShaderNodeFloatCurve"
|
|
3062
|
+
node: bpy.types.ShaderNodeFloatCurve
|
|
3063
|
+
|
|
3064
|
+
def __init__(self, factor: TYPE_INPUT_VALUE = 1.0, value: TYPE_INPUT_VALUE = 1.0):
|
|
3065
|
+
super().__init__()
|
|
3066
|
+
key_args = {"Factor": factor, "Value": value}
|
|
3067
|
+
self._establish_links(**key_args)
|
|
3068
|
+
|
|
3069
|
+
@property
|
|
3070
|
+
def i_factor(self) -> SocketLinker:
|
|
3071
|
+
"""Input socket: Factor"""
|
|
3072
|
+
return self._input("Factor")
|
|
3073
|
+
|
|
3074
|
+
@property
|
|
3075
|
+
def i_value(self) -> SocketLinker:
|
|
3076
|
+
"""Input socket: Value"""
|
|
3077
|
+
return self._input("Value")
|
|
3078
|
+
|
|
3079
|
+
@property
|
|
3080
|
+
def o_value(self) -> SocketLinker:
|
|
3081
|
+
"""Output socket: Value"""
|
|
3082
|
+
return self._output("Value")
|
|
3083
|
+
|
|
3084
|
+
|
|
3085
|
+
class IntegerMath(NodeBuilder):
|
|
3086
|
+
"""Perform various math operations on the given integer inputs"""
|
|
3087
|
+
|
|
3088
|
+
name = "FunctionNodeIntegerMath"
|
|
3089
|
+
node: bpy.types.FunctionNodeIntegerMath
|
|
3090
|
+
|
|
3091
|
+
def __init__(
|
|
3092
|
+
self,
|
|
3093
|
+
operation: _IntegerMathOperations = "ADD",
|
|
3094
|
+
**kwargs,
|
|
3095
|
+
):
|
|
3096
|
+
super().__init__()
|
|
3097
|
+
key_args = {}
|
|
3098
|
+
key_args.update(kwargs)
|
|
3099
|
+
self.operation = operation
|
|
3100
|
+
self._establish_links(**key_args)
|
|
3101
|
+
|
|
3102
|
+
@classmethod
|
|
3103
|
+
def add(cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0) -> "IntegerMath":
|
|
3104
|
+
"""Create Integer Math with operation 'Add'."""
|
|
3105
|
+
return cls(operation="ADD", Value=a, Value_001=b)
|
|
3106
|
+
|
|
3107
|
+
@classmethod
|
|
3108
|
+
def subtract(cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0) -> "IntegerMath":
|
|
3109
|
+
"""Create Integer Math with operation 'Subtract'."""
|
|
3110
|
+
return cls(operation="SUBTRACT", Value=a, Value_001=b)
|
|
3111
|
+
|
|
3112
|
+
@classmethod
|
|
3113
|
+
def multiply(
|
|
3114
|
+
cls, a: TYPE_INPUT_INT = 0, value_001: TYPE_INPUT_INT = 0
|
|
3115
|
+
) -> "IntegerMath":
|
|
3116
|
+
"""Create Integer Math with operation 'Multiply'."""
|
|
3117
|
+
return cls(operation="MULTIPLY", Value=a, Value_001=value_001)
|
|
3118
|
+
|
|
3119
|
+
@classmethod
|
|
3120
|
+
def divide(
|
|
3121
|
+
cls, a: TYPE_INPUT_INT = 0, value_001: TYPE_INPUT_INT = 0
|
|
3122
|
+
) -> "IntegerMath":
|
|
3123
|
+
"""Create Integer Math with operation 'Divide'."""
|
|
3124
|
+
return cls(operation="DIVIDE", Value=a, Value_001=value_001)
|
|
3125
|
+
|
|
3126
|
+
@classmethod
|
|
3127
|
+
def multiplyadd(
|
|
3128
|
+
cls,
|
|
3129
|
+
value: TYPE_INPUT_INT = 0,
|
|
3130
|
+
multiplier: TYPE_INPUT_INT = 0,
|
|
3131
|
+
addend: TYPE_INPUT_INT = 0,
|
|
3132
|
+
) -> "IntegerMath":
|
|
3133
|
+
"""Create Integer Math with operation 'Multiply Add'."""
|
|
3134
|
+
return cls(
|
|
3135
|
+
operation="MULTIPLY_ADD",
|
|
3136
|
+
Value=value,
|
|
3137
|
+
Value_001=multiplier,
|
|
3138
|
+
Value_002=addend,
|
|
3139
|
+
)
|
|
3140
|
+
|
|
3141
|
+
@classmethod
|
|
3142
|
+
def absolute(cls, value: TYPE_INPUT_INT = 0) -> "IntegerMath":
|
|
3143
|
+
"""Create Integer Math with operation 'Absolute'."""
|
|
3144
|
+
return cls(operation="ABSOLUTE", Value=value)
|
|
3145
|
+
|
|
3146
|
+
@classmethod
|
|
3147
|
+
def negate(cls, value: TYPE_INPUT_INT = 0) -> "IntegerMath":
|
|
3148
|
+
"""Create Integer Math with operation 'Negate'."""
|
|
3149
|
+
return cls(operation="NEGATE", Value=value)
|
|
3150
|
+
|
|
3151
|
+
@classmethod
|
|
3152
|
+
def power(
|
|
3153
|
+
cls, base: TYPE_INPUT_INT = 0, exponent: TYPE_INPUT_INT = 0
|
|
3154
|
+
) -> "IntegerMath":
|
|
3155
|
+
"""Create Integer Math with operation 'Power'."""
|
|
3156
|
+
return cls(operation="POWER", Value=base, Value_001=exponent)
|
|
3157
|
+
|
|
3158
|
+
@classmethod
|
|
3159
|
+
def minimum(cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0) -> "IntegerMath":
|
|
3160
|
+
"""Create Integer Math with operation 'Minimum'."""
|
|
3161
|
+
return cls(operation="MINIMUM", Value=a, Value_001=b)
|
|
3162
|
+
|
|
3163
|
+
@classmethod
|
|
3164
|
+
def maximum(cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0) -> "IntegerMath":
|
|
3165
|
+
"""Create Integer Math with operation 'Maximum'."""
|
|
3166
|
+
return cls(operation="MAXIMUM", Value=a, Value_001=b)
|
|
3167
|
+
|
|
3168
|
+
@classmethod
|
|
3169
|
+
def sign(cls, value: TYPE_INPUT_INT = 0) -> "IntegerMath":
|
|
3170
|
+
"""Create Integer Math with operation 'Sign'."""
|
|
3171
|
+
return cls(operation="SIGN", Value=value)
|
|
3172
|
+
|
|
3173
|
+
@classmethod
|
|
3174
|
+
def divide_round(
|
|
3175
|
+
cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0
|
|
3176
|
+
) -> "IntegerMath":
|
|
3177
|
+
"""Create Integer Math with operation 'Divide Round'."""
|
|
3178
|
+
return cls(operation="DIVIDE_ROUND", Value=a, Value_001=b)
|
|
3179
|
+
|
|
3180
|
+
@classmethod
|
|
3181
|
+
def divide_floor(
|
|
3182
|
+
cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0
|
|
3183
|
+
) -> "IntegerMath":
|
|
3184
|
+
"""Create Integer Math with operation 'Divide Floor'."""
|
|
3185
|
+
return cls(operation="DIVIDE_FLOOR", Value=a, Value_001=b)
|
|
3186
|
+
|
|
3187
|
+
@classmethod
|
|
3188
|
+
def divide_ceil(cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0) -> "IntegerMath":
|
|
3189
|
+
"""Create Integer Math with operation 'Divide Ceiling'."""
|
|
3190
|
+
return cls(operation="DIVIDE_CEIL", Value=a, Value_001=b)
|
|
3191
|
+
|
|
3192
|
+
@classmethod
|
|
3193
|
+
def floored_modulo(
|
|
3194
|
+
cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0
|
|
3195
|
+
) -> "IntegerMath":
|
|
3196
|
+
"""Create Integer Math with operation 'Floored Modulo'."""
|
|
3197
|
+
return cls(operation="FLOORED_MODULO", Value=a, Value_001=b)
|
|
3198
|
+
|
|
3199
|
+
@classmethod
|
|
3200
|
+
def modulo(cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0) -> "IntegerMath":
|
|
3201
|
+
"""Create Integer Math with operation 'Modulo'."""
|
|
3202
|
+
return cls(operation="MODULO", Value=a, Value_001=b)
|
|
3203
|
+
|
|
3204
|
+
@classmethod
|
|
3205
|
+
def greatest_common_divisor(
|
|
3206
|
+
cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0
|
|
3207
|
+
) -> "IntegerMath":
|
|
3208
|
+
"""Create Integer Math with operation 'Greatest Common Divisor'."""
|
|
3209
|
+
return cls(operation="GCD", Value=a, Value_001=b)
|
|
3210
|
+
|
|
3211
|
+
@classmethod
|
|
3212
|
+
def least_common_multiple(
|
|
3213
|
+
cls, a: TYPE_INPUT_INT = 0, b: TYPE_INPUT_INT = 0
|
|
3214
|
+
) -> "IntegerMath":
|
|
3215
|
+
"""Create Integer Math with operation 'Least Common Multiple'."""
|
|
3216
|
+
return cls(operation="LCM", Value=a, Value_001=b)
|
|
3217
|
+
|
|
3218
|
+
@property
|
|
3219
|
+
def i_value(self) -> SocketLinker:
|
|
3220
|
+
"""Input socket: Value"""
|
|
3221
|
+
return self._input("Value")
|
|
3222
|
+
|
|
3223
|
+
@property
|
|
3224
|
+
def i_value_001(self) -> SocketLinker:
|
|
3225
|
+
"""Input socket: Value"""
|
|
3226
|
+
return self._input("Value_001")
|
|
3227
|
+
|
|
3228
|
+
@property
|
|
3229
|
+
def i_value_002(self) -> SocketLinker:
|
|
3230
|
+
"""Input socket: Value"""
|
|
3231
|
+
return self._input("Value_002")
|
|
3232
|
+
|
|
3233
|
+
@property
|
|
3234
|
+
def o_value(self) -> SocketLinker:
|
|
3235
|
+
"""Output socket: Value"""
|
|
3236
|
+
return self._output("Value")
|
|
3237
|
+
|
|
3238
|
+
@property
|
|
3239
|
+
def operation(
|
|
3240
|
+
self,
|
|
3241
|
+
) -> _IntegerMathOperations:
|
|
3242
|
+
return self.node.operation
|
|
3243
|
+
|
|
3244
|
+
@operation.setter
|
|
3245
|
+
def operation(
|
|
3246
|
+
self,
|
|
3247
|
+
value: _IntegerMathOperations,
|
|
3248
|
+
):
|
|
3249
|
+
self.node.operation = value
|
|
3250
|
+
|
|
3251
|
+
|
|
3252
|
+
class InvertMatrix(NodeBuilder):
|
|
3253
|
+
"""Compute the inverse of the given matrix, if one exists"""
|
|
3254
|
+
|
|
3255
|
+
name = "FunctionNodeInvertMatrix"
|
|
3256
|
+
node: bpy.types.FunctionNodeInvertMatrix
|
|
3257
|
+
|
|
3258
|
+
def __init__(self, matrix: TYPE_INPUT_MATRIX = None):
|
|
3259
|
+
super().__init__()
|
|
3260
|
+
key_args = {"Matrix": matrix}
|
|
3261
|
+
self._establish_links(**key_args)
|
|
3262
|
+
|
|
3263
|
+
@property
|
|
3264
|
+
def i_matrix(self) -> SocketLinker:
|
|
3265
|
+
"""Input socket: Matrix"""
|
|
3266
|
+
return self._input("Matrix")
|
|
3267
|
+
|
|
3268
|
+
@property
|
|
3269
|
+
def o_matrix(self) -> SocketLinker:
|
|
3270
|
+
"""Output socket: Matrix"""
|
|
3271
|
+
return self._output("Matrix")
|
|
3272
|
+
|
|
3273
|
+
@property
|
|
3274
|
+
def o_invertible(self) -> SocketLinker:
|
|
3275
|
+
"""Output socket: Invertible"""
|
|
3276
|
+
return self._output("Invertible")
|
|
3277
|
+
|
|
3278
|
+
|
|
3279
|
+
class InvertRotation(NodeBuilder):
|
|
3280
|
+
"""Compute the inverse of the given rotation"""
|
|
3281
|
+
|
|
3282
|
+
name = "FunctionNodeInvertRotation"
|
|
3283
|
+
node: bpy.types.FunctionNodeInvertRotation
|
|
3284
|
+
|
|
3285
|
+
def __init__(self, rotation: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0)):
|
|
3286
|
+
super().__init__()
|
|
3287
|
+
key_args = {"Rotation": rotation}
|
|
3288
|
+
self._establish_links(**key_args)
|
|
3289
|
+
|
|
3290
|
+
@property
|
|
3291
|
+
def i_rotation(self) -> SocketLinker:
|
|
3292
|
+
"""Input socket: Rotation"""
|
|
3293
|
+
return self._input("Rotation")
|
|
3294
|
+
|
|
3295
|
+
@property
|
|
3296
|
+
def o_rotation(self) -> SocketLinker:
|
|
3297
|
+
"""Output socket: Rotation"""
|
|
3298
|
+
return self._output("Rotation")
|
|
3299
|
+
|
|
3300
|
+
|
|
3301
|
+
class MatchString(NodeBuilder):
|
|
3302
|
+
"""Check if a given string exists within another string"""
|
|
3303
|
+
|
|
3304
|
+
name = "FunctionNodeMatchString"
|
|
3305
|
+
node: bpy.types.FunctionNodeMatchString
|
|
3306
|
+
|
|
3307
|
+
def __init__(
|
|
3308
|
+
self,
|
|
3309
|
+
string: TYPE_INPUT_STRING = "",
|
|
3310
|
+
operation: Literal["Starts With", "Ends With", "Contains"]
|
|
3311
|
+
| TYPE_INPUT_MENU = "Starts With",
|
|
3312
|
+
key: TYPE_INPUT_STRING = "",
|
|
3313
|
+
):
|
|
3314
|
+
super().__init__()
|
|
3315
|
+
key_args = {"String": string, "Operation": operation, "Key": key}
|
|
3316
|
+
self._establish_links(**key_args)
|
|
3317
|
+
|
|
3318
|
+
@property
|
|
3319
|
+
def i_string(self) -> SocketLinker:
|
|
3320
|
+
"""Input socket: String"""
|
|
3321
|
+
return self._input("String")
|
|
3322
|
+
|
|
3323
|
+
@property
|
|
3324
|
+
def i_operation(self) -> SocketLinker:
|
|
3325
|
+
"""Input socket: Operation"""
|
|
3326
|
+
return self._input("Operation")
|
|
3327
|
+
|
|
3328
|
+
@property
|
|
3329
|
+
def i_key(self) -> SocketLinker:
|
|
3330
|
+
"""Input socket: Key"""
|
|
3331
|
+
return self._input("Key")
|
|
3332
|
+
|
|
3333
|
+
@property
|
|
3334
|
+
def o_result(self) -> SocketLinker:
|
|
3335
|
+
"""Output socket: Result"""
|
|
3336
|
+
return self._output("Result")
|
|
3337
|
+
|
|
3338
|
+
|
|
3339
|
+
class MatrixDeterminant(NodeBuilder):
|
|
3340
|
+
"""Compute the determinant of the given matrix"""
|
|
3341
|
+
|
|
3342
|
+
name = "FunctionNodeMatrixDeterminant"
|
|
3343
|
+
node: bpy.types.FunctionNodeMatrixDeterminant
|
|
3344
|
+
|
|
3345
|
+
def __init__(self, matrix: TYPE_INPUT_MATRIX = None):
|
|
3346
|
+
super().__init__()
|
|
3347
|
+
key_args = {"Matrix": matrix}
|
|
3348
|
+
self._establish_links(**key_args)
|
|
3349
|
+
|
|
3350
|
+
@property
|
|
3351
|
+
def i_matrix(self) -> SocketLinker:
|
|
3352
|
+
"""Input socket: Matrix"""
|
|
3353
|
+
return self._input("Matrix")
|
|
3354
|
+
|
|
3355
|
+
@property
|
|
3356
|
+
def o_determinant(self) -> SocketLinker:
|
|
3357
|
+
"""Output socket: Determinant"""
|
|
3358
|
+
return self._output("Determinant")
|
|
3359
|
+
|
|
3360
|
+
|
|
3361
|
+
class MultiplyMatrices(NodeBuilder):
|
|
3362
|
+
"""Perform a matrix multiplication on two input matrices"""
|
|
3363
|
+
|
|
3364
|
+
name = "FunctionNodeMatrixMultiply"
|
|
3365
|
+
node: bpy.types.FunctionNodeMatrixMultiply
|
|
3366
|
+
|
|
3367
|
+
def __init__(
|
|
3368
|
+
self, matrix: TYPE_INPUT_MATRIX = None, matrix_001: TYPE_INPUT_MATRIX = None
|
|
3369
|
+
):
|
|
3370
|
+
super().__init__()
|
|
3371
|
+
key_args = {"Matrix": matrix, "Matrix_001": matrix_001}
|
|
3372
|
+
self._establish_links(**key_args)
|
|
3373
|
+
|
|
3374
|
+
@property
|
|
3375
|
+
def i_matrix(self) -> SocketLinker:
|
|
3376
|
+
"""Input socket: Matrix"""
|
|
3377
|
+
return self._input("Matrix")
|
|
3378
|
+
|
|
3379
|
+
@property
|
|
3380
|
+
def i_matrix_001(self) -> SocketLinker:
|
|
3381
|
+
"""Input socket: Matrix"""
|
|
3382
|
+
return self._input("Matrix_001")
|
|
3383
|
+
|
|
3384
|
+
@property
|
|
3385
|
+
def o_matrix(self) -> SocketLinker:
|
|
3386
|
+
"""Output socket: Matrix"""
|
|
3387
|
+
return self._output("Matrix")
|
|
3388
|
+
|
|
3389
|
+
|
|
3390
|
+
class ProjectPoint(NodeBuilder):
|
|
3391
|
+
"""Project a point using a matrix, using location, rotation, scale, and perspective divide"""
|
|
3392
|
+
|
|
3393
|
+
name = "FunctionNodeProjectPoint"
|
|
3394
|
+
node: bpy.types.FunctionNodeProjectPoint
|
|
3395
|
+
|
|
3396
|
+
def __init__(
|
|
3397
|
+
self,
|
|
3398
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
3399
|
+
transform: TYPE_INPUT_MATRIX = None,
|
|
3400
|
+
):
|
|
3401
|
+
super().__init__()
|
|
3402
|
+
key_args = {"Vector": vector, "Transform": transform}
|
|
3403
|
+
self._establish_links(**key_args)
|
|
3404
|
+
|
|
3405
|
+
@property
|
|
3406
|
+
def i_vector(self) -> SocketLinker:
|
|
3407
|
+
"""Input socket: Vector"""
|
|
3408
|
+
return self._input("Vector")
|
|
3409
|
+
|
|
3410
|
+
@property
|
|
3411
|
+
def i_transform(self) -> SocketLinker:
|
|
3412
|
+
"""Input socket: Transform"""
|
|
3413
|
+
return self._input("Transform")
|
|
3414
|
+
|
|
3415
|
+
@property
|
|
3416
|
+
def o_vector(self) -> SocketLinker:
|
|
3417
|
+
"""Output socket: Vector"""
|
|
3418
|
+
return self._output("Vector")
|
|
3419
|
+
|
|
3420
|
+
|
|
3421
|
+
class QuaternionToRotation(NodeBuilder):
|
|
3422
|
+
"""Build a rotation from quaternion components"""
|
|
3423
|
+
|
|
3424
|
+
name = "FunctionNodeQuaternionToRotation"
|
|
3425
|
+
node: bpy.types.FunctionNodeQuaternionToRotation
|
|
3426
|
+
|
|
3427
|
+
def __init__(
|
|
3428
|
+
self,
|
|
3429
|
+
w: TYPE_INPUT_VALUE = 1.0,
|
|
3430
|
+
x: TYPE_INPUT_VALUE = 0.0,
|
|
3431
|
+
y: TYPE_INPUT_VALUE = 0.0,
|
|
3432
|
+
z: TYPE_INPUT_VALUE = 0.0,
|
|
3433
|
+
):
|
|
3434
|
+
super().__init__()
|
|
3435
|
+
key_args = {"W": w, "X": x, "Y": y, "Z": z}
|
|
3436
|
+
self._establish_links(**key_args)
|
|
3437
|
+
|
|
3438
|
+
@property
|
|
3439
|
+
def i_w(self) -> SocketLinker:
|
|
3440
|
+
"""Input socket: W"""
|
|
3441
|
+
return self._input("W")
|
|
3442
|
+
|
|
3443
|
+
@property
|
|
3444
|
+
def i_x(self) -> SocketLinker:
|
|
3445
|
+
"""Input socket: X"""
|
|
3446
|
+
return self._input("X")
|
|
3447
|
+
|
|
3448
|
+
@property
|
|
3449
|
+
def i_y(self) -> SocketLinker:
|
|
3450
|
+
"""Input socket: Y"""
|
|
3451
|
+
return self._input("Y")
|
|
3452
|
+
|
|
3453
|
+
@property
|
|
3454
|
+
def i_z(self) -> SocketLinker:
|
|
3455
|
+
"""Input socket: Z"""
|
|
3456
|
+
return self._input("Z")
|
|
3457
|
+
|
|
3458
|
+
@property
|
|
3459
|
+
def o_rotation(self) -> SocketLinker:
|
|
3460
|
+
"""Output socket: Rotation"""
|
|
3461
|
+
return self._output("Rotation")
|
|
3462
|
+
|
|
3463
|
+
|
|
3464
|
+
class ReplaceString(NodeBuilder):
|
|
3465
|
+
"""Replace a given string segment with another"""
|
|
3466
|
+
|
|
3467
|
+
name = "FunctionNodeReplaceString"
|
|
3468
|
+
node: bpy.types.FunctionNodeReplaceString
|
|
3469
|
+
|
|
3470
|
+
def __init__(
|
|
3471
|
+
self,
|
|
3472
|
+
string: TYPE_INPUT_STRING = "",
|
|
3473
|
+
find: TYPE_INPUT_STRING = "",
|
|
3474
|
+
replace: TYPE_INPUT_STRING = "",
|
|
3475
|
+
):
|
|
3476
|
+
super().__init__()
|
|
3477
|
+
key_args = {"String": string, "Find": find, "Replace": replace}
|
|
3478
|
+
self._establish_links(**key_args)
|
|
3479
|
+
|
|
3480
|
+
@property
|
|
3481
|
+
def i_string(self) -> SocketLinker:
|
|
3482
|
+
"""Input socket: String"""
|
|
3483
|
+
return self._input("String")
|
|
3484
|
+
|
|
3485
|
+
@property
|
|
3486
|
+
def i_find(self) -> SocketLinker:
|
|
3487
|
+
"""Input socket: Find"""
|
|
3488
|
+
return self._input("Find")
|
|
3489
|
+
|
|
3490
|
+
@property
|
|
3491
|
+
def i_replace(self) -> SocketLinker:
|
|
3492
|
+
"""Input socket: Replace"""
|
|
3493
|
+
return self._input("Replace")
|
|
3494
|
+
|
|
3495
|
+
@property
|
|
3496
|
+
def o_string(self) -> SocketLinker:
|
|
3497
|
+
"""Output socket: String"""
|
|
3498
|
+
return self._output("String")
|
|
3499
|
+
|
|
3500
|
+
|
|
3501
|
+
class RotateEuler(NodeBuilder):
|
|
3502
|
+
"""Apply a secondary Euler rotation to a given Euler rotation"""
|
|
3503
|
+
|
|
3504
|
+
name = "FunctionNodeRotateEuler"
|
|
3505
|
+
node: bpy.types.FunctionNodeRotateEuler
|
|
3506
|
+
|
|
3507
|
+
def __init__(
|
|
3508
|
+
self,
|
|
3509
|
+
rotation: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0),
|
|
3510
|
+
rotate_by: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0),
|
|
3511
|
+
*,
|
|
3512
|
+
rotation_type: Literal["AXIS_ANGLE", "EULER"] = "EULER",
|
|
3513
|
+
space: Literal["OBJECT", "LOCAL"] = "OBJECT",
|
|
3514
|
+
):
|
|
3515
|
+
super().__init__()
|
|
3516
|
+
key_args = {"Rotation": rotation, "Rotate By": rotate_by}
|
|
3517
|
+
self.rotation_type = rotation_type
|
|
3518
|
+
self.space = space
|
|
3519
|
+
self._establish_links(**key_args)
|
|
3520
|
+
|
|
3521
|
+
@property
|
|
3522
|
+
def i_rotation(self) -> SocketLinker:
|
|
3523
|
+
"""Input socket: Rotation"""
|
|
3524
|
+
return self._input("Rotation")
|
|
3525
|
+
|
|
3526
|
+
@property
|
|
3527
|
+
def i_rotate_by(self) -> SocketLinker:
|
|
3528
|
+
"""Input socket: Rotate By"""
|
|
3529
|
+
return self._input("Rotate By")
|
|
3530
|
+
|
|
3531
|
+
@property
|
|
3532
|
+
def o_rotation(self) -> SocketLinker:
|
|
3533
|
+
"""Output socket: Rotation"""
|
|
3534
|
+
return self._output("Rotation")
|
|
3535
|
+
|
|
3536
|
+
@property
|
|
3537
|
+
def rotation_type(self) -> Literal["AXIS_ANGLE", "EULER"]:
|
|
3538
|
+
return self.node.rotation_type
|
|
3539
|
+
|
|
3540
|
+
@rotation_type.setter
|
|
3541
|
+
def rotation_type(self, value: Literal["AXIS_ANGLE", "EULER"]):
|
|
3542
|
+
self.node.rotation_type = value
|
|
3543
|
+
|
|
3544
|
+
@property
|
|
3545
|
+
def space(self) -> Literal["OBJECT", "LOCAL"]:
|
|
3546
|
+
return self.node.space
|
|
3547
|
+
|
|
3548
|
+
@space.setter
|
|
3549
|
+
def space(self, value: Literal["OBJECT", "LOCAL"]):
|
|
3550
|
+
self.node.space = value
|
|
3551
|
+
|
|
3552
|
+
|
|
3553
|
+
class RotateRotation(NodeBuilder):
|
|
3554
|
+
"""Apply a secondary rotation to a given rotation value"""
|
|
3555
|
+
|
|
3556
|
+
name = "FunctionNodeRotateRotation"
|
|
3557
|
+
node: bpy.types.FunctionNodeRotateRotation
|
|
3558
|
+
|
|
3559
|
+
def __init__(
|
|
3560
|
+
self,
|
|
3561
|
+
rotation: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0),
|
|
3562
|
+
rotate_by: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0),
|
|
3563
|
+
*,
|
|
3564
|
+
rotation_space: Literal["GLOBAL", "LOCAL"] = "GLOBAL",
|
|
3565
|
+
):
|
|
3566
|
+
super().__init__()
|
|
3567
|
+
key_args = {"Rotation": rotation, "Rotate By": rotate_by}
|
|
3568
|
+
self.rotation_space = rotation_space
|
|
3569
|
+
self._establish_links(**key_args)
|
|
3570
|
+
|
|
3571
|
+
@property
|
|
3572
|
+
def i_rotation(self) -> SocketLinker:
|
|
3573
|
+
"""Input socket: Rotation"""
|
|
3574
|
+
return self._input("Rotation")
|
|
3575
|
+
|
|
3576
|
+
@property
|
|
3577
|
+
def i_rotate_by(self) -> SocketLinker:
|
|
3578
|
+
"""Input socket: Rotate By"""
|
|
3579
|
+
return self._input("Rotate By")
|
|
3580
|
+
|
|
3581
|
+
@property
|
|
3582
|
+
def o_rotation(self) -> SocketLinker:
|
|
3583
|
+
"""Output socket: Rotation"""
|
|
3584
|
+
return self._output("Rotation")
|
|
3585
|
+
|
|
3586
|
+
@property
|
|
3587
|
+
def rotation_space(self) -> Literal["GLOBAL", "LOCAL"]:
|
|
3588
|
+
return self.node.rotation_space
|
|
3589
|
+
|
|
3590
|
+
@rotation_space.setter
|
|
3591
|
+
def rotation_space(self, value: Literal["GLOBAL", "LOCAL"]):
|
|
3592
|
+
self.node.rotation_space = value
|
|
3593
|
+
|
|
3594
|
+
|
|
3595
|
+
class RotateVector(NodeBuilder):
|
|
3596
|
+
"""Apply a rotation to a given vector"""
|
|
3597
|
+
|
|
3598
|
+
name = "FunctionNodeRotateVector"
|
|
3599
|
+
node: bpy.types.FunctionNodeRotateVector
|
|
3600
|
+
|
|
3601
|
+
def __init__(
|
|
3602
|
+
self,
|
|
3603
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
3604
|
+
rotation: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0),
|
|
3605
|
+
):
|
|
3606
|
+
super().__init__()
|
|
3607
|
+
key_args = {"Vector": vector, "Rotation": rotation}
|
|
3608
|
+
self._establish_links(**key_args)
|
|
3609
|
+
|
|
3610
|
+
@property
|
|
3611
|
+
def i_vector(self) -> SocketLinker:
|
|
3612
|
+
"""Input socket: Vector"""
|
|
3613
|
+
return self._input("Vector")
|
|
3614
|
+
|
|
3615
|
+
@property
|
|
3616
|
+
def i_rotation(self) -> SocketLinker:
|
|
3617
|
+
"""Input socket: Rotation"""
|
|
3618
|
+
return self._input("Rotation")
|
|
3619
|
+
|
|
3620
|
+
@property
|
|
3621
|
+
def o_vector(self) -> SocketLinker:
|
|
3622
|
+
"""Output socket: Vector"""
|
|
3623
|
+
return self._output("Vector")
|
|
3624
|
+
|
|
3625
|
+
|
|
3626
|
+
class RotationToAxisAngle(NodeBuilder):
|
|
3627
|
+
"""Convert a rotation to axis angle components"""
|
|
3628
|
+
|
|
3629
|
+
name = "FunctionNodeRotationToAxisAngle"
|
|
3630
|
+
node: bpy.types.FunctionNodeRotationToAxisAngle
|
|
3631
|
+
|
|
3632
|
+
def __init__(self, rotation: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0)):
|
|
3633
|
+
super().__init__()
|
|
3634
|
+
key_args = {"Rotation": rotation}
|
|
3635
|
+
self._establish_links(**key_args)
|
|
3636
|
+
|
|
3637
|
+
@property
|
|
3638
|
+
def i_rotation(self) -> SocketLinker:
|
|
3639
|
+
"""Input socket: Rotation"""
|
|
3640
|
+
return self._input("Rotation")
|
|
3641
|
+
|
|
3642
|
+
@property
|
|
3643
|
+
def o_axis(self) -> SocketLinker:
|
|
3644
|
+
"""Output socket: Axis"""
|
|
3645
|
+
return self._output("Axis")
|
|
3646
|
+
|
|
3647
|
+
@property
|
|
3648
|
+
def o_angle(self) -> SocketLinker:
|
|
3649
|
+
"""Output socket: Angle"""
|
|
3650
|
+
return self._output("Angle")
|
|
3651
|
+
|
|
3652
|
+
|
|
3653
|
+
class RotationToEuler(NodeBuilder):
|
|
3654
|
+
"""Convert a standard rotation value to an Euler rotation"""
|
|
3655
|
+
|
|
3656
|
+
name = "FunctionNodeRotationToEuler"
|
|
3657
|
+
node: bpy.types.FunctionNodeRotationToEuler
|
|
3658
|
+
|
|
3659
|
+
def __init__(self, rotation: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0)):
|
|
3660
|
+
super().__init__()
|
|
3661
|
+
key_args = {"Rotation": rotation}
|
|
3662
|
+
self._establish_links(**key_args)
|
|
3663
|
+
|
|
3664
|
+
@property
|
|
3665
|
+
def i_rotation(self) -> SocketLinker:
|
|
3666
|
+
"""Input socket: Rotation"""
|
|
3667
|
+
return self._input("Rotation")
|
|
3668
|
+
|
|
3669
|
+
@property
|
|
3670
|
+
def o_euler(self) -> SocketLinker:
|
|
3671
|
+
"""Output socket: Euler"""
|
|
3672
|
+
return self._output("Euler")
|
|
3673
|
+
|
|
3674
|
+
|
|
3675
|
+
class RotationToQuaternion(NodeBuilder):
|
|
3676
|
+
"""Retrieve the quaternion components representing a rotation"""
|
|
3677
|
+
|
|
3678
|
+
name = "FunctionNodeRotationToQuaternion"
|
|
3679
|
+
node: bpy.types.FunctionNodeRotationToQuaternion
|
|
3680
|
+
|
|
3681
|
+
def __init__(self, rotation: TYPE_INPUT_ROTATION = (0.0, 0.0, 0.0)):
|
|
3682
|
+
super().__init__()
|
|
3683
|
+
key_args = {"Rotation": rotation}
|
|
3684
|
+
self._establish_links(**key_args)
|
|
3685
|
+
|
|
3686
|
+
@property
|
|
3687
|
+
def i_rotation(self) -> SocketLinker:
|
|
3688
|
+
"""Input socket: Rotation"""
|
|
3689
|
+
return self._input("Rotation")
|
|
3690
|
+
|
|
3691
|
+
@property
|
|
3692
|
+
def o_w(self) -> SocketLinker:
|
|
3693
|
+
"""Output socket: W"""
|
|
3694
|
+
return self._output("W")
|
|
3695
|
+
|
|
3696
|
+
@property
|
|
3697
|
+
def o_x(self) -> SocketLinker:
|
|
3698
|
+
"""Output socket: X"""
|
|
3699
|
+
return self._output("X")
|
|
3700
|
+
|
|
3701
|
+
@property
|
|
3702
|
+
def o_y(self) -> SocketLinker:
|
|
3703
|
+
"""Output socket: Y"""
|
|
3704
|
+
return self._output("Y")
|
|
3705
|
+
|
|
3706
|
+
@property
|
|
3707
|
+
def o_z(self) -> SocketLinker:
|
|
3708
|
+
"""Output socket: Z"""
|
|
3709
|
+
return self._output("Z")
|
|
3710
|
+
|
|
3711
|
+
|
|
3712
|
+
class SeparateColor(NodeBuilder):
|
|
3713
|
+
"""Split a color into separate channels, based on a particular color model"""
|
|
3714
|
+
|
|
3715
|
+
name = "FunctionNodeSeparateColor"
|
|
3716
|
+
node: bpy.types.FunctionNodeSeparateColor
|
|
3717
|
+
|
|
3718
|
+
def __init__(
|
|
3719
|
+
self,
|
|
3720
|
+
color: TYPE_INPUT_COLOR = (
|
|
3721
|
+
1.0,
|
|
3722
|
+
1.0,
|
|
3723
|
+
1.0,
|
|
3724
|
+
1.0,
|
|
3725
|
+
),
|
|
3726
|
+
*,
|
|
3727
|
+
mode: Literal["RGB", "HSV", "HSL"] = "RGB",
|
|
3728
|
+
):
|
|
3729
|
+
super().__init__()
|
|
3730
|
+
key_args = {"Color": color}
|
|
3731
|
+
self.mode = mode
|
|
3732
|
+
self._establish_links(**key_args)
|
|
3733
|
+
|
|
3734
|
+
@property
|
|
3735
|
+
def i_color(self) -> SocketLinker:
|
|
3736
|
+
"""Input socket: Color"""
|
|
3737
|
+
return self._input("Color")
|
|
3738
|
+
|
|
3739
|
+
@property
|
|
3740
|
+
def o_red(self) -> SocketLinker:
|
|
3741
|
+
"""Output socket: Red"""
|
|
3742
|
+
return self._output("Red")
|
|
3743
|
+
|
|
3744
|
+
@property
|
|
3745
|
+
def o_green(self) -> SocketLinker:
|
|
3746
|
+
"""Output socket: Green"""
|
|
3747
|
+
return self._output("Green")
|
|
3748
|
+
|
|
3749
|
+
@property
|
|
3750
|
+
def o_blue(self) -> SocketLinker:
|
|
3751
|
+
"""Output socket: Blue"""
|
|
3752
|
+
return self._output("Blue")
|
|
3753
|
+
|
|
3754
|
+
@property
|
|
3755
|
+
def o_alpha(self) -> SocketLinker:
|
|
3756
|
+
"""Output socket: Alpha"""
|
|
3757
|
+
return self._output("Alpha")
|
|
3758
|
+
|
|
3759
|
+
@property
|
|
3760
|
+
def mode(self) -> Literal["RGB", "HSV", "HSL"]:
|
|
3761
|
+
return self.node.mode
|
|
3762
|
+
|
|
3763
|
+
@mode.setter
|
|
3764
|
+
def mode(self, value: Literal["RGB", "HSV", "HSL"]):
|
|
3765
|
+
self.node.mode = value
|
|
3766
|
+
|
|
3767
|
+
|
|
3768
|
+
class SeparateMatrix(NodeBuilder):
|
|
3769
|
+
"""Split a 4x4 matrix into its individual values"""
|
|
3770
|
+
|
|
3771
|
+
name = "FunctionNodeSeparateMatrix"
|
|
3772
|
+
node: bpy.types.FunctionNodeSeparateMatrix
|
|
3773
|
+
|
|
3774
|
+
def __init__(self, matrix: TYPE_INPUT_MATRIX = None):
|
|
3775
|
+
super().__init__()
|
|
3776
|
+
key_args = {"Matrix": matrix}
|
|
3777
|
+
self._establish_links(**key_args)
|
|
3778
|
+
|
|
3779
|
+
@property
|
|
3780
|
+
def i_matrix(self) -> SocketLinker:
|
|
3781
|
+
"""Input socket: Matrix"""
|
|
3782
|
+
return self._input("Matrix")
|
|
3783
|
+
|
|
3784
|
+
@property
|
|
3785
|
+
def o_column_1_row_1(self) -> SocketLinker:
|
|
3786
|
+
"""Output socket: Column 1 Row 1"""
|
|
3787
|
+
return self._output("Column 1 Row 1")
|
|
3788
|
+
|
|
3789
|
+
@property
|
|
3790
|
+
def o_column_1_row_2(self) -> SocketLinker:
|
|
3791
|
+
"""Output socket: Column 1 Row 2"""
|
|
3792
|
+
return self._output("Column 1 Row 2")
|
|
3793
|
+
|
|
3794
|
+
@property
|
|
3795
|
+
def o_column_1_row_3(self) -> SocketLinker:
|
|
3796
|
+
"""Output socket: Column 1 Row 3"""
|
|
3797
|
+
return self._output("Column 1 Row 3")
|
|
3798
|
+
|
|
3799
|
+
@property
|
|
3800
|
+
def o_column_1_row_4(self) -> SocketLinker:
|
|
3801
|
+
"""Output socket: Column 1 Row 4"""
|
|
3802
|
+
return self._output("Column 1 Row 4")
|
|
3803
|
+
|
|
3804
|
+
@property
|
|
3805
|
+
def o_column_2_row_1(self) -> SocketLinker:
|
|
3806
|
+
"""Output socket: Column 2 Row 1"""
|
|
3807
|
+
return self._output("Column 2 Row 1")
|
|
3808
|
+
|
|
3809
|
+
@property
|
|
3810
|
+
def o_column_2_row_2(self) -> SocketLinker:
|
|
3811
|
+
"""Output socket: Column 2 Row 2"""
|
|
3812
|
+
return self._output("Column 2 Row 2")
|
|
3813
|
+
|
|
3814
|
+
@property
|
|
3815
|
+
def o_column_2_row_3(self) -> SocketLinker:
|
|
3816
|
+
"""Output socket: Column 2 Row 3"""
|
|
3817
|
+
return self._output("Column 2 Row 3")
|
|
3818
|
+
|
|
3819
|
+
@property
|
|
3820
|
+
def o_column_2_row_4(self) -> SocketLinker:
|
|
3821
|
+
"""Output socket: Column 2 Row 4"""
|
|
3822
|
+
return self._output("Column 2 Row 4")
|
|
3823
|
+
|
|
3824
|
+
@property
|
|
3825
|
+
def o_column_3_row_1(self) -> SocketLinker:
|
|
3826
|
+
"""Output socket: Column 3 Row 1"""
|
|
3827
|
+
return self._output("Column 3 Row 1")
|
|
3828
|
+
|
|
3829
|
+
@property
|
|
3830
|
+
def o_column_3_row_2(self) -> SocketLinker:
|
|
3831
|
+
"""Output socket: Column 3 Row 2"""
|
|
3832
|
+
return self._output("Column 3 Row 2")
|
|
3833
|
+
|
|
3834
|
+
@property
|
|
3835
|
+
def o_column_3_row_3(self) -> SocketLinker:
|
|
3836
|
+
"""Output socket: Column 3 Row 3"""
|
|
3837
|
+
return self._output("Column 3 Row 3")
|
|
3838
|
+
|
|
3839
|
+
@property
|
|
3840
|
+
def o_column_3_row_4(self) -> SocketLinker:
|
|
3841
|
+
"""Output socket: Column 3 Row 4"""
|
|
3842
|
+
return self._output("Column 3 Row 4")
|
|
3843
|
+
|
|
3844
|
+
@property
|
|
3845
|
+
def o_column_4_row_1(self) -> SocketLinker:
|
|
3846
|
+
"""Output socket: Column 4 Row 1"""
|
|
3847
|
+
return self._output("Column 4 Row 1")
|
|
3848
|
+
|
|
3849
|
+
@property
|
|
3850
|
+
def o_column_4_row_2(self) -> SocketLinker:
|
|
3851
|
+
"""Output socket: Column 4 Row 2"""
|
|
3852
|
+
return self._output("Column 4 Row 2")
|
|
3853
|
+
|
|
3854
|
+
@property
|
|
3855
|
+
def o_column_4_row_3(self) -> SocketLinker:
|
|
3856
|
+
"""Output socket: Column 4 Row 3"""
|
|
3857
|
+
return self._output("Column 4 Row 3")
|
|
3858
|
+
|
|
3859
|
+
@property
|
|
3860
|
+
def o_column_4_row_4(self) -> SocketLinker:
|
|
3861
|
+
"""Output socket: Column 4 Row 4"""
|
|
3862
|
+
return self._output("Column 4 Row 4")
|
|
3863
|
+
|
|
3864
|
+
|
|
3865
|
+
class SeparateTransform(NodeBuilder):
|
|
3866
|
+
"""Split a transformation matrix into a translation vector, a rotation, and a scale vector"""
|
|
3867
|
+
|
|
3868
|
+
name = "FunctionNodeSeparateTransform"
|
|
3869
|
+
node: bpy.types.FunctionNodeSeparateTransform
|
|
3870
|
+
|
|
3871
|
+
def __init__(self, transform: TYPE_INPUT_MATRIX = None):
|
|
3872
|
+
super().__init__()
|
|
3873
|
+
key_args = {"Transform": transform}
|
|
3874
|
+
self._establish_links(**key_args)
|
|
3875
|
+
|
|
3876
|
+
@property
|
|
3877
|
+
def i_transform(self) -> SocketLinker:
|
|
3878
|
+
"""Input socket: Transform"""
|
|
3879
|
+
return self._input("Transform")
|
|
3880
|
+
|
|
3881
|
+
@property
|
|
3882
|
+
def o_translation(self) -> SocketLinker:
|
|
3883
|
+
"""Output socket: Translation"""
|
|
3884
|
+
return self._output("Translation")
|
|
3885
|
+
|
|
3886
|
+
@property
|
|
3887
|
+
def o_rotation(self) -> SocketLinker:
|
|
3888
|
+
"""Output socket: Rotation"""
|
|
3889
|
+
return self._output("Rotation")
|
|
3890
|
+
|
|
3891
|
+
@property
|
|
3892
|
+
def o_scale(self) -> SocketLinker:
|
|
3893
|
+
"""Output socket: Scale"""
|
|
3894
|
+
return self._output("Scale")
|
|
3895
|
+
|
|
3896
|
+
|
|
3897
|
+
class SliceString(NodeBuilder):
|
|
3898
|
+
"""Extract a string segment from a larger string"""
|
|
3899
|
+
|
|
3900
|
+
name = "FunctionNodeSliceString"
|
|
3901
|
+
node: bpy.types.FunctionNodeSliceString
|
|
3902
|
+
|
|
3903
|
+
def __init__(
|
|
3904
|
+
self,
|
|
3905
|
+
string: TYPE_INPUT_STRING = "",
|
|
3906
|
+
position: TYPE_INPUT_INT = 0,
|
|
3907
|
+
length: TYPE_INPUT_INT = 10,
|
|
3908
|
+
):
|
|
3909
|
+
super().__init__()
|
|
3910
|
+
key_args = {"String": string, "Position": position, "Length": length}
|
|
3911
|
+
self._establish_links(**key_args)
|
|
3912
|
+
|
|
3913
|
+
@property
|
|
3914
|
+
def i_string(self) -> SocketLinker:
|
|
3915
|
+
"""Input socket: String"""
|
|
3916
|
+
return self._input("String")
|
|
3917
|
+
|
|
3918
|
+
@property
|
|
3919
|
+
def i_position(self) -> SocketLinker:
|
|
3920
|
+
"""Input socket: Position"""
|
|
3921
|
+
return self._input("Position")
|
|
3922
|
+
|
|
3923
|
+
@property
|
|
3924
|
+
def i_length(self) -> SocketLinker:
|
|
3925
|
+
"""Input socket: Length"""
|
|
3926
|
+
return self._input("Length")
|
|
3927
|
+
|
|
3928
|
+
@property
|
|
3929
|
+
def o_string(self) -> SocketLinker:
|
|
3930
|
+
"""Output socket: String"""
|
|
3931
|
+
return self._output("String")
|
|
3932
|
+
|
|
3933
|
+
|
|
3934
|
+
class StringLength(NodeBuilder):
|
|
3935
|
+
"""Output the number of characters in the given string"""
|
|
3936
|
+
|
|
3937
|
+
name = "FunctionNodeStringLength"
|
|
3938
|
+
node: bpy.types.FunctionNodeStringLength
|
|
3939
|
+
|
|
3940
|
+
def __init__(self, string: TYPE_INPUT_STRING = ""):
|
|
3941
|
+
super().__init__()
|
|
3942
|
+
key_args = {"String": string}
|
|
3943
|
+
self._establish_links(**key_args)
|
|
3944
|
+
|
|
3945
|
+
@property
|
|
3946
|
+
def i_string(self) -> SocketLinker:
|
|
3947
|
+
"""Input socket: String"""
|
|
3948
|
+
return self._input("String")
|
|
3949
|
+
|
|
3950
|
+
@property
|
|
3951
|
+
def o_length(self) -> SocketLinker:
|
|
3952
|
+
"""Output socket: Length"""
|
|
3953
|
+
return self._output("Length")
|
|
3954
|
+
|
|
3955
|
+
|
|
3956
|
+
class StringToValue(NodeBuilder):
|
|
3957
|
+
"""Derive a numeric value from a given string representation"""
|
|
3958
|
+
|
|
3959
|
+
name = "FunctionNodeStringToValue"
|
|
3960
|
+
node: bpy.types.FunctionNodeStringToValue
|
|
3961
|
+
|
|
3962
|
+
def __init__(
|
|
3963
|
+
self,
|
|
3964
|
+
string: TYPE_INPUT_STRING = "",
|
|
3965
|
+
*,
|
|
3966
|
+
data_type: Literal["FLOAT", "INT"] = "FLOAT",
|
|
3967
|
+
):
|
|
3968
|
+
super().__init__()
|
|
3969
|
+
key_args = {"String": string}
|
|
3970
|
+
self.data_type = data_type
|
|
3971
|
+
self._establish_links(**key_args)
|
|
3972
|
+
|
|
3973
|
+
@property
|
|
3974
|
+
def i_string(self) -> SocketLinker:
|
|
3975
|
+
"""Input socket: String"""
|
|
3976
|
+
return self._input("String")
|
|
3977
|
+
|
|
3978
|
+
@property
|
|
3979
|
+
def o_value(self) -> SocketLinker:
|
|
3980
|
+
"""Output socket: Value"""
|
|
3981
|
+
return self._output("Value")
|
|
3982
|
+
|
|
3983
|
+
@property
|
|
3984
|
+
def o_length(self) -> SocketLinker:
|
|
3985
|
+
"""Output socket: Length"""
|
|
3986
|
+
return self._output("Length")
|
|
3987
|
+
|
|
3988
|
+
@property
|
|
3989
|
+
def data_type(self) -> Literal["FLOAT", "INT"]:
|
|
3990
|
+
return self.node.data_type
|
|
3991
|
+
|
|
3992
|
+
@data_type.setter
|
|
3993
|
+
def data_type(self, value: Literal["FLOAT", "INT"]):
|
|
3994
|
+
self.node.data_type = value
|
|
3995
|
+
|
|
3996
|
+
|
|
3997
|
+
class TransformDirection(NodeBuilder):
|
|
3998
|
+
"""Apply a transformation matrix (excluding translation) to the given vector"""
|
|
3999
|
+
|
|
4000
|
+
name = "FunctionNodeTransformDirection"
|
|
4001
|
+
node: bpy.types.FunctionNodeTransformDirection
|
|
4002
|
+
|
|
4003
|
+
def __init__(
|
|
4004
|
+
self,
|
|
4005
|
+
direction: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
4006
|
+
transform: TYPE_INPUT_MATRIX = None,
|
|
4007
|
+
):
|
|
4008
|
+
super().__init__()
|
|
4009
|
+
key_args = {"Direction": direction, "Transform": transform}
|
|
4010
|
+
self._establish_links(**key_args)
|
|
4011
|
+
|
|
4012
|
+
@property
|
|
4013
|
+
def i_direction(self) -> SocketLinker:
|
|
4014
|
+
"""Input socket: Direction"""
|
|
4015
|
+
return self._input("Direction")
|
|
4016
|
+
|
|
4017
|
+
@property
|
|
4018
|
+
def i_transform(self) -> SocketLinker:
|
|
4019
|
+
"""Input socket: Transform"""
|
|
4020
|
+
return self._input("Transform")
|
|
4021
|
+
|
|
4022
|
+
@property
|
|
4023
|
+
def o_direction(self) -> SocketLinker:
|
|
4024
|
+
"""Output socket: Direction"""
|
|
4025
|
+
return self._output("Direction")
|
|
4026
|
+
|
|
4027
|
+
|
|
4028
|
+
class TransformPoint(NodeBuilder):
|
|
4029
|
+
"""Apply a transformation matrix to the given vector"""
|
|
4030
|
+
|
|
4031
|
+
name = "FunctionNodeTransformPoint"
|
|
4032
|
+
node: bpy.types.FunctionNodeTransformPoint
|
|
4033
|
+
|
|
4034
|
+
def __init__(
|
|
4035
|
+
self,
|
|
4036
|
+
vector: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
4037
|
+
transform: TYPE_INPUT_MATRIX = None,
|
|
4038
|
+
):
|
|
4039
|
+
super().__init__()
|
|
4040
|
+
key_args = {"Vector": vector, "Transform": transform}
|
|
4041
|
+
self._establish_links(**key_args)
|
|
4042
|
+
|
|
4043
|
+
@property
|
|
4044
|
+
def i_vector(self) -> SocketLinker:
|
|
4045
|
+
"""Input socket: Vector"""
|
|
4046
|
+
return self._input("Vector")
|
|
4047
|
+
|
|
4048
|
+
@property
|
|
4049
|
+
def i_transform(self) -> SocketLinker:
|
|
4050
|
+
"""Input socket: Transform"""
|
|
4051
|
+
return self._input("Transform")
|
|
4052
|
+
|
|
4053
|
+
@property
|
|
4054
|
+
def o_vector(self) -> SocketLinker:
|
|
4055
|
+
"""Output socket: Vector"""
|
|
4056
|
+
return self._output("Vector")
|
|
4057
|
+
|
|
4058
|
+
|
|
4059
|
+
class TransposeMatrix(NodeBuilder):
|
|
4060
|
+
"""Flip a matrix over its diagonal, turning columns into rows and vice-versa"""
|
|
4061
|
+
|
|
4062
|
+
name = "FunctionNodeTransposeMatrix"
|
|
4063
|
+
node: bpy.types.FunctionNodeTransposeMatrix
|
|
4064
|
+
|
|
4065
|
+
def __init__(self, matrix: TYPE_INPUT_MATRIX = None):
|
|
4066
|
+
super().__init__()
|
|
4067
|
+
key_args = {"Matrix": matrix}
|
|
4068
|
+
self._establish_links(**key_args)
|
|
4069
|
+
|
|
4070
|
+
@property
|
|
4071
|
+
def i_matrix(self) -> SocketLinker:
|
|
4072
|
+
"""Input socket: Matrix"""
|
|
4073
|
+
return self._input("Matrix")
|
|
4074
|
+
|
|
4075
|
+
@property
|
|
4076
|
+
def o_matrix(self) -> SocketLinker:
|
|
4077
|
+
"""Output socket: Matrix"""
|
|
4078
|
+
return self._output("Matrix")
|
|
4079
|
+
|
|
4080
|
+
|
|
4081
|
+
class ValueToString(NodeBuilder):
|
|
4082
|
+
"""Generate a string representation of the given input value"""
|
|
4083
|
+
|
|
4084
|
+
name = "FunctionNodeValueToString"
|
|
4085
|
+
node: bpy.types.FunctionNodeValueToString
|
|
4086
|
+
|
|
4087
|
+
def __init__(
|
|
4088
|
+
self,
|
|
4089
|
+
value: TYPE_INPUT_VALUE = 0.0,
|
|
4090
|
+
decimals: TYPE_INPUT_INT = 0,
|
|
4091
|
+
*,
|
|
4092
|
+
data_type: Literal["FLOAT", "INT"] = "FLOAT",
|
|
4093
|
+
):
|
|
4094
|
+
super().__init__()
|
|
4095
|
+
key_args = {"Value": value, "Decimals": decimals}
|
|
4096
|
+
self.data_type = data_type
|
|
4097
|
+
self._establish_links(**key_args)
|
|
4098
|
+
|
|
4099
|
+
@property
|
|
4100
|
+
def i_value(self) -> SocketLinker:
|
|
4101
|
+
"""Input socket: Value"""
|
|
4102
|
+
return self._input("Value")
|
|
4103
|
+
|
|
4104
|
+
@property
|
|
4105
|
+
def i_decimals(self) -> SocketLinker:
|
|
4106
|
+
"""Input socket: Decimals"""
|
|
4107
|
+
return self._input("Decimals")
|
|
4108
|
+
|
|
4109
|
+
@property
|
|
4110
|
+
def o_string(self) -> SocketLinker:
|
|
4111
|
+
"""Output socket: String"""
|
|
4112
|
+
return self._output("String")
|
|
4113
|
+
|
|
4114
|
+
@property
|
|
4115
|
+
def data_type(self) -> Literal["FLOAT", "INT"]:
|
|
4116
|
+
return self.node.data_type
|
|
4117
|
+
|
|
4118
|
+
@data_type.setter
|
|
4119
|
+
def data_type(self, value: Literal["FLOAT", "INT"]):
|
|
4120
|
+
self.node.data_type = value
|
|
4121
|
+
|
|
4122
|
+
|
|
4123
|
+
class Clamp(NodeBuilder):
|
|
4124
|
+
"""Clamp a value between a minimum and a maximum"""
|
|
4125
|
+
|
|
4126
|
+
name = "ShaderNodeClamp"
|
|
4127
|
+
node: bpy.types.ShaderNodeClamp
|
|
4128
|
+
|
|
4129
|
+
def __init__(
|
|
4130
|
+
self,
|
|
4131
|
+
value: TYPE_INPUT_VALUE = 1.0,
|
|
4132
|
+
min: TYPE_INPUT_VALUE = 0.0,
|
|
4133
|
+
max: TYPE_INPUT_VALUE = 1.0,
|
|
4134
|
+
*,
|
|
4135
|
+
clamp_type: Literal["MINMAX", "RANGE"] = "MINMAX",
|
|
4136
|
+
):
|
|
4137
|
+
super().__init__()
|
|
4138
|
+
key_args = {"Value": value, "Min": min, "Max": max}
|
|
4139
|
+
self.clamp_type = clamp_type
|
|
4140
|
+
self._establish_links(**key_args)
|
|
4141
|
+
|
|
4142
|
+
@property
|
|
4143
|
+
def i_value(self) -> SocketLinker:
|
|
4144
|
+
"""Input socket: Value"""
|
|
4145
|
+
return self._input("Value")
|
|
4146
|
+
|
|
4147
|
+
@property
|
|
4148
|
+
def i_min(self) -> SocketLinker:
|
|
4149
|
+
"""Input socket: Min"""
|
|
4150
|
+
return self._input("Min")
|
|
4151
|
+
|
|
4152
|
+
@property
|
|
4153
|
+
def i_max(self) -> SocketLinker:
|
|
4154
|
+
"""Input socket: Max"""
|
|
4155
|
+
return self._input("Max")
|
|
4156
|
+
|
|
4157
|
+
@property
|
|
4158
|
+
def o_result(self) -> SocketLinker:
|
|
4159
|
+
"""Output socket: Result"""
|
|
4160
|
+
return self._output("Result")
|
|
4161
|
+
|
|
4162
|
+
@property
|
|
4163
|
+
def clamp_type(self) -> Literal["MINMAX", "RANGE"]:
|
|
4164
|
+
return self.node.clamp_type
|
|
4165
|
+
|
|
4166
|
+
@clamp_type.setter
|
|
4167
|
+
def clamp_type(self, value: Literal["MINMAX", "RANGE"]):
|
|
4168
|
+
self.node.clamp_type = value
|
|
4169
|
+
|
|
4170
|
+
|
|
4171
|
+
class MapRange(NodeBuilder):
|
|
4172
|
+
"""Remap a value from a range to a target range"""
|
|
4173
|
+
|
|
4174
|
+
name = "ShaderNodeMapRange"
|
|
4175
|
+
node: bpy.types.ShaderNodeMapRange
|
|
4176
|
+
|
|
4177
|
+
def __init__(
|
|
4178
|
+
self,
|
|
4179
|
+
*,
|
|
4180
|
+
interpolation_type: Literal[
|
|
4181
|
+
"LINEAR", "STEPPED", "SMOOTHSTEP", "SMOOTHERSTEP"
|
|
4182
|
+
] = "LINEAR",
|
|
4183
|
+
data_type: Literal["FLOAT", "FLOAT_VECTOR"] = "FLOAT",
|
|
4184
|
+
clamp: bool = False,
|
|
4185
|
+
**kwargs,
|
|
4186
|
+
):
|
|
4187
|
+
super().__init__()
|
|
4188
|
+
key_args = {}
|
|
4189
|
+
key_args.update(kwargs)
|
|
4190
|
+
self.clamp = clamp
|
|
4191
|
+
self.interpolation_type = interpolation_type
|
|
4192
|
+
self.data_type = data_type
|
|
4193
|
+
self._establish_links(**key_args)
|
|
4194
|
+
|
|
4195
|
+
@classmethod
|
|
4196
|
+
def float(
|
|
4197
|
+
cls,
|
|
4198
|
+
value: TYPE_INPUT_VALUE = 1.0,
|
|
4199
|
+
from_min: TYPE_INPUT_VALUE = 0.0,
|
|
4200
|
+
from_max: TYPE_INPUT_VALUE = 1.0,
|
|
4201
|
+
to_min: TYPE_INPUT_VALUE = 0.0,
|
|
4202
|
+
to_max: TYPE_INPUT_VALUE = 1.0,
|
|
4203
|
+
steps: TYPE_INPUT_VALUE = 1.0,
|
|
4204
|
+
*,
|
|
4205
|
+
interpolation_type: Literal[
|
|
4206
|
+
"LINEAR", "STEPPED", "SMOOTHSTEP", "SMOOTHERSTEP"
|
|
4207
|
+
] = "LINEAR",
|
|
4208
|
+
clamp: bool = False,
|
|
4209
|
+
**kwargs,
|
|
4210
|
+
):
|
|
4211
|
+
key_args = {
|
|
4212
|
+
"Value": value,
|
|
4213
|
+
"From Min": from_min,
|
|
4214
|
+
"From Max": from_max,
|
|
4215
|
+
"To Min": to_min,
|
|
4216
|
+
"To Max": to_max,
|
|
4217
|
+
"Steps": steps,
|
|
4218
|
+
}
|
|
4219
|
+
return cls(
|
|
4220
|
+
**key_args,
|
|
4221
|
+
interpolation_type=interpolation_type,
|
|
4222
|
+
data_type="FLOAT",
|
|
4223
|
+
clamp=clamp,
|
|
4224
|
+
)
|
|
4225
|
+
|
|
4226
|
+
@classmethod
|
|
4227
|
+
def vector(
|
|
4228
|
+
cls,
|
|
4229
|
+
value: TYPE_INPUT_VECTOR = (1.0, 1.0, 1.0),
|
|
4230
|
+
from_min: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
4231
|
+
from_max: TYPE_INPUT_VECTOR = (1.0, 1.0, 1.0),
|
|
4232
|
+
to_min: TYPE_INPUT_VECTOR = (0.0, 0.0, 0.0),
|
|
4233
|
+
to_max: TYPE_INPUT_VECTOR = (1.0, 1.0, 1.0),
|
|
4234
|
+
steps: TYPE_INPUT_VECTOR = (1.0, 1.0, 1.0),
|
|
4235
|
+
*,
|
|
4236
|
+
interpolation_type: Literal[
|
|
4237
|
+
"LINEAR", "STEPPED", "SMOOTHSTEP", "SMOOTHERSTEP"
|
|
4238
|
+
] = "LINEAR",
|
|
4239
|
+
clamp: bool = False,
|
|
4240
|
+
):
|
|
4241
|
+
key_args = {
|
|
4242
|
+
"Vector": value,
|
|
4243
|
+
"From_Min_FLOAT3": from_min,
|
|
4244
|
+
"From_Max_FLOAT3": from_max,
|
|
4245
|
+
"To_Min_FLOAT3": to_min,
|
|
4246
|
+
"To_Max_FLOAT3": to_max,
|
|
4247
|
+
"Steps_FLOAT3": steps,
|
|
4248
|
+
}
|
|
4249
|
+
return cls(
|
|
4250
|
+
**key_args,
|
|
4251
|
+
data_type="FLOAT_VECTOR",
|
|
4252
|
+
interpolation_type=interpolation_type,
|
|
4253
|
+
clamp=clamp,
|
|
4254
|
+
)
|
|
4255
|
+
|
|
4256
|
+
@property
|
|
4257
|
+
def i_value(self) -> SocketLinker:
|
|
4258
|
+
"""Input socket: Value"""
|
|
4259
|
+
return self._input("Value" if self.data_type == "FLOAT" else "Vector")
|
|
4260
|
+
|
|
4261
|
+
@property
|
|
4262
|
+
def i_from_min(self) -> SocketLinker:
|
|
4263
|
+
"""Input socket: From Min"""
|
|
4264
|
+
return self._input(
|
|
4265
|
+
"From Min" if self.data_type == "FLOAT" else "From_Min_FLOAT3"
|
|
4266
|
+
)
|
|
4267
|
+
|
|
4268
|
+
@property
|
|
4269
|
+
def i_from_max(self) -> SocketLinker:
|
|
4270
|
+
"""Input socket: From Max"""
|
|
4271
|
+
return self._input(
|
|
4272
|
+
"From Max" if self.data_type == "FLOAT" else "From_Max_FLOAT3"
|
|
4273
|
+
)
|
|
4274
|
+
|
|
4275
|
+
@property
|
|
4276
|
+
def i_to_min(self) -> SocketLinker:
|
|
4277
|
+
"""Input socket: To Min"""
|
|
4278
|
+
return self._input("To Min" if self.data_type == "FLOAT" else "To_Min_FLOAT3")
|
|
4279
|
+
|
|
4280
|
+
@property
|
|
4281
|
+
def i_to_max(self) -> SocketLinker:
|
|
4282
|
+
"""Input socket: To Max"""
|
|
4283
|
+
return self._input("To Max" if self.data_type == "FLOAT" else "To_Max_FLOAT3")
|
|
4284
|
+
|
|
4285
|
+
@property
|
|
4286
|
+
def i_steps(self) -> SocketLinker:
|
|
4287
|
+
"""Input socket: Steps"""
|
|
4288
|
+
return self._input("Steps" if self.data_type == "FLOAT" else "Steps_FLOAT3")
|
|
4289
|
+
|
|
4290
|
+
@property
|
|
4291
|
+
def o_result(self) -> SocketLinker:
|
|
4292
|
+
"""Output socket: Result"""
|
|
4293
|
+
return self._output("Result" if self.data_type == "FLOAT" else "Vector")
|
|
4294
|
+
|
|
4295
|
+
@property
|
|
4296
|
+
def clamp(self) -> bool:
|
|
4297
|
+
return self.node.clamp
|
|
4298
|
+
|
|
4299
|
+
@clamp.setter
|
|
4300
|
+
def clamp(self, value: bool):
|
|
4301
|
+
self.node.clamp = value
|
|
4302
|
+
|
|
4303
|
+
@property
|
|
4304
|
+
def interpolation_type(
|
|
4305
|
+
self,
|
|
4306
|
+
) -> Literal["LINEAR", "STEPPED", "SMOOTHSTEP", "SMOOTHERSTEP"]:
|
|
4307
|
+
return self.node.interpolation_type
|
|
4308
|
+
|
|
4309
|
+
@interpolation_type.setter
|
|
4310
|
+
def interpolation_type(
|
|
4311
|
+
self, value: Literal["LINEAR", "STEPPED", "SMOOTHSTEP", "SMOOTHERSTEP"]
|
|
4312
|
+
):
|
|
4313
|
+
self.node.interpolation_type = value
|
|
4314
|
+
|
|
4315
|
+
@property
|
|
4316
|
+
def data_type(self) -> Literal["FLOAT", "FLOAT_VECTOR"]:
|
|
4317
|
+
return self.node.data_type
|
|
4318
|
+
|
|
4319
|
+
@data_type.setter
|
|
4320
|
+
def data_type(self, value: Literal["FLOAT", "FLOAT_VECTOR"]):
|
|
4321
|
+
self.node.data_type = value
|
|
4322
|
+
|
|
4323
|
+
|
|
4324
|
+
def _typed_index_switch(data_type: SOCKET_TYPES):
|
|
4325
|
+
@classmethod
|
|
4326
|
+
def method(cls, *args: TYPE_INPUT_ALL, index: TYPE_INPUT_INT = 0) -> "IndexSwitch":
|
|
4327
|
+
"""Create an IndexSwitch node with a pre-set data_type"""
|
|
4328
|
+
return cls(*args, index=index, data_type=data_type)
|
|
4329
|
+
|
|
4330
|
+
return method
|
|
4331
|
+
|
|
4332
|
+
|
|
4333
|
+
class IndexSwitch(NodeBuilder):
|
|
4334
|
+
"""Node builder for the Index Switch node"""
|
|
4335
|
+
|
|
4336
|
+
name = "GeometryNodeIndexSwitch"
|
|
4337
|
+
node: bpy.types.GeometryNodeIndexSwitch
|
|
4338
|
+
float = _typed_index_switch("FLOAT")
|
|
4339
|
+
integer = _typed_index_switch("INT")
|
|
4340
|
+
boolean = _typed_index_switch("BOOLEAN")
|
|
4341
|
+
vector = _typed_index_switch("VECTOR")
|
|
4342
|
+
color = _typed_index_switch("RGBA")
|
|
4343
|
+
rotation = _typed_index_switch("ROTATION")
|
|
4344
|
+
matrix = _typed_index_switch("MATRIX")
|
|
4345
|
+
string = _typed_index_switch("STRING")
|
|
4346
|
+
menu = _typed_index_switch("MENU")
|
|
4347
|
+
object = _typed_index_switch("OBJECT")
|
|
4348
|
+
geometry = _typed_index_switch("GEOMETRY")
|
|
4349
|
+
collection = _typed_index_switch("COLLECTION")
|
|
4350
|
+
image = _typed_index_switch("IMAGE")
|
|
4351
|
+
material = _typed_index_switch("MATERIAL")
|
|
4352
|
+
bundle = _typed_index_switch("BUNDLE")
|
|
4353
|
+
closure = _typed_index_switch("CLOSURE")
|
|
4354
|
+
|
|
4355
|
+
def __init__(
|
|
4356
|
+
self,
|
|
4357
|
+
*args: TYPE_INPUT_ALL,
|
|
4358
|
+
index: TYPE_INPUT_INT = 0,
|
|
4359
|
+
data_type: SOCKET_TYPES = "FLOAT",
|
|
4360
|
+
):
|
|
4361
|
+
super().__init__()
|
|
4362
|
+
self.data_type = data_type
|
|
4363
|
+
key_args: dict[str, TYPE_INPUT_ALL] = {"Index": index}
|
|
4364
|
+
self.node.index_switch_items.clear()
|
|
4365
|
+
self._link_args(*args)
|
|
4366
|
+
self._establish_links(**key_args)
|
|
4367
|
+
|
|
4368
|
+
def _create_socket(self) -> NodeSocket:
|
|
4369
|
+
item = self.node.index_switch_items.new()
|
|
4370
|
+
return self.node.inputs[item.identifier]
|
|
4371
|
+
|
|
4372
|
+
def _link_args(self, *args: TYPE_INPUT_ALL):
|
|
4373
|
+
for arg in args:
|
|
4374
|
+
if _is_default_value(arg):
|
|
4375
|
+
socket = self._create_socket()
|
|
4376
|
+
socket.default_value = arg
|
|
4377
|
+
else:
|
|
4378
|
+
source = self._source_socket(arg)
|
|
4379
|
+
self.tree.link(source, self.node.inputs["__extend__"])
|
|
4380
|
+
|
|
4381
|
+
@property
|
|
4382
|
+
def inputs(self) -> list[SocketLinker]:
|
|
4383
|
+
"""Input sockets"""
|
|
4384
|
+
return [
|
|
4385
|
+
SocketLinker(self.node.inputs[i + 1])
|
|
4386
|
+
for i in range(len(self.node.index_switch_items))
|
|
4387
|
+
]
|
|
4388
|
+
|
|
4389
|
+
@property
|
|
4390
|
+
def i_index(self) -> SocketLinker:
|
|
4391
|
+
"""Input socket: Index"""
|
|
4392
|
+
return self._input("Index")
|
|
4393
|
+
|
|
4394
|
+
@property
|
|
4395
|
+
def o_output(self) -> SocketLinker:
|
|
4396
|
+
"""Output socket: Output"""
|
|
4397
|
+
return self._output("Output")
|
|
4398
|
+
|
|
4399
|
+
@property
|
|
4400
|
+
def data_type(self) -> SOCKET_TYPES:
|
|
4401
|
+
"""Input socket: Data Type"""
|
|
4402
|
+
return self.node.data_type # type: ignore
|
|
4403
|
+
|
|
4404
|
+
@data_type.setter
|
|
4405
|
+
def data_type(self, value: SOCKET_TYPES):
|
|
4406
|
+
"""Input socket: Data Type"""
|
|
4407
|
+
self.node.data_type = value
|
|
4408
|
+
|
|
4409
|
+
|
|
4410
|
+
def _typed_menu_switch(data_type: SOCKET_TYPES):
|
|
4411
|
+
@classmethod
|
|
4412
|
+
def method(
|
|
4413
|
+
cls,
|
|
4414
|
+
*args: TYPE_INPUT_ALL,
|
|
4415
|
+
menu: TYPE_INPUT_MENU = None,
|
|
4416
|
+
data_type: SOCKET_TYPES = "FLOAT",
|
|
4417
|
+
**kwargs: TYPE_INPUT_ALL,
|
|
4418
|
+
) -> "IndexSwitch":
|
|
4419
|
+
"""Create an IndexSwitch node with a pre-set data_type"""
|
|
4420
|
+
return cls(*args, menu=menu, data_type=data_type, **kwargs)
|
|
4421
|
+
|
|
4422
|
+
return method
|
|
4423
|
+
|
|
4424
|
+
|
|
4425
|
+
class MenuSwitch(NodeBuilder):
|
|
4426
|
+
"""Node builder for the Index Switch node"""
|
|
4427
|
+
|
|
4428
|
+
name = "GeometryNodeMenuSwitch"
|
|
4429
|
+
node: bpy.types.GeometryNodeMenuSwitch
|
|
4430
|
+
|
|
4431
|
+
float = _typed_menu_switch("FLOAT")
|
|
4432
|
+
integer = _typed_menu_switch("INT")
|
|
4433
|
+
boolean = _typed_menu_switch("BOOLEAN")
|
|
4434
|
+
vector = _typed_menu_switch("VECTOR")
|
|
4435
|
+
color = _typed_menu_switch("RGBA")
|
|
4436
|
+
rotation = _typed_menu_switch("ROTATION")
|
|
4437
|
+
matrix = _typed_menu_switch("MATRIX")
|
|
4438
|
+
string = _typed_menu_switch("STRING")
|
|
4439
|
+
menu = _typed_menu_switch("MENU")
|
|
4440
|
+
object = _typed_menu_switch("OBJECT")
|
|
4441
|
+
geometry = _typed_menu_switch("GEOMETRY")
|
|
4442
|
+
collection = _typed_menu_switch("COLLECTION")
|
|
4443
|
+
image = _typed_menu_switch("IMAGE")
|
|
4444
|
+
material = _typed_menu_switch("MATERIAL")
|
|
4445
|
+
bundle = _typed_menu_switch("BUNDLE")
|
|
4446
|
+
closure = _typed_menu_switch("CLOSURE")
|
|
4447
|
+
|
|
4448
|
+
def __init__(
|
|
4449
|
+
self,
|
|
4450
|
+
*args: TYPE_INPUT_ALL,
|
|
4451
|
+
menu: TYPE_INPUT_MENU = None,
|
|
4452
|
+
data_type: SOCKET_TYPES = "FLOAT",
|
|
4453
|
+
**kwargs: TYPE_INPUT_ALL,
|
|
4454
|
+
):
|
|
4455
|
+
super().__init__()
|
|
4456
|
+
self.data_type = data_type
|
|
4457
|
+
self.node.enum_items.clear()
|
|
4458
|
+
key_args = {"Menu": menu}
|
|
4459
|
+
self._link_args(*args, **kwargs)
|
|
4460
|
+
self._establish_links(**key_args)
|
|
4461
|
+
|
|
4462
|
+
def _link_args(self, *args: TYPE_INPUT_ALL, **kwargs: TYPE_INPUT_ALL):
|
|
4463
|
+
for arg in args:
|
|
4464
|
+
if _is_default_value(arg):
|
|
4465
|
+
socket = self._create_socket(f"Item_{len(self.node.enum_items)}")
|
|
4466
|
+
socket.default_value = arg
|
|
4467
|
+
else:
|
|
4468
|
+
source = self._source_socket(arg)
|
|
4469
|
+
self.tree.link(source, self.node.inputs["__extend__"])
|
|
4470
|
+
|
|
4471
|
+
for key, value in kwargs.items():
|
|
4472
|
+
if _is_default_value(value):
|
|
4473
|
+
socket = self._create_socket(key)
|
|
4474
|
+
socket.default_value = value
|
|
4475
|
+
else:
|
|
4476
|
+
source = self._source_socket(value) # type: ignore
|
|
4477
|
+
self._link(source, self.node.inputs["__extend__"])
|
|
4478
|
+
self.node.enum_items[-1].name = key
|
|
4479
|
+
|
|
4480
|
+
def _create_socket(self, name: str) -> bpy.types.NodeSocket:
|
|
4481
|
+
item = self.node.enum_items.new(name)
|
|
4482
|
+
return self.node.inputs[item.name]
|
|
4483
|
+
|
|
4484
|
+
@property
|
|
4485
|
+
def inputs(self) -> dict[str, SocketLinker]:
|
|
4486
|
+
"""Input sockets"""
|
|
4487
|
+
return {
|
|
4488
|
+
item.name: SocketLinker(self.node.inputs[item.name])
|
|
4489
|
+
for item in self.node.enum_items
|
|
4490
|
+
}
|
|
4491
|
+
|
|
4492
|
+
@property
|
|
4493
|
+
def outputs(self) -> dict[str, SocketLinker]:
|
|
4494
|
+
"""Input sockets"""
|
|
4495
|
+
return {
|
|
4496
|
+
item.name: SocketLinker(self.node.outputs[item.name])
|
|
4497
|
+
for item in self.node.enum_items
|
|
4498
|
+
}
|
|
4499
|
+
|
|
4500
|
+
@property
|
|
4501
|
+
def i_menu(self) -> SocketLinker:
|
|
4502
|
+
"""Input socket: Menu"""
|
|
4503
|
+
return self._input("Menu")
|
|
4504
|
+
|
|
4505
|
+
@property
|
|
4506
|
+
def o_output(self) -> SocketLinker:
|
|
4507
|
+
"""Output socket: Output"""
|
|
4508
|
+
return self._output("Output")
|
|
4509
|
+
|
|
4510
|
+
@property
|
|
4511
|
+
def data_type(self) -> SOCKET_TYPES:
|
|
4512
|
+
"""Input socket: Data Type"""
|
|
4513
|
+
return self.node.data_type # type: ignore
|
|
4514
|
+
|
|
4515
|
+
@data_type.setter
|
|
4516
|
+
def data_type(self, value: SOCKET_TYPES):
|
|
4517
|
+
"""Input socket: Data Type"""
|
|
4518
|
+
self.node.data_type = value
|