MetaFusion/scripts/dnalib/behavior.py
2025-02-09 21:35:41 +08:00

372 lines
13 KiB
Python

from dataclasses import dataclass, field
from typing import List, Optional, cast
from dna import BinaryStreamReader as DNAReader
from .definition import Definition
from .layer import Layer
class Behavior(Definition):
"""
@type reader: BinaryStreamReader
@param reader: The binary stream reader being used
@type gui_to_raw: ConditionalTable
@param gui_to_raw: Mapping data about gui to raw values
@type psd: PSDMatrix
@param psd: The data representing Pose Space Deformation
@type blend_shapes: BlendShapesData
@param blend_shapes: The data representing blend shapes
@type animated_maps: AnimatedMapsConditionalTable
@param animated_maps: The data representing animated maps
@type joints: JointGroups
@param joints: The data representing joints
"""
def __init__(self, reader: DNAReader, layers: Optional[List[Layer]]) -> None:
super().__init__(reader, layers)
self.gui_to_raw = ConditionalTable()
self.psd = PSDMatrix()
self.blend_shapes = BlendShapesData()
self.animated_maps_conditional_table = AnimatedMapsConditionalTable()
self.joint_groups = JointGroups()
self.behavior_read = False
def start_read(self) -> None:
super().start_read()
self.behavior_read = False
def is_read(self) -> bool:
return super().is_read() and self.behavior_read
def read(self) -> None:
"""
Starts reading in the behavior part of the DNA
"""
super().read()
if not self.behavior_read and self.layer_enabled(Layer.behavior):
self.behavior_read = True
self.add_gui_to_raw()
self.add_psd()
self.add_joint_groups()
self.add_blend_shapes()
self.add_animated_maps_conditional_table()
def get_animated_map_lods(self) -> List[int]:
return cast(List[int], self.reader.getAnimatedMapLODs())
def get_animated_map_from_values(self) -> List[float]:
return cast(List[float], self.reader.getAnimatedMapFromValues())
def get_animated_map_to_values(self) -> List[float]:
return cast(List[float], self.reader.getAnimatedMapToValues())
def get_animated_map_slope_values(self) -> List[float]:
return cast(List[float], self.reader.getAnimatedMapSlopeValues())
def get_animated_map_cut_values(self) -> List[float]:
return cast(List[float], self.reader.getAnimatedMapCutValues())
def get_animated_map_input_indices(self) -> List[int]:
return cast(List[int], self.reader.getAnimatedMapInputIndices())
def get_animated_map_output_indices(self) -> List[int]:
return cast(List[int], self.reader.getAnimatedMapOutputIndices())
def get_gui_to_raw_from_values(self) -> List[float]:
return cast(List[float], self.reader.getGUIToRawFromValues())
def get_gui_to_raw_to_values(self) -> List[float]:
return cast(List[float], self.reader.getGUIToRawToValues())
def gget_gui_to_raw_slope_values(self) -> List[float]:
return cast(List[float], self.reader.getGUIToRawSlopeValues())
def get_gui_to_raw_cut_values(self) -> List[float]:
return cast(List[float], self.reader.getGUIToRawCutValues())
def get_gui_to_raw_input_indices(self) -> List[int]:
return cast(List[int], self.reader.getGUIToRawInputIndices())
def get_gui_to_raw_output_indices(self) -> List[int]:
return cast(List[int], self.reader.getGUIToRawOutputIndices())
def get_psd_count(self) -> int:
return cast(int, self.reader.getPSDCount())
def get_psd_row_indices(self) -> List[int]:
return cast(List[int], self.reader.getPSDRowIndices())
def get_psd_column_indices(self) -> List[int]:
return cast(List[int], self.reader.getPSDColumnIndices())
def get_psd_values(self) -> List[float]:
return cast(List[float], self.reader.getPSDValues())
def get_blend_shape_channel_lods(self) -> List[int]:
return cast(List[int], self.reader.getBlendShapeChannelLODs())
def get_blend_shape_channel_input_indices(self) -> List[int]:
return cast(List[int], self.reader.getBlendShapeChannelInputIndices())
def get_blend_shape_channel_output_indices(self) -> List[int]:
return cast(List[int], self.reader.getBlendShapeChannelOutputIndices())
def get_joint_row_count(self) -> int:
return cast(int, self.reader.getJointRowCount())
def get_joint_column_count(self) -> int:
return cast(int, self.reader.getJointColumnCount())
def get_joint_variable_attribute_indices(self) -> int:
return cast(int, self.reader.getJointVariableAttributeIndices())
def get_joint_group_count(self) -> int:
return cast(int, self.reader.getJointGroupCount())
def get_joint_group_logs(self, joint_group_index: int) -> List[int]:
return cast(List[int], self.reader.getJointGroupLODs(joint_group_index))
def get_joint_group_input_indices(self, joint_group_index: int) -> List[int]:
return cast(List[int], self.reader.getJointGroupInputIndices(joint_group_index))
def get_joint_group_output_indices(self, joint_group_index: int) -> List[int]:
return cast(
List[int], self.reader.getJointGroupOutputIndices(joint_group_index)
)
def get_joint_group_values(self, joint_group_index: int) -> List[float]:
return cast(List[float], self.reader.getJointGroupValues(joint_group_index))
def get_joint_group_joint_indices(self, joint_group_index: int) -> List[int]:
return cast(List[int], self.reader.getJointGroupJointIndices(joint_group_index))
def add_gui_to_raw(self) -> None:
"""Reads in the gui to raw mapping"""
self.reader.gui_to_raw = ConditionalTable(
inputs=self.get_gui_to_raw_input_indices(),
outputs=self.get_gui_to_raw_output_indices(),
from_values=self.get_gui_to_raw_from_values(),
to_values=self.get_gui_to_raw_to_values(),
slope_values=self.gget_gui_to_raw_slope_values(),
cut_values=self.get_gui_to_raw_cut_values(),
)
def add_psd(self) -> None:
"""Reads in the PSD part of the behavior"""
self.psd = PSDMatrix(
count=self.get_psd_count(),
rows=self.get_psd_row_indices(),
columns=self.get_psd_column_indices(),
values=self.get_psd_values(),
)
def add_joint_groups(self) -> None:
"""Reads in the joints part of the behavior"""
self.joint_groups.joint_row_count = self.reader.getJointRowCount()
self.joint_groups.joint_column_count = self.reader.getJointColumnCount()
for lod in range(self.get_lod_count()):
self.joint_groups.joint_variable_attribute_indices.append(
self.reader.getJointVariableAttributeIndices(lod)
)
for joint_group_index in range(self.get_joint_group_count()):
self.joint_groups.joint_groups.append(
JointGroup(
lods=self.get_joint_group_logs(joint_group_index),
inputs=self.get_joint_group_input_indices(joint_group_index),
outputs=self.get_joint_group_output_indices(joint_group_index),
values=self.get_joint_group_values(joint_group_index),
joints=self.get_joint_group_joint_indices(joint_group_index),
)
)
def add_blend_shapes(self) -> None:
"""Reads in the blend shapes part of the behavior"""
self.blend_shapes = BlendShapesData(
lods=self.get_blend_shape_channel_lods(),
inputs=self.get_blend_shape_channel_input_indices(),
outputs=self.get_blend_shape_channel_output_indices(),
)
def add_animated_maps_conditional_table(self) -> None:
"""Reads in the animated maps part of the behavior"""
self.reader.animated_maps_conditional_table = AnimatedMapsConditionalTable(
lods=self.get_animated_map_lods(),
conditional_table=ConditionalTable(
from_values=self.get_animated_map_from_values(),
to_values=self.get_animated_map_to_values(),
slope_values=self.get_animated_map_slope_values(),
cut_values=self.get_animated_map_cut_values(),
inputs=self.get_animated_map_input_indices(),
outputs=self.get_animated_map_output_indices(),
),
)
@dataclass
class ConditionalTable:
"""
A model class for holding various values
Attributes
----------
@type from_values: List[float]
@param from_values: The list of values
@type to_values: List[float]
@param to_values: The list of values
@type slope_values: List[float]
@param slope_values: The list of slope values
@type cut_values: List[float]
@param cut_values: The list of cut values
@type inputs: List[int]
@param inputs: The indices of inputs
@type outputs: List[int]
@param outputs: The indices of outputs
"""
from_values: List[float] = field(default_factory=list)
to_values: List[float] = field(default_factory=list)
slope_values: List[float] = field(default_factory=list)
cut_values: List[float] = field(default_factory=list)
inputs: List[int] = field(default_factory=list)
outputs: List[int] = field(default_factory=list)
@dataclass
class PSDMatrix:
"""
A model class for holding data about Pose Space Deformation
Attributes
----------
@type count: int
@param count: The list of values
@type rows: List[int]
@param rows: List of row indices used for storing values
@type columns: List[int]
@param columns: List of row indices used for storing values
@type values: List[float]
@param values: The list of values, that can be accessed from the row and column index
"""
count: Optional[int] = field(default=None)
rows: List[int] = field(default_factory=list)
columns: List[int] = field(default_factory=list)
values: List[float] = field(default_factory=list)
@dataclass
class JointGroup:
"""
A model class for holding data about joint groups
Attributes
----------
@type lods: List[int]
@param lods: A list of lod indices that the joint group is contained within
@type values: List[float]
@param values: A list of values
@type joints: List[int]
@param joints: A list of joint indices
@type inputs: List[int]
@param inputs: The indices of inputs
@type outputs: List[int]
@param outputs: The indices of outputs
"""
lods: List[int] = field(default_factory=list)
values: List[float] = field(default_factory=list)
joints: List[int] = field(default_factory=list)
inputs: List[int] = field(default_factory=list)
outputs: List[int] = field(default_factory=list)
@dataclass
class BlendShapesData:
"""
A model class for holding data about blend shapes
Attributes
----------
@type lods: List[int]
@param lods: A list of lod indices that the blend shapes are contained within
@type inputs: List[int]
@param inputs: The indices of inputs
@type outputs: List[int]
@param outputs: The indices of outputs
"""
lods: List[int] = field(default_factory=list)
inputs: List[int] = field(default_factory=list)
outputs: List[int] = field(default_factory=list)
@dataclass
class AnimatedMapsConditionalTable:
"""
A model class for holding data about animated maps
Attributes
----------
@type lods: List[int]
@param lods: A list of lod indices that the blend shapes are contained within
@type conditional_table: ConditionalTable
@param conditional_table: Data needed for animated maps
"""
lods: List[int] = field(default_factory=list)
conditional_table: ConditionalTable = field(default_factory=ConditionalTable)
@dataclass
class JointGroups:
"""
A model class for storing data about joints
Attributes
----------
@type joint_row_count: int
@param joint_row_count: The row count of the matrix that stores the joints data
@type joint_column_count: int
@param joint_column_count: The column count of the matrix that stores the joints data
@type joint_variable_attribute_indices: List[List[int]]
@param joint_variable_attribute_indices: List of joint variable attribute indices per LOD
@type joint_groups: List[JointGroup]
@param joint_groups: The list of joint groups
"""
joint_row_count: Optional[int] = field(default=None)
joint_column_count: Optional[int] = field(default=None)
joint_variable_attribute_indices: List[List[int]] = field(default_factory=list)
joint_groups: List[JointGroup] = field(default_factory=list)