WIP import functionality (PSK working, PSA in the works)
This commit is contained in:
@@ -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),
|
||||
|
||||
15
io_export_psk_psa/psa/importer.py
Normal file
15
io_export_psk_psa/psa/importer.py
Normal 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)
|
||||
@@ -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'}
|
||||
|
||||
53
io_export_psk_psa/psa/reader.py
Normal file
53
io_export_psk_psa/psa/reader.py
Normal 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
|
||||
Reference in New Issue
Block a user