procfunc 0.30.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.
Files changed (76) hide show
  1. procfunc/__init__.py +87 -0
  2. procfunc/color.py +57 -0
  3. procfunc/compute_graph/__init__.py +28 -0
  4. procfunc/compute_graph/compute_graph.py +115 -0
  5. procfunc/compute_graph/node.py +200 -0
  6. procfunc/compute_graph/operators_info.py +92 -0
  7. procfunc/compute_graph/proxy.py +173 -0
  8. procfunc/compute_graph/util.py +282 -0
  9. procfunc/context.py +115 -0
  10. procfunc/control.py +174 -0
  11. procfunc/nodes/__init__.py +66 -0
  12. procfunc/nodes/bindings_util.py +196 -0
  13. procfunc/nodes/bpy_node_info.py +280 -0
  14. procfunc/nodes/compositor.py +2242 -0
  15. procfunc/nodes/execute/construct_nodes.py +571 -0
  16. procfunc/nodes/execute/construct_special_cases.py +246 -0
  17. procfunc/nodes/execute/execute.py +548 -0
  18. procfunc/nodes/execute/infer_runtime_data_type.py +195 -0
  19. procfunc/nodes/execute/util.py +247 -0
  20. procfunc/nodes/func.py +1417 -0
  21. procfunc/nodes/geo.py +4240 -0
  22. procfunc/nodes/manifest.json +8769 -0
  23. procfunc/nodes/math.py +644 -0
  24. procfunc/nodes/node_function.py +160 -0
  25. procfunc/nodes/shader.py +2359 -0
  26. procfunc/nodes/types.py +347 -0
  27. procfunc/ops/__init__.py +35 -0
  28. procfunc/ops/_util.py +275 -0
  29. procfunc/ops/addons.py +59 -0
  30. procfunc/ops/attr.py +426 -0
  31. procfunc/ops/collection.py +90 -0
  32. procfunc/ops/curve.py +18 -0
  33. procfunc/ops/file.py +126 -0
  34. procfunc/ops/manifest.json +39149 -0
  35. procfunc/ops/mesh.py +1510 -0
  36. procfunc/ops/modifier.py +603 -0
  37. procfunc/ops/object.py +258 -0
  38. procfunc/ops/primitives/__init__.py +31 -0
  39. procfunc/ops/primitives/camera.py +45 -0
  40. procfunc/ops/primitives/curve.py +71 -0
  41. procfunc/ops/primitives/light.py +114 -0
  42. procfunc/ops/primitives/mesh.py +358 -0
  43. procfunc/ops/uv.py +271 -0
  44. procfunc/random.py +247 -0
  45. procfunc/tracer/__init__.py +43 -0
  46. procfunc/tracer/decorator.py +121 -0
  47. procfunc/tracer/patch.py +494 -0
  48. procfunc/tracer/proxy.py +127 -0
  49. procfunc/tracer/trace.py +222 -0
  50. procfunc/transforms/__init__.py +49 -0
  51. procfunc/transforms/cleanup.py +214 -0
  52. procfunc/transforms/convert.py +20 -0
  53. procfunc/transforms/distribution.py +191 -0
  54. procfunc/transforms/extract_materials.py +116 -0
  55. procfunc/transforms/infer_distribution.py +326 -0
  56. procfunc/transforms/parameters.py +15 -0
  57. procfunc/transforms/util.py +35 -0
  58. procfunc/transpiler/__init__.py +24 -0
  59. procfunc/transpiler/bpy_to_computegraph.py +1348 -0
  60. procfunc/transpiler/codegen.py +919 -0
  61. procfunc/transpiler/identifiers.py +595 -0
  62. procfunc/transpiler/main.py +299 -0
  63. procfunc/types.py +380 -0
  64. procfunc/util/__init__.py +0 -0
  65. procfunc/util/bpy_info.py +145 -0
  66. procfunc/util/camera.py +0 -0
  67. procfunc/util/keyframe.py +70 -0
  68. procfunc/util/log.py +96 -0
  69. procfunc/util/manifest.py +121 -0
  70. procfunc/util/pytree.py +343 -0
  71. procfunc/util/teardown.py +37 -0
  72. procfunc-0.30.0.dist-info/METADATA +120 -0
  73. procfunc-0.30.0.dist-info/RECORD +76 -0
  74. procfunc-0.30.0.dist-info/WHEEL +5 -0
  75. procfunc-0.30.0.dist-info/licenses/LICENSE.md +11 -0
  76. procfunc-0.30.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,246 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ import bpy
