From ca856e5ee75dd183695092426dd521564f0829a2 Mon Sep 17 00:00:00 2001 From: Patrick Dulebohn Date: Sat, 2 Oct 2021 08:16:20 -0400 Subject: [PATCH 1/3] Add named animation EnumProperty Adds a needed animation picker for new named animations for the Python script texture node. Code borrowed from node_messages.py --- korman/nodes/node_python.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/korman/nodes/node_python.py b/korman/nodes/node_python.py index dd0b94a..5e720c3 100644 --- a/korman/nodes/node_python.py +++ b/korman/nodes/node_python.py @@ -852,6 +852,34 @@ class PlasmaAttribTextureNode(idprops.IDPropMixin, PlasmaAttribNodeBase, bpy.typ else: return True + # Blender memory workaround + _ENTIRE_ANIMATION = "(Entire Animation)" + def _get_anim_names(self, context): + if self.anim_type == "TEXTURE": + if self.target_texture is not None: + items = [(anim.animation_name, anim.animation_name, "") + for anim in self.target_texture.plasma_layer.subanimations] + elif self.target_material is not None or self.target_object is not None: + if self.target_material is None: + materials = (i.material for i in self.target_object.material_slots if i and i.material) + else: + materials = (self.target_material,) + layer_props = (i.texture.plasma_layer for mat in materials for i in mat.texture_slots if i and i.texture) + all_anims = frozenset((anim.animation_name for i in layer_props for anim in i.subanimations)) + items = [(i, i, "") for i in all_anims] + else: + items = [(PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, "")] + else: + raise RuntimeError() + + # We always want "(Entire Animation)", if it exists, to be the first item. + entire = items.index((PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, "")) + if entire not in (-1, 0): + items.pop(entire) + items.insert(0, (PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, "")) + + return items + target_object = PointerProperty(name="Object", description="", type=bpy.types.Object, @@ -864,6 +892,10 @@ class PlasmaAttribTextureNode(idprops.IDPropMixin, PlasmaAttribNodeBase, bpy.typ description="Texture to expose to Python", type=bpy.types.Texture, poll=_poll_texture) + anim_name = EnumProperty(name="Animation", + description="Name of the animation to control", + items=_get_anim_names, + options=set()) def init(self, context): super().init(context) @@ -881,10 +913,14 @@ class PlasmaAttribTextureNode(idprops.IDPropMixin, PlasmaAttribNodeBase, bpy.typ if not frozenset(self.texture.users_material) & frozenset(iter_materials()): layout.label("The selected texture is not on a material linked to the target object.", icon="ERROR") layout.alert = True + if self.anim_name is None: + layout.label("The selected texture has no animation data.", icon="ERROR") + layout.alert = True layout.prop(self, "target_object") layout.prop(self, "material") layout.prop(self, "texture") + layout.prop(self, "anim_name") def get_key(self, exporter, so): if not any((self.target_object, self.material, self.texture)): From 2ca2349d815ff22d99c860784a1e81d12d867727 Mon Sep 17 00:00:00 2001 From: Patrick Dulebohn Date: Sat, 2 Oct 2021 19:47:32 -0400 Subject: [PATCH 2/3] Some Adjustments A few adjustments to my poor copy paste to hopefully match it better with the node's other pieces. --- korman/nodes/node_python.py | 45 +++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/korman/nodes/node_python.py b/korman/nodes/node_python.py index 5e720c3..6d4aafd 100644 --- a/korman/nodes/node_python.py +++ b/korman/nodes/node_python.py @@ -852,46 +852,47 @@ class PlasmaAttribTextureNode(idprops.IDPropMixin, PlasmaAttribNodeBase, bpy.typ else: return True + target_object = PointerProperty(name="Object", + description="", + type=bpy.types.Object, + poll=idprops.poll_drawable_objects) + material = PointerProperty(name="Material", + description="Material the texture is attached to", + type=bpy.types.Material, + poll=_poll_material) + texture = PointerProperty(name="Texture", + description="Texture to expose to Python", + type=bpy.types.Texture, + poll=_poll_texture) + # Blender memory workaround _ENTIRE_ANIMATION = "(Entire Animation)" def _get_anim_names(self, context): - if self.anim_type == "TEXTURE": - if self.target_texture is not None: + if self.texture.plasma_layer.subanimations: + if self.texture is not None: items = [(anim.animation_name, anim.animation_name, "") - for anim in self.target_texture.plasma_layer.subanimations] - elif self.target_material is not None or self.target_object is not None: - if self.target_material is None: + for anim in self.texture.plasma_layer.subanimations] + elif self.material is not None or self.target_object is not None: + if self.material is None: materials = (i.material for i in self.target_object.material_slots if i and i.material) else: - materials = (self.target_material,) + materials = (self.material,) layer_props = (i.texture.plasma_layer for mat in materials for i in mat.texture_slots if i and i.texture) all_anims = frozenset((anim.animation_name for i in layer_props for anim in i.subanimations)) items = [(i, i, "") for i in all_anims] else: - items = [(PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, "")] + items = [(PlasmaAttribTextureNode._ENTIRE_ANIMATION, PlasmaAttribTextureNode._ENTIRE_ANIMATION, "")] else: raise RuntimeError() # We always want "(Entire Animation)", if it exists, to be the first item. - entire = items.index((PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, "")) + entire = items.index((PlasmaAttribTextureNode._ENTIRE_ANIMATION, PlasmaAttribTextureNode._ENTIRE_ANIMATION, "")) if entire not in (-1, 0): items.pop(entire) - items.insert(0, (PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, PlasmaAnimCmdMsgNode._ENTIRE_ANIMATION, "")) + items.insert(0, (PlasmaAttribTextureNode._ENTIRE_ANIMATION, PlasmaAttribTextureNode._ENTIRE_ANIMATION, "")) return items - target_object = PointerProperty(name="Object", - description="", - type=bpy.types.Object, - poll=idprops.poll_drawable_objects) - material = PointerProperty(name="Material", - description="Material the texture is attached to", - type=bpy.types.Material, - poll=_poll_material) - texture = PointerProperty(name="Texture", - description="Texture to expose to Python", - type=bpy.types.Texture, - poll=_poll_texture) anim_name = EnumProperty(name="Animation", description="Name of the animation to control", items=_get_anim_names, @@ -916,7 +917,7 @@ class PlasmaAttribTextureNode(idprops.IDPropMixin, PlasmaAttribNodeBase, bpy.typ if self.anim_name is None: layout.label("The selected texture has no animation data.", icon="ERROR") layout.alert = True - + layout.alert = not any((self.target_object, self.material, self.texture)) layout.prop(self, "target_object") layout.prop(self, "material") layout.prop(self, "texture") From cd5db19410ffe19d624cd6134605c4de41c5e5ba Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 26 Feb 2022 16:42:36 -0500 Subject: [PATCH 3/3] Finish up the logic for multiple-animation Python nodes. --- korman/nodes/node_python.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/korman/nodes/node_python.py b/korman/nodes/node_python.py index 6d4aafd..3149f3e 100644 --- a/korman/nodes/node_python.py +++ b/korman/nodes/node_python.py @@ -868,22 +868,19 @@ class PlasmaAttribTextureNode(idprops.IDPropMixin, PlasmaAttribNodeBase, bpy.typ # Blender memory workaround _ENTIRE_ANIMATION = "(Entire Animation)" def _get_anim_names(self, context): - if self.texture.plasma_layer.subanimations: - if self.texture is not None: - items = [(anim.animation_name, anim.animation_name, "") - for anim in self.texture.plasma_layer.subanimations] - elif self.material is not None or self.target_object is not None: - if self.material is None: - materials = (i.material for i in self.target_object.material_slots if i and i.material) - else: - materials = (self.material,) - layer_props = (i.texture.plasma_layer for mat in materials for i in mat.texture_slots if i and i.texture) - all_anims = frozenset((anim.animation_name for i in layer_props for anim in i.subanimations)) - items = [(i, i, "") for i in all_anims] + if self.texture is not None: + items = [(anim.animation_name, anim.animation_name, "") + for anim in self.texture.plasma_layer.subanimations] + elif self.material is not None or self.target_object is not None: + if self.material is None: + materials = (i.material for i in self.target_object.material_slots if i and i.material) else: - items = [(PlasmaAttribTextureNode._ENTIRE_ANIMATION, PlasmaAttribTextureNode._ENTIRE_ANIMATION, "")] + materials = (self.material,) + layer_props = (i.texture.plasma_layer for mat in materials for i in mat.texture_slots if i and i.texture) + all_anims = frozenset((anim.animation_name for i in layer_props for anim in i.subanimations)) + items = [(i, i, "") for i in all_anims] else: - raise RuntimeError() + items = [(PlasmaAttribTextureNode._ENTIRE_ANIMATION, PlasmaAttribTextureNode._ENTIRE_ANIMATION, "")] # We always want "(Entire Animation)", if it exists, to be the first item. entire = items.index((PlasmaAttribTextureNode._ENTIRE_ANIMATION, PlasmaAttribTextureNode._ENTIRE_ANIMATION, "")) @@ -914,14 +911,15 @@ class PlasmaAttribTextureNode(idprops.IDPropMixin, PlasmaAttribNodeBase, bpy.typ if not frozenset(self.texture.users_material) & frozenset(iter_materials()): layout.label("The selected texture is not on a material linked to the target object.", icon="ERROR") layout.alert = True - if self.anim_name is None: - layout.label("The selected texture has no animation data.", icon="ERROR") - layout.alert = True layout.alert = not any((self.target_object, self.material, self.texture)) layout.prop(self, "target_object") layout.prop(self, "material") layout.prop(self, "texture") - layout.prop(self, "anim_name") + wants_anim = bool(self.to_socket and self.to_socket.attribute_type == "ptAttribMaterialAnimation") + col = layout.column() + col.alert = False + col.active = wants_anim + col.prop(self, "anim_name") def get_key(self, exporter, so): if not any((self.target_object, self.material, self.texture)): @@ -939,7 +937,8 @@ class PlasmaAttribTextureNode(idprops.IDPropMixin, PlasmaAttribNodeBase, bpy.typ yield from filter(lambda x: x and isinstance(x.object, plDynamicTextMap), (i.object.texture for i in layer_generator)) elif attrib == "ptAttribMaterialAnimation": - yield from filter(lambda x: x and isinstance(x.object, plLayerAnimationBase), layer_generator) + anim_generator = exporter.mesh.material.get_texture_animation_key(self.target_object, self.material, self.texture, self.anim_name) + yield from filter(lambda x: not isinstance(x.object, (plAgeGlobalAnim, plLayerSDLAnimation)), anim_generator) elif attrib == "ptAttribMaterialList": yield from filter(lambda x: x and not isinstance(x.object, plLayerAnimationBase), bottom_layers) elif attrib == "ptAttribMaterial":