-
Notifications
You must be signed in to change notification settings - Fork 235
/
Copy pathvd_attr_node.py
232 lines (189 loc) · 9.17 KB
/
vd_attr_node.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# This file is part of project Sverchok. It's copyrighted by the contributors
# recorded in the version control history of the file, available from
# its original location https://github.com/nortikin/sverchok/commit/master
#
# SPDX-License-Identifier: GPL3
# License-Filename: LICENSE
import json
import copy
import bpy
from bpy.props import BoolProperty, StringProperty, IntProperty, CollectionProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, enum_item_5
from sverchok.old_nodes.vd_draw_experimental import SvVDExperimental
from sverchok.utils.handle_blender_data import get_func_and_args
sock_str = {
'enum': "SvStringsSocket",
'3f': "SvVerticesSocket",
'4f': "SvColorSocket",
'i': "SvStringsSocket",
'b': "SvStringsSocket"
}
socket_colors = {
"SvStringsSocket": (0.6, 1.0, 0.6, 1.0),
"SvVerticesSocket": (0.9, 0.6, 0.2, 1.0),
"SvColorSocket": (0.9, 0.8, 0.0, 1.0),
}
def props(**x):
prop = lambda: None
_ = [setattr(prop, k, v) for k, v in x.items()]
return prop
# this dict (ordered by default as per python 3.7 ?..) determines the order of sockets
maximum_spec_vd_dict = dict(
vert_color=props(name="points rgba", kind="4f"),
edge_color=props(name="edge rgba", kind="4f"),
face_color=props(name="face rgba", kind="4f"),
display_verts=props(name="display verts", kind="b"),
display_edges=props(name="display edges", kind="b"),
display_faces=props(name="display faces", kind="b"),
selected_draw_mode=props(name="shade mode", kind="enum"),
draw_gl_wireframe=props(name="wireframe", kind="b"),
draw_gl_polygonoffset=props(name="fix zfighting", kind="b"),
point_size=props(name="point size", kind="i"),
line_width=props(name="line width", kind="i"),
extended_matrix=props(name="extended matrix", kind="b"),
vector_light=props(name="light direction", kind="3f"),
activate=props(name="activate", kind="b")
)
def property_change(item, context, changed_attr):
# prior to node initialization this function will be called, but will generate errors until
# the vd mk 3 item group is also fully initialized.
if not item.origin_node_name:
return
# seems link to the node is lost, but not the nodetree
ng = item.id_data
node = ng.nodes[item.origin_node_name]
socket_name = maximum_spec_vd_dict[item.attr_name].name
if changed_attr == 'show_socket':
node.inputs[socket_name].hide_safe = not getattr(item, changed_attr)
class SvVDMK3Item(bpy.types.PropertyGroup):
attr_name: StringProperty(options={'SKIP_SAVE'})
show_socket: BoolProperty(default=False, update=lambda s, c: property_change(s, c, 'show_socket'))
use_default: BoolProperty(default=False, update=lambda s, c: property_change(s, c, 'use_default'))
origin_node_name: StringProperty(options={'SKIP_SAVE'})
class SvVDMK3Properties(bpy.types.PropertyGroup):
# this populates a property-group using VDExperimental.__annotations__ as the source -
__annotations__ = {}
for key, v in maximum_spec_vd_dict.items():
prop_func, kw_args = get_func_and_args(SvVDExperimental.__annotations__[key])
copy_kw_args = copy.deepcopy(kw_args)
copy_kw_args.pop('update', None)
__annotations__[key] = prop_func(**copy_kw_args)
class SV_UL_VDMK3ItemList(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
# is there a nicer way to do this? can we use .active_node ?
node = context.space_data.edit_tree.nodes[item.origin_node_name]
attr_name = item.attr_name
socket_string_name = sock_str[maximum_spec_vd_dict[attr_name].kind]
layout.template_node_socket(color=socket_colors[socket_string_name])
layout.prop(item, "show_socket", text="", icon='TRACKING', toggle=True)
layout.prop(item, "use_default", text="", icon='SETTINGS', toggle=True)
layout.label(text=attr_name)
layout.prop(node.vd_items_props[0], attr_name, text='')
class SvVDAttrsNode(SverchCustomTreeNode, bpy.types.Node):
"""
Triggers: vd attr
Tooltip: Attribute Node for Viewer Draw Experimental
Allows access to VD Experimental's attributes which control how the
node draws faces/edges. It can also switch off the node.
"""
bl_idname = 'SvVDAttrsNode'
bl_label = 'VD Attributes'
bl_icon = 'MOD_HUE_SATURATION'
replacement_nodes = [('SvVDAttrsNodeMk2', dict(verts='Vertices', edges='Edges', faces='Polygons', matrix='Matrix'), None)]
property_index: IntProperty(name='index', default=0)
vd_items_group: CollectionProperty(name="vd attrs", type=SvVDMK3Item)
vd_items_props: CollectionProperty(name="vd props", type=SvVDMK3Properties)
def draw_group(self, context, layout):
if self.vd_items_group:
layout.template_list("SV_UL_VDMK3ItemList", "", self, "vd_items_group", self, "property_index")
def vd_init_sockets(self, context):
self.outputs.new("SvStringsSocket", name="attrs")
inew = self.inputs.new
for prop_name, socket in maximum_spec_vd_dict.items():
socket = inew(sock_str[socket.kind], socket.name)
socket.hide = True
if prop_name == 'vector_light':
socket.quick_link_to_node = "GenVectorsNode"
def vd_init_uilayout_data(self, context):
for key, value in maximum_spec_vd_dict.items():
item = self.vd_items_group.add()
item.attr_name = key
item.show_socket = False
item.origin_node_name = self.name
self.vd_items_props.add()
def sv_init(self, context):
self.vd_init_sockets(context)
self.vd_init_uilayout_data(context)
def draw_buttons(self, context, layout):
layout.prop(context.space_data, "show_region_ui", toggle=True)
def draw_buttons_ext(self, context, layout):
self.draw_group(context, layout)
def ensure_correct_origin_node_name(self):
if self.vd_items_group:
if not self.vd_items_group[0].origin_node_name == self.name:
for item in self.vd_items_group:
item.origin_node_name = self.name
def get_repr_and_socket_from_attr_name(self, attr_name):
socket_repr = maximum_spec_vd_dict[attr_name]
return socket_repr, self.inputs[socket_repr.name]
def get_attr_from_input(self, item):
socket_repr, associated_socket = self.get_repr_and_socket_from_attr_name(item.attr_name)
if associated_socket.is_linked:
data = associated_socket.sv_get()
if socket_repr.kind in {'4f', '3f', 'i'}:
return data[0][0]
elif socket_repr.kind in {'b'}:
return bool(data[0][0])
elif socket_repr.kind in {'enum'}:
prop_signature = self.vd_items_props.__annotations__[item.attr_name][1]
enum_index = data[0][0]
enum_item = prop_signature['items'][enum_index]
return enum_item[0]
else:
return None
def make_value_serializable(self, attr, value):
if maximum_spec_vd_dict[attr].kind in {'3f', '4f'}:
value = value[:]
return value
@property
def attrdict_from_state(self):
current_attr_dict = {}
if self.vd_items_group and self.vd_items_props:
for item in self.vd_items_group:
attr = item.attr_name
if not item.show_socket and not item.use_default:
# apparantly no desire to pass this attr
continue
if item.use_default or not item.show_socket:
value = getattr(self.vd_items_props[0], attr)
value = self.make_value_serializable(attr, value)
else:
value = self.get_attr_from_input(item)
if value is None:
continue
current_attr_dict[attr] = value
return current_attr_dict
def process(self):
self.ensure_correct_origin_node_name()
self.outputs['attrs'].sv_set([self.attrdict_from_state])
## ---- UI JSON STORAGE SECTION BELOW THIS LINE
def load_from_json(self, node_data: dict, import_version: float):
""" this gets triggered by IOJSON to populate this node from json """
if import_version <= 0.08:
strings_json = node_data['attr_storage']
attrs_dict = json.loads(strings_json)['attrs']
state_dict = json.loads(strings_json)['state']
# repopulate vd_items_group
for item in self.vd_items_group:
attr_details = attrs_dict[item.attr_name]
socket_repr, associated_socket = self.get_repr_and_socket_from_attr_name(item.attr_name)
if attr_details['show_socket']:
item.show_socket = True
if attr_details['use_default']:
item.use_default = True
# repopulate vd_items_props
for item, value in state_dict.items():
setattr(self.vd_items_props[0], item, value)
classes = [SvVDMK3Item, SvVDMK3Properties, SV_UL_VDMK3ItemList, SvVDAttrsNode]
register, unregister = bpy.utils.register_classes_factory(classes)