Lots of typing fixes and simplifications (using list and dict instead of the typing.List etc.)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from bpy.types import Action, AnimData, Context, Object, PoseBone
|
||||
|
||||
from psk_psa_py.psa.data import Psa
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
from typing import Tuple
|
||||
from mathutils import Matrix, Quaternion, Vector
|
||||
|
||||
from ..shared.helpers import PsxBoneCollection, convert_bpy_quaternion_to_psx_quaternion, convert_vector_to_vector3, create_psx_bones, get_coordinate_system_transform
|
||||
@@ -10,7 +10,7 @@ from ..shared.helpers import PsxBoneCollection, convert_bpy_quaternion_to_psx_qu
|
||||
class PsaBuildSequence:
|
||||
class NlaState:
|
||||
def __init__(self):
|
||||
self.action: Optional[Action] = None
|
||||
self.action: Action | None = None
|
||||
self.frame_start: int = 0
|
||||
self.frame_end: int = 0
|
||||
|
||||
@@ -22,16 +22,16 @@ class PsaBuildSequence:
|
||||
self.compression_ratio: float = 1.0
|
||||
self.key_quota: int = 0
|
||||
self.fps: float = 30.0
|
||||
self.group: Optional[str] = None
|
||||
self.group: str | None = None
|
||||
|
||||
|
||||
class PsaBuildOptions:
|
||||
def __init__(self):
|
||||
self.armature_objects: List[Object] = []
|
||||
self.animation_data: Optional[AnimData] = None
|
||||
self.sequences: List[PsaBuildSequence] = []
|
||||
self.armature_objects: list[Object] = []
|
||||
self.animation_data: AnimData | None = None
|
||||
self.sequences: list[PsaBuildSequence] = []
|
||||
self.bone_filter_mode: str = 'ALL'
|
||||
self.bone_collection_indices: List[PsxBoneCollection] = []
|
||||
self.bone_collection_indices: list[PsxBoneCollection] = []
|
||||
self.sequence_name_prefix: str = ''
|
||||
self.sequence_name_suffix: str = ''
|
||||
self.scale = 1.0
|
||||
@@ -307,7 +307,6 @@ def build_psa(context: Context, options: PsaBuildOptions) -> Psa:
|
||||
options.export_space,
|
||||
export_bone.scale,
|
||||
coordinate_system_transform=coordinate_system_transform
|
||||
# has_false_root_bone=psx_bone_create_result.has_false_root_bone,
|
||||
)
|
||||
last_frame_bone_poses.append((location, rotation))
|
||||
|
||||
@@ -331,7 +330,6 @@ def build_psa(context: Context, options: PsaBuildOptions) -> Psa:
|
||||
export_space=options.export_space,
|
||||
scale=export_bone.scale,
|
||||
coordinate_system_transform=coordinate_system_transform,
|
||||
# has_false_root_bone=psx_bone_create_result.has_false_root_bone,
|
||||
)
|
||||
next_frame_bone_poses.append((location, rotation))
|
||||
|
||||
@@ -359,7 +357,6 @@ def build_psa(context: Context, options: PsaBuildOptions) -> Psa:
|
||||
export_space=options.export_space,
|
||||
scale=export_bone.scale,
|
||||
coordinate_system_transform=coordinate_system_transform,
|
||||
# has_false_root_bone=psx_bone_create_result.has_false_root_bone,
|
||||
)
|
||||
add_key(location, rotation)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import re
|
||||
from configparser import ConfigParser
|
||||
from typing import Dict, List
|
||||
|
||||
REMOVE_TRACK_LOCATION = (1 << 0)
|
||||
REMOVE_TRACK_ROTATION = (1 << 1)
|
||||
@@ -8,7 +7,7 @@ REMOVE_TRACK_ROTATION = (1 << 1)
|
||||
|
||||
class PsaConfig:
|
||||
def __init__(self):
|
||||
self.sequence_bone_flags: Dict[str, Dict[int, int]] = dict()
|
||||
self.sequence_bone_flags: dict[str, dict[int, int]] = dict()
|
||||
|
||||
|
||||
def _load_config_file(file_path: str) -> ConfigParser:
|
||||
@@ -48,7 +47,7 @@ def _get_bone_flags_from_value(value: str) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def read_psa_config(psa_sequence_names: List[str], file_path: str) -> PsaConfig:
|
||||
def read_psa_config(psa_sequence_names: list[str], file_path: str) -> PsaConfig:
|
||||
psa_config = PsaConfig()
|
||||
|
||||
config = _load_config_file(file_path)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from abc import abstractmethod
|
||||
from collections import Counter
|
||||
from typing import List, Iterable, Dict, Protocol, Sequence, Tuple, cast as typing_cast
|
||||
from typing import Iterable, Sequence, Tuple, cast as typing_cast
|
||||
|
||||
import bpy
|
||||
import re
|
||||
@@ -19,7 +19,7 @@ from .ui import PSA_UL_export_sequences
|
||||
from ..builder import build_psa, PsaBuildSequence, PsaBuildOptions
|
||||
from psk_psa_py.psa.writer import write_psa_to_file
|
||||
from ...shared.helpers import get_collection_export_operator_from_context, get_collection_from_context, get_psk_input_objects_for_collection, populate_bone_collection_list, get_nla_strips_in_frame_range, PsxBoneCollection
|
||||
from ...shared.types import BpyCollectionProperty, PSX_PG_action_export
|
||||
from ...shared.types import PSX_PG_action_export
|
||||
from ...shared.ui import draw_bone_filter_mode
|
||||
from ...shared.operators import PSK_OT_bone_collection_list_populate, PSK_OT_bone_collection_list_select_all
|
||||
|
||||
@@ -179,7 +179,7 @@ def get_sequence_compression_ratio(
|
||||
def get_timeline_marker_sequence_frame_ranges(
|
||||
animation_data: AnimData,
|
||||
scene: Scene,
|
||||
marker_names: List[str],
|
||||
marker_names: list[str],
|
||||
) -> dict[str, tuple[int, int]]:
|
||||
# Timeline markers need to be sorted so that we can determine the sequence start and end positions.
|
||||
sequence_frame_ranges: dict[str, tuple[int, int]] = dict()
|
||||
@@ -240,7 +240,7 @@ def get_sequences_from_action(action: Action):
|
||||
|
||||
def get_sequences_from_action_pose_markers(
|
||||
action: Action,
|
||||
pose_markers: List[TimelineMarker],
|
||||
pose_markers: list[TimelineMarker],
|
||||
pose_marker: TimelineMarker,
|
||||
pose_marker_index: int,
|
||||
):
|
||||
@@ -259,7 +259,7 @@ def get_sequences_from_action_pose_markers(
|
||||
yield from get_sequences_from_name_and_frame_range(sequence_name, frame_start, frame_end)
|
||||
|
||||
|
||||
def get_visible_sequences(pg: PsaExportMixin, sequences) -> List[PsaExportSequenceMixin]:
|
||||
def get_visible_sequences(pg: PsaExportMixin, sequences) -> list[PsaExportSequenceMixin]:
|
||||
visible_sequences = []
|
||||
for i, flag in enumerate(filter_sequences(pg, sequences)):
|
||||
if bool(flag & (1 << 30)):
|
||||
@@ -471,7 +471,7 @@ def create_psa_export_options(context: Context, armature_objects: Sequence[Objec
|
||||
raise RuntimeError(f'No armatures')
|
||||
|
||||
animation_data = armature_objects[0].animation_data
|
||||
export_sequences: List[PsaBuildSequence] = []
|
||||
export_sequences: list[PsaBuildSequence] = []
|
||||
|
||||
# TODO: this needs to be changed so that we iterate over all of the armature objects?
|
||||
# do we need to check for primary key? (data vs. object?)
|
||||
@@ -507,7 +507,7 @@ def create_psa_export_options(context: Context, armature_objects: Sequence[Objec
|
||||
export_sequences.append(export_sequence)
|
||||
case 'TIMELINE_MARKERS':
|
||||
for marker_item in filter(lambda x: x.is_selected, pg.marker_list):
|
||||
nla_strips_actions: List[Action] = []
|
||||
nla_strips_actions: list[Action] = []
|
||||
for nla_strip in get_nla_strips_in_frame_range(animation_data, marker_item.frame_start, marker_item.frame_end):
|
||||
if nla_strip.action:
|
||||
nla_strips_actions.append(nla_strip.action)
|
||||
@@ -584,7 +584,7 @@ class PSA_OT_export(Operator, ExportHelper):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.armature_objects: List[Object] = []
|
||||
self.armature_objects: list[Object] = []
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import re
|
||||
import sys
|
||||
from fnmatch import fnmatch
|
||||
from typing import List, Optional, Sequence
|
||||
from typing import Sequence
|
||||
import bpy
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
@@ -58,7 +58,7 @@ class PSA_PG_export_sequence(PsaExportSequenceMixin):
|
||||
|
||||
def get_sequences_from_name_and_frame_range(name: str, frame_start: int, frame_end: int):
|
||||
# Check for loop
|
||||
anims: List[tuple[str, int, int]] = []
|
||||
anims: list[tuple[str, int, int]] = []
|
||||
loop_pattern = r'\@(\d+)\:(.+)'
|
||||
loop_match = re.match(loop_pattern, name)
|
||||
if loop_match:
|
||||
@@ -107,7 +107,7 @@ def nla_track_update_cb(self: 'PSA_PG_export', context: Context) -> None:
|
||||
strip.frame_end = frame_end
|
||||
|
||||
|
||||
def get_animation_data(pg: 'PSA_PG_export', context: Context) -> Optional[AnimData]:
|
||||
def get_animation_data(pg: 'PSA_PG_export', context: Context) -> AnimData | None:
|
||||
animation_data_object = context.object
|
||||
return animation_data_object.animation_data if animation_data_object else None
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
from bpy.props import CollectionProperty, StringProperty
|
||||
from bpy.types import Context, Event, FileHandler, Object, Operator, OperatorFileListElement
|
||||
from bpy.types import Context, Event, Object, Operator, OperatorFileListElement
|
||||
from bpy_extras.io_utils import ImportHelper
|
||||
|
||||
from .properties import PsaImportMixin, get_visible_sequences
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import re
|
||||
from fnmatch import fnmatch
|
||||
from typing import List
|
||||
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
@@ -133,7 +132,7 @@ class PSA_PG_import(PropertyGroup):
|
||||
select_text: PointerProperty(type=Text)
|
||||
|
||||
|
||||
def filter_sequences(pg: PSA_PG_import, sequences) -> List[int]:
|
||||
def filter_sequences(pg: PSA_PG_import, sequences) -> list[int]:
|
||||
bitflag_filter_item = 1 << 30
|
||||
flt_flags = [bitflag_filter_item] * len(sequences)
|
||||
|
||||
@@ -167,7 +166,7 @@ def filter_sequences(pg: PSA_PG_import, sequences) -> List[int]:
|
||||
return flt_flags
|
||||
|
||||
|
||||
def get_visible_sequences(pg: PSA_PG_import, sequences) -> List[PSA_PG_import_action_list_item]:
|
||||
def get_visible_sequences(pg: PSA_PG_import, sequences) -> list[PSA_PG_import_action_list_item]:
|
||||
bitflag_filter_item = 1 << 30
|
||||
visible_sequences = []
|
||||
for i, flag in enumerate(filter_sequences(pg, sequences)):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Sequence, Iterable, List, Optional, cast as typing_cast
|
||||
from typing import Sequence, Iterable, cast as typing_cast
|
||||
|
||||
import bpy
|
||||
import numpy as np
|
||||
@@ -32,7 +32,7 @@ class PsaImportOptions(object):
|
||||
fps_custom: float = 30.0,
|
||||
fps_source: str = 'SEQUENCE',
|
||||
psa_config: PsaConfig = PsaConfig(),
|
||||
sequence_names: Optional[List[str]] = None,
|
||||
sequence_names: list[str] | None = None,
|
||||
should_convert_to_samples: bool = False,
|
||||
should_overwrite: bool = False,
|
||||
should_stash: bool = False,
|
||||
@@ -61,13 +61,13 @@ class PsaImportOptions(object):
|
||||
class ImportBone(object):
|
||||
def __init__(self, psa_bone: PsxBone):
|
||||
self.psa_bone: PsxBone = psa_bone
|
||||
self.parent: Optional[ImportBone] = None
|
||||
self.armature_bone: Optional[Bone] = None
|
||||
self.pose_bone: Optional[PoseBone] = None
|
||||
self.parent: ImportBone | None = None
|
||||
self.armature_bone: Bone | None = None
|
||||
self.pose_bone: PoseBone | None = None
|
||||
self.original_location: Vector = Vector()
|
||||
self.original_rotation: Quaternion = Quaternion()
|
||||
self.post_rotation: Quaternion = Quaternion()
|
||||
self.fcurves: List[FCurve] = []
|
||||
self.fcurves: list[FCurve] = []
|
||||
|
||||
|
||||
def _calculate_fcurve_data(import_bone: ImportBone, key_data: Sequence[float]):
|
||||
@@ -90,10 +90,10 @@ def _calculate_fcurve_data(import_bone: ImportBone, key_data: Sequence[float]):
|
||||
|
||||
class PsaImportResult:
|
||||
def __init__(self):
|
||||
self.warnings: List[str] = []
|
||||
self.warnings: list[str] = []
|
||||
|
||||
|
||||
def _get_armature_bone_index_for_psa_bone(psa_bone_name: str, armature_bone_names: List[str], bone_mapping: BoneMapping) -> Optional[int]:
|
||||
def _get_armature_bone_index_for_psa_bone(psa_bone_name: str, armature_bone_names: list[str], bone_mapping: BoneMapping) -> int | None:
|
||||
"""
|
||||
@param psa_bone_name: The name of the PSA bone.
|
||||
@param armature_bone_names: The names of the bones in the armature.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import bmesh
|
||||
import bpy
|
||||
import numpy as np
|
||||
from bpy.types import Armature, Context, Object, Mesh
|
||||
from bpy.types import Armature, Context, Object, Mesh, Material
|
||||
from mathutils import Matrix
|
||||
from typing import Dict, Iterable, List, Optional, cast as typing_cast
|
||||
from typing import Iterable, Sequence, cast as typing_cast
|
||||
from psk_psa_py.shared.data import Vector3
|
||||
from psk_psa_py.psk.data import Psk
|
||||
from .properties import triangle_type_and_bit_flags_to_poly_flags
|
||||
@@ -23,10 +23,10 @@ from ..shared.helpers import (
|
||||
class PskBuildOptions(object):
|
||||
def __init__(self):
|
||||
self.bone_filter_mode = 'ALL'
|
||||
self.bone_collection_indices: List[PsxBoneCollection] = []
|
||||
self.bone_collection_indices: list[PsxBoneCollection] = []
|
||||
self.object_eval_state = 'EVALUATED'
|
||||
self.material_order_mode = 'AUTOMATIC'
|
||||
self.material_name_list: List[str] = []
|
||||
self.material_name_list: list[str] = []
|
||||
self.scale = 1.0
|
||||
self.export_space = 'WORLD'
|
||||
self.forward_axis = 'X'
|
||||
@@ -37,7 +37,7 @@ class PskBuildOptions(object):
|
||||
class PskBuildResult(object):
|
||||
def __init__(self, psk: Psk, warnings: list[str]):
|
||||
self.psk: Psk = psk
|
||||
self.warnings: List[str] = warnings
|
||||
self.warnings: list[str] = warnings
|
||||
|
||||
|
||||
def _get_mesh_export_space_matrix(node: ObjectNode | None, export_space: str) -> Matrix:
|
||||
@@ -70,7 +70,7 @@ def _get_mesh_export_space_matrix(node: ObjectNode | None, export_space: str) ->
|
||||
assert False, f'Invalid export space: {export_space}'
|
||||
|
||||
|
||||
def _get_material_name_indices(obj: Object, material_names: List[str]) -> Iterable[int]:
|
||||
def _get_material_name_indices(obj: Object, material_names: list[str]) -> Iterable[int]:
|
||||
"""
|
||||
Returns the index of the material in the list of material names.
|
||||
If the material is not found, the index 0 is returned.
|
||||
@@ -206,7 +206,7 @@ def build_psk(context: Context, input_objects: PskInputObjects, options: PskBuil
|
||||
bm.to_mesh(mesh_data)
|
||||
del bm
|
||||
evaluated_mesh_object = bpy.data.objects.new('', mesh_data)
|
||||
mesh_object = evaluated_mesh_object
|
||||
mesh_object = evaluated_mesh_object
|
||||
mesh_object.matrix_world = matrix_world
|
||||
|
||||
# Extract the scale from the matrix.
|
||||
@@ -271,6 +271,7 @@ def build_psk(context: Context, input_objects: PskInputObjects, options: PskBuil
|
||||
for loop_index, loop in enumerate(mesh_data.loops):
|
||||
wedges.append(Psk.Wedge(point_index=loop.vertex_index + vertex_offset, u=0.0, v=0.0))
|
||||
|
||||
|
||||
# Assign material indices to the wedges.
|
||||
for triangle in mesh_data.loop_triangles:
|
||||
for loop_index in triangle.loops:
|
||||
@@ -315,7 +316,7 @@ def build_psk(context: Context, input_objects: PskInputObjects, options: PskBuil
|
||||
|
||||
bone_names = psx_bone_create_result.armature_object_bone_names[armature_object]
|
||||
vertex_group_names = [x.name for x in mesh_object.vertex_groups]
|
||||
vertex_group_bone_indices: Dict[int, int] = dict()
|
||||
vertex_group_bone_indices: dict[int, int] = dict()
|
||||
for vertex_group_index, vertex_group_name in enumerate(vertex_group_names):
|
||||
try:
|
||||
vertex_group_bone_indices[vertex_group_index] = bone_names.index(vertex_group_name) + bone_index_offset
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from pathlib import Path
|
||||
from typing import Iterable, List, cast as typing_cast
|
||||
from typing import Iterable, cast as typing_cast
|
||||
|
||||
import bpy
|
||||
from bpy.props import StringProperty
|
||||
@@ -173,7 +173,7 @@ class PSK_OT_material_list_name_move_down(Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def get_sorted_materials_by_names(materials: Iterable[Material], material_names: List[str]) -> List[Material]:
|
||||
def get_sorted_materials_by_names(materials: Iterable[Material], material_names: list[str]) -> list[Material]:
|
||||
"""
|
||||
Sorts the materials by the order of the material names list. Any materials not in the list will be appended to the
|
||||
end of the list in the order they are found.
|
||||
|
||||
@@ -4,7 +4,7 @@ import numpy as np
|
||||
|
||||
from bpy.types import Context, Object, VertexGroup, ArmatureModifier, FloatColorAttribute
|
||||
from mathutils import Matrix, Quaternion, Vector
|
||||
from typing import List, Optional, cast as typing_cast
|
||||
from typing import cast as typing_cast
|
||||
|
||||
from psk_psa_py.psk.data import Psk
|
||||
from psk_psa_py.shared.data import PsxBone
|
||||
@@ -35,12 +35,11 @@ class ImportBone:
|
||||
def __init__(self, index: int, psk_bone: PsxBone):
|
||||
self.index: int = index
|
||||
self.psk_bone: PsxBone = psk_bone
|
||||
self.parent: Optional[ImportBone] = None
|
||||
self.parent: ImportBone | None = None
|
||||
self.local_rotation: Quaternion = Quaternion()
|
||||
self.local_translation: Vector = Vector()
|
||||
self.world_rotation_matrix: Matrix = Matrix()
|
||||
self.world_matrix: Matrix = Matrix()
|
||||
self.vertex_group = None
|
||||
self.original_rotation: Quaternion = Quaternion()
|
||||
self.original_location: Vector = Vector()
|
||||
self.post_rotation: Quaternion = Quaternion()
|
||||
@@ -48,9 +47,9 @@ class ImportBone:
|
||||
|
||||
class PskImportResult:
|
||||
def __init__(self):
|
||||
self.warnings: List[str] = []
|
||||
self.armature_object: Optional[Object] = None
|
||||
self.mesh_object: Optional[Object] = None
|
||||
self.warnings: list[str] = []
|
||||
self.armature_object: Object | None = None
|
||||
self.mesh_object: Object | None = None
|
||||
|
||||
@property
|
||||
def root_object(self) -> Object:
|
||||
@@ -83,7 +82,7 @@ def import_psk(psk: Psk, context: Context, name: str, options: PskImportOptions)
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
import_bones: List[ImportBone] = []
|
||||
import_bones: list[ImportBone] = []
|
||||
|
||||
for bone_index, psk_bone in enumerate(psk.bones):
|
||||
import_bone = ImportBone(bone_index, psk_bone)
|
||||
@@ -263,7 +262,7 @@ def import_psk(psk: Psk, context: Context, name: str, options: PskImportOptions)
|
||||
# Weights
|
||||
# Get a list of all bones that have weights associated with them.
|
||||
vertex_group_bone_indices = set(map(lambda weight: weight.bone_index, psk.weights))
|
||||
vertex_groups: List[Optional[VertexGroup]] = [None] * len(psk.bones)
|
||||
vertex_groups: list[VertexGroup | None] = [None] * len(psk.bones)
|
||||
for bone_index, psk_bone in map(lambda x: (x, psk.bones[x]), vertex_group_bone_indices):
|
||||
vertex_groups[bone_index] = mesh_object.vertex_groups.new(name=psk_bone.name.decode('windows-1252'))
|
||||
|
||||
|
||||
@@ -16,3 +16,8 @@ class PskImportMixin:
|
||||
should_import_shape_keys: bool
|
||||
scale: float
|
||||
bdk_repository_id: str
|
||||
|
||||
|
||||
def triangle_type_and_bit_flags_to_poly_flags(mesh_triangle_type: str, mesh_triangle_bit_flags: set[str]) -> int: ...
|
||||
|
||||
def poly_flags_to_triangle_type_and_bit_flags(poly_flags: int) -> tuple[str, set[str]]: ...
|
||||
|
||||
@@ -5,7 +5,7 @@ These functions are used to iterate over objects in a collection or view layer i
|
||||
instances. This is useful for exporters that need to traverse the object hierarchy in a predictable order.
|
||||
"""
|
||||
|
||||
from typing import Optional, Set, Iterable, List
|
||||
from typing import Iterable
|
||||
|
||||
from bpy.types import Collection, Object, ViewLayer, LayerCollection
|
||||
from mathutils import Matrix
|
||||
@@ -15,7 +15,7 @@ class DfsObject:
|
||||
"""
|
||||
Represents an object in a depth-first search.
|
||||
"""
|
||||
def __init__(self, obj: Object, instance_objects: List[Object], matrix_world: Matrix):
|
||||
def __init__(self, obj: Object, instance_objects: list[Object], matrix_world: Matrix):
|
||||
self.obj = obj
|
||||
self.instance_objects = instance_objects
|
||||
self.matrix_world = matrix_world
|
||||
@@ -85,9 +85,9 @@ def dfs_collection_objects(collection: Collection, visible_only: bool = False) -
|
||||
|
||||
def _dfs_collection_objects_recursive(
|
||||
collection: Collection,
|
||||
instance_objects: Optional[List[Object]] = None,
|
||||
instance_objects: list[Object] | None = None,
|
||||
matrix_world: Matrix = Matrix.Identity(4),
|
||||
visited: Optional[Set[Object]]=None
|
||||
visited: set[Object] | None = None
|
||||
) -> Iterable[DfsObject]:
|
||||
"""
|
||||
Depth-first search of objects in a collection, including recursing into instances.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import bpy
|
||||
from collections import Counter
|
||||
from typing import List, Iterable, Optional, Dict, Tuple, cast as typing_cast
|
||||
from typing import Iterable, cast as typing_cast
|
||||
from bpy.types import Armature, AnimData, Collection, Context, Object, ArmatureModifier, SpaceProperties, PropertyGroup
|
||||
from mathutils import Matrix, Vector, Quaternion as BpyQuaternion
|
||||
from psk_psa_py.shared.data import PsxBone, Quaternion, Vector3
|
||||
@@ -102,7 +102,7 @@ def populate_bone_collection_list(
|
||||
item.is_selected = bone_collection.name in selected_assigned_collection_names if has_selected_collections else True
|
||||
|
||||
|
||||
def get_export_bone_names(armature_object: Object, bone_filter_mode: str, bone_collection_indices: Iterable[int]) -> List[str]:
|
||||
def get_export_bone_names(armature_object: Object, bone_filter_mode: str, bone_collection_indices: Iterable[int]) -> list[str]:
|
||||
"""
|
||||
Returns a sorted list of bone indices that should be exported for the given bone filter mode and bone collections.
|
||||
|
||||
@@ -172,9 +172,9 @@ def convert_string_to_cp1252_bytes(string: str) -> bytes:
|
||||
|
||||
|
||||
def create_psx_bones_from_blender_bones(
|
||||
bones: List[bpy.types.Bone],
|
||||
bones: list[bpy.types.Bone],
|
||||
armature_object_matrix_world: Matrix,
|
||||
) -> List[PsxBone]:
|
||||
) -> list[PsxBone]:
|
||||
"""
|
||||
Creates PSX bones from the given Blender bones.
|
||||
|
||||
@@ -183,7 +183,7 @@ def create_psx_bones_from_blender_bones(
|
||||
# Apply the scale of the armature object to the bone location.
|
||||
_, _, armature_object_scale = armature_object_matrix_world.decompose()
|
||||
|
||||
psx_bones: List[PsxBone] = []
|
||||
psx_bones: list[PsxBone] = []
|
||||
for bone in bones:
|
||||
psx_bone = PsxBone()
|
||||
psx_bone.name = convert_string_to_cp1252_bytes(bone.name)
|
||||
@@ -237,10 +237,6 @@ class PsxBoneCreateResult:
|
||||
self.bones = bones
|
||||
self.armature_object_root_bone_indices = armature_object_root_bone_indices
|
||||
self.armature_object_bone_names = armature_object_bone_names
|
||||
|
||||
@property
|
||||
def has_false_root_bone(self) -> bool:
|
||||
return len(self.bones) > 0 and self.bones[0].armature_object is None
|
||||
|
||||
|
||||
def convert_vector_to_vector3(vector: Vector) -> Vector3:
|
||||
@@ -280,7 +276,7 @@ class ObjectNode:
|
||||
def __init__(self, obj: Object):
|
||||
self.object = obj
|
||||
self.parent: ObjectNode | None = None
|
||||
self.children: List[ObjectNode] = []
|
||||
self.children: list[ObjectNode] = []
|
||||
|
||||
@property
|
||||
def root(self):
|
||||
@@ -298,8 +294,8 @@ class ObjectTree:
|
||||
A tree of the armature objects based on their hierarchy.
|
||||
'''
|
||||
def __init__(self, objects: Iterable[Object]):
|
||||
self.root_nodes: List[ObjectNode] = []
|
||||
object_node_map: Dict[Object, ObjectNode] = {x: ObjectNode(x) for x in objects}
|
||||
self.root_nodes: list[ObjectNode] = []
|
||||
object_node_map: dict[Object, ObjectNode] = {x: ObjectNode(x) for x in objects}
|
||||
|
||||
for obj, object_node in object_node_map.items():
|
||||
if obj.parent in object_node_map:
|
||||
@@ -334,14 +330,14 @@ class ObjectTree:
|
||||
|
||||
|
||||
def create_psx_bones(
|
||||
armature_objects: List[Object],
|
||||
armature_objects: list[Object],
|
||||
export_space: str = 'WORLD',
|
||||
root_bone_name: str = 'ROOT',
|
||||
forward_axis: str = 'X',
|
||||
up_axis: str = 'Z',
|
||||
scale: float = 1.0,
|
||||
bone_filter_mode: str = 'ALL',
|
||||
bone_collection_indices: Optional[List[PsxBoneCollection]] = None,
|
||||
bone_collection_indices: list[PsxBoneCollection] | None = None,
|
||||
bone_collection_primary_key: str = 'OBJECT',
|
||||
) -> PsxBoneCreateResult:
|
||||
"""
|
||||
@@ -366,9 +362,9 @@ def create_psx_bones(
|
||||
total_bone_count += len(armature_data.bones)
|
||||
|
||||
# Store the bone names to be exported for each armature object.
|
||||
armature_object_bone_names: Dict[Object, List[str]] = dict()
|
||||
armature_object_bone_names: dict[Object, list[str]] = dict()
|
||||
for armature_object in armature_objects:
|
||||
armature_bone_collection_indices: List[int] = []
|
||||
armature_bone_collection_indices: list[int] = []
|
||||
match bone_collection_primary_key:
|
||||
case 'OBJECT':
|
||||
armature_bone_collection_indices.extend([x.index for x in bone_collection_indices if x.armature_object_name == armature_object.name])
|
||||
@@ -390,6 +386,13 @@ def create_psx_bones(
|
||||
armature_data = typing_cast(Armature, armature_object.data)
|
||||
armature_bones = [armature_data.bones[bone_name] for bone_name in bone_names]
|
||||
|
||||
# Ensure that we don't have multiple root bones in this armature.
|
||||
root_bone_count = sum(1 for bone in armature_bones if bone.parent is None)
|
||||
if root_bone_count > 1:
|
||||
raise RuntimeError(f'Armature object \'{armature_object.name}\' has multiple root bones. '
|
||||
f'Only one root bone is allowed per armature.'
|
||||
)
|
||||
|
||||
armature_psx_bones = create_psx_bones_from_blender_bones(
|
||||
bones=armature_bones,
|
||||
armature_object_matrix_world=armature_object.matrix_world,
|
||||
@@ -611,8 +614,8 @@ from bpy.types import Depsgraph
|
||||
|
||||
class PskInputObjects(object):
|
||||
def __init__(self):
|
||||
self.mesh_dfs_objects: List[DfsObject] = []
|
||||
self.armature_objects: List[Object] = []
|
||||
self.mesh_dfs_objects: list[DfsObject] = []
|
||||
self.armature_objects: list[Object] = []
|
||||
|
||||
|
||||
def get_materials_for_mesh_objects(depsgraph: Depsgraph, mesh_objects: Iterable[Object]):
|
||||
@@ -640,7 +643,7 @@ def get_mesh_objects_for_context(context: Context) -> Iterable[DfsObject]:
|
||||
yield dfs_object
|
||||
|
||||
|
||||
def get_armature_for_mesh_object(mesh_object: Object) -> Optional[Object]:
|
||||
def get_armature_for_mesh_object(mesh_object: Object) -> Object | None:
|
||||
if mesh_object.type != 'MESH':
|
||||
return None
|
||||
# Get the first armature modifier with a non-empty armature object.
|
||||
|
||||
@@ -59,3 +59,5 @@ class PsxBoneExportMixin:
|
||||
|
||||
class PSX_PG_scene_export(TransformSourceMixin):
|
||||
pass
|
||||
|
||||
bone_filter_mode_items: tuple[tuple[str, str, str]]
|
||||
|
||||
Reference in New Issue
Block a user