Browse Source

Use Python Node Attribute Arguments.

Parses and loads the PFM arguments into accessible properties, used
by numeric nodes for range, dropdown nodes for enums, etc.

Also moves PlasmaAttribDropDownListNode into its proper alphabetical
position.
pull/68/head
Joseph Davies 7 years ago
parent
commit
72547b0570
Signed by untrusted user: Deledrius
GPG Key ID: 28ACC6E8D2B24B8A
  1. 116
      korman/nodes/node_python.py
  2. 57
      korman/operators/op_nodes.py

116
korman/nodes/node_python.py

@ -86,6 +86,52 @@ _attrib_key_types = {
"ptAttribGrassShader": plFactory.ClassIndex("plGrassShaderMod"), "ptAttribGrassShader": plFactory.ClassIndex("plGrassShaderMod"),
} }
class StringVectorProperty(bpy.types.PropertyGroup):
value = StringProperty()
class PlasmaAttributeArguments(bpy.types.PropertyGroup):
byObject = BoolProperty()
default = StringProperty()
options = CollectionProperty(type=StringVectorProperty)
range_values = FloatVectorProperty(size=2)
netForce = BoolProperty()
netPropagate = BoolProperty()
stateList = CollectionProperty(type=StringVectorProperty)
visListId = IntProperty()
visListStates = CollectionProperty(type=StringVectorProperty)
def set_arguments(self, args):
for name in args:
if name == "byObject":
self.byObject = bool(args[name])
elif name == "default":
self.default = str(args[name])
elif name == "options":
for option in args[name]:
item = self.options.add()
item.value = str(option)
elif name in ("range", "rang"):
self.range_values = args[name]
elif name == "netForce":
self.netForce = bool(args[name])
elif name in ("netPropagate", "netProp"):
self.netPropagate = bool(args[name])
elif name == "stateList":
for state in args[name]:
item = self.stateList.add()
item.value = str(state)
elif name == "vislistid":
self.visListId = int(args[name])
elif name == "visliststates":
for state in args[name]:
item = self.visListStates.add()
item.value = str(state)
else:
print("Unknown argument '{}' with value '{}'!".format(name, args[name]))
class PlasmaAttribute(bpy.types.PropertyGroup): class PlasmaAttribute(bpy.types.PropertyGroup):
attribute_id = IntProperty() attribute_id = IntProperty()
attribute_type = StringProperty() attribute_type = StringProperty()
@ -98,6 +144,9 @@ class PlasmaAttribute(bpy.types.PropertyGroup):
value_float = FloatProperty() value_float = FloatProperty()
value_bool = BoolProperty() value_bool = BoolProperty()
# Special Arguments
attribute_arguments = PointerProperty(type=PlasmaAttributeArguments)
_simple_attrs = { _simple_attrs = {
"ptAttribString": "value_string", "ptAttribString": "value_string",
"ptAttribDropDownList": "value_string", "ptAttribDropDownList": "value_string",
@ -292,6 +341,10 @@ class PlasmaPythonFileNodeSocket(bpy.types.NodeSocket):
def simple_value(self): def simple_value(self):
return self.node.attribute_map[self.attribute_id].simple_value return self.node.attribute_map[self.attribute_id].simple_value
@property
def attribute_arguments(self):
return self.node.attribute_map[self.attribute_id].attribute_arguments
class PlasmaPythonAttribNodeSocket(bpy.types.NodeSocket): class PlasmaPythonAttribNodeSocket(bpy.types.NodeSocket):
def draw(self, context, layout, node, text): def draw(self, context, layout, node, text):
@ -372,6 +425,31 @@ class PlasmaAttribBoolNode(PlasmaAttribNodeBase, bpy.types.Node):
self.inited = True self.inited = True
class PlasmaAttribDropDownListNode(PlasmaAttribNodeBase, bpy.types.Node):
bl_category = "PYTHON"
bl_idname = "PlasmaAttribDropDownListNode"
bl_label = "Drop Down List Attribute"
pl_attrib = "ptAttribDropDownList"
def _list_items(self, context):
attrib = self.to_socket
if attrib is not None:
return [(option.value, option.value, "") for option in attrib.attribute_arguments.options]
else:
return []
value = EnumProperty(items=_list_items)
def draw_buttons(self, context, layout):
layout.prop(self, "value", text=self.attribute_name)
def update(self):
super().update()
attrib = self.to_socket
if attrib is not None and not self.value:
self.value = attrib.simple_value
class PlasmaAttribNumericNode(PlasmaAttribNodeBase, bpy.types.Node): class PlasmaAttribNumericNode(PlasmaAttribNodeBase, bpy.types.Node):
bl_category = "PYTHON" bl_category = "PYTHON"
bl_idname = "PlasmaAttribNumericNode" bl_idname = "PlasmaAttribNumericNode"
@ -397,11 +475,16 @@ class PlasmaAttribNumericNode(PlasmaAttribNodeBase, bpy.types.Node):
def draw_buttons(self, context, layout): def draw_buttons(self, context, layout):
attrib = self.to_socket attrib = self.to_socket
if attrib is None: if attrib is None:
layout.prop(self, "value_int", text="Value") layout.prop(self, "value_int", text="Value")
elif attrib.attribute_type == "ptAttribFloat": elif attrib.attribute_type == "ptAttribFloat":
self._range_label(layout)
layout.alert = self._out_of_range(self.value_float)
layout.prop(self, "value_float", text=attrib.name) layout.prop(self, "value_float", text=attrib.name)
elif attrib.attribute_type == "ptAttribInt": elif attrib.attribute_type == "ptAttribInt":
self._range_label(layout)
layout.alert = self._out_of_range(self.value_int)
layout.prop(self, "value_int", text=attrib.name) layout.prop(self, "value_int", text=attrib.name)
else: else:
raise RuntimeError() raise RuntimeError()
@ -421,6 +504,19 @@ class PlasmaAttribNumericNode(PlasmaAttribNodeBase, bpy.types.Node):
else: else:
return self.value_float return self.value_float
def _range_label(self, layout):
attrib = self.to_socket
layout.label(text="Range: [{}, {}]".format(attrib.attribute_arguments.range_values[0], attrib.attribute_arguments.range_values[1]))
def _out_of_range(self, value):
attrib = self.to_socket
if attrib.attribute_arguments.range_values[0] == attrib.attribute_arguments.range_values[1]:
# Ignore degenerate intervals
return False
if attrib.attribute_arguments.range_values[0] <= value <= attrib.attribute_arguments.range_values[1]:
return False
return True
class PlasmaAttribObjectNode(idprops.IDPropObjectMixin, PlasmaAttribNodeBase, bpy.types.Node): class PlasmaAttribObjectNode(idprops.IDPropObjectMixin, PlasmaAttribNodeBase, bpy.types.Node):
bl_category = "PYTHON" bl_category = "PYTHON"
@ -476,24 +572,6 @@ class PlasmaAttribObjectNode(idprops.IDPropObjectMixin, PlasmaAttribNodeBase, bp
return {"target_object": "object_name"} return {"target_object": "object_name"}
class PlasmaAttribDropDownListNode(PlasmaAttribNodeBase, bpy.types.Node):
bl_category = "PYTHON"
bl_idname = "PlasmaAttribDropDownListNode"
bl_label = "Drop Down List Attribute"
pl_attrib = "ptAttribDropDownList"
value = StringProperty()
def draw_buttons(self, context, layout):
layout.prop(self, "value", text=self.attribute_name)
def update(self):
super().update()
attrib = self.to_socket
if attrib is not None and not self.value:
self.value = attrib.simple_value
class PlasmaAttribStringNode(PlasmaAttribNodeBase, bpy.types.Node): class PlasmaAttribStringNode(PlasmaAttribNodeBase, bpy.types.Node):
bl_category = "PYTHON" bl_category = "PYTHON"
bl_idname = "PlasmaAttribStringNode" bl_idname = "PlasmaAttribStringNode"
@ -605,12 +683,12 @@ _attrib_colors = {
"ptAttribActivatorList": (0.188, 0.086, 0.349, 1.0), "ptAttribActivatorList": (0.188, 0.086, 0.349, 1.0),
"ptAttribBoolean": (0.71, 0.706, 0.655, 1.0), "ptAttribBoolean": (0.71, 0.706, 0.655, 1.0),
"ptAttribExcludeRegion": (0.031, 0.110, 0.290, 1.0), "ptAttribExcludeRegion": (0.031, 0.110, 0.290, 1.0),
"ptAttribDropDownList": (0.475, 0.459, 0.494, 1.0),
"ptAttribNamedActivator": (0.188, 0.086, 0.349, 1.0), "ptAttribNamedActivator": (0.188, 0.086, 0.349, 1.0),
"ptAttribNamedResponder": (0.031, 0.110, 0.290, 1.0), "ptAttribNamedResponder": (0.031, 0.110, 0.290, 1.0),
"ptAttribResponder": (0.031, 0.110, 0.290, 1.0), "ptAttribResponder": (0.031, 0.110, 0.290, 1.0),
"ptAttribResponderList": (0.031, 0.110, 0.290, 1.0), "ptAttribResponderList": (0.031, 0.110, 0.290, 1.0),
"ptAttribString": (0.675, 0.659, 0.494, 1.0), "ptAttribString": (0.675, 0.659, 0.494, 1.0),
"ptAttribDropDownList": (0.475, 0.459, 0.494, 1.0),
PlasmaAttribNumericNode.pl_attrib: (0.443, 0.439, 0.392, 1.0), PlasmaAttribNumericNode.pl_attrib: (0.443, 0.439, 0.392, 1.0),
PlasmaAttribObjectNode.pl_attrib: (0.565, 0.267, 0.0, 1.0), PlasmaAttribObjectNode.pl_attrib: (0.565, 0.267, 0.0, 1.0),

57
korman/operators/op_nodes.py

@ -47,6 +47,47 @@ class SelectFileOperator(NodeOperator, bpy.types.Operator):
context.window_manager.fileselect_add(self) context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"} return {"RUNNING_MODAL"}
pyAttribArgMap= {
"ptAttribute":
["vislistid", "visliststates"],
"ptAttribBoolean":
["default"],
"ptAttribInt":
["default", "rang"],
"ptAttribFloat":
["default", "rang"],
"ptAttribString":
["default"],
"ptAttribDropDownList":
["options"],
"ptAttribSceneobject":
["netForce"],
"ptAttribSceneobjectList":
["byObject", "netForce"],
"ptAttributeKeyList":
["byObject", "netForce"],
"ptAttribActivator":
["byObject", "netForce"],
"ptAttribActivatorList":
["byObject", "netForce"],
"ptAttribResponder":
["stateList", "byObject", "netForce", "netPropagate"],
"ptAttribResponderList":
["stateList", "byObject", "netForce", "netPropagate"],
"ptAttribNamedActivator":
["byObject", "netForce"],
"ptAttribNamedResponder":
["stateList", "byObject", "netForce", "netPropagate"],
"ptAttribDynamicMap":
["netForce"],
"ptAttribAnimation":
["byObject", "netForce"],
"ptAttribBehavior":
["netForce", "netProp"],
"ptAttribMaterialList":
["byObject", "netForce"],
}
class PlPyAttributeNodeOperator(NodeOperator, bpy.types.Operator): class PlPyAttributeNodeOperator(NodeOperator, bpy.types.Operator):
bl_idname = "node.plasma_attributes_to_node" bl_idname = "node.plasma_attributes_to_node"
@ -81,5 +122,21 @@ class PlPyAttributeNodeOperator(NodeOperator, bpy.types.Operator):
default = attrib.get("default", None) default = attrib.get("default", None)
if default is not None and cached.is_simple_value: if default is not None and cached.is_simple_value:
cached.simple_value = default cached.simple_value = default
argmap = {}
args = attrib.get("args", None)
# Load our default argument mapping
if args is not None:
if cached.attribute_type in pyAttribArgMap.keys():
argmap.update(dict(zip(pyAttribArgMap[cached.attribute_type], args)))
else:
print("Found ptAttribute type '{}' with unknown arguments: {}".format(cached.attribute_type, args))
# Add in/set any arguments provided by keyword
if not set(pyAttribArgMap[cached.attribute_type]).isdisjoint(attrib.keys()):
argmap.update({key: attrib[key] for key in attrib if key in pyAttribArgMap[cached.attribute_type]})
# Attach the arguments to the attribute
if argmap:
cached.attribute_arguments.set_arguments(argmap)
node.update() node.update()
return {"FINISHED"} return {"FINISHED"}

Loading…
Cancel
Save