diff options
| author | yum <yum.food.vr@gmail.com> | 2025-07-23 22:53:08 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2025-07-23 22:53:08 -0700 |
| commit | 4539f87e36cb3ca554e1e174c19206b552107c57 (patch) | |
| tree | 6f9aca818989773cc10f3c465224a07f847eb279 /Scripts/libtastt.py | |
| parent | f6b93a20d754579008076e85f5c0a97e1bcbc258 (diff) | |
Delete unused filesv1.0.0-beta00
Diffstat (limited to 'Scripts/libtastt.py')
| -rw-r--r-- | Scripts/libtastt.py | 1085 |
1 files changed, 0 insertions, 1085 deletions
diff --git a/Scripts/libtastt.py b/Scripts/libtastt.py deleted file mode 100644 index 81baa8b..0000000 --- a/Scripts/libtastt.py +++ /dev/null @@ -1,1085 +0,0 @@ -#!/usr/bin/env python3 - -import app_config -import argparse -import array -import generate_utils -import libunity -import os -import pickle -import sys -import typing - -# TODO(yum) we're getting the encoding scheme from here, but I think it should -# be in a different layer. -import osc_ctrl - -SCALE_ANIMATION_TEMPLATE = """ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!74 &7400000 -AnimationClip: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: TaSTT_Scale_0 - serializedVersion: 6 - m_Legacy: 0 - m_Compressed: 0 - m_UseHighQualityCurve: 1 - m_RotationCurves: [] - m_CompressedRotationCurves: [] - m_EulerCurves: [] - m_PositionCurves: [] - m_ScaleCurves: - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: {x: 5, y: 5, z: 5} - inSlope: {x: 0, y: 0, z: 0} - outSlope: {x: 0, y: 0, z: 0} - tangentMode: 0 - weightedMode: 0 - inWeight: {x: 0, y: 0.33333334, z: 0.33333334} - outWeight: {x: 0, y: 0.33333334, z: 0.33333334} - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - path: World Constraint/Container/TaSTT - m_FloatCurves: [] - m_PPtrCurves: [] - m_SampleRate: 60 - m_WrapMode: 0 - m_Bounds: - m_Center: {x: 0, y: 0, z: 0} - m_Extent: {x: 0, y: 0, z: 0} - m_ClipBindingConstant: - genericBindings: - - serializedVersion: 2 - path: 1272388438 - attribute: 3 - script: {fileID: 0} - typeID: 4 - customType: 0 - isPPtrCurve: 0 - - serializedVersion: 2 - path: 1272388438 - attribute: 1225223716 - script: {fileID: 0} - typeID: 23 - customType: 0 - isPPtrCurve: 0 - pptrCurveMapping: [] - m_AnimationClipSettings: - serializedVersion: 2 - m_AdditiveReferencePoseClip: {fileID: 0} - m_AdditiveReferencePoseTime: 0 - m_StartTime: 0 - m_StopTime: 0.016666668 - m_OrientationOffsetY: 0 - m_Level: 0 - m_CycleOffset: 0 - m_HasAdditiveReferencePose: 0 - m_LoopTime: 1 - m_LoopBlend: 0 - m_LoopBlendOrientation: 0 - m_LoopBlendPositionY: 0 - m_LoopBlendPositionXZ: 0 - m_KeepOriginalOrientation: 0 - m_KeepOriginalPositionY: 1 - m_KeepOriginalPositionXZ: 0 - m_HeightFromFeet: 0 - m_Mirror: 0 - m_EditorCurves: - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 5 - inSlope: 0 - outSlope: 0 - tangentMode: 136 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: m_LocalScale.x - path: World Constraint/Container/TaSTT - classID: 4 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 5 - inSlope: 0 - outSlope: 0 - tangentMode: 136 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: m_LocalScale.y - path: World Constraint/Container/TaSTT - classID: 4 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 5 - inSlope: 0 - outSlope: 0 - tangentMode: 136 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: m_LocalScale.z - path: World Constraint/Container/TaSTT - classID: 4 - script: {fileID: 0} - m_EulerEditorCurves: [] - m_HasGenericRootTransform: 0 - m_HasMotionFloatCurves: 0 - m_Events: [] -""" - -SOUND_ANIMATION_TEMPLATE = """ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!74 &7400000 -AnimationClip: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: Sound1_On - serializedVersion: 6 - m_Legacy: 0 - m_Compressed: 0 - m_UseHighQualityCurve: 1 - m_RotationCurves: [] - m_CompressedRotationCurves: [] - m_EulerCurves: [] - m_PositionCurves: [] - m_ScaleCurves: [] - m_FloatCurves: - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1 - inSlope: Infinity - outSlope: Infinity - tangentMode: 103 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: m_IsActive - path: World Constraint/Container/TaSTT/Audio 1 - classID: 1 - script: {fileID: 0} - m_PPtrCurves: [] - m_SampleRate: 60 - m_WrapMode: 0 - m_Bounds: - m_Center: {x: 0, y: 0, z: 0} - m_Extent: {x: 0, y: 0, z: 0} - m_ClipBindingConstant: - genericBindings: - - serializedVersion: 2 - path: 2267216663 - attribute: 2086281974 - script: {fileID: 0} - typeID: 1 - customType: 0 - isPPtrCurve: 0 - pptrCurveMapping: [] - m_AnimationClipSettings: - serializedVersion: 2 - m_AdditiveReferencePoseClip: {fileID: 0} - m_AdditiveReferencePoseTime: 0 - m_StartTime: 0 - m_StopTime: 0 - m_OrientationOffsetY: 0 - m_Level: 0 - m_CycleOffset: 0 - m_HasAdditiveReferencePose: 0 - m_LoopTime: 0 - m_LoopBlend: 0 - m_LoopBlendOrientation: 0 - m_LoopBlendPositionY: 0 - m_LoopBlendPositionXZ: 0 - m_KeepOriginalOrientation: 0 - m_KeepOriginalPositionY: 1 - m_KeepOriginalPositionXZ: 0 - m_HeightFromFeet: 0 - m_Mirror: 0 - m_EditorCurves: [] - m_EulerEditorCurves: [] - m_HasGenericRootTransform: 0 - m_HasMotionFloatCurves: 0 - m_Events: [] -""" - -LETTER_ANIMATION_TEMPLATE = """ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!74 &7400000 -AnimationClip: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: REPLACEME_ANIMATION_NAME - serializedVersion: 6 - m_Legacy: 0 - m_Compressed: 0 - m_UseHighQualityCurve: 1 - m_RotationCurves: [] - m_CompressedRotationCurves: [] - m_EulerCurves: [] - m_PositionCurves: [] - m_ScaleCurves: [] - m_FloatCurves: - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: REPLACEME_LETTER_VALUE - inSlope: 0 - outSlope: 0 - tangentMode: 136 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016666668 - value: REPLACEME_LETTER_VALUE - inSlope: 0 - outSlope: 0 - tangentMode: 136 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: material.REPLACEME_LETTER_PARAM - path: TaSTT - classID: 23 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: REPLACEME_LETTER_VALUE - inSlope: 0 - outSlope: 0 - tangentMode: 136 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016666668 - value: REPLACEME_LETTER_VALUE - inSlope: 0 - outSlope: 0 - tangentMode: 136 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: material.REPLACEME_LETTER_PARAM - path: TaSTT - classID: 137 - script: {fileID: 0} - m_PPtrCurves: [] - m_SampleRate: 60 - m_WrapMode: 0 - m_Bounds: - m_Center: {x: 0, y: 0, z: 0} - m_Extent: {x: 0, y: 0, z: 0} - m_ClipBindingConstant: - genericBindings: - - serializedVersion: 2 - path: 2794480623 - attribute: 2284639795 - script: {fileID: 0} - typeID: 137 - customType: 22 - isPPtrCurve: 0 - pptrCurveMapping: [] - m_AnimationClipSettings: - serializedVersion: 2 - m_AdditiveReferencePoseClip: {fileID: 0} - m_AdditiveReferencePoseTime: 0 - m_StartTime: 0 - m_StopTime: 0 - m_OrientationOffsetY: 0 - m_Level: 0 - m_CycleOffset: 0 - m_HasAdditiveReferencePose: 0 - m_LoopTime: 1 - m_LoopBlend: 0 - m_LoopBlendOrientation: 0 - m_LoopBlendPositionY: 0 - m_LoopBlendPositionXZ: 0 - m_KeepOriginalOrientation: 0 - m_KeepOriginalPositionY: 1 - m_KeepOriginalPositionXZ: 0 - m_HeightFromFeet: 0 - m_Mirror: 0 - m_EditorCurves: - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: REPLACEME_LETTER_VALUE - inSlope: 0 - outSlope: 0 - tangentMode: 136 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016666668 - value: REPLACEME_LETTER_VALUE - inSlope: 0 - outSlope: 0 - tangentMode: 136 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: material.REPLACEME_LETTER_PARAM - path: TaSTT - classID: 23 - script: {fileID: 0} - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: REPLACEME_LETTER_VALUE - inSlope: 0 - outSlope: 0 - tangentMode: 136 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 0.016666668 - value: REPLACEME_LETTER_VALUE - inSlope: 0 - outSlope: 0 - tangentMode: 136 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: material.REPLACEME_LETTER_PARAM - path: TaSTT - classID: 137 - script: {fileID: 0} - m_EulerEditorCurves: [] - m_HasGenericRootTransform: 0 - m_HasMotionFloatCurves: 0 - m_Events: [] -""" - -ANIMATOR_TEMPLATE = """ ---- !u!91 &9100000 -AnimatorController: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: TaSTT_fx - serializedVersion: 5 - m_AnimatorParameters: [] - m_AnimatorLayers: [] -""" - -# For whatever reason, running unrelated animations s.a. -# facial expressions can have a slight effect on supposedly -# unrelated parameters, causing letter to flip. Add a -# little buffer to reduce the odds that this effect causes -# a letter to change after it has been written. -UNITY_ANIMATION_FUDGE_MARGIN = 0.1 - -def generateClearAnimation(anim_dir: str, guid_map: typing.Dict[str, str]): - print("Generating board clearing animation", file=sys.stderr) - - parser = libunity.UnityParser() - parser.parse(LETTER_ANIMATION_TEMPLATE) - - anim_node = parser.nodes[0] - anim_clip = anim_node.mapping['AnimationClip'] - curve_template = anim_clip.mapping['m_FloatCurves'].sequence[0] - anim_clip.mapping['m_FloatCurves'].sequence = [] - anim_clip.mapping['m_EditorCurves'].sequence = [] - - letter = 0 - - for byte in range(0, generate_utils.config.BYTES_PER_CHAR): - for row in range(0, generate_utils.config.BOARD_ROWS): - for col in range(0, generate_utils.config.BOARD_COLS): - curve = curve_template.copy() - for keyframe in curve.mapping['curve'].mapping['m_Curve'].sequence: - keyframe.mapping['value'] = str(letter + - UNITY_ANIMATION_FUDGE_MARGIN) - curve.mapping['attribute'] = "material.{}".format(generate_utils.getShaderParamByRowColByte(row, col, byte)) - curve.mapping['path'] = "World Constraint/Container/TaSTT" - # Add curve to animation - anim_clip.mapping['m_FloatCurves'].sequence.append(curve) - anim_clip.mapping['m_EditorCurves'].sequence.append(curve) - # Serialize animation to file - anim_name = generate_utils.getClearAnimationName() - anim_path = os.path.join(anim_dir, anim_name + ".anim") - print("Generating clear animation at {}".format(anim_path), file=sys.stderr) - with open(anim_path, "w", encoding="utf-8") as f: - f.write(libunity.unityYamlToString([anim_node])) - # Generate metadata - meta = libunity.Metadata() - with open(anim_path + ".meta", "w", encoding="utf-8") as f: - f.write(str(meta)) - # Add metadata to guid map - guid_map[anim_path] = meta.guid - guid_map[meta.guid] = anim_path - -# sound_chord: whether to play a, e, i, o, u -# value: 0 or 1 -def generateSoundAnimation(sound_chord: typing.Tuple[int,int,int,int,int], - value: int, - anim_name: str, - anim_dir: str, guid_map: typing.Dict[str, str], - anim_delay_frames = 2): - print(f"Generating sound animation {sound_chord} / {anim_name}", file=sys.stderr) - - parser = libunity.UnityParser() - parser.parse(SOUND_ANIMATION_TEMPLATE) - - anim_node = parser.nodes[0] - anim_clip = anim_node.mapping['AnimationClip'] - curve_template = anim_clip.mapping['m_FloatCurves'].sequence[0] - anim_clip.mapping['m_FloatCurves'].sequence = [] - anim_clip.mapping['m_EditorCurves'].sequence = [] - - # Animate all notes. - for note_i in range(len(sound_chord)): - curve = curve_template.copy() - - keyframe_template = curve.mapping['curve'].mapping['m_Curve'].sequence[0] - curve.mapping['curve'].mapping['m_Curve'].sequence = [] - - # First keyframe: zero all but first note - if note_i != 0: - keyframe = keyframe_template.copy() - keyframe.mapping['time'] = 0 - keyframe.mapping['value'] = 0 - curve.mapping['path'] = f"World Constraint/Container/TaSTT/Audio {note_i + 1}" - curve.mapping['curve'].mapping['m_Curve'].sequence.append(keyframe) - - # Subsequent keyframes: animate as normal - keyframe = keyframe_template.copy() - keyframe.mapping['time']= str(note_i * anim_delay_frames * 1.0 / 60.0) - keyframe.mapping['value'] = str(sound_chord[note_i]) - curve.mapping['path'] = f"World Constraint/Container/TaSTT/Audio {note_i + 1}" - curve.mapping['curve'].mapping['m_Curve'].sequence.append(keyframe) - - # Add curve to animation - anim_clip.mapping['m_FloatCurves'].sequence.append(curve) - anim_clip.mapping['m_EditorCurves'].sequence.append(curve) - - anim_clip.mapping['m_AnimationClipSettings'].mapping['m_StopTime'] = str((len(sound_chord)-1) * anim_delay_frames * 1.0 / 60.0) - - # Serialize animation to file - anim_path = os.path.join(anim_dir, anim_name + ".anim") - with open(anim_path, "w", encoding="utf-8") as f: - f.write(libunity.unityYamlToString([anim_node])) - # Generate metadata - meta = libunity.Metadata() - with open(anim_path + ".meta", "w", encoding="utf-8") as f: - f.write(str(meta)) - # Add metadata to guid map - guid_map[anim_path] = meta.guid - guid_map[meta.guid] = anim_path - -# Generate a toggle animation for a shader parameter. -def generateToggleAnimations(anim_dir, shader_param, guid_map): - print("Generating shader toggle animation", file=sys.stderr) - - parser = libunity.UnityParser() - parser.parse(LETTER_ANIMATION_TEMPLATE) - - # 0.0 represents false, 1.0 represents true. Don't forget that we add - # `UNITY_ANIMATION_FUDGE_MARGIN` to everything. - for shader_value in range(0, 2): - anim_node = parser.nodes[0] - anim_clip = anim_node.mapping['AnimationClip'] - curve_template = anim_clip.mapping['m_FloatCurves'].sequence[0] - anim_clip.mapping['m_FloatCurves'].sequence = [] - anim_clip.mapping['m_EditorCurves'].sequence = [] - - curve = curve_template.copy() - for keyframe in curve.mapping['curve'].mapping['m_Curve'].sequence: - keyframe.mapping['value'] = str(float(shader_value) + - UNITY_ANIMATION_FUDGE_MARGIN) - curve.mapping['attribute'] = "material.{}".format(shader_param) - curve.mapping['path'] = "World Constraint/Container/TaSTT" - # Add curve to animation - anim_clip.mapping['m_FloatCurves'].sequence.append(curve) - anim_clip.mapping['m_EditorCurves'].sequence.append(curve) - - # Serialize animation to file - anim_name = generate_utils.getClearAnimationName() - anim_suffix = "_Off" - if shader_value == 1: - anim_suffix = "_On" - anim_path = os.path.join(anim_dir, shader_param + anim_suffix + - ".anim") - with open(anim_path, "w", encoding="utf-8") as f: - f.write(libunity.unityYamlToString([anim_node])) - # Generate metadata - meta = libunity.Metadata() - with open(anim_path + ".meta", "w", encoding="utf-8") as f: - f.write(str(meta)) - # Add metadata to guid map - guid_map[anim_path] = meta.guid - guid_map[meta.guid] = anim_path - -# Generate a toggle animation for a shader parameter. -def generateScaleAnimation(anim_name: str, anim_dir: str, - path: str, - value: float, - guid_map: typing.Dict[str, str]) -> str: - print("Generating scale animation {}".format(path), - file=sys.stderr) - - parser = libunity.UnityParser() - parser.parse(SCALE_ANIMATION_TEMPLATE) - - #print("kill me", file=sys.stderr) - #print(libunity.unityYamlToString([parser.nodes[0]]), file=sys.stdout) - #print("NOW", file=sys.stdout) - - # 0.0 represents false, 1.0 represents true. Don't forget that we add - # `UNITY_ANIMATION_FUDGE_MARGIN` to everything. - anim_node = parser.nodes[0] - anim_clip = anim_node.mapping['AnimationClip'] - #print("here 3", file=sys.stderr) - for curve in anim_clip.mapping['m_ScaleCurves'].sequence: - for keyframe in curve.mapping['curve'].mapping['m_Curve'].sequence: - keyframe.mapping['value'].mapping['x'] = str(value) - keyframe.mapping['value'].mapping['y'] = str(value) - keyframe.mapping['value'].mapping['z'] = str(value) - #print("here 4", file=sys.stderr) - for curve in anim_clip.mapping['m_EditorCurves'].sequence: - for keyframe in curve.mapping['curve'].mapping['m_Curve'].sequence: - keyframe.mapping['value'] = value - - #print("here 5", file=sys.stderr) - - # Serialize animation to file - anim_path = os.path.join(anim_dir, anim_name + ".anim") - with open(anim_path, "w", encoding="utf-8") as f: - f.write(libunity.unityYamlToString([anim_node])) - # Generate metadata - meta = libunity.Metadata() - with open(anim_path + ".meta", "w", encoding="utf-8") as f: - f.write(str(meta)) - # Add metadata to guid map - guid_map[anim_path] = meta.guid - guid_map[meta.guid] = anim_path - - return meta.guid - -def generateAnimations(anim_dir: str, guid_map: typing.Dict[str, str]): - generateClearAnimation(anim_dir, guid_map) - - for chord_bits in range(2**5): - chord = [0, 0, 0, 0, 0] - for i in range(5): - if (chord_bits >> i) % 2 == 1: - chord[i] = 1 - print(f"Generating chord {chord}", file=sys.stderr) - anim_name = f"Sound_a{chord[0]}_e{chord[1]}_i{chord[2]}_o{chord[3]}_u{chord[4]}" - generateSoundAnimation(chord, 0, anim_name, anim_dir, guid_map) - - print("Generating letter animations", file=sys.stderr) - - parser = libunity.UnityParser() - parser.parse(LETTER_ANIMATION_TEMPLATE) - - anim_node = parser.nodes[0] - anim_clip = anim_node.mapping['AnimationClip'] - curve_template = anim_clip.mapping['m_FloatCurves'].sequence[0] - anim_clip.mapping['m_FloatCurves'].sequence = [] - anim_clip.mapping['m_EditorCurves'].sequence = [] - - # To support more languages, we use 2 bytes per character, giving us a 64K character set. - for byte in range(0, generate_utils.config.BYTES_PER_CHAR): - for row in range(0, generate_utils.config.BOARD_ROWS): - print("Generating letter animations (row {}/{}) (byte {}/2)".format(row, - generate_utils.config.BOARD_ROWS, byte), file=sys.stderr) - for col in range(0, generate_utils.config.BOARD_COLS): - for letter in range(0, 2): - if letter == 1: - letter = generate_utils.config.CHARS_PER_CELL - 1 - - # Make a deep copy of the templates - node = anim_node.copy() - curve = curve_template.copy() - clip = node.mapping['AnimationClip'] - # Populate animation name - anim_name = generate_utils.getLetterAnimationName(row, col, letter, byte) - clip.mapping['m_Name'] = anim_name - # Populate letter value - for keyframe in curve.mapping['curve'].mapping['m_Curve'].sequence: - keyframe.mapping['value'] = str(letter + UNITY_ANIMATION_FUDGE_MARGIN) - # Populate path to letter parameter - curve.mapping['attribute'] = "material.{}".format(generate_utils.getShaderParamByRowColByte(row, col, byte)) - curve.mapping['path'] = "World Constraint/Container/TaSTT" - # Add curve to animation - clip.mapping['m_FloatCurves'].sequence.append(curve) - clip.mapping['m_EditorCurves'].sequence.append(curve) - # Serialize animation to file - anim_path = os.path.join(anim_dir, anim_name + ".anim") - with open(anim_path, "w", encoding="utf-8") as f: - f.write(libunity.unityYamlToString([node])) - # Generate metadata - meta = libunity.Metadata() - with open(anim_path + ".meta", "w", encoding="utf-8") as f: - f.write(str(meta)) - # Add metadata to guid map - guid_map[anim_path] = meta.guid - guid_map[meta.guid] = anim_path - -def generateFXController(anim: libunity.UnityAnimator) -> typing.Dict[int, libunity.UnityDocument]: - parser = libunity.UnityParser() - parser.parse(ANIMATOR_TEMPLATE) - anim.addNodes(parser.nodes) - - anim.addParameter(generate_utils.getEnableParam(), bool) - anim.addParameter(generate_utils.getDummyParam(), bool) - anim.addParameter(generate_utils.getToggleParam(), bool) - anim.addParameter(generate_utils.getClearBoardParam(), bool) - anim.addParameter(generate_utils.getScaleParam(), float) - anim.addParameter(generate_utils.getEnablePhonemeParam(), bool) - - for i in range(5): - anim.addParameter(generate_utils.getSoundParam(i+1), bool) - - anim.addLayer("=== TaSTT ===", weight=0.0) - - layers = {} - for byte in range(0, generate_utils.config.BYTES_PER_CHAR): - layers[byte] = {} - for i in range(0, generate_utils.config.CHARS_PER_SYNC): - anim.addParameter(generate_utils.getBlendParam(i, byte), float) - - layer = anim.addLayer(generate_utils.getLayerName(i, byte)) - layers[byte][i] = layer - anim.addParameter(generate_utils.getSelectParam(), int) - - return layers - -def generateFXLayer(which_layer: int, anim: libunity.UnityAnimator, layer: - libunity.UnityDocument, gen_anim_dir: str, byte: int): - is_default_state = True - default_state = anim.addAnimatorState(layer, - generate_utils.getDefaultStateName(which_layer, byte), is_default_state) - - dy = 100 - active_state = anim.addAnimatorState(layer, - generate_utils.getActiveStateName(which_layer, byte), dy = dy) - - active_state_transition = anim.addTransition(active_state) - enable_param = generate_utils.getEnableParam() - anim.addTransitionBooleanCondition(default_state, active_state_transition, - enable_param, True) - - select_states = {} - for i in range(0, generate_utils.config.numRegions(which_layer)): - dx = i * 200 - dy = 200 - - # Create blend tree for this region. - anim_lo_path = os.path.join(gen_anim_dir, - generate_utils.getAnimationNameByLayerAndIndex( - which_layer, i, 0, byte) + \ - ".anim") - guid_lo = guid_map[anim_lo_path] - anim_hi_path = os.path.join(gen_anim_dir, - generate_utils.getAnimationNameByLayerAndIndex( - which_layer, i, generate_utils.config.CHARS_PER_CELL - 1, byte) + \ - ".anim") - guid_hi = guid_map[anim_hi_path] - - select_states[i] = anim.addAnimatorBlendTree(layer, - generate_utils.getBlendStateName(which_layer, i, byte), - generate_utils.getBlendParam(which_layer, byte), - guid_lo, guid_hi, dx = dx, dy = dy) - state = select_states[i] - - # Create transition to state. - select_state_transition = anim.addTransition(state) - select_param = generate_utils.getSelectParam() - anim.addTransitionIntegerEqualityCondition(active_state, - select_state_transition, select_param, i) - - # Create return-home transition. - home_state_transition = anim.addTransition(default_state) - home_state_transition.mapping['AnimatorStateTransition'].mapping['m_InterruptionSource'] = '0' - dummy_param = generate_utils.getDummyParam() - anim.addTransitionBooleanCondition(state, - home_state_transition, dummy_param, False) - - if generate_utils.config.layerNeedsParity(which_layer): - # There may be layers which never write to the text box. In this case, - # when those layers are turned on to write to that last region, they - # simply transition back to the default (idle) state. - home_state_transition = anim.addTransition(default_state) - select_param = generate_utils.getSelectParam() - i = generate_utils.config.numRegions(0) - 1 - anim.addTransitionIntegerEqualityCondition(active_state, - home_state_transition, select_param, i) - -# Generic toggle adding utility. -# Generates the layer and parameter. -# Returns a map containing the off and on states, as well as the -# transitions between them. -def generateToggle(layer_name: str, - parameter_name: str, - gen_anim_dir: str, - off_anim_basename: str, - on_anim_basename: str, - anim: libunity.UnityAnimator, - guid_map: typing.Dict[str, str], - duration_s: float = 0.0) -> typing.Dict[str, - libunity.UnityDocument]: - layer = anim.addLayer(layer_name) - - # For simplicity, use the layer name as the parameter name. - anim.addParameter(parameter_name, bool) - - off_state = anim.addAnimatorState(layer, layer_name + "_Off", - is_default_state = True) - on_state = anim.addAnimatorState(layer, layer_name + "_On", dy=100) - - if off_anim_basename: - off_anim_path = os.path.join(gen_anim_dir, off_anim_basename) - off_anim_meta = libunity.Metadata() - off_anim_meta.loadOrCreate(off_anim_path, guid_map) - anim.setAnimatorStateAnimation(off_state, off_anim_meta.guid) - - if on_anim_basename: - on_anim_path = os.path.join(gen_anim_dir, on_anim_basename) - on_anim_meta = libunity.Metadata() - on_anim_meta.loadOrCreate(on_anim_path, guid_map) - anim.setAnimatorStateAnimation(on_state, on_anim_meta.guid) - - off_to_on_trans = anim.addTransition(on_state, duration_s) - anim.addTransitionBooleanCondition(off_state, - off_to_on_trans, parameter_name, True) - - on_to_off_trans = anim.addTransition(off_state, duration_s) - anim.addTransitionBooleanCondition(on_state, - on_to_off_trans, parameter_name, False) - - result = {} - result["off"] = off_state - result["on"] = on_state - result["off_to_on"] = off_to_on_trans - result["on_to_off"] = on_to_off_trans - - return result - -def generateScaleLayer(anim: libunity.UnityAnimator, - gen_anim_dir: str, - guid_map: typing.Dict[str, str]): - - scale_layer = anim.addLayer(generate_utils.getScaleParam()) - - path = "World Constraint/Container/TaSTT" - attribute = "blendShape.Scale" - - guid_lo = generateScaleAnimation("TaSTT_Scale_0", gen_anim_dir, - path, - 5.0, guid_map) - guid_hi = generateScaleAnimation("TaSTT_Scale_100", gen_anim_dir, - path, - 100.0, guid_map) - - anim.addAnimatorBlendTree(scale_layer, - generate_utils.getScaleParam(), - generate_utils.getScaleParam(), - guid_lo, guid_hi, - lo_threshold = 0.0, hi_threshold = 1.0); - - pass - -def generateSoundLayer(anim: libunity.UnityAnimator, - gen_anim_dir: str, - guid_map: typing.Dict[str, str], - anim_len_s = 12.0/60.0): - - layer = anim.addLayer("TaSTT_Sound") - - idle_state = anim.addAnimatorState(layer, "Idle", is_default_state=True, dy=-100) - a_state = anim.addAnimatorState(layer, "a") - - trans = anim.addTransition(a_state) - param = generate_utils.getEnablePhonemeParam() - anim.addTransitionBooleanCondition(idle_state, trans, param, True) - - for a_bool in range(2): - dy = 100 - dx = a_bool * 800 - # Create `e` state. - ax_e_state = anim.addAnimatorState(layer, - f"a{a_bool}_e", - dy=dy, dx=dx) - # Create transition based on whether `a` is set. - trans = anim.addTransition(ax_e_state) - param = generate_utils.getSoundParam(1) - anim.addTransitionBooleanCondition(a_state, trans, param, a_bool) - - for e_bool in range(2): - dy = 200 - dx = a_bool * 800 + e_bool * 400 - - # Create `i` state. - ax_ex_i_state = anim.addAnimatorState(layer, - f"a{a_bool}_e{e_bool}_i", - dy=dy, dx=dx) - - # Create transition based on whether `e` is set. - trans = anim.addTransition(ax_ex_i_state) - param = generate_utils.getSoundParam(2) - anim.addTransitionBooleanCondition(ax_e_state, trans, param, e_bool) - - for i_bool in range(2): - dy = 300 - dx = a_bool * 800 + e_bool * 400 + i_bool * 200 - - # Create `o` state. - ax_ex_ix_o_state = anim.addAnimatorState(layer, - f"a{a_bool}_e{e_bool}_i{i_bool}_o", - dy=dy, dx=dx) - # Create transition based on whether `i` is set. - trans = anim.addTransition(ax_ex_ix_o_state) - param = generate_utils.getSoundParam(3) - anim.addTransitionBooleanCondition(ax_ex_i_state, trans, param, i_bool) - - for o_bool in range(2): - dy = 400 - dx = a_bool * 800 + e_bool * 400 + i_bool * 200 + o_bool * 100 - - # Create `u` state. - ax_ex_ix_ox_u_state = anim.addAnimatorState(layer, - f"a{a_bool}_e{e_bool}_i{i_bool}_o{o_bool}_u", - dy=dy, dx=dx) - # Create transition based on whether `o` is set. - trans = anim.addTransition(ax_ex_ix_ox_u_state) - param = generate_utils.getSoundParam(4) - anim.addTransitionBooleanCondition(ax_ex_ix_o_state, - trans, param, o_bool) - - for u_bool in range(2): - dy = 500 - dx = a_bool * 800 + e_bool * 400 + i_bool * 200 + o_bool * 100 + u_bool * 50 - if u_bool == 1: - dy = 550 - - # Create `u` state. - ax_ex_ix_ox_ux_state = anim.addAnimatorState(layer, - f"a{a_bool}_e{e_bool}_i{i_bool}_o{o_bool}_u{u_bool}", - dy=dy, dx=dx) - # Create transition based on whether `u` is set. - trans = anim.addTransition(ax_ex_ix_ox_ux_state) - param = generate_utils.getSoundParam(5) - anim.addTransitionBooleanCondition(ax_ex_ix_ox_u_state, - trans, param, u_bool) - - chord = [a_bool, e_bool, i_bool, o_bool, u_bool] - anim_name = f"Sound_a{chord[0]}_e{chord[1]}_i{chord[2]}_o{chord[3]}_u{chord[4]}" - anim_path = os.path.join(gen_anim_dir, anim_name + ".anim") - anim_guid = guid_map[anim_path] - anim.setAnimatorStateAnimation(ax_ex_ix_ox_ux_state, anim_guid) - - # Create return-home transitions. - trans = anim.addTransition(idle_state, dur_s = anim_len_s) - trans.mapping['AnimatorStateTransition'].mapping['m_InterruptionSource'] = '0' - param = generate_utils.getSoundParam(1) - anim.addTransitionBooleanCondition(ax_ex_ix_ox_ux_state, trans, param, 1 - a_bool) - - trans = anim.addTransition(idle_state, dur_s = anim_len_s) - trans.mapping['AnimatorStateTransition'].mapping['m_InterruptionSource'] = '0' - param = generate_utils.getSoundParam(2) - anim.addTransitionBooleanCondition(ax_ex_ix_ox_ux_state, trans, param, 1 - e_bool) - - trans = anim.addTransition(idle_state, dur_s = anim_len_s) - trans.mapping['AnimatorStateTransition'].mapping['m_InterruptionSource'] = '0' - param = generate_utils.getSoundParam(3) - anim.addTransitionBooleanCondition(ax_ex_ix_ox_ux_state, trans, param, 1 - i_bool) - - trans = anim.addTransition(idle_state, dur_s = anim_len_s) - trans.mapping['AnimatorStateTransition'].mapping['m_InterruptionSource'] = '0' - param = generate_utils.getSoundParam(4) - anim.addTransitionBooleanCondition(ax_ex_ix_ox_ux_state, trans, param, 1 - o_bool) - - trans = anim.addTransition(idle_state, dur_s = anim_len_s) - trans.mapping['AnimatorStateTransition'].mapping['m_InterruptionSource'] = '0' - param = generate_utils.getSoundParam(5) - anim.addTransitionBooleanCondition(ax_ex_ix_ox_ux_state, trans, param, 1 - u_bool) - -def generateFX(guid_map, gen_anim_dir): - anim = libunity.UnityAnimator() - - layers = generateFXController(anim) - - # TODO(yum) parallelize - for byte in range(0, generate_utils.config.BYTES_PER_CHAR): - for which_layer, layer in layers[byte].items(): - print("Generating layer {}/{}".format(which_layer, len(layers[byte].items())), file=sys.stderr) - generateFXLayer(which_layer, anim, layer, gen_anim_dir, byte) - - generateToggle(generate_utils.getToggleParam(), - generate_utils.getToggleParam(), - gen_anim_dir, - "TaSTT_Toggle_Off.anim", - "TaSTT_Toggle_On.anim", - anim, guid_map) - generateToggle(generate_utils.getLockWorldParam(), - generate_utils.getLockWorldParam(), - gen_anim_dir, - "TaSTT_Lock_World_Disable.anim", - "TaSTT_Lock_World_Enable.anim", - anim, guid_map) - generateToggle(generate_utils.getEllipsisParam(), - generate_utils.getEllipsisParam(), - gen_anim_dir, - "TaSTT_Ellipsis_Off.anim", - "TaSTT_Ellipsis_On.anim", - anim, guid_map) - generateToggle( - generate_utils.getClearBoardParam(), - generate_utils.getClearBoardParam(), - gen_anim_dir, - None, # No animation in the `off` state. - generate_utils.getClearAnimationName() + ".anim", - anim, guid_map) - generateToggle("TaSTT_Expand", - generate_utils.getToggleParam(), - gen_anim_dir, - "TaSTT_Emerge_000.anim", - "TaSTT_Emerge_100.anim", - anim, guid_map, 0.5) - - generateScaleLayer(anim, gen_anim_dir, guid_map) - generateSoundLayer(anim, gen_anim_dir, guid_map) - - return anim - -def parseArgs(): - print("args: {}".format(" ".join(sys.argv))) - - parser = argparse.ArgumentParser() - parser.add_argument("cmd", type=str, help="") - parser.add_argument("--config", type=str, help="The app config.") - parser.add_argument("--gen_dir", type=str, help="The directory under " + - "which all generated assets are placed") - parser.add_argument("--gen_anim_dir", type=str, help="The directory under " + - "which all generated animations are placed.") - parser.add_argument("--guid_map", type=str, help="The path to a file which will store guids") - parser.add_argument("--fx_dest", type=str, help="The path at which to save the generated FX controller") - args = parser.parse_args() - - if not args.gen_dir: - args.gen_dir = "generated/" - - if not args.config: - print("--config required") - sys.exit(1) - - if not args.gen_anim_dir: - args.gen_anim_dir = args.gen_dir + "animations/" - - if not args.guid_map: - args.guid_map = "guid.map" - - if not args.fx_dest: - args.fx_dest = args.gen_dir + "TaSTT_fx.controller" - - return args - -if __name__ == "__main__": - args = parseArgs() - cfg = app_config.getConfig(args.config) - - print(f"chdir to {os.path.dirname(os.path.abspath(__file__))}") - os.chdir(os.path.dirname(os.path.abspath(__file__))) - - if args.cmd == "gen_anims": - generate_utils.config.BYTES_PER_CHAR = int(cfg["bytes_per_char"]) - generate_utils.config.CHARS_PER_SYNC = int(cfg["chars_per_sync"]) - generate_utils.config.BOARD_ROWS = int(cfg["rows"]) - generate_utils.config.BOARD_COLS = int(cfg["cols"]) - - guid_map = {} - with open(args.guid_map, 'rb') as f: - guid_map = pickle.load(f) - - os.makedirs(args.gen_anim_dir, exist_ok=True) - generateAnimations(args.gen_anim_dir, guid_map) - - with open(args.guid_map, 'wb') as f: - pickle.dump(guid_map, f) - elif args.cmd == "gen_fx": - generate_utils.config.BYTES_PER_CHAR = int(cfg["bytes_per_char"]) - generate_utils.config.CHARS_PER_SYNC = int(cfg["chars_per_sync"]) - generate_utils.config.BOARD_ROWS = int(cfg["rows"]) - generate_utils.config.BOARD_COLS = int(cfg["cols"]) - - guid_map = {} - with open(args.guid_map, 'rb') as f: - guid_map = pickle.load(f) - os.makedirs(os.path.dirname(args.fx_dest), exist_ok=True) - with open(args.fx_dest, "w", encoding="utf-8") as f: - f.write(str(generateFX(guid_map, args.gen_anim_dir))) - with open(args.guid_map, 'wb') as f: - pickle.dump(guid_map, f) - - # If we don't do this, then VRChat will fail to update the animator - # when users update their avatars. - if os.path.exists(args.fx_dest + ".meta"): - os.remove(args.fx_dest + ".meta") - |
