From 2c81ec426021b7e0261de1e7cd102ec093c96bbc Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Mon, 22 Apr 2019 17:14:15 -0400 Subject: [PATCH 01/13] Fix Undefined Variable in SEAnim.py --- seanim.py | 1186 ++++++++++++++++++++++++++--------------------------- 1 file changed, 593 insertions(+), 593 deletions(-) diff --git a/seanim.py b/seanim.py index c24dbc9..9bab360 100644 --- a/seanim.py +++ b/seanim.py @@ -1,593 +1,593 @@ -import time -import struct - -# - -LOG_READ_TIME = False -LOG_WRITE_TIME = False - -LOG_ANIM_HEADER = False -LOG_ANIM_BONES = False -LOG_ANIM_BONE_MODIFIERS = False -LOG_ANIM_BONES_KEYS = False -LOG_ANIM_NOTES = False - - -def enum(**enums): - return type('Enum', (), enums) - - -SEANIM_TYPE = enum( - SEANIM_TYPE_ABSOLUTE=0, - SEANIM_TYPE_ADDITIVE=1, - SEANIM_TYPE_RELATIVE=2, - SEANIM_TYPE_DELTA=3) - -SEANIM_PRESENCE_FLAGS = enum( - # These describe what type of keyframe data is present for the bones - SEANIM_BONE_LOC=1 << 0, - SEANIM_BONE_ROT=1 << 1, - SEANIM_BONE_SCALE=1 << 2, - # If any of the above flags are set, then bone keyframe data is present, - # thus this comparing against this mask will return true - SEANIM_PRESENCE_BONE=1 << 0 | 1 << 1 | 1 << 2, - SEANIM_PRESENCE_NOTE=1 << 6, # The file contains notetrack data - SEANIM_PRESENCE_CUSTOM=1 << 7, # The file contains a custom data block -) - - -SEANIM_PROPERTY_FLAGS = enum( - SEANIM_PRECISION_HIGH=1 << 0) - -SEANIM_FLAGS = enum( - SEANIM_LOOPED=1 << 0) - - -class Info(object): - __slots__ = ('version', 'magic') - - def __init__(self, file=None): - self.version = 1 - self.magic = b'SEAnim' - if file is not None: - self.load(file) - - def load(self, file): - bytes = file.read(8) - data = struct.unpack('6ch', bytes) - - magic = b'' - for i in range(6): - magic += data[i] - - version = data[6] - - assert magic == self.magic - assert version == self.version - - def save(self, file): - bytes = self.magic - bytes += struct.pack('h', self.version) - file.write(bytes) - - -class Header(object): - __slots__ = ( - 'animType', 'animFlags', - 'dataPresenceFlags', 'dataPropertyFlags', - 'framerate', 'frameCount', - 'boneCount', 'boneAnimModifierCount', - 'noteCount' - ) - - def __init__(self, file=None): - self.animType = SEANIM_TYPE.SEANIM_TYPE_RELATIVE # Relative is default - self.animFlags = 0x0 - - self.dataPresenceFlags = 0x0 - self.dataPropertyFlags = 0x0 - - self.framerate = 0 - self.frameCount = 0 - - self.boneCount = 0 - self.boneAnimModifierCount = 0 - - self.noteCount = 0 - - if file is not None: - self.load(file) - - def load(self, file): - bytes = file.read(2) - data = struct.unpack('h', bytes) - - headerSize = data[0] - bytes = file.read(headerSize - 2) - # = prefix tell is to ignore C struct packing rules - data = struct.unpack('=6BfII4BI', bytes) - - self.animType = data[0] - self.animFlags = data[1] - self.dataPresenceFlags = data[2] - self.dataPropertyFlags = data[3] - # reserved = data[4] - # reserved = data[5] - self.framerate = data[6] - self.frameCount = data[7] - self.boneCount = data[8] - self.boneAnimModifierCount = data[9] - # reserved = data[10] - # reserved = data[11] - # reserved = data[12] - self.noteCount = data[13] - - def save(self, file): - bytes = struct.pack('=6BfII4BI', - self.animType, self.animFlags, - self.dataPresenceFlags, self.dataPropertyFlags, - 0, 0, - self.framerate, - self.frameCount, self.boneCount, - self.boneAnimModifierCount, 0, 0, 0, - self.noteCount) - - size = struct.pack('h', len(bytes) + 2) - file.write(size) - file.write(bytes) - - -class Frame_t(object): - """ - The Frame_t class is only ever used to get the size - and format character used by frame indices in a given seanim file - """ - __slots__ = ('size', 'char') - - def __init__(self, header): - if header.frameCount <= 0xFF: - self.size = 1 - self.char = 'B' - elif header.frameCount <= 0xFFFF: - self.size = 2 - self.char = 'H' - else: # if header.frameCount <= 0xFFFFFFFF: - self.size = 4 - self.char = 'I' - - -class Bone_t(object): - """ - The Bone_t class is only ever used to get the size - and format character used by frame indices in a given seanim file - """ - __slots__ = ('size', 'char') - - def __init__(self, header): - if header.boneCount <= 0xFF: - self.size = 1 - self.char = 'B' - elif header.boneCount <= 0xFFFF: - self.size = 2 - self.char = 'H' - else: # if header.boneCount <= 0xFFFFFFFF: - self.size = 4 - self.char = 'I' - - -class Precision_t(object): - """ - The Precision_t class is only ever used to get the size - and format character used by vec3_t, quat_t, etc. in a given sanim file - """ - __slots__ = ('size', 'char') - - def __init__(self, header): - if (header.dataPropertyFlags & - SEANIM_PROPERTY_FLAGS.SEANIM_PRECISION_HIGH): - self.size = 8 - self.char = 'd' - else: - self.size = 4 - self.char = 'f' - - -class KeyFrame(object): - """ - A small class used for holding keyframe data - """ - __slots__ = ('frame', 'data') - - def __init__(self, frame, data): - self.frame = frame - self.data = data - - -class Bone(object): - __slots__ = ( - 'name', 'flags', - 'locKeyCount', 'rotKeyCount', 'scaleKeyCount', - 'posKeys', 'rotKeys', 'scaleKeys', - 'useModifier', 'modifier' - ) - - def __init__(self, file=None): - self.name = "" - - self.flags = 0x0 - - self.locKeyCount = 0 - self.rotKeyCount = 0 - self.scaleKeyCount = 0 - - self.posKeys = [] - self.rotKeys = [] - self.scaleKeys = [] - - self.useModifier = False - self.modifier = 0 - - if file is not None: - self.load(file) - - def load(self, file): - bytes = b'' - b = file.read(1) - while not b == b'\x00': - bytes += b - b = file.read(1) - self.name = bytes.decode("utf-8") - - def loadData(self, file, frame_t, precision_t, - useLoc=False, useRot=False, useScale=False): - # Read the flags for the bone - bytes = file.read(1) - data = struct.unpack("B", bytes) - self.flags = data[0] - - # Load the position keyframes if they are present - if useLoc: - bytes = file.read(frame_t.size) - data = struct.unpack('%c' % frame_t.char, bytes) - self.locKeyCount = data[0] - - for i in range(self.locKeyCount): - bytes = file.read(frame_t.size + 3 * precision_t.size) - data = struct.unpack('=%c3%c' % - (frame_t.char, precision_t.char), bytes) - - frame = data[0] - pos = (data[1], data[2], data[3]) - - self.posKeys.append(KeyFrame(frame, pos)) - - # Load the rotation keyframes if they are present - if useRot: - bytes = file.read(frame_t.size) - data = struct.unpack('%c' % frame_t.char, bytes) - self.rotKeyCount = data[0] - - for i in range(self.rotKeyCount): - - bytes = file.read(frame_t.size + 4 * precision_t.size) - data = struct.unpack('=%c4%c' % - (frame_t.char, precision_t.char), bytes) - - frame = data[0] - # Load the quaternion as XYZW - quat = (data[1], data[2], data[3], data[4]) - - self.rotKeys.append(KeyFrame(frame, quat)) - - # Load the Scale Keyrames - if useScale: - bytes = file.read(frame_t.size) - data = struct.unpack('%c' % frame_t.char, bytes) - self.scaleKeyCount = data[0] - for i in range(self.scaleKeyCount): - bytes = file.read(frame_t.size + 3 * precision_t.size) - data = struct.unpack('=%c3%c' % - (frame_t.char, precision_t.char), bytes) - - frame = data[0] - scale = (data[1], data[2], data[3]) - - self.scaleKeys.append(KeyFrame(frame, scale)) - - def save(self, file, frame_t, bone_t, precision_t, - useLoc=False, useRot=False, useScale=False): - bytes = struct.pack("B", self.flags) - file.write(bytes) - - if useLoc: - bytes = struct.pack('%c' % frame_t.char, len(self.posKeys)) - file.write(bytes) - - for i, key in enumerate(self.posKeys): - bytes = struct.pack('=%c3%c' % - (frame_t.char, precision_t.char), - key.frame, - key.data[0], key.data[1], key.data[2]) - file.write(bytes) - - if useRot: - bytes = struct.pack('%c' % frame_t.char, len(self.rotKeys)) - file.write(bytes) - - for i, key in enumerate(self.rotKeys): - bytes = struct.pack('=%c4%c' % - (frame_t.char, precision_t.char), - key.frame, - key.data[0], key.data[1], - key.data[2], key.data[3]) - file.write(bytes) - - if useScale: - bytes = struct.pack('%c' % frame_t.char, len(self.scaleKeys)) - file.write(bytes) - - for i, key in enumerate(self.scaleKeys): - bytes = struct.pack('=%c3%c' % - (frame_t.char, precision_t.char), - key.frame, - key.data[0], key.data[1], key.data[2]) - file.write(bytes) - - -class Note(object): - __slots__ = ('frame', 'name') - - def __init__(self, file=None, frame_t=None): - self.frame = -1 - self.name = "" - - if file is not None: - self.load(file, frame_t) - - def load(self, file, frame_t): - bytes = file.read(frame_t.size) - data = struct.unpack('%c' % frame_t.char, bytes) - - self.frame = data[0] - - bytes = b'' - b = file.read(1) - while not b == b'\x00': - bytes += b - b = file.read(1) - self.name = bytes.decode("utf-8") - - def save(self, file, frame_t): - bytes = struct.pack('%c' % frame_t.char, self.frame) - file.write(bytes) - - bytes = struct.pack('%ds' % (len(self.name) + 1), self.name.encode()) - file.write(bytes) - - -class Anim(object): - __slots__ = ('__info', 'info', 'header', 'bones', - 'boneAnimModifiers', 'notes') - - def __init__(self, path=None): - self.__info = Info() - self.header = Header() - - self.bones = [] - self.boneAnimModifiers = [] - self.notes = [] - - if path is not None: - self.load(path) - - # Update the header flags based on the presence of certain keyframe / - # notetrack data - def update_metadata(self, high_precision=False, looping=False): - anim_locKeyCount = 0 - anim_rotKeyCount = 0 - anim_scaleKeyCount = 0 - - header = self.header - header.boneCount = len(self.bones) - - dataPresenceFlags = header.dataPresenceFlags - dataPropertyFlags = header.dataPropertyFlags - - max_frame_index = 0 - - for bone in self.bones: - bone.locKeyCount = len(bone.posKeys) - bone.rotKeyCount = len(bone.rotKeys) - bone.scaleKeyCount = len(bone.scaleKeys) - - anim_locKeyCount += bone.locKeyCount - anim_rotKeyCount += bone.rotKeyCount - anim_scaleKeyCount += bone.scaleKeyCount - - for key in bone.posKeys: - max_frame_index = max(max_frame_index, key.frame) - - for key in bone.rotKeys: - max_frame_index = max(max_frame_index, key.frame) - - for key in bone.scaleKeys: - max_frame_index = max(max_frame_index, key.frame) - - if anim_locKeyCount: - dataPresenceFlags |= SEANIM_PRESENCE_FLAGS.SEANIM_BONE_LOC - if anim_rotKeyCount: - dataPresenceFlags |= SEANIM_PRESENCE_FLAGS.SEANIM_BONE_ROT - if anim_scaleKeyCount: - dataPresenceFlags |= SEANIM_PRESENCE_FLAGS.SEANIM_BONE_SCALE - - for note in self.notes: - max_frame_index = max(max_frame_index, note.frame) - - header.noteCount = len(self.notes) - - if header.noteCount: - dataPresenceFlags |= SEANIM_PRESENCE_FLAGS.SEANIM_PRESENCE_NOTE - - if high_precision: - dataPropertyFlags |= SEANIM_PROPERTY_FLAGS.SEANIM_PRECISION_HIGH - - if looping: - header.animFlags |= SEANIM_FLAGS.SEANIM_LOOPED - - header.dataPresenceFlags = dataPresenceFlags - header.dataPropertyFlags = dataPropertyFlags - - # FrameCount represents the length of the animation in frames - # and since all animations start at frame 0 - we simply grab - # the max frame number (from keys / notes / etc.) and add 1 to it - header.frameCount = max_frame_index + 1 - - def load(self, path): - if LOG_READ_TIME: - time_start = time.time() - print("Loading: '%s'" % path) - - try: - file = open(path, "rb") - except IOError: - print("Could not open file for reading:\n %s" % path) - return - - self.info = Info(file) - self.header = Header(file) - self.boneAnimModifiers = [] - - # Init the frame_t, bone_t and precision_t info - frame_t = Frame_t(self.header) - bone_t = Bone_t(self.header) - precision_t = Precision_t(self.header) - - dataPresenceFlags = self.header.dataPresenceFlags - - if LOG_ANIM_HEADER: - print("Magic: %s" % self.info.magic) - print("Version: %d" % self.info.version) - - print("AnimType: %d" % self.header.animType) - print("AnimFlags: %d" % self.header.animFlags) - print("PresenceFlags: %d" % dataPresenceFlags) - print("PropertyFlags: %d" % self.header.dataPropertyFlags) - print("FrameRate: %f" % self.header.framerate) - print("FrameCount: %d" % self.header.frameCount) - print("BoneCount: %d" % self.header.boneCount) - print("NoteCount: %d" % self.header.noteCount) - print("BoneModifierCount: %d" % self.header.boneAnimModifierCount) - - print("Frame_t Size: %d" % frame_t.size) - print("Frame_t Char: '%s'" % frame_t.char) - - self.bones = [] - if dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_PRESENCE_BONE: - useLoc = dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_BONE_LOC - useRot = dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_BONE_ROT - useScale = (dataPresenceFlags & - SEANIM_PRESENCE_FLAGS.SEANIM_BONE_SCALE) - - for i in range(self.header.boneCount): - if LOG_ANIM_BONES: - print("Loading Name for Bone[%d]" % i) - self.bones.append(Bone(file)) - - for i in range(self.header.boneAnimModifierCount): - bytes = file.read(bone_t.size + 1) - data = struct.unpack("%cB" % bone_t.char, bytes) - index = data[0] - self.bones[index].useModifier = True - self.bones[index].modifier = data[1] - - self.boneAnimModifiers.append(self.bones[index]) - - if LOG_ANIM_BONE_MODIFIERS: - print("Loaded Modifier %d for '%s" % - (index, self.bones[index].name)) - - for i in range(self.header.boneCount): - if LOG_ANIM_BONES: - print("Loading Data For Bone[%d] '%s'" % ( - i, self.bones[i].name)) - self.bones[i].loadData( - file, frame_t, precision_t, useLoc, useRot, useScale) - if LOG_ANIM_BONES_KEYS: - for key in self.bones[i].posKeys: - print("%s LOC %d %s" % - (self.bones[i].name, key.frame, key.data)) - for key in self.bones[i].rotKeys: - print("%s ROT %d %s" % - (self.bones[i].name, key.frame, key.data)) - for key in self.bones[i].scaleKeys: - print("%s SCALE %d %s" % - (self.bones[i].name, key.frame, key.data)) - - self.notes = [] - if (self.header.dataPresenceFlags & - SEANIM_PRESENCE_FLAGS.SEANIM_PRESENCE_NOTE): - for i in range(self.header.noteCount): - note = Note(file, frame_t) - self.notes.append(note) - if LOG_ANIM_NOTES: - print("Loaded Note[%d]:" % i) - print(" Frame %d: %s" % (note.frame, note.name)) - - file.close() - - if LOG_READ_TIME: - time_end = time.time() - time_elapsed = time_end - time_start - print("Done! - Completed in %ss" % time_elapsed) - - def save(self, filepath="", high_precision=False, looping=False): - if LOG_WRITE_TIME: - time_start = time.time() - print("Saving: '%s'" % filepath) - - try: - file = open(filepath, "wb") - except IOError: - print("Could not open file for writing:\n %s" % path) - return - - # Update the header flags, based on the presence of different keyframe - # types - self.update_metadata(high_precision, looping) - - self.__info.save(file) - self.header.save(file) - for bone in self.bones: - bytes = struct.pack( - '%ds' % (len(bone.name) + 1), bone.name.encode()) - file.write(bytes) - - dataPresenceFlags = self.header.dataPresenceFlags - - useLoc = dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_BONE_LOC - useRot = dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_BONE_ROT - useScale = dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_BONE_SCALE - - frame_t = Frame_t(self.header) - bone_t = Bone_t(self.header) - precision_t = Precision_t(self.header) - - for index, bone in enumerate(self.bones): - if bone.useModifier: - bytes = struct.pack('%cB' % bone_t.char, index, bone.modifier) - file.write(bytes) - - for bone in self.bones: - bone.save(file, frame_t, bone_t, precision_t, - useLoc, useRot, useScale) - - if dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_PRESENCE_NOTE: - for note in self.notes: - note.save(file, frame_t) - - file.close() - - if LOG_WRITE_TIME: - time_end = time.time() - time_elapsed = time_end - time_start - print("Done! - Completed in %ss" % time_elapsed) +import time +import struct + +# + +LOG_READ_TIME = False +LOG_WRITE_TIME = False + +LOG_ANIM_HEADER = False +LOG_ANIM_BONES = False +LOG_ANIM_BONE_MODIFIERS = False +LOG_ANIM_BONES_KEYS = False +LOG_ANIM_NOTES = False + + +def enum(**enums): + return type('Enum', (), enums) + + +SEANIM_TYPE = enum( + SEANIM_TYPE_ABSOLUTE=0, + SEANIM_TYPE_ADDITIVE=1, + SEANIM_TYPE_RELATIVE=2, + SEANIM_TYPE_DELTA=3) + +SEANIM_PRESENCE_FLAGS = enum( + # These describe what type of keyframe data is present for the bones + SEANIM_BONE_LOC=1 << 0, + SEANIM_BONE_ROT=1 << 1, + SEANIM_BONE_SCALE=1 << 2, + # If any of the above flags are set, then bone keyframe data is present, + # thus this comparing against this mask will return true + SEANIM_PRESENCE_BONE=1 << 0 | 1 << 1 | 1 << 2, + SEANIM_PRESENCE_NOTE=1 << 6, # The file contains notetrack data + SEANIM_PRESENCE_CUSTOM=1 << 7, # The file contains a custom data block +) + + +SEANIM_PROPERTY_FLAGS = enum( + SEANIM_PRECISION_HIGH=1 << 0) + +SEANIM_FLAGS = enum( + SEANIM_LOOPED=1 << 0) + + +class Info(object): + __slots__ = ('version', 'magic') + + def __init__(self, file=None): + self.version = 1 + self.magic = b'SEAnim' + if file is not None: + self.load(file) + + def load(self, file): + bytes = file.read(8) + data = struct.unpack('6ch', bytes) + + magic = b'' + for i in range(6): + magic += data[i] + + version = data[6] + + assert magic == self.magic + assert version == self.version + + def save(self, file): + bytes = self.magic + bytes += struct.pack('h', self.version) + file.write(bytes) + + +class Header(object): + __slots__ = ( + 'animType', 'animFlags', + 'dataPresenceFlags', 'dataPropertyFlags', + 'framerate', 'frameCount', + 'boneCount', 'boneAnimModifierCount', + 'noteCount' + ) + + def __init__(self, file=None): + self.animType = SEANIM_TYPE.SEANIM_TYPE_RELATIVE # Relative is default + self.animFlags = 0x0 + + self.dataPresenceFlags = 0x0 + self.dataPropertyFlags = 0x0 + + self.framerate = 0 + self.frameCount = 0 + + self.boneCount = 0 + self.boneAnimModifierCount = 0 + + self.noteCount = 0 + + if file is not None: + self.load(file) + + def load(self, file): + bytes = file.read(2) + data = struct.unpack('h', bytes) + + headerSize = data[0] + bytes = file.read(headerSize - 2) + # = prefix tell is to ignore C struct packing rules + data = struct.unpack('=6BfII4BI', bytes) + + self.animType = data[0] + self.animFlags = data[1] + self.dataPresenceFlags = data[2] + self.dataPropertyFlags = data[3] + # reserved = data[4] + # reserved = data[5] + self.framerate = data[6] + self.frameCount = data[7] + self.boneCount = data[8] + self.boneAnimModifierCount = data[9] + # reserved = data[10] + # reserved = data[11] + # reserved = data[12] + self.noteCount = data[13] + + def save(self, file): + bytes = struct.pack('=6BfII4BI', + self.animType, self.animFlags, + self.dataPresenceFlags, self.dataPropertyFlags, + 0, 0, + self.framerate, + self.frameCount, self.boneCount, + self.boneAnimModifierCount, 0, 0, 0, + self.noteCount) + + size = struct.pack('h', len(bytes) + 2) + file.write(size) + file.write(bytes) + + +class Frame_t(object): + """ + The Frame_t class is only ever used to get the size + and format character used by frame indices in a given seanim file + """ + __slots__ = ('size', 'char') + + def __init__(self, header): + if header.frameCount <= 0xFF: + self.size = 1 + self.char = 'B' + elif header.frameCount <= 0xFFFF: + self.size = 2 + self.char = 'H' + else: # if header.frameCount <= 0xFFFFFFFF: + self.size = 4 + self.char = 'I' + + +class Bone_t(object): + """ + The Bone_t class is only ever used to get the size + and format character used by frame indices in a given seanim file + """ + __slots__ = ('size', 'char') + + def __init__(self, header): + if header.boneCount <= 0xFF: + self.size = 1 + self.char = 'B' + elif header.boneCount <= 0xFFFF: + self.size = 2 + self.char = 'H' + else: # if header.boneCount <= 0xFFFFFFFF: + self.size = 4 + self.char = 'I' + + +class Precision_t(object): + """ + The Precision_t class is only ever used to get the size + and format character used by vec3_t, quat_t, etc. in a given sanim file + """ + __slots__ = ('size', 'char') + + def __init__(self, header): + if (header.dataPropertyFlags & + SEANIM_PROPERTY_FLAGS.SEANIM_PRECISION_HIGH): + self.size = 8 + self.char = 'd' + else: + self.size = 4 + self.char = 'f' + + +class KeyFrame(object): + """ + A small class used for holding keyframe data + """ + __slots__ = ('frame', 'data') + + def __init__(self, frame, data): + self.frame = frame + self.data = data + + +class Bone(object): + __slots__ = ( + 'name', 'flags', + 'locKeyCount', 'rotKeyCount', 'scaleKeyCount', + 'posKeys', 'rotKeys', 'scaleKeys', + 'useModifier', 'modifier' + ) + + def __init__(self, file=None): + self.name = "" + + self.flags = 0x0 + + self.locKeyCount = 0 + self.rotKeyCount = 0 + self.scaleKeyCount = 0 + + self.posKeys = [] + self.rotKeys = [] + self.scaleKeys = [] + + self.useModifier = False + self.modifier = 0 + + if file is not None: + self.load(file) + + def load(self, file): + bytes = b'' + b = file.read(1) + while not b == b'\x00': + bytes += b + b = file.read(1) + self.name = bytes.decode("utf-8") + + def loadData(self, file, frame_t, precision_t, + useLoc=False, useRot=False, useScale=False): + # Read the flags for the bone + bytes = file.read(1) + data = struct.unpack("B", bytes) + self.flags = data[0] + + # Load the position keyframes if they are present + if useLoc: + bytes = file.read(frame_t.size) + data = struct.unpack('%c' % frame_t.char, bytes) + self.locKeyCount = data[0] + + for i in range(self.locKeyCount): + bytes = file.read(frame_t.size + 3 * precision_t.size) + data = struct.unpack('=%c3%c' % + (frame_t.char, precision_t.char), bytes) + + frame = data[0] + pos = (data[1], data[2], data[3]) + + self.posKeys.append(KeyFrame(frame, pos)) + + # Load the rotation keyframes if they are present + if useRot: + bytes = file.read(frame_t.size) + data = struct.unpack('%c' % frame_t.char, bytes) + self.rotKeyCount = data[0] + + for i in range(self.rotKeyCount): + + bytes = file.read(frame_t.size + 4 * precision_t.size) + data = struct.unpack('=%c4%c' % + (frame_t.char, precision_t.char), bytes) + + frame = data[0] + # Load the quaternion as XYZW + quat = (data[1], data[2], data[3], data[4]) + + self.rotKeys.append(KeyFrame(frame, quat)) + + # Load the Scale Keyrames + if useScale: + bytes = file.read(frame_t.size) + data = struct.unpack('%c' % frame_t.char, bytes) + self.scaleKeyCount = data[0] + for i in range(self.scaleKeyCount): + bytes = file.read(frame_t.size + 3 * precision_t.size) + data = struct.unpack('=%c3%c' % + (frame_t.char, precision_t.char), bytes) + + frame = data[0] + scale = (data[1], data[2], data[3]) + + self.scaleKeys.append(KeyFrame(frame, scale)) + + def save(self, file, frame_t, bone_t, precision_t, + useLoc=False, useRot=False, useScale=False): + bytes = struct.pack("B", self.flags) + file.write(bytes) + + if useLoc: + bytes = struct.pack('%c' % frame_t.char, len(self.posKeys)) + file.write(bytes) + + for i, key in enumerate(self.posKeys): + bytes = struct.pack('=%c3%c' % + (frame_t.char, precision_t.char), + key.frame, + key.data[0], key.data[1], key.data[2]) + file.write(bytes) + + if useRot: + bytes = struct.pack('%c' % frame_t.char, len(self.rotKeys)) + file.write(bytes) + + for i, key in enumerate(self.rotKeys): + bytes = struct.pack('=%c4%c' % + (frame_t.char, precision_t.char), + key.frame, + key.data[0], key.data[1], + key.data[2], key.data[3]) + file.write(bytes) + + if useScale: + bytes = struct.pack('%c' % frame_t.char, len(self.scaleKeys)) + file.write(bytes) + + for i, key in enumerate(self.scaleKeys): + bytes = struct.pack('=%c3%c' % + (frame_t.char, precision_t.char), + key.frame, + key.data[0], key.data[1], key.data[2]) + file.write(bytes) + + +class Note(object): + __slots__ = ('frame', 'name') + + def __init__(self, file=None, frame_t=None): + self.frame = -1 + self.name = "" + + if file is not None: + self.load(file, frame_t) + + def load(self, file, frame_t): + bytes = file.read(frame_t.size) + data = struct.unpack('%c' % frame_t.char, bytes) + + self.frame = data[0] + + bytes = b'' + b = file.read(1) + while not b == b'\x00': + bytes += b + b = file.read(1) + self.name = bytes.decode("utf-8") + + def save(self, file, frame_t): + bytes = struct.pack('%c' % frame_t.char, self.frame) + file.write(bytes) + + bytes = struct.pack('%ds' % (len(self.name) + 1), self.name.encode()) + file.write(bytes) + + +class Anim(object): + __slots__ = ('__info', 'info', 'header', 'bones', + 'boneAnimModifiers', 'notes') + + def __init__(self, path=None): + self.__info = Info() + self.header = Header() + + self.bones = [] + self.boneAnimModifiers = [] + self.notes = [] + + if path is not None: + self.load(path) + + # Update the header flags based on the presence of certain keyframe / + # notetrack data + def update_metadata(self, high_precision=False, looping=False): + anim_locKeyCount = 0 + anim_rotKeyCount = 0 + anim_scaleKeyCount = 0 + + header = self.header + header.boneCount = len(self.bones) + + dataPresenceFlags = header.dataPresenceFlags + dataPropertyFlags = header.dataPropertyFlags + + max_frame_index = 0 + + for bone in self.bones: + bone.locKeyCount = len(bone.posKeys) + bone.rotKeyCount = len(bone.rotKeys) + bone.scaleKeyCount = len(bone.scaleKeys) + + anim_locKeyCount += bone.locKeyCount + anim_rotKeyCount += bone.rotKeyCount + anim_scaleKeyCount += bone.scaleKeyCount + + for key in bone.posKeys: + max_frame_index = max(max_frame_index, key.frame) + + for key in bone.rotKeys: + max_frame_index = max(max_frame_index, key.frame) + + for key in bone.scaleKeys: + max_frame_index = max(max_frame_index, key.frame) + + if anim_locKeyCount: + dataPresenceFlags |= SEANIM_PRESENCE_FLAGS.SEANIM_BONE_LOC + if anim_rotKeyCount: + dataPresenceFlags |= SEANIM_PRESENCE_FLAGS.SEANIM_BONE_ROT + if anim_scaleKeyCount: + dataPresenceFlags |= SEANIM_PRESENCE_FLAGS.SEANIM_BONE_SCALE + + for note in self.notes: + max_frame_index = max(max_frame_index, note.frame) + + header.noteCount = len(self.notes) + + if header.noteCount: + dataPresenceFlags |= SEANIM_PRESENCE_FLAGS.SEANIM_PRESENCE_NOTE + + if high_precision: + dataPropertyFlags |= SEANIM_PROPERTY_FLAGS.SEANIM_PRECISION_HIGH + + if looping: + header.animFlags |= SEANIM_FLAGS.SEANIM_LOOPED + + header.dataPresenceFlags = dataPresenceFlags + header.dataPropertyFlags = dataPropertyFlags + + # FrameCount represents the length of the animation in frames + # and since all animations start at frame 0 - we simply grab + # the max frame number (from keys / notes / etc.) and add 1 to it + header.frameCount = max_frame_index + 1 + + def load(self, path): + if LOG_READ_TIME: + time_start = time.time() + print("Loading: '%s'" % path) + + try: + file = open(path, "rb") + except IOError: + print("Could not open file for reading:\n %s" % path) + return + + self.info = Info(file) + self.header = Header(file) + self.boneAnimModifiers = [] + + # Init the frame_t, bone_t and precision_t info + frame_t = Frame_t(self.header) + bone_t = Bone_t(self.header) + precision_t = Precision_t(self.header) + + dataPresenceFlags = self.header.dataPresenceFlags + + if LOG_ANIM_HEADER: + print("Magic: %s" % self.info.magic) + print("Version: %d" % self.info.version) + + print("AnimType: %d" % self.header.animType) + print("AnimFlags: %d" % self.header.animFlags) + print("PresenceFlags: %d" % dataPresenceFlags) + print("PropertyFlags: %d" % self.header.dataPropertyFlags) + print("FrameRate: %f" % self.header.framerate) + print("FrameCount: %d" % self.header.frameCount) + print("BoneCount: %d" % self.header.boneCount) + print("NoteCount: %d" % self.header.noteCount) + print("BoneModifierCount: %d" % self.header.boneAnimModifierCount) + + print("Frame_t Size: %d" % frame_t.size) + print("Frame_t Char: '%s'" % frame_t.char) + + self.bones = [] + if dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_PRESENCE_BONE: + useLoc = dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_BONE_LOC + useRot = dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_BONE_ROT + useScale = (dataPresenceFlags & + SEANIM_PRESENCE_FLAGS.SEANIM_BONE_SCALE) + + for i in range(self.header.boneCount): + if LOG_ANIM_BONES: + print("Loading Name for Bone[%d]" % i) + self.bones.append(Bone(file)) + + for i in range(self.header.boneAnimModifierCount): + bytes = file.read(bone_t.size + 1) + data = struct.unpack("%cB" % bone_t.char, bytes) + index = data[0] + self.bones[index].useModifier = True + self.bones[index].modifier = data[1] + + self.boneAnimModifiers.append(self.bones[index]) + + if LOG_ANIM_BONE_MODIFIERS: + print("Loaded Modifier %d for '%s" % + (index, self.bones[index].name)) + + for i in range(self.header.boneCount): + if LOG_ANIM_BONES: + print("Loading Data For Bone[%d] '%s'" % ( + i, self.bones[i].name)) + self.bones[i].loadData( + file, frame_t, precision_t, useLoc, useRot, useScale) + if LOG_ANIM_BONES_KEYS: + for key in self.bones[i].posKeys: + print("%s LOC %d %s" % + (self.bones[i].name, key.frame, key.data)) + for key in self.bones[i].rotKeys: + print("%s ROT %d %s" % + (self.bones[i].name, key.frame, key.data)) + for key in self.bones[i].scaleKeys: + print("%s SCALE %d %s" % + (self.bones[i].name, key.frame, key.data)) + + self.notes = [] + if (self.header.dataPresenceFlags & + SEANIM_PRESENCE_FLAGS.SEANIM_PRESENCE_NOTE): + for i in range(self.header.noteCount): + note = Note(file, frame_t) + self.notes.append(note) + if LOG_ANIM_NOTES: + print("Loaded Note[%d]:" % i) + print(" Frame %d: %s" % (note.frame, note.name)) + + file.close() + + if LOG_READ_TIME: + time_end = time.time() + time_elapsed = time_end - time_start + print("Done! - Completed in %ss" % time_elapsed) + + def save(self, filepath="", high_precision=False, looping=False): + if LOG_WRITE_TIME: + time_start = time.time() + print("Saving: '%s'" % filepath) + + try: + file = open(filepath, "wb") + except IOError: + print("Could not open file for writing:\n %s" % filepath) + return + + # Update the header flags, based on the presence of different keyframe + # types + self.update_metadata(high_precision, looping) + + self.__info.save(file) + self.header.save(file) + for bone in self.bones: + bytes = struct.pack( + '%ds' % (len(bone.name) + 1), bone.name.encode()) + file.write(bytes) + + dataPresenceFlags = self.header.dataPresenceFlags + + useLoc = dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_BONE_LOC + useRot = dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_BONE_ROT + useScale = dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_BONE_SCALE + + frame_t = Frame_t(self.header) + bone_t = Bone_t(self.header) + precision_t = Precision_t(self.header) + + for index, bone in enumerate(self.bones): + if bone.useModifier: + bytes = struct.pack('%cB' % bone_t.char, index, bone.modifier) + file.write(bytes) + + for bone in self.bones: + bone.save(file, frame_t, bone_t, precision_t, + useLoc, useRot, useScale) + + if dataPresenceFlags & SEANIM_PRESENCE_FLAGS.SEANIM_PRESENCE_NOTE: + for note in self.notes: + note.save(file, frame_t) + + file.close() + + if LOG_WRITE_TIME: + time_end = time.time() + time_elapsed = time_end - time_start + print("Done! - Completed in %ss" % time_elapsed) From fd720fe62271faf0b07a1d0fe793942b63eabb84 Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Mon, 22 Apr 2019 17:48:33 -0400 Subject: [PATCH 02/13] Upgrade SEAnim.py to New Enum API We must appease the linter! --- seanim.py | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/seanim.py b/seanim.py index 9bab360..05bf81e 100644 --- a/seanim.py +++ b/seanim.py @@ -1,6 +1,15 @@ import time import struct +try: + # Try to import the Python 3.x enum module + from enum import IntEnum +except: + # If we're on Python 2.x we need to define + # a dummy replacement + class IntEnum: + pass + # LOG_READ_TIME = False @@ -13,34 +22,32 @@ LOG_ANIM_NOTES = False -def enum(**enums): - return type('Enum', (), enums) - +class SEANIM_TYPE(IntEnum): + SEANIM_TYPE_ABSOLUTE = 0 + SEANIM_TYPE_ADDITIVE = 1 + SEANIM_TYPE_RELATIVE = 2 + SEANIM_TYPE_DELTA = 3 -SEANIM_TYPE = enum( - SEANIM_TYPE_ABSOLUTE=0, - SEANIM_TYPE_ADDITIVE=1, - SEANIM_TYPE_RELATIVE=2, - SEANIM_TYPE_DELTA=3) -SEANIM_PRESENCE_FLAGS = enum( +class SEANIM_PRESENCE_FLAGS(IntEnum): # These describe what type of keyframe data is present for the bones - SEANIM_BONE_LOC=1 << 0, - SEANIM_BONE_ROT=1 << 1, - SEANIM_BONE_SCALE=1 << 2, + SEANIM_BONE_LOC = 1 << 0 + SEANIM_BONE_ROT = 1 << 1 + SEANIM_BONE_SCALE = 1 << 2 + # If any of the above flags are set, then bone keyframe data is present, # thus this comparing against this mask will return true - SEANIM_PRESENCE_BONE=1 << 0 | 1 << 1 | 1 << 2, - SEANIM_PRESENCE_NOTE=1 << 6, # The file contains notetrack data - SEANIM_PRESENCE_CUSTOM=1 << 7, # The file contains a custom data block -) + SEANIM_PRESENCE_BONE = 1 << 0 | 1 << 1 | 1 << 2 + SEANIM_PRESENCE_NOTE = 1 << 6 # The file contains notetrack data + SEANIM_PRESENCE_CUSTOM = 1 << 7 # The file contains a custom data block + +class SEANIM_PROPERTY_FLAGS(IntEnum): + SEANIM_PRECISION_HIGH = 1 << 0 -SEANIM_PROPERTY_FLAGS = enum( - SEANIM_PRECISION_HIGH=1 << 0) -SEANIM_FLAGS = enum( - SEANIM_LOOPED=1 << 0) +class SEANIM_FLAGS(IntEnum): + SEANIM_LOOPED = 1 << 0 class Info(object): From 0cd853fd14fb2824d59b280a658168ccd8d25a92 Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Mon, 22 Apr 2019 17:58:14 -0400 Subject: [PATCH 03/13] Fix Unused Index Variable Names --- seanim.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seanim.py b/seanim.py index 05bf81e..c53ab53 100644 --- a/seanim.py +++ b/seanim.py @@ -258,7 +258,7 @@ def loadData(self, file, frame_t, precision_t, data = struct.unpack('%c' % frame_t.char, bytes) self.locKeyCount = data[0] - for i in range(self.locKeyCount): + for _ in range(self.locKeyCount): bytes = file.read(frame_t.size + 3 * precision_t.size) data = struct.unpack('=%c3%c' % (frame_t.char, precision_t.char), bytes) @@ -274,7 +274,7 @@ def loadData(self, file, frame_t, precision_t, data = struct.unpack('%c' % frame_t.char, bytes) self.rotKeyCount = data[0] - for i in range(self.rotKeyCount): + for _ in range(self.rotKeyCount): bytes = file.read(frame_t.size + 4 * precision_t.size) data = struct.unpack('=%c4%c' % @@ -291,7 +291,7 @@ def loadData(self, file, frame_t, precision_t, bytes = file.read(frame_t.size) data = struct.unpack('%c' % frame_t.char, bytes) self.scaleKeyCount = data[0] - for i in range(self.scaleKeyCount): + for _ in range(self.scaleKeyCount): bytes = file.read(frame_t.size + 3 * precision_t.size) data = struct.unpack('=%c3%c' % (frame_t.char, precision_t.char), bytes) From 37d18565b1bdb531623f4869041c0002cd4d5a26 Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Mon, 22 Apr 2019 17:59:26 -0400 Subject: [PATCH 04/13] Remove Unnecessary enumerate() Calls --- seanim.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seanim.py b/seanim.py index c53ab53..502c959 100644 --- a/seanim.py +++ b/seanim.py @@ -310,7 +310,7 @@ def save(self, file, frame_t, bone_t, precision_t, bytes = struct.pack('%c' % frame_t.char, len(self.posKeys)) file.write(bytes) - for i, key in enumerate(self.posKeys): + for key in self.posKeys: bytes = struct.pack('=%c3%c' % (frame_t.char, precision_t.char), key.frame, @@ -321,7 +321,7 @@ def save(self, file, frame_t, bone_t, precision_t, bytes = struct.pack('%c' % frame_t.char, len(self.rotKeys)) file.write(bytes) - for i, key in enumerate(self.rotKeys): + for key in self.rotKeys: bytes = struct.pack('=%c4%c' % (frame_t.char, precision_t.char), key.frame, @@ -333,7 +333,7 @@ def save(self, file, frame_t, bone_t, precision_t, bytes = struct.pack('%c' % frame_t.char, len(self.scaleKeys)) file.write(bytes) - for i, key in enumerate(self.scaleKeys): + for key in self.scaleKeys: bytes = struct.pack('=%c3%c' % (frame_t.char, precision_t.char), key.frame, From cdc657a58bacf229d4abe7343510acefba22d56b Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Sat, 16 Feb 2019 19:17:19 -0500 Subject: [PATCH 05/13] Use the @ Operator for Matrix Multiplication --- import_seanim.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/import_seanim.py b/import_seanim.py index ede5279..25185f9 100644 --- a/import_seanim.py +++ b/import_seanim.py @@ -178,7 +178,7 @@ def load_seanim(self, context, progress, filepath=""): # j_gun has a SEANIM_TYPE_RELATIVE override if (animType == SEAnim.SEANIM_TYPE.SEANIM_TYPE_ABSOLUTE and bone.parent is not None): - bone.matrix.translation = bone.parent.matrix * offset + bone.matrix.translation = bone.parent.matrix @ offset else: # Use DELTA / RELATIVE results (ADDITIVE is unknown) bone.matrix_basis.translation = offset @@ -220,7 +220,7 @@ def load_seanim(self, context, progress, filepath=""): bone.matrix_basis.identity() mat = angle.to_4x4() else: - mat = (bone.parent.matrix.to_3x3() * angle).to_4x4() + mat = (bone.parent.matrix.to_3x3() @ angle).to_4x4() bone.matrix = mat From b72e3eef6e989b98e8f2432e716ccc3568dd51cd Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Sat, 16 Feb 2019 19:45:47 -0500 Subject: [PATCH 06/13] Use 2.8x Class Registration Method --- __init__.py | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/__init__.py b/__init__.py index 84e2155..e1105ed 100644 --- a/__init__.py +++ b/__init__.py @@ -3,6 +3,8 @@ from bpy.types import Operator, AddonPreferences from bpy.props import * from bpy_extras.io_utils import ExportHelper, ImportHelper +from bpy.utils import register_class +from bpy.utils import unregister_class import time @@ -13,7 +15,7 @@ "blender": (2, 78, 0), "location": "File > Import", "description": "Import SEAnim", - "warning": "ADDITIVE animations are not implemented at this time", + "warning": "ADDITIVE animations are not currently supported", "wiki_url": "https://github.com/SE2Dev/io_anim_seanim", "tracker_url": "https://github.com/SE2Dev/io_anim_seanim/issues", "support": "COMMUNITY", @@ -199,16 +201,32 @@ def menu_func_seanim_export(self, context): self.layout.operator(ExportSEAnim.bl_idname, text="SEAnim (.seanim)") +''' + CLASS REGISTRATION + SEE https://wiki.blender.org/wiki/Reference/Release_Notes/2.80/Python_API/Addons +''' + +classes = ( + ImportSEAnim, + ExportSEAnim +) + + def register(): - bpy.utils.register_module(__name__) - bpy.types.INFO_MT_file_import.append(menu_func_seanim_import) - bpy.types.INFO_MT_file_export.append(menu_func_seanim_export) + for cls in classes: + bpy.utils.register_class(cls) + + bpy.types.TOPBAR_MT_file_import.append(menu_func_seanim_import) + bpy.types.TOPBAR_MT_file_export.append(menu_func_seanim_export) def unregister(): - bpy.utils.unregister_module(__name__) - bpy.types.INFO_MT_file_import.remove(menu_func_seanim_import) - bpy.types.INFO_MT_file_export.remove(menu_func_seanim_export) + bpy.types.TOPBAR_MT_file_import.remove(menu_func_seanim_import) + bpy.types.TOPBAR_MT_file_export.remove(menu_func_seanim_export) + + for cls in classes: + bpy.utils.unregister_class(cls) + if __name__ == "__main__": From 47b6f7d6eaa8e2e9745abcd5c21e4046a00f7a43 Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Sat, 16 Feb 2019 20:11:47 -0500 Subject: [PATCH 07/13] Upgrade to New ProgressReport Module Warning: Possibly undocumented! --- export_seanim.py | 2 +- import_seanim.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/export_seanim.py b/export_seanim.py index cba46f8..22d2182 100644 --- a/export_seanim.py +++ b/export_seanim.py @@ -1,7 +1,7 @@ import bpy import bpy_types from mathutils import * -from progress_report import ProgressReport, ProgressReportSubstep +from bpy_extras.wm_utils.progress_report import ProgressReport, ProgressReportSubstep import os from . import seanim as SEAnim diff --git a/import_seanim.py b/import_seanim.py index 25185f9..c1de63c 100644 --- a/import_seanim.py +++ b/import_seanim.py @@ -1,6 +1,6 @@ import bpy from mathutils import * -from progress_report import ProgressReport, ProgressReportSubstep +from bpy_extras.wm_utils.progress_report import ProgressReport, ProgressReportSubstep import os from . import seanim as SEAnim From af860020f19f06b8feeb5f9e2d7aae988279da2a Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Mon, 18 Feb 2019 18:51:17 -0500 Subject: [PATCH 08/13] Use Property Annotations --- __init__.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/__init__.py b/__init__.py index e1105ed..0cf371f 100644 --- a/__init__.py +++ b/__init__.py @@ -39,9 +39,9 @@ class ImportSEAnim(bpy.types.Operator, ImportHelper): bl_options = {'PRESET'} filename_ext = ".seanim" - filter_glob = StringProperty(default="*.seanim", options={'HIDDEN'}) + filter_glob: StringProperty(default="*.seanim", options={'HIDDEN'}) - files = CollectionProperty(type=bpy.types.PropertyGroup) + files: CollectionProperty(type=bpy.types.PropertyGroup) def execute(self, context): # print("Selected: " + context.active_object.name) @@ -79,11 +79,11 @@ class ExportSEAnim(bpy.types.Operator, ExportHelper): bl_options = {'PRESET'} filename_ext = ".seanim" - filter_glob = StringProperty(default="*.seanim", options={'HIDDEN'}) + filter_glob: StringProperty(default="*.seanim", options={'HIDDEN'}) - files = CollectionProperty(type=bpy.types.PropertyGroup) + files: CollectionProperty(type=bpy.types.PropertyGroup) - anim_type = EnumProperty( + anim_type: EnumProperty( name="Anim Type", description="Choose between two items", items=( ('OPT_ABSOLUTE', "Absolute", "Used for viewmodel animations"), @@ -93,7 +93,7 @@ class ExportSEAnim(bpy.types.Operator, ExportHelper): default='OPT_RELATIVE', ) - key_types = EnumProperty( + key_types: EnumProperty( name="Keyframe Types", description="Export specific keyframe types", options={'ENUM_FLAG'}, @@ -104,36 +104,36 @@ class ExportSEAnim(bpy.types.Operator, ExportHelper): default={'LOC', 'ROT'}, # , 'SCALE'}, ) - every_frame = BoolProperty( + every_frame: BoolProperty( name="Every Frame", description="Automatically generate keyframes for every single frame", default=False) - high_precision = BoolProperty( + high_precision: BoolProperty( name="High Precision", description=("Use double precision floating point values for " "quaternions and vectors (Note: Increases file size)"), default=False) - is_looped = BoolProperty( + is_looped: BoolProperty( name="Looped", description="Mark the animation as a looping animation", default=False) - use_actions = BoolProperty( + use_actions: BoolProperty( name="Export All Actions", description="Export all actions to the target path", default=False) # PREFIX & SUFFIX Require "use_actions" to be true and are enabled / # disabled from __update_use_actions - prefix = StringProperty( + prefix: StringProperty( name="File Prefix", description=("The prefix string that is applied to the beginning " "of the filename for each exported action"), default="") - suffix = StringProperty( + suffix: StringProperty( name="File Suffix", description=("The suffix string that is applied to the end " "of the filename for each exported action"), From 34f3a823821701cf94e3bdd7030c8c8628d18758 Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Mon, 18 Feb 2019 18:57:18 -0500 Subject: [PATCH 09/13] Fix Keyword Argument Error Fix issue where row.label() now requires the text argument to be defined via keyword --- __init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index 0cf371f..c9eb820 100644 --- a/__init__.py +++ b/__init__.py @@ -144,7 +144,7 @@ def draw(self, context): layout.prop(self, "anim_type") row = layout.row() - row.label("Include:") + row.label(text="Include:") row.prop(self, "key_types") layout.prop(self, "high_precision") From 9f740ef24b3cf79d823ee4e3bb9868eaacfaf476 Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Mon, 22 Apr 2019 18:26:11 -0400 Subject: [PATCH 10/13] Bump Minimum Supported Blender Version to 2.80 This is required for the plugin to load in 2.8x --- __init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index c9eb820..cb9c153 100644 --- a/__init__.py +++ b/__init__.py @@ -12,7 +12,7 @@ "name": "SEAnim Support", "author": "SE2Dev", "version": (0, 3, 8), - "blender": (2, 78, 0), + "blender": (2, 80, 0), "location": "File > Import", "description": "Import SEAnim", "warning": "ADDITIVE animations are not currently supported", From dc755563aae09bd3f08fa1e8166a0220a5009a19 Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Sun, 11 Aug 2019 18:43:12 -0400 Subject: [PATCH 11/13] Bump Version from 0.3.8 -> 0.4.0 --- __init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index cb9c153..1ca0c73 100644 --- a/__init__.py +++ b/__init__.py @@ -11,7 +11,7 @@ bl_info = { "name": "SEAnim Support", "author": "SE2Dev", - "version": (0, 3, 8), + "version": (0, 4, 0), "blender": (2, 80, 0), "location": "File > Import", "description": "Import SEAnim", From 46ca1ccf7ba1e9b71f4860e2a17f87dc81f391cc Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Sat, 14 Sep 2019 13:55:01 -0400 Subject: [PATCH 12/13] Fix Invalid Scene Update Call --- import_seanim.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/import_seanim.py b/import_seanim.py index c1de63c..49f99fe 100644 --- a/import_seanim.py +++ b/import_seanim.py @@ -279,5 +279,5 @@ def load_seanim(self, context, progress, filepath=""): notetrack = ob.animation_data.action.pose_markers.new(note.name) notetrack.frame = note.frame - bpy.context.scene.update() + bpy.context.evaluated_depsgraph_get().update() bpy.ops.object.mode_set(mode='POSE') From f28c42cf6daae8782a17e745e35274a0d4a09eed Mon Sep 17 00:00:00 2001 From: SE2Dev Date: Sat, 14 Sep 2019 14:08:19 -0400 Subject: [PATCH 13/13] Remove Unnecessary Try Statement --- import_seanim.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/import_seanim.py b/import_seanim.py index 49f99fe..5761a4e 100644 --- a/import_seanim.py +++ b/import_seanim.py @@ -212,9 +212,7 @@ def load_seanim(self, context, progress, filepath=""): angle = quat.to_matrix().to_3x3() bone.matrix_basis.identity() - try: - bone.parent.matrix - except: + if bone.parent is None: # I don't actually remember why this is here - probably # to set the root bone(s) to its rest pos / angle bone.matrix_basis.identity()