almost there with this one, LZMA and LZ4 don't work

This commit is contained in:
989onan
2024-12-14 18:21:32 -05:00
parent c83f14f88b
commit 758cf0e760
11 changed files with 1356 additions and 165 deletions
+1
View File
@@ -3,6 +3,7 @@
"D:\\SteamLibrary\\steamapps\\common\\Blender\\4.3\\scripts\\addons", "D:\\SteamLibrary\\steamapps\\common\\Blender\\4.3\\scripts\\addons",
"C:\\Users\\Onan\\AppData\\Roaming\\Blender Foundation\\Blender\\4.3\\extensions\\user_default\\",//C:/Users/Onan/AppData/Roaming/Blender Foundation/Blender/4.0/scripts/addons "C:\\Users\\Onan\\AppData\\Roaming\\Blender Foundation\\Blender\\4.3\\extensions\\user_default\\",//C:/Users/Onan/AppData/Roaming/Blender Foundation/Blender/4.0/scripts/addons
"D:\\blender stuff\\blendercodestuff\\4.3", "D:\\blender stuff\\blendercodestuff\\4.3",
"D:\\SteamLibrary\\steamapps\\common\\Blender\\4.3\\python\\lib\\site-packages",
"/Users/frankche/Documents/blendercoding/4.1/", "/Users/frankche/Documents/blendercoding/4.1/",
"/Users/frankche/Library/Application Support/Blender/4.3/extensions/user_default/" "/Users/frankche/Library/Application Support/Blender/4.3/extensions/user_default/"
], ],
+64 -1
View File
@@ -1,11 +1,14 @@
import bpy import bpy
import numpy as np import numpy as np
from .dictionaries import bone_names
import threading import threading
import time import time
import webbrowser import webbrowser
import typing import typing
import struct
from io import BytesIO
from .dictionaries import bone_names
from ..core.register import register_wrap from ..core.register import register_wrap
from typing import List, Optional, Tuple from typing import List, Optional, Tuple
from bpy.types import Object, ShapeKey, Mesh, Context, Material, PropertyGroup from bpy.types import Object, ShapeKey, Mesh, Context, Material, PropertyGroup
@@ -497,3 +500,63 @@ def transfer_vertex_weights(context: Context, obj: bpy.types.Object, source_grou
return True return True
#Binary tools
import ctypes
def ReadCSharp_str(data: BytesIO) -> str:
return data.read(read7bitEncoded_int(data)).decode('utf-16-le')
def WriteCSharp_str(data: BytesIO, string: str) -> str:
write7bitEncoded_int(len(string)*2)
return data.write(string.encode("utf-16-le"))
def read7bitEncoded_ulong(data: BytesIO) -> np.int64:
num: ctypes.c_uint = ctypes.c_uint(0)
num2: int = 0
flag: bool = True
while (flag):
b: ctypes.c_ubyte = ctypes.c_ubyte(struct.unpack('<B', data.read(1))[0])
flag = ((b & 128) > 0)
num |= ((b & 127) << num2)
num2 += 7
if not flag:
break
return num
def read7bitEncoded_int(data: BytesIO) -> ctypes.c_int:
num: ctypes.c_int = ctypes.c_int(0)
num2:ctypes.c_int = ctypes.c_int(0)
while (num2 != 35):
b: ctypes.c_ubyte = ctypes.c_ubyte(struct.unpack('<B', data.read(1))[0])
num |= int(b & 127) << num2
num2 += 7
if ((b & 128) == 0):
return num
return -1
def write7bitEncoded_ulong(data: BytesIO, integer: ctypes.c_ulong) -> None:
while integer > ctypes.c_ulong(0):
b: ctypes.c_ubyte = ctypes.c_ubyte(integer & ctypes.c_ulong(127))
integer >>= 7
if integer > ctypes.c_ulong(0):
b |= 128
data.write(b)
if integer <= ctypes.c_ulong(0):
return
def write7bitEncoded_int(data: BytesIO, value: ctypes.c_int) -> None:
num: ctypes.c_uint = ctypes.c_uint(value)
while(num >= ctypes.c_ubyte(128)):
data.write(ctypes.c_ubyte(num | ctypes.c_ubyte(128)))
num >>= 7
data.Write(ctypes.c_ubyte(num))
#encoding FrooxEngine/C# types in binary:
-36
View File
@@ -1,36 +0,0 @@
import bpy
from typing import List, Optional
from .common import get_armature
from bpy.types import Object, ShapeKey, Mesh, Context, Operator
from functools import lru_cache
from ..core.register import register_wrap
from ..functions.translations import t
@register_wrap
class AvatarToolKit_OT_ExportResonite(Operator):
bl_idname = 'avatar_toolkit.export_resonite'
bl_label = t("Importer.export_resonite.label")
bl_description = t("Importer.export_resonite.desc")
bl_options = {'REGISTER', 'UNDO'}
filepath: bpy.props.StringProperty()
@classmethod
def poll(cls, context: Context):
if get_armature(context) is None:
return False
return True
def execute(self, context: Context):
#settings stolen from cats.
bpy.ops.export_scene.gltf('INVOKE_AREA',
export_image_format = 'WEBP',
export_image_quality = 75,
export_materials = 'EXPORT',
export_animations = True,
export_animation_mode = 'ACTIONS',
export_nla_strips_merged_animation_name = 'Animation',
export_nla_strips = True)
return {'FINISHED'}
+1
View File
@@ -43,6 +43,7 @@ import_types: dict[str, typing.Callable[[str, list[dict[str,str]], str], None]]
"vrm": (lambda directory, files, filepath: bpy.ops.import_scene.vrm(filepath=filepath)), "vrm": (lambda directory, files, filepath: bpy.ops.import_scene.vrm(filepath=filepath)),
"pmx": (lambda directory, files, filepath : import_pmx(filepath)), "pmx": (lambda directory, files, filepath : import_pmx(filepath)),
"pmd": (lambda directory, files, filepath : import_pmd(filepath)), "pmd": (lambda directory, files, filepath : import_pmd(filepath)),
"animx": (lambda directory, files, filepath : bpy.ops.avatar_toolkit.animx_importer(directory=directory,files=files,filepath=filepath)),
} }
def concat_imports_filter(imports): def concat_imports_filter(imports):
+2 -1
View File
@@ -1,3 +1,4 @@
{ {
"language": 0 "language": 0,
"last_update_check": 1734208835.8049936
} }
+56
View File
@@ -0,0 +1,56 @@
import ctypes
import typing
import struct
from io import BytesIO
def ReadCSharp_str(data: BytesIO) -> str:
charamount = read7bitEncoded_int(data)
print(charamount)
return data.read(charamount).decode('utf-8', errors="replace")
def WriteCSharp_str(data: BytesIO, string: str) -> str:
write7bitEncoded_int(len(string))
return data.write(string.encode("utf-8", errors="replace"))
def read7bitEncoded_ulong(data: BytesIO) -> int:
num: int = int(0)
num2: int = 0
flag: bool = True
while (flag):
b: int = int(struct.unpack('<B', data.read(1))[0])
flag = ((b & 128) > 0)
num |= ((b & 127) << num2)
num2 += 7
if not flag:
break
return num
def read7bitEncoded_int(data: BytesIO) -> int:
num: int= int(0)
num2:int = int(0)
while (num2 != 35):
b: int = int(struct.unpack('<B', data.read(1))[0])
num |= int(b & 127) << num2
num2 += 7
if ((b & 128) == 0):
return num
return -1
def write7bitEncoded_ulong(data: BytesIO, integer: int) -> None:
while integer > int(0):
b: int = ctypes.c_ubyte(integer & int(127))
integer >>= 7
if integer > int(0):
b |= 128
data.write(b)
if integer <= int(0):
return
def write7bitEncoded_int(data: BytesIO, value: int) -> None:
num: int = int(value)
while(num >= int(128)):
data.write(int(num | int(128)))
num >>= 7
data.Write(int(num))
+472
View File
@@ -0,0 +1,472 @@
from __future__ import annotations
import lz4.block
from . import resonite_types
from . import common
import ctypes
import typing
import struct
from io import BytesIO
KeyframeInterpolation: dict[str, int] = {
"Hold": 1,
"Linear": 2,
"Tangent": 3,
"CubicBezier": 4
}
class KeyFrame():
time: resonite_types.float = 0
interpolation: resonite_types.int = 0
value: resonite_types.ResoType
left_tan: resonite_types.ResoType
right_tan: resonite_types.ResoType
def __getattr__(self, name: str):
if name == "interpolation":
interp: int = 0
if (self.__dict__["left_tan"] != None and self.__dict__["right_tan"] != None):
interp = 3
return resonite_types.int(interp)
return self.__dict__[name]
def __setattr__(self, name, value):
self.__dict__[name] = value
def __init__(self):
pass
def RequiresTangents(self) -> bool:
if KeyframeInterpolation[self.interpolation.x] == "Tangent" or KeyframeInterpolation[self.interpolation.x] == "CubicBezier":
return True
return False
class ResoTrack(resonite_types.ResoType):
_node: resonite_types.string
_property: resonite_types.string
Owner: AnimX
FrameType: type[resonite_types.ResoType]
keyframes: list[KeyFrame] = []
def __init__(self,FrameType):
self.FrameType = FrameType
def write(self, data: BytesIO):
self._node.write(data)
self._property.write(data)
common.write7bitEncoded_ulong(data, len(self.keyframes))
def read(self, data:BytesIO):
self._node.read(data)
self._property.read(data)
track_amount: int = int(common.read7bitEncoded_ulong(data))
for i in range(0, track_amount):
self.keyframes.append(KeyFrame())
def removeKeyframe(self, time: float | int) -> bool:
"""Takes a time and removes one with the same time"""
if (time < 0):
raise IndexError("Keyframe time cannot be lower than 0. Value: " + str(time))
if(type(time) == float):
num: int = -1
for num2 in range(0,len(self.keyframes)):
if (self.keyframes[num2].time.x == float(time)):
num = num2
if num == -1:
return False
self.keyframes.remove(self.keyframes[num])
return True
else:
if (int(time) >= len(self.keyframes)):
raise IndexError("Keyframe time cannot be bigger than the amount of keyframes. Value: " + str(time))
self.keyframes.remove(self.keyframes[int(time)])
def replaceKeyframe(self, keyframe: KeyFrame) -> bool:
"""Takes a keyframe and replaces one with the same time"""
if (keyframe.time.x < 0):
raise IndexError("Keyframe time cannot be lower than 0. Value: " + str(keyframe.time.x))
num: int = 0
if (keyframe.time.x == self.keyframes[self.GetKeyframeIndex(keyframe.time.x)].time.x):
num = len(self.keyframes)
else:
return False
self.keyframes[num] = keyframe
return True
def addKeyframe(self, keyframe: KeyFrame) -> int:
if (keyframe.time.x < 0):
raise IndexError("Keyframe time cannot be lower than 0. Value: " + str(keyframe.time.x))
num: int
if (len(self.keyframes) == 0):
num = 0
elif (keyframe.time.x >= self.keyframes[-1].time.x):
num = len(self.keyframes)
else:
num = self.GetKeyframeIndex(keyframe.time.x) + 1
self.keyframes.insert(num, keyframe)
return num
def GetKeyframeIndex(self, time:float | int)-> int:
if(type(time) == float):
if (len(self.keyframes) > 0):
num: int = 0
if (self.keyframes[-1].time < float(time)):
num = len(self.keyframes)
while (num < len(self.keyframes) and self.keyframes[num].time < time):
num += 1
return num - 1
return -1
else:
return int(time)
class RawTrack(ResoTrack):
interval: resonite_types.float = 0
def __getattr__(self, name: str):
if name == "interval":
return self.Owner.interval.x
return self.__dict__[name]
def __init__(self, FrameType):
super().__init__(FrameType)
def write(self, data: BytesIO):
super().write(data)
self.interval.write(data)
for key in self.keyframes:
key.value.write(data)
def read(self, data:BytesIO):
super().read(data)
self.interval.read(data)
for key in self.keyframes:
key.value.read(data)
def addKeyframe(self, keyframe: KeyFrame) -> int:
num: int = super().addKeyframe(keyframe)
for i in range(0,len(self.keyframes)):
self.keyframes[i].time = i
return num
def removeKeyframe(self, time: float | int) -> bool:
success: bool = super().removeKeyframe(int(time))
for i in range(0,len(self.keyframes)):
self.keyframes[i].time = i
return success
class DiscreteTrack(ResoTrack):
def __init__(self, FrameType):
super().__init__(FrameType)
def write(self, data: BytesIO):
super().write(data)
def read(self, data:BytesIO):
super().read(data)
def addKeyframe(self, keyframe: KeyFrame) -> int:
num: int = super().addKeyframe(keyframe)
return num
def removeKeyframe(self, time: float | int) -> bool:
success: bool = super().removeKeyframe(time)
return success
class CurveTrack(ResoTrack):
interpolations: bool = False
tangents: bool = False
sharedinterpolation: resonite_types.int = -1
def __getattr__(self, name: str):
if name == "interpolations":
for key in self.keyframes:
if key.interpolation.x != self.sharedinterpolation.x:
return True
elif name == "tangents":
for key in self.keyframes:
if key.interpolation.x == 3 or key.interpolation.x == 4:
return True
return self.__dict__[name]
def __init__(self, FrameType):
super().__init__(FrameType)
def write(self, data: BytesIO):
super().write(data)
resonite_types.byte((1 if self.interpolations else 0) | (2 if self.tangents else 0)).write(data)
if(self.interpolations):
for key in self.keyframes:
key.interpolation.write(data)
else:
self.sharedinterpolation.write(data)
for key in self.keyframes:
key.value.write(data)
key.time.write(data)
if(self.tangents):
for key in self.keyframes:
key.left_tan.write(data)
key.right_tan.write(data)
def read(self, data:BytesIO):
super().read(data)
flags: int = struct.unpack("<B",data.read(1))
self.interpolations = flags & 1
self.tangents = flags & 2
if(self.interpolations):
for key in self.keyframes:
key.interpolation.read(data)
else:
self.sharedinterpolation.read(data)
for key in self.keyframes:
key.value.read(data)
key.time.read(data)
if(self.tangents):
for key in self.keyframes:
key.left_tan.read(data)
key.right_tan.read(data)
class BezierTrack(ResoTrack):
"""PLACE HOLDER CLASS, DO NOT USE"""
def __init__(self, FrameType):
super().__init__(FrameType)
"""PLACE HOLDER METHOD, DO NOT USE"""
#raise Exception("BezierTrack track type is unsupported in resonite's code")
def write(self, data: BytesIO):
"""PLACE HOLDER METHOD, DO NOT USE"""
raise Exception("BezierTrack track type is unsupported in resonite's code")
def read(self, data:BytesIO):
"""PLACE HOLDER METHOD, DO NOT USE"""
raise Exception("BezierTrack track type is unsupported in resonite's code")
def removeKeyframe(self, keyframe: KeyFrame) -> bool:
"""PLACE HOLDER METHOD, DO NOT USE"""
raise Exception("BezierTrack track type is unsupported in resonite's code")
def replaceKeyframe(self, keyframe: KeyFrame) -> bool:
"""PLACE HOLDER METHOD, DO NOT USE"""
raise Exception("BezierTrack track type is unsupported in resonite's code")
def addKeyframe(self, keyframe: KeyFrame) -> int:
"""PLACE HOLDER METHOD, DO NOT USE"""
raise Exception("BezierTrack track type is unsupported in resonite's code")
def GetKeyframeIndex(self, time:float)-> int:
"""PLACE HOLDER METHOD, DO NOT USE"""
raise Exception("BezierTrack track type is unsupported in resonite's code")
#This is weird, but thank you python - @989onan
TrackTypes: list[type[ResoTrack]] = [
RawTrack,
DiscreteTrack,
CurveTrack,
BezierTrack
]
#TODO: add all types here
#wooooo - @989onan
elementTypes: list[type[resonite_types.ResoType]] = [
resonite_types.bool,
resonite_types.bool2,
resonite_types.bool3,
resonite_types.bool4,
resonite_types.byte,
resonite_types.ushort,
resonite_types.uint,
resonite_types.ulong,
resonite_types.sbyte,
resonite_types.short,
resonite_types.int,
resonite_types.long,
resonite_types.int2,
resonite_types.int3,
resonite_types.int4,
resonite_types.uint2,
resonite_types.uint3,
resonite_types.uint4,
resonite_types.long2,
resonite_types.long3,
resonite_types.long4,
resonite_types.float,
resonite_types.float2,
resonite_types.float3,
resonite_types.float4,
resonite_types.floatQ,
resonite_types.float2x2,
resonite_types.float3x3,
resonite_types.float4x4,
resonite_types.double,
resonite_types.double2,
resonite_types.double3,
resonite_types.double4,
resonite_types.doubleQ,
resonite_types.double2x2,
resonite_types.double3x3,
resonite_types.double4x4,
resonite_types.color,
resonite_types.color32,
resonite_types.string
]
most_recent_AnimX_vers: int = 1
class AnimX():
"""
To use Raw Track properly, please set interval (seconds between frames) after reading/creating.\n
Represents data to be written to or read from an AnimX file.
"""
file_version: resonite_types.int = resonite_types.int()
track_amount: resonite_types.int = resonite_types.int()
global_duration: resonite_types.float = resonite_types.float()
name: resonite_types.string = resonite_types.string()
tracks: list[ResoTrack] = []
interval: resonite_types.float = resonite_types.float(1/25) #default value
def __init__(self):
pass
def read(self, file: str) -> bool:
"""
Takes an absolute file path and reads a binary animx file with it, and populates this class object with the data.
"""
with open(file, 'rb') as filecontents:
data: BytesIO = BytesIO(filecontents.read())
magic_word = common.ReadCSharp_str(data)
if magic_word != 'AnimX':
print("AnimX != "+magic_word)
return False
self.file_version.read(data)
if self.file_version.x > 1:
raise Exception("AnimX version is higher than the supported one")
self.track_amount.x = common.read7bitEncoded_ulong(data)
self.global_duration.read(data)
print(self.track_amount.x)
self.name.read(data)
match (struct.unpack('<B', data.read(1))[0]):
case 0:
pass
case 1:
from lz4.frame import decompress #why do you have to be a wheel? - @989onan
data = BytesIO(decompress(data.read()))
case 2:
import lzma#HALLLOOOYAH HALLOYAH!! - @989onan
filters = [{"id": "", "preset": lzma.PRESET_DEFAULT}]
data = BytesIO(lzma.decompress(data.read(), filters=filters))
case _:
raise Exception("Invalid encoding")
for i in range(0,self.track_amount.x):
trackType2: int = 0
num4: int = 0
if (self.file_version == 0):
b: ctypes.c_ubyte = ctypes.c_ubyte(struct.unpack('<B', data.read(1))[0])
num3: int = int(b & 1)
trackType: int = 0
if (num3 != 0):
if (num3 != 1):
raise Exception("[InvalidDataException]: Invalid track type data: " + str(b))
trackType = 2
else:
trackType = 0
trackType2 = trackType
num4 = b >> 1
else:
trackType2 = int(struct.unpack('<B', data.read(1))[0])
num4 = int(struct.unpack('<B', data.read(1))[0])
animationTrack: ResoTrack = AnimX.GetTrackType(trackType2, elementTypes[num4], data)
animationTrack.Owner = self
self.tracks.append(animationTrack)
return True
def write(self, file: str) -> bool:
"""
Takes an absolute file path and writes a binary animx file into it's contents, replacing them using this class's data.
"""
with open(file, 'rb') as filecontents:
data: BytesIO = BytesIO(filecontents)
common.WriteCSharp_str(data, 'AnimX')
self.file_version.x = most_recent_AnimX_vers #we wanna write an up to date file version type.
self.file_version.write(data)
self.track_amount.x = len(self.tracks)
common.write7bitEncoded_ulong(self.track_amount.x)
self.global_duration.write(data)
self.name.write(data)
data.write(struct.pack('<B', 0)) #default encoding, so we don't have to use lzma.
for i in range(0,self.track_amount.x):
data.write(struct.pack('<B', TrackTypes.index(type(self.tracks[i])))[0])
data.write(struct.pack('<B', elementTypes.index(self.tracks[i].FrameType)))
self.tracks[i].write(data)
return True
@classmethod
def GetTrackType(cls, trackType2: int, value_type: int, data: BytesIO) -> ResoTrack:
TrackType: type[ResoTrack] = TrackTypes[trackType2]
Track: ResoTrack = TrackType[elementTypes[value_type]](elementTypes[value_type])
Track.read(data)
return Track
+655
View File
@@ -0,0 +1,655 @@
import ctypes
import typing
from io import BytesIO
import struct
from . import common
class ResoType():
def __init__(self):
pass
def write(self, data: BytesIO):
pass
def read(cls, data: BytesIO):
pass
#These below are collection of the basic resonite typing made from C#. This is in order to store data in a sane way and decode/encode it.
class color(ResoType):
r: float = 0
g: float = 0
b: float = 0
a: float = 0
def __init__(self):
pass
def write(self, data: BytesIO):
data.write(struct.pack("<ffff", self.r, self.g, self.b, self.a))
def read(self,data):
self.r, self.g, self.b, self.a = struct.unpack("<ffff", data.read(4*4))[0]
class color32(ResoType):
r: int = 0
g: int = 0
b: int = 0
a: int = 0
def __init__(self):
pass
def write(self, data: BytesIO):
data.write(struct.pack("<BBBB", self.r, self.g, self.b, self.a))
def read(self,data):
self.r, self.g, self.b, self.a = struct.unpack("<BBBB", data.read(4))[0]
class string(ResoType):
x: str
def __str__(self) -> str:
return self.x
def __init__(self,value=""):
self.x = value
def write(self, data: BytesIO):
common.WriteCSharp_str(data,self.x)
def read(self,data):
self.x = common.ReadCSharp_str(data)
class byte(ResoType):
x: int = 0
def __int__(self):
return self.x
def __init__(self):
pass
def write(self, data: BytesIO):
data.write(struct.pack("<B", self.x))
def read(self,data):
self.x = struct.unpack("<B", data.read(1))[0]
class sbyte(ResoType):
x: int = 0
def __int__(self):
return self.x
def __init__(self,value=0):
self.x = value
def write(self, data: BytesIO):
data.write(struct.pack("<b", self.x))
def read(self,data):
self.x = struct.unpack("<b", data.read(1))[0]
class ushort(ResoType):
x: int = 0
def __int__(self):
return self.x
def __init__(self,value=0):
self.x = value
def write(self, data: BytesIO):
data.write(struct.pack("<H", self.x))
def read(self,data):
self.x = struct.unpack("<H", data.read(2))[0]
class short(ResoType):
x: int = 0
def __int__(self):
return self.x
def __init__(self):
pass
def write(self, data: BytesIO):
data.write(struct.pack("<h", self.x))
def read(self,data):
self.x = struct.unpack("<h", data.read(2))[0]
class bool(ResoType):
x: bool = False
def __bool__(self) -> bool:
return self.x
def __init__(self,value=False):
self.x = value
def write(self, data: BytesIO):
data.write(struct.pack("?", self.x))
def read(self,data):
self.x = struct.unpack("?", data.read(1))[0]
class bool2(bool):
y: bool = False
def __init__(self):
pass
def read(self,data: BytesIO):
byte: ctypes.c_ubyte = ctypes.c_ubyte(struct.unpack("<B",data.read(1))[0])
self.x = (byte & 1) > 0
self.y = (byte & 2) > 0
def createflags(self) -> ctypes.c_byte:
flags: ctypes.c_ubyte = ctypes.c_ubyte(0)
flags |= (1 if self.x else 0)
flags |= (2 if self.y else 0)
return flags
def write(self, data: BytesIO):
data.write(struct.pack("<B", self.createflags()))
class bool3(bool2):
z: bool = False
def __init__(self):
pass
def read(self,data):
byte: ctypes.c_ubyte = ctypes.c_ubyte(struct.unpack("<B",data.read(1))[0])
self.x = (byte & 1) > 0
self.y = (byte & 2) > 0
self.z = (byte & 4) > 0
def createflags(self) -> ctypes.c_byte:
flags: ctypes.c_ubyte = ctypes.c_ubyte(0)
flags |= (1 if self.x else 0)
flags |= (2 if self.y else 0)
flags |= (3 if self.z else 0)
return flags
def write(self, data: BytesIO):
data.write(struct.pack("<B", self.createflags()))
class bool4(bool3):
w: bool = False
def __init__(self):
pass
def read(self,data: BytesIO):
byte: ctypes.c_ubyte = ctypes.c_ubyte(struct.unpack("<B",data.read(1))[0])
self.x = (byte & 1) > 0
self.y = (byte & 2) > 0
self.z = (byte & 4) > 0
self.w = (byte & 8) > 0
def createflags(self) -> ctypes.c_ubyte:
flags: ctypes.c_ubyte = ctypes.c_ubyte(0)
flags |= (1 if self.x else 0)
flags |= (2 if self.y else 0)
flags |= (4 if self.z else 0)
flags |= (8 if self.w else 0)
return flags
def write(self, data: BytesIO):
data.write(struct.pack("<B", self.createflags()))
class int(ResoType):
x: int = 0
def __int__(self):
return self.x
def __init__(self,value=0):
self.x = value
def read(self,data: BytesIO):
self.x = struct.unpack("<i", data.read(4))[0]
def write(self, data: BytesIO):
data.write(struct.pack("<i", self.x))
class int2(int):
y: int = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().write(data)
self.y = struct.unpack("<i", data.read(4))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<i", self.y))
class int3(int2):
z: int = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().write(data)
self.z = struct.unpack("<i", data.read(4))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<i", self.z))
class int4(int3):
w: int = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().write(data)
self.w = struct.unpack("<i", data.read(4))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<i", self.w))
class uint(ResoType):
x: int = 0
def __int__(self):
return self.x
def __init__(self,value=0):
self.x = value
def read(self,data: BytesIO):
self.x = struct.unpack("<I", data.read(4))[0]
def write(self, data: BytesIO):
data.write(struct.pack("<I", self.x))
class uint2(uint):
y: int = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().write(data)
self.y = struct.unpack("<I", data.read(4))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<I", self.y))
class uint3(uint2):
z: int = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().write(data)
self.z = struct.unpack("<I", data.read(4))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<I", self.z))
class uint4(uint3):
w: int = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().write(data)
self.w = struct.unpack("<I", data.read(4))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<I", self.w))
class ulong(ResoType):
x: int = 0
def __int__(self):
return self.x
def __init__(self,value=0):
self.x = value
def read(self,data: BytesIO):
self.x = struct.unpack("<Q", data.read(8))[0]
def write(self, data: BytesIO):
data.write(struct.pack("<Q", self.x))
class long(ResoType):
x: int = 0
def __init__(self):
pass
def read(self,data: BytesIO):
self.x = struct.unpack("<q", data.read(8))[0]
def write(self, data: BytesIO):
data.write(struct.pack("<q", self.x))
class long2(long):
y: int = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().read(data)
self.y = struct.unpack("<q", data.read(8))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<q", self.y))
class long3(long2):
z: int = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().read(data)
self.z = struct.unpack("<q", data.read(8))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<q", self.z))
class long4(long3):
w: int = 0
def __init__(self):
pass
def __init__(self):
pass
def read(self,data: BytesIO):
super().read(data)
self.w = struct.unpack("<q", data.read(8))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<q", self.w))
class double(ResoType):
x: float = 0
def __float__(self):
return self.x
def __init__(self,value=0):
self.x = value
def read(self,data: BytesIO):
self.x = struct.unpack("<d", data.read(8))[0]
def write(self, data: BytesIO):
data.write(struct.pack("<d", self.x))
class double2(double):
y: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().read(data)
self.y = struct.unpack("<d", data.read(8))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<d", self.y))
class double3(double2):
z: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().read(data)
self.z = struct.unpack("<d", data.read(8))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<d", self.z))
class double4(double3):
w: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().read(data)
self.w = struct.unpack("<d", data.read(8))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<d", self.w))
class double2x2(ResoType):
m00: float = 0
m01: float = 0
m10: float = 0
m11: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
self.m00,self.m01,self.m10,self.m11 = struct.unpack("<dddd", data.read(8*(2*2)))
def write(self, data: BytesIO):
data.write(struct.pack("<dddd", self.m00,self.m01, self.m10,self.m11))
class double3x3(double2x2):
m02: float = 0
m12: float = 0
m22: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
self.m00,self.m01,self.m02,self.m10,self.m11,self.m12,self.m20,self.m21,self.m22 = struct.unpack("<ddddddddd", data.read(8*(3*3)))
def write(self, data: BytesIO):
data.write(struct.pack("<ddddddddd", self.m00,self.m01,self.m02,self.m10,self.m11,self.m12,self.m20,self.m21,self.m22))
class double4x4(double3x3):
m03: float = 0
m13: float = 0
m23: float = 0
m33: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
self.m00,self.m01,self.m02,self.m03,self.m10,self.m11,self.m12,self.m13,self.m20,self.m21,self.m22,self.m23,self.m30,self.m31,self.m32,self.m33 = struct.unpack("<dddddddddddddddd", data.read(8*(4*4)))
def write(self, data: BytesIO):
data.write(struct.pack("<dddddddddddddddd", self.m00,self.m01,self.m02,self.m03,self.m10,self.m11,self.m12,self.m13,self.m20,self.m21,self.m22,self.m23,self.m30,self.m31,self.m32,self.m33))
class doubleQ(double4):
def __init__(self):
pass
def write(self, data: BytesIO):
super().write(data)
@classmethod
def read(cls, data: BytesIO):
super().read(data)
class float(ResoType):
x: float = 0
def __float__(self):
return self.x
def __init__(self, value=0):
self.x = value
def read(self,data: BytesIO):
self.x = struct.unpack("<f", data.read(4))[0]
def write(self, data: BytesIO):
data.write(struct.pack("<f", self.x))
class float2(float):
y: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().read(data)
self.y = struct.unpack("<f", data.read(4))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<f", self.y))
class float3(float2):
z: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().read(data)
self.z = struct.unpack("<f", data.read(4))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<f", self.z))
class float4(float3):
w: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
super().read(data)
self.w = struct.unpack("<f", data.read(4))[0]
def write(self, data: BytesIO):
super().write(data)
data.write(struct.pack("<f", self.w))
class float2x2(ResoType):
m00: float = 0
m01: float = 0
m10: float = 0
m11: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
self.m00,self.m01,self.m10,self.m11 = struct.unpack("<ffff", data.read(4*(2*2)))
def write(self, data: BytesIO):
data.write(struct.pack("<ffff", self.m00,self.m01, self.m10,self.m11))
class float3x3(float2x2):
m02: float = 0
m12: float = 0
m22: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
self.m00,self.m01,self.m02,self.m10,self.m11,self.m12,self.m20,self.m21,self.m22 = struct.unpack("<fffffffff", data.read(4*(3*3)))
def write(self, data: BytesIO):
data.write(struct.pack("<fffffffff", self.m00,self.m01,self.m02,self.m10,self.m11,self.m12,self.m20,self.m21,self.m22))
class float4x4(float3x3):
m03: float = 0
m13: float = 0
m23: float = 0
m33: float = 0
def __init__(self):
pass
def read(self,data: BytesIO):
self.m00,self.m01,self.m02,self.m03,self.m10,self.m11,self.m12,self.m13,self.m20,self.m21,self.m22,self.m23,self.m30,self.m31,self.m32,self.m33 = struct.unpack("<ffffffffffffffff", data.read(4*(4*4)))
def write(self, data: BytesIO):
data.write(struct.pack("<ffffffffffffffff", self.m00,self.m01,self.m02,self.m03,self.m10,self.m11,self.m12,self.m13,self.m20,self.m21,self.m22,self.m23,self.m30,self.m31,self.m32,self.m33))
class floatQ(float4):
def __init__(self):
pass
def write(self, data: BytesIO):
super().write(data)
@classmethod
def read(cls, data: BytesIO):
super().read(data)
+102 -12
View File
@@ -1,11 +1,17 @@
import bpy import bpy
import bpy_extras
from typing import List, Optional from .common import get_armature, get_selected_armature, simplify_bonename, is_valid_armature
from .common import get_armature
from bpy.types import Object, ShapeKey, Mesh, Context, Operator from bpy.types import Object, ShapeKey, Mesh, Context, Operator
from functools import lru_cache from functools import lru_cache
from ..core.register import register_wrap from ..core.register import register_wrap
from ..functions.translations import t from ..functions.translations import t
from ..core.dictionaries import bone_names
import re
from .resonite_loader import resonite_animx, resonite_types
import os
@register_wrap @register_wrap
@@ -34,16 +40,6 @@ class AvatarToolKit_OT_ExportResonite(Operator):
export_nla_strips_merged_animation_name = 'Animation', export_nla_strips_merged_animation_name = 'Animation',
export_nla_strips = True) export_nla_strips = True)
return {'FINISHED'} return {'FINISHED'}
import bpy
from ..core.register import register_wrap
from typing import List, Optional
import re
from bpy.types import Operator, Context, Object
from ..core.dictionaries import bone_names
from ..core.common import get_selected_armature, simplify_bonename, is_valid_armature
from ..functions.translations import t
@register_wrap @register_wrap
class AvatarToolKit_OT_ConvertToResonite(Operator): class AvatarToolKit_OT_ConvertToResonite(Operator):
@@ -151,3 +147,97 @@ class AvatarToolKit_OT_ConvertToResonite(Operator):
self.report({'INFO'}, t("Tools.bones_translated_success")) self.report({'INFO'}, t("Tools.bones_translated_success"))
return {'FINISHED'} return {'FINISHED'}
@register_wrap
class AvatarToolKit_OT_AnimX_Importer(Operator,bpy_extras.io_utils.ImportHelper):
bl_idname = 'avatar_toolkit.animx_importer'
bl_label = t('Tools.animx_importer.label')
bl_description = t('Tools.animx_importer.desc')
bl_options = {'REGISTER', 'UNDO'}
#fps = bpy.props.FloatProperty(default=25) #25 fps
filter_glob: bpy.props.StringProperty(
default="*.animx",
options={'HIDDEN'}
)
files: bpy.props.CollectionProperty(type=bpy.types.OperatorFileListElement, options={'HIDDEN', 'SKIP_SAVE'})
filepath: bpy.props.StringProperty()
directory:bpy.props.StringProperty(subtype='DIR_PATH')
@classmethod
def poll(cls, context: Context) -> bool:
return True
def execute(self, context: Context) -> set:
Froox_animations: list[resonite_animx.AnimX] = []
#decoding using self contained library:
files = [file.name for file in self.files]
files.append(self.filepath)
for file in files:
froox_animation: resonite_animx.AnimX = resonite_animx.AnimX()
froox_animation.interval.x = 1/25
froox_animation.read(file = os.path.join(self.directory,file))
Froox_animations.append(froox_animation)
#Load data into Blender Animations.
for froox_animation in Froox_animations:
action: bpy.types.Action = bpy.data.actions.new(froox_animation.name.x)
action.use_fake_user = True
for track in froox_animation.tracks:
print("hit here1")
print(track.FrameType)
if(track.FrameType != type(resonite_types.float) and track.FrameType != type(resonite_types.double)):
continue
data_path: str = track._node.x+"."+track._property.x
fcurve_reso = action.fcurves.new(data_path,None,track._node.x)
print("hit here2")
match(type(track)):
case (type(resonite_animx.RawTrack)):
rawtrack: resonite_animx.RawTrack = track
for frame in rawtrack.keyframes:
key: bpy.types.Keyframe = fcurve_reso.keyframe_points.insert(frame.time, float(frame.value))
case (type(resonite_animx.DiscreteTrack)):
discretetrack: resonite_animx.RawTrack = track
for frame in rawtrack.keyframes:
key: bpy.types.Keyframe = fcurve_reso.keyframe_points.insert(frame.time, float(frame.value))
case(type(resonite_animx.CurveTrack)):
curvetrack: resonite_animx.RawTrack = track
for frame in curvetrack.keyframes:
key: bpy.types.Keyframe = fcurve_reso.keyframe_points.insert(frame.time, float(frame.value))
key.handle_left = float(frame.left_tan)
key.handle_left = float(frame.right_tan)
case(type(resonite_animx.BezierTrack)):
beziertrack: resonite_animx.RawTrack = track
# Bezier is not supported rn, ignore.
return {'FINISHED'}
-115
View File
@@ -1,115 +0,0 @@
import bpy
from ..core.register import register_wrap
from typing import List, Optional
import re
from bpy.types import Operator, Context, Object
from ..core.dictionaries import bone_names
from ..core.common import get_selected_armature, simplify_bonename, is_valid_armature
from ..functions.translations import t
@register_wrap
class AvatarToolKit_OT_ConvertToResonite(Operator):
bl_idname = 'avatar_toolkit.convert_to_resonite'
bl_label = t('Tools.convert_to_resonite.label')
bl_description = t('Tools.convert_to_resonite.desc')
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context: Context) -> bool:
armature = get_selected_armature(context)
return armature is not None and is_valid_armature(armature)
def execute(self, context: Context) -> set:
armature = get_selected_armature(context)
if not armature:
self.report({'WARNING'}, t("Tools.no_armature_selected"))
return {'CANCELLED'}
translate_bone_fails = 0
untranslated_bones = set()
reverse_bone_lookup = dict()
for (preferred_name, name_list) in bone_names.items():
for name in name_list:
reverse_bone_lookup[name] = preferred_name
resonite_translations = {
'hips': "Hips",
'spine': "Spine",
'chest': "Chest",
'neck': "Neck",
'head': "Head",
'left_eye': "Eye.L",
'right_eye': "Eye.R",
'right_leg': "UpperLeg.R",
'right_knee': "Calf.R",
'right_ankle': "Foot.R",
'right_toe': 'Toes.R',
'right_shoulder': "Shoulder.R",
'right_arm': "UpperArm.R",
'right_elbow': "ForeArm.R",
'right_wrist': "Hand.R",
'left_leg': "UpperLeg.L",
'left_knee': "Calf.L",
'left_ankle': "Foot.L",
'left_toe': "Toes.L",
'left_shoulder': "Shoulder.L",
'left_arm': "UpperArm.L",
'left_elbow': "ForeArm.L",
'left_wrist': "Hand.R",
'pinkie_1_l': "pinkie1.L",
'pinkie_2_l': "pinkie2.L",
'pinkie_3_l': "pinkie3.L",
'ring_1_l': "ring1.L",
'ring_2_l': "ring2.L",
'ring_3_l': "ring3.L",
'middle_1_l': "middle1.L",
'middle_2_l': "middle2.L",
'middle_3_l': "middle3.L",
'index_1_l': "index1.L",
'index_2_l': "index2.L",
'index_3_l': "index3.L",
'thumb_1_l': "thumb1.L",
'thumb_2_l': "thumb2.L",
'thumb_3_l': "thumb3.L",
'pinkie_1_r': "pinkie1.R",
'pinkie_2_r': "pinkie2.R",
'pinkie_3_r': "pinkie3.R",
'ring_1_r': "ring1.R",
'ring_2_r': "ring2.R",
'ring_3_r': "ring3.R",
'middle_1_r': "middle1.R",
'middle_2_r': "middle2.R",
'middle_3_r': "middle3.R",
'index_1_r': "index1.R",
'index_2_r': "index2.R",
'index_3_r': "index3.R",
'thumb_1_r': "thumb1.R",
'thumb_2_r': "thumb2.R",
'thumb_3_r': "thumb3.R"
}
context.view_layer.objects.active = armature
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.object.mode_set(mode='OBJECT')
bone.name = re.compile(re.escape("<noik>"), re.IGNORECASE).sub("",bone.name) #remove "NOIK" from bones before translating again, in case an update was done that fixes a translation.
for bone in armature.data.bones:
if simplify_bonename(bone.name) in reverse_bone_lookup and reverse_bone_lookup[simplify_bonename(bone.name)] in resonite_translations:
bone.name = resonite_translations[reverse_bone_lookup[simplify_bonename(bone.name)]]
else:
untranslated_bones.add(bone.name)
bone.name = bone.name+"<noik>"
translate_bone_fails += 1
bpy.ops.object.mode_set(mode='OBJECT')
if translate_bone_fails > 0:
self.report({'INFO'}, t("Tools.bones_translated_with_fails").format(translate_bone_fails=translate_bone_fails))
else:
self.report({'INFO'}, t("Tools.bones_translated_success"))
return {'FINISHED'}
+3
View File
@@ -287,6 +287,9 @@ class AvatarToolkit_OT_AlignUVEdgesToTarget(Operator):
uv_lay.uv[corner].vector = lerped_point #put the vertcies at the point we calculated. uv_lay.uv[corner].vector = lerped_point #put the vertcies at the point we calculated.
except: except:
print("This is probably fine? - @989onan") #TODO: What happened here? The magic of making code so complex you forget if this is even an issue. - @989onan print("This is probably fine? - @989onan") #TODO: What happened here? The magic of making code so complex you forget if this is even an issue. - @989onan
#Note: The above print statement may require reading what this entire operator does before understanding if the above print statment means anything
#so if you value your time, just do a bunch of tests until the above print stament is ran or something
#if in doubt and you cannot get it to run, just spend some time trying to understand the operator - @989onan
print("Finished mesh \""+source+"\" for UV's") print("Finished mesh \""+source+"\" for UV's")