Merge pull request 'main' (#118) from Onek8/LNXSDK:main into main

Reviewed-on: #118
This commit is contained in:
2026-05-17 17:55:02 +00:00
2 changed files with 32 additions and 15 deletions

View File

@ -276,10 +276,22 @@ class LeenkxExporter:
if armature.animation_data:
action = armature.animation_data.action
if action:
return [fcurve for fcurve in action.fcurves if fcurve.data_path.startswith(path)]
fcurves = LeenkxExporter.get_action_fcurves(action, armature.animation_data)
return [fcurve for fcurve in fcurves if fcurve.data_path.startswith(path)]
return []
@staticmethod
def get_action_fcurves(action: bpy.types.Action, anim_data: Optional[bpy.types.AnimData] = None) -> List[bpy.types.FCurve]:
if bpy.app.version >= (5, 0, 0):
if anim_data and anim_data.action_slot:
from bpy_extras import anim_utils
channelbag = anim_utils.action_ensure_channelbag_for_slot(action, anim_data.action_slot)
return channelbag.fcurves if channelbag else []
return []
else:
return action.fcurves
def export_bone(self, armature, bone: bpy.types.Bone, o, action: bpy.types.Action):
rpdat = lnx.utils.get_rp()
bobject_ref = self.bobject_bone_array.get(bone)
@ -319,7 +331,7 @@ class LeenkxExporter:
oanim['root_motion_rot'] = action.lnx_root_motion_rot
@staticmethod
def calculate_anim_frame_range(action: bpy.types.Action) -> Tuple[int, int]:
def calculate_anim_frame_range(action: bpy.types.Action, anim_data: Optional[bpy.types.AnimData] = None) -> Tuple[int, int]:
"""Calculates the required frame range of the given action by
also taking fcurve modifiers into account.
@ -330,14 +342,16 @@ class LeenkxExporter:
start = frame_range[0]
end = frame_range[1]
fcurves = LeenkxExporter.get_action_fcurves(action, anim_data)
# Blender 4.0+ compatibility: Handle zero-length frame ranges
if start == end:
start = 1
end = 2
if action.fcurves:
if fcurves:
all_keyframes = []
for fcurve in action.fcurves:
for fcurve in fcurves:
if fcurve.keyframe_points:
for keyframe in fcurve.keyframe_points:
all_keyframes.append(keyframe.co[0])
@ -350,7 +364,7 @@ class LeenkxExporter:
# Take FCurve modifiers into account if they have a restricted
# frame range
for fcurve in action.fcurves:
for fcurve in fcurves:
for modifier in fcurve.modifiers:
if not modifier.use_restricted_range:
continue
@ -404,7 +418,7 @@ class LeenkxExporter:
o['object_actions'] = []
o['object_actions'].append('action_' + action_name + ext)
frame_range = self.calculate_anim_frame_range(action)
frame_range = self.calculate_anim_frame_range(action, bobject.animation_data)
out_anim = {
'begin': frame_range[0],
'end': frame_range[1],
@ -414,7 +428,8 @@ class LeenkxExporter:
self.export_pose_markers(out_anim, action)
unresolved_data_paths = set()
for fcurve in action.fcurves:
fcurves = self.get_action_fcurves(action, bobject.animation_data)
for fcurve in fcurves:
data_path = fcurve.data_path
try:
@ -535,7 +550,7 @@ class LeenkxExporter:
fcurve_list = self.collect_bone_animation(armature, bone.name)
if fcurve_list and pose_bone:
begin_frame, end_frame = self.calculate_anim_frame_range(action)
begin_frame, end_frame = self.calculate_anim_frame_range(action, armature.animation_data)
out_track = {'target': "transform", 'frames': [], 'values': []}
o['anim'] = {'tracks': [out_track]}
@ -653,8 +668,8 @@ class LeenkxExporter:
return fov
return None
def write_bone_matrices(self, scene, action):
begin_frame, end_frame = self.calculate_anim_frame_range(action)
def write_bone_matrices(self, scene, action, anim_data: Optional[bpy.types.AnimData] = None):
begin_frame, end_frame = self.calculate_anim_frame_range(action, anim_data)
if len(self.bone_tracks) > 0:
hidden_states = {}
try:
@ -807,7 +822,8 @@ class LeenkxExporter:
# if (shapeKeys.animation_data):
# action = shapeKeys.animation_data.action
# if (action):
# for fcurve in action.fcurves:
# fcurves = self.get_action_fcurves(action, shapeKeys.animation_data)
# for fcurve in fcurves:
# if ((fcurve.data_path.startswith("key_blocks[")) and (fcurve.data_path.endswith("].value"))):
# keyName = fcurve.data_path.strip("abcdehklopstuvy[]_.")
# if ((keyName[0] == "\"") or (keyName[0] == "'")):
@ -822,7 +838,8 @@ class LeenkxExporter:
# if ((not action) and (node.animation_data)):
# action = node.animation_data.action
# if (action):
# for fcurve in action.fcurves:
# fcurves = self.get_action_fcurves(action, node.animation_data)
# for fcurve in fcurves:
# if ((fcurve.data_path.startswith("data.shape_keys.key_blocks[")) and (fcurve.data_path.endswith("].value"))):
# keyName = fcurve.data_path.strip("abcdehklopstuvy[]_.")
# if ((keyName[0] == "\"") or (keyName[0] == "'")):
@ -1324,7 +1341,7 @@ class LeenkxExporter:
_bake_hidden[_obj] = False
_obj.hide_viewport = True
start, end = self.calculate_anim_frame_range(action)
start, end = self.calculate_anim_frame_range(action, skelobj.animation_data)
bake_result = bpy.ops.nla.bake(
frame_start=start,
@ -1361,7 +1378,7 @@ class LeenkxExporter:
boneo = {}
self.export_bone(skelobj, bone, boneo, action)
bones.append(boneo)
self.write_bone_matrices(bpy.context.scene, action)
self.write_bone_matrices(bpy.context.scene, action, skelobj.animation_data)
if len(bones) > 0 and 'anim' in bones[0]:
self.export_pose_markers(bones[0]['anim'], original_action)
self.export_root_motion(bones[0]['anim'], original_action)

View File

@ -27,7 +27,7 @@ class ChannelMessageID extends MessageID {
final PDstAttenuation;
#if (kha_html5 || kha_debug_html5)
final PVolumeLeft;Add commentMore actions
final PVolumeLeft;
final PVolumeRight;
#end
}