5
+
6
+ from procfunc import compute_graph as cg
7
+ from procfunc.nodes import bpy_node_info as bni
8
+ from procfunc.nodes import types as nt
9
+
10
+ from .util import assign_default_value
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def special_case_color_ramp(
16
+ bl_node: bpy.types.Node,
17
+ attrs: dict[str, Any],
18
+ **_kwargs,
19
+ ):
20
+ color_ramp = bl_node.color_ramp # colorramp actually starts with 2 elements already
21
+ color_ramp.interpolation = attrs.pop("interpolation", "LINEAR")
22
+ color_ramp.color_mode = attrs.pop("color_mode", "RGB")
23
+
24
+ points = attrs.pop("points", None)
25
+ if points is None:
26
+ return
27
+
28
+ while len(color_ramp.elements) < len(points):
29
+ color_ramp.elements.new(0)
30
+
31
+ # Set positions and colors for all elements
32
+ for i, (position, color) in enumerate(points):
33
+ if i < len(color_ramp.elements):
34
+ color_ramp.elements[i].position = position
35
+ if len(color) == 3:
36
+ color_ramp.elements[i].color = (color[0], color[1], color[2], 1.0)
37
+ else:
38
+ color_ramp.elements[i].color = color
39
+
40
+
41
+ def special_case_float_curve(
42
+ bl_node: bpy.types.Node,
43
+ attrs: dict[str, Any],
44
+ **_kwargs,
45
+ ):
46
+ """Handle float curve nodes with points attribute."""
47
+ points = attrs.pop("mapping", None)
48
+
49
+ handle_type = attrs.pop("handle_type", "AUTO")
50
+ if handle_type != "AUTO":
51
+ raise NotImplementedError(
52
+ f"handle_type={handle_type!r} is not yet supported, only 'AUTO' is implemented"
53
+ )
54
+ use_clip = attrs.pop("use_clip", True)
55
+ bl_node.mapping.use_clip = use_clip
56
+
57
+ if points is None:
58
+ return
59
+
60
+ curve = bl_node.mapping.curves[0]
61
+
62
+ # Add new points if needed (starts with 2 by default)
63
+ if len(points) > 2:
64
+ for _ in range(len(points) - 2):
65
+ curve.points.new(0, 0)
66
+
67
+ # Set positions for all points
68
+ for i, (x, y) in enumerate(points):
69
+ if i < len(curve.points):
70
+ curve.points[i].location = (x, y)
71
+
72
+
73
+ def special_case_rgb_curves(
74
+ bl_node: bpy.types.Node,
75
+ attrs: dict[str, Any],
76
+ **_kwargs,
77
+ ):
78
+ """Handle RGB curve nodes with points attribute."""
79
+
80
+ curves = attrs.pop("curves", None)
81
+ if curves is None:
82
+ return
83
+
84
+ for bl_curve, curve_np in zip(bl_node.mapping.curves, curves):
85
+ while len(bl_curve.points) < len(curve_np):
86
+ bl_curve.points.new(0, 0)
87
+
88
+ for i, (x, y) in enumerate(curve_np):
89
+ bl_curve.points[i].location = (x, y)
90
+
91
+
92
+ def special_case_vector_curves(
93
+ bl_node: bpy.types.Node,
94
+ attrs: dict[str, Any],
95
+ **_kwargs,
96
+ ):
97
+ """Handle vector curve nodes with points attribute."""
98
+
99
+ curves = attrs.pop("curves", None)
100
+ if curves is None:
101
+ return
102
+
103
+ for bl_curve, curve_np in zip(bl_node.mapping.curves, curves):
104
+ while len(bl_curve.points) < len(curve_np):
105
+ bl_curve.points.new(0, 0)
106
+
107
+ for i, (x, y) in enumerate(curve_np):
108
+ bl_curve.points[i].location = (x, y)
109
+
110
+
111
+ def special_case_file_output(
112
+ bl_node: bpy.types.Node,
113
+ attrs: dict[str, Any],
114
+ inputs: dict[str, Any],
115
+ **_kwargs,
116
+ ):
117
+ assert bl_node.bl_idname == "CompositorNodeOutputFile"
118
+
119
+ bl_node.file_slots.clear()
120
+ for k in inputs.keys():
121
+ if k == 0 or k in attrs:
122
+ continue
123
+ bl_node.file_slots.new(k)
124
+
125
+ if file_format := attrs.pop("format", None):
126
+ for k, v in file_format.items():
127
+ setattr(bl_node.format, k, v)
128
+
129
+ if slot_paths := attrs.pop("slot_paths", None):
130
+ for k, v in slot_paths.items():
131
+ bl_node.file_slots[k].path = v
132
+
133
+
134
+ def special_case_input(
135
+ node: nt.ProcNode,
136
+ node_tree: bpy.types.NodeTree,
137
+ bl_node: bpy.types.Node,
138
+ attrs: dict[str, Any],
139
+ **_kwargs,
140
+ ):
141
+ raise NotImplementedError(f"{special_case_input.__name__} is not implemented")
142
+
143
+ # TODO node is actually a cg.Node
144
+
145
+ if node.type != nt.INPUT_NODE_TYPE:
146
+ raise ValueError(
147
+ f"{special_case_input.__name__} requires {nt.INPUT_NODE_TYPE!r}, got {node.type}"
148
+ )
149
+
150
+ socket_types: list[nt.SocketType] = attrs.pop("socket_types")
151
+ defaults: list = attrs.pop("default_values")
152
+
153
+ output_sockets = node._output_sockets()
154
+
155
+ if output_sockets is None:
156
+ raise ValueError(f"{node=} has no output sockets")
157
+
158
+ for name, socket_type, default in zip(output_sockets, socket_types, defaults):
159
+ if name in node_tree.interface.items_tree:
160
+ raise ValueError(f"Socket {name} already exists in {node_tree.name}")
161
+ soc = node_tree.interface.new_socket(
162
+ name=name,
163
+ in_out="INPUT",
164
+ socket_type=socket_type.value,
165
+ )
166
+ data_type = nt.SOCKET_CLASS_TO_DATATYPE[socket_type.value]
167
+ assign_default_value(soc, default, data_type)
168
+
169
+ if name not in bl_node.outputs:
170
+ raise ValueError(f"Failed to add {name=} {socket_type=} to {bl_node.name=}")
171
+
172
+
173
+ def special_case_map_range(
174
+ attrs: dict[str, Any],
175
+ kwargs: dict[str, Any],
176
+ inputs: dict[str, Any],
177
+ **_kwargs,
178
+ ):
179
+ if attrs["data_type"] == bni.NodeDataType.FLOAT_VECTOR.value:
180
+ assert "Value" in inputs, inputs
181
+ inputs["Vector"] = inputs.pop("Value")
182
+ kwargs["Vector"] = kwargs.pop("Value")
183
+
184
+
185
+ def special_case_capture_attribute(
186
+ bl_node: bpy.types.Node,
187
+ inputs: dict[str, Any],
188
+ kwargs: dict[str, Any],
189
+ **_kwargs,
190
+ ):
191
+ for input_name, input_val in inputs.items():
192
+ if input_name == "Geometry":
193
+ continue
194
+
195
+ kwargval = kwargs.get(input_name)
196
+ if isinstance(kwargval, cg.Node) and (
197
+ annot := kwargval.metadata.get("known_value_type")
198
+ ):
199
+ soc_type = bni.PYTHON_TYPE_TO_SOCKET_TYPE[annot]
200
+ data_type = bni.SOCKET_CLASS_TO_DATATYPE[soc_type.value]
201
+ elif isinstance(input_val, bpy.types.NodeSocket):
202
+ data_type = bni.SOCKET_CLASS_TO_DATATYPE[input_val.bl_idname]
203
+ elif type(input_val) in bni.PYTHON_TYPE_TO_SOCKET_TYPE:
204
+ soc_type = bni.PYTHON_TYPE_TO_SOCKET_TYPE[type(input_val)]
205
+ data_type = bni.SOCKET_CLASS_TO_DATATYPE[soc_type.value]
206
+ else:
207
+ raise ValueError(f"Could not determine data type for {input_val=}")
208
+
209
+ data_type = (
210
+ "VECTOR" # NodeDataType uses FLOAT_VECTOR here but that seems incorrect for CaptureAttribute??
211
+ if data_type == bni.NodeDataType.FLOAT_VECTOR
212
+ else data_type.value
213
+ )
214
+
215
+ try:
216
+ bl_node.capture_items.new(data_type, name=input_name)
217
+ except Exception as e:
218
+ raise ValueError(
219
+ f"Could not add capture item {input_name=} {data_type} to {bl_node.name=}. "
220
+ f"{bl_node.capture_items.keys()=}. {e=}"
221
+ ) from e
222
+
223
+
224
+ def special_case_value_outputdefault(
225
+ bl_node: bpy.types.Node,
226
+ attrs: dict[str, Any],
227
+ **_kwargs,
228
+ ):
229
+ value = attrs.pop("value", None)
230
+ if value is not None and hasattr(value, "__len__") and len(value) == 3:
231
+ value = (*value, 1.0)
232
+ bl_node.outputs[0].default_value = value
233
+
234
+
235
+ NODE_SPECIAL_CASES = {
236
+ "ShaderNodeValToRGB": special_case_color_ramp,
237
+ "ShaderNodeFloatCurve": special_case_float_curve,
238
+ "ShaderNodeMapRange": special_case_map_range,
239
+ "ShaderNodeRGBCurve": special_case_rgb_curves,
240
+ "ShaderNodeVectorCurve": special_case_vector_curves,
241
+ "CompositorNodeOutputFile": special_case_file_output,
242
+ nt.INPUT_NODE_TYPE: special_case_input,
243
+ "GeometryNodeCaptureAttribute": special_case_capture_attribute,
244
+ "ShaderNodeValue": special_case_value_outputdefault,
245
+ "ShaderNodeRGB": special_case_value_outputdefault,
246
+ }