WIP import functionality (PSK working, PSA in the works)

This commit is contained in:
Colin Basnett
2021-09-07 00:02:59 -07:00
parent 0622cf43e5
commit 4a9a921583
11 changed files with 327 additions and 18 deletions

View File

@@ -22,7 +22,7 @@ class Psa(object):
('bone_count', c_int32),
('root_include', c_int32),
('compression_style', c_int32),
('key_quotum', c_int32), # what the fuck is a quotum
('key_quotum', c_int32),
('key_reduction', c_float),
('track_time', c_float),
('fps', c_float),

View File

@@ -0,0 +1,15 @@
import bpy
import bmesh
import mathutils
from .data import Psa
class PsaImporter(object):
def __init__(self):
pass
def import_psa(self, psa: Psa, context):
print('importing yay')
print(psa.sequences)
for sequence in psa.sequences:
print(sequence.name, sequence.frame_start_index, sequence.frame_count)

View File

@@ -1,12 +1,23 @@
from bpy.types import Operator, Action, UIList, PropertyGroup
from bpy_extras.io_utils import ExportHelper
from bpy_extras.io_utils import ExportHelper, ImportHelper
from bpy.props import StringProperty, BoolProperty, CollectionProperty, PointerProperty
from .builder import PsaBuilder, PsaBuilderOptions
from .exporter import PsaExporter
from .reader import PsaReader
from .importer import PsaImporter
import bpy
import re
class ImportActionListItem(PropertyGroup):
action_name: StringProperty()
is_selected: BoolProperty(default=True)
@property
def name(self):
return self.action_name
class ActionListItem(PropertyGroup):
action: PointerProperty(type=Action)
is_selected: BoolProperty(default=False)
@@ -16,6 +27,22 @@ class ActionListItem(PropertyGroup):
return self.action.name
class PSA_UL_ImportActionList(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
layout.alignment = 'LEFT'
layout.prop(item, 'is_selected', icon_only=True)
layout.label(text=item.action_name)
# def filter_items(self, context, data, property):
# # TODO: returns two lists, apparently
# actions = getattr(data, property)
# flt_flags = []
# flt_neworder = []
# if self.filter_name:
# flt_flags = bpy.types.UI_UL_list.filter_items_by_name(self.filter_name, self.bitflag_filter_item, actions, 'name', reverse=self.use_filter_invert)
# return flt_flags, flt_neworder
class PSA_UL_ActionList(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
layout.alignment = 'LEFT'
@@ -37,8 +64,8 @@ class PsaExportOperator(Operator, ExportHelper):
bl_label = 'Export'
__doc__ = 'PSA Exporter (.psa)'
filename_ext = '.psa'
filter_glob : StringProperty(default='*.psa', options={'HIDDEN'})
filepath : StringProperty(
filter_glob: StringProperty(default='*.psa', options={'HIDDEN'})
filepath: StringProperty(
name='File Path',
description='File path used for exporting the PSA file',
maxlen=1024,
@@ -103,3 +130,47 @@ class PsaExportOperator(Operator, ExportHelper):
exporter = PsaExporter(psk)
exporter.export(self.filepath)
return {'FINISHED'}
class PsaImportOperator(Operator, ImportHelper):
# TODO: list out the actions to be imported
bl_idname = 'import.psa'
bl_label = 'Import'
__doc__ = 'PSA Importer (.psa)'
filename_ext = '.psa'
filter_glob: StringProperty(default='*.psa', options={'HIDDEN'})
filepath: StringProperty(
name='File Path',
description='File path used for importing the PSA file',
maxlen=1024,
default='')
def invoke(self, context, event):
action_names = []
try:
action_names = PsaReader().scan_sequence_names(self.filepath)
except IOError:
pass
context.scene.psa_import_action_list.clear()
for action_name in action_names:
item = context.scene.psa_action_list.add()
item.action_name = action_name
item.is_selected = True
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
def draw(self, context):
layout = self.layout
scene = context.scene
box = layout.box()
box.label(text='Actions', icon='ACTION')
row = box.row()
row.template_list('PSA_UL_ImportActionList', 'asd', scene, 'psa_import_action_list', scene, 'psa_import_action_list_index', rows=len(context.scene.psa_import_action_list))
def execute(self, context):
reader = PsaReader()
psa = reader.read(self.filepath)
PsaImporter().import_psa(psa, context)
return {'FINISHED'}

View File

@@ -0,0 +1,53 @@
from .data import *
from typing import AnyStr
import ctypes
class PsaReader(object):
def __init__(self):
pass
@staticmethod
def read_types(fp, data_class: ctypes.Structure, section: Section, data):
buffer_length = section.data_size * section.data_count
buffer = fp.read(buffer_length)
offset = 0
for _ in range(section.data_count):
data.append(data_class.from_buffer_copy(buffer, offset))
offset += section.data_size
def scan_sequence_names(self, path) -> List[AnyStr]:
sequences = []
with open(path, 'rb') as fp:
if fp.read(8) != b'ANIMINFO':
raise IOError('Unexpected file format')
fp.seek(0, 0)
while fp.read(1):
fp.seek(-1, 1)
section = Section.from_buffer_copy(fp.read(ctypes.sizeof(Section)))
if section.name == b'ANIMINFO':
PsaReader.read_types(fp, Psa.Sequence, section, sequences)
return [sequence.name for sequence in sequences]
else:
fp.seek(section.data_size * section.data_count, 1)
return []
def read(self, path) -> Psa:
psa = Psa()
with open(path, 'rb') as fp:
while fp.read(1):
fp.seek(-1, 1)
section = Section.from_buffer_copy(fp.read(ctypes.sizeof(Section)))
if section.name == b'ANIMHEAD':
pass
elif section.name == b'BONENAMES':
PsaReader.read_types(fp, Psa.Bone, section, psa.bones)
elif section.name == b'ANIMINFO':
PsaReader.read_types(fp, Psa.Sequence, section, psa.sequences)
elif section.name == b'ANIMKEYS':
PsaReader.read_types(fp, Psa.Key, section, psa.keys)
else:
raise RuntimeError(f'Unrecognized section "{section.name}"')
return psa
1