diff --git a/io_scene_niftools/modules/nif_export/armature/__init__.py b/io_scene_niftools/modules/nif_export/armature/__init__.py index ea3906f84..66af92fdf 100644 --- a/io_scene_niftools/modules/nif_export/armature/__init__.py +++ b/io_scene_niftools/modules/nif_export/armature/__init__.py @@ -40,7 +40,7 @@ from io_scene_niftools.modules.nif_export import types from io_scene_niftools.modules.nif_export.animation.transform import TransformAnimation from io_scene_niftools.modules.nif_export.block_registry import block_store -from io_scene_niftools.utils import math +from io_scene_niftools.utils import math, consts class Armature: @@ -83,6 +83,9 @@ def export_bone(self, b_obj, b_bone, n_parent_node, n_root_node): for b_child in b_bone.children: self.export_bone(b_obj, b_child, n_node, n_root_node) + if b_bone.niftools.lag_bone.enabled: + self.export_lag_bone(b_bone, n_node) + def export_bone_flags(self, b_bone, n_node): """Exports or sets the flags according to the custom data in b_bone or the game version if none was set""" if b_bone.niftools.flags != 0: @@ -110,4 +113,26 @@ def export_bone_flags(self, b_bone, n_node): # default for Div 2 final bones n_node.flags = 0x0196 else: - n_node.flags = 0x0002 # default for Morrowind bones \ No newline at end of file + n_node.flags = 0x0002 # default for Morrowind bones + + def export_lag_bone(self, b_bone, n_node): + """Exports a BSLagBoneController for the bone""" + + #BSLagBoneControllers are only for skyrim and later, afaik + game = bpy.context.scene.niftools_scene.game + if game not in ('SKYRIM'): + return + + n_controller = block_store.create_block("BSLagBoneController") + n_controller.name = block_store.get_full_name(b_bone) + #This should be active and cycle, what I've seen in game. + n_controller.flags = b_bone.niftools.lag_bone.flags #0x0048? hexa? + n_controller.frequency = 1.0 + n_controller.phase = 0.0 + n_controller.start_time = consts.FLOAT_MIN + n_controller.stop_time = consts.FLOAT_MAX + n_controller.linear_velocity = b_bone.niftools.lag_bone.linear_velocity + n_controller.linear_rotation = b_bone.niftools.lag_bone.linear_rotation + n_controller.maximum_distance = b_bone.niftools.lag_bone.maximum_distance + #add controller to _this_ block + n_node.add_controller(n_controller) \ No newline at end of file diff --git a/io_scene_niftools/modules/nif_import/armature/__init__.py b/io_scene_niftools/modules/nif_import/armature/__init__.py index 7e4b4a59e..c161b8602 100644 --- a/io_scene_niftools/modules/nif_import/armature/__init__.py +++ b/io_scene_niftools/modules/nif_import/armature/__init__.py @@ -220,6 +220,11 @@ def import_armature(self, n_armature): if NifOp.props.animation: self.transform_anim.import_transforms(n_block, b_armature_obj, bone_name) + #Maybe better place to put this? + # Check for bs lagbone controllers and set them + self.import_bslagbonecontrollers(n_block, b_bone) + + # import pose for b_name, n_block in self.name_to_block.items(): n_pose = self.pose_store[n_block] @@ -231,6 +236,19 @@ def import_armature(self, n_armature): return b_armature_obj + + def import_bslagbonecontrollers(self, n_block, b_bone): + """Check for and import bslagbonecontrollers.""" + ctrl = n_block.controller + if isinstance(ctrl, NifFormat.BSLagBoneController): + #Enable bscontrollerlagboneprop + b_bone.niftools.lag_bone.enabled = True + #Set the props we care about; flags, linear_velocity, linear_rotation, maximum distance + b_bone.niftools.lag_bone.flags = ctrl.flags + b_bone.niftools.lag_bone.linear_velocity = ctrl.linear_velocity + b_bone.niftools.lag_bone.linear_rotation = ctrl.linear_rotation + b_bone.niftools.lag_bone.maximum_distance = ctrl.maximum_distance + def import_bone_bind(self, n_block, b_armature_data, n_armature, b_parent_bone=None): """Adds a bone to the armature in edit mode.""" # check that n_block is indeed a bone diff --git a/io_scene_niftools/properties/armature.py b/io_scene_niftools/properties/armature.py index 89271f374..9a74de2c2 100644 --- a/io_scene_niftools/properties/armature.py +++ b/io_scene_niftools/properties/armature.py @@ -41,13 +41,42 @@ from bpy.props import (PointerProperty, IntProperty, EnumProperty, - StringProperty + StringProperty, + BoolProperty, + FloatProperty ) from bpy.types import PropertyGroup from io_scene_niftools.utils.decorators import register_classes, unregister_classes +class LagBoneControllerProperty(PropertyGroup): + enabled: BoolProperty( + name='BSLagBoneController', + default=False + ) + + flags: IntProperty( + name='flags', + default=72 + ) + + linear_velocity: FloatProperty( + name='linear velocity', + default=20.0 + ) + + linear_rotation: FloatProperty( + name='linear rotation', + default=20.0 + ) + + maximum_distance: FloatProperty( + name='maximum distance', + default=10.0 + ) + + class BoneProperty(PropertyGroup): flags: IntProperty( name='Bone Flag', @@ -61,35 +90,38 @@ class BoneProperty(PropertyGroup): name='Nif Long Name' ) + lag_bone: PointerProperty(type=LagBoneControllerProperty) + class ArmatureProperty(PropertyGroup): axis_forward: EnumProperty( - name="Forward", - items=(('X', "X Forward", ""), - ('Y', "Y Forward", ""), - ('Z', "Z Forward", ""), - ('-X', "-X Forward", ""), - ('-Y', "-Y Forward", ""), - ('-Z', "-Z Forward", ""), - ), - default="X", - ) + name="Forward", + items=(('X', "X Forward", ""), + ('Y', "Y Forward", ""), + ('Z', "Z Forward", ""), + ('-X', "-X Forward", ""), + ('-Y', "-Y Forward", ""), + ('-Z', "-Z Forward", ""), + ), + default="X", + ) axis_up: EnumProperty( - name="Up", - items=(('X', "X Up", ""), - ('Y', "Y Up", ""), - ('Z', "Z Up", ""), - ('-X', "-X Up", ""), - ('-Y', "-Y Up", ""), - ('-Z', "-Z Up", ""), - ), - default="Y", - ) + name="Up", + items=(('X', "X Up", ""), + ('Y', "Y Up", ""), + ('Z', "Z Up", ""), + ('-X', "-X Up", ""), + ('-Y', "-Y Up", ""), + ('-Z', "-Z Up", ""), + ), + default="Y", + ) CLASSES = [ + LagBoneControllerProperty, BoneProperty, ArmatureProperty ] diff --git a/io_scene_niftools/ui/armature.py b/io_scene_niftools/ui/armature.py index 69e377b08..e8262c015 100644 --- a/io_scene_niftools/ui/armature.py +++ b/io_scene_niftools/ui/armature.py @@ -63,6 +63,31 @@ def draw(self, context): row.prop(nif_bone_props, "priority") row.prop(nif_bone_props, "longname") +class BoneControllerPanel(Panel): + bl_idname = "NIFTOOLS_PT_BoneControllerPanel" + bl_label = "Niftools Bone Controller Props" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = 'bone' + + # noinspection PyUnusedLocal + @classmethod + def poll(cls, context): + return context.bone is not None + + def draw(self, context): + nif_bone_props = context.bone.niftools + + row = self.layout.column() + row.prop(nif_bone_props.lag_bone, "enabled") + row2 = self.layout.column() + row2.prop(nif_bone_props.lag_bone, "flags") + row2.prop(nif_bone_props.lag_bone, "linear_velocity") + row2.prop(nif_bone_props.lag_bone, "linear_rotation") + row2.prop(nif_bone_props.lag_bone, "maximum_distance") + row2.enabled = nif_bone_props.lag_bone.enabled + + class ArmaturePanel(Panel): bl_label = "Niftools Armature Props" @@ -88,7 +113,8 @@ def draw(self, context): classes = [ BonePanel, - ArmaturePanel + ArmaturePanel, + BoneControllerPanel ]