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

@@ -159,9 +159,9 @@ class PskBuilder(object):
for f in object.data.loop_triangles:
face = Psk.Face()
face.material_index = material_indices[f.material_index]
face.wedge_index_1 = f.loops[2] + wedge_offset
face.wedge_index_2 = f.loops[1] + wedge_offset
face.wedge_index_3 = f.loops[0] + wedge_offset
face.wedge_indices[0] = f.loops[2] + wedge_offset
face.wedge_indices[1] = f.loops[1] + wedge_offset
face.wedge_indices[2] = f.loops[0] + wedge_offset
face.smoothing_groups = poly_groups[f.polygon_index]
psk.faces.append(face)
# update the material index of the wedges

View File

@@ -25,9 +25,7 @@ class Psk(object):
class Face(Structure):
_fields_ = [
('wedge_index_1', c_int16),
('wedge_index_2', c_int16),
('wedge_index_3', c_int16),
('wedge_indices', c_int16 * 3),
('material_index', c_int8),
('aux_material_index', c_int8),
('smoothing_groups', c_int32)

View File

@@ -0,0 +1,71 @@
import bpy
import bmesh
import mathutils
from .data import Psk
class PskImporter(object):
def __init__(self):
pass
def import_psk(self, psk: Psk, context):
# ARMATURE
armature_data = bpy.data.armatures.new('armature')
armature_object = bpy.data.objects.new('new_ao', armature_data)
context.scene.collection.objects.link(armature_object)
try:
bpy.ops.object.mode_set(mode='OBJECT')
except:
pass
armature_object.select_set(state=True)
bpy.context.view_layer.objects.active = armature_object
bpy.ops.object.mode_set(mode='EDIT')
for bone in psk.bones:
edit_bone = armature_data.edit_bones.new(bone.name.decode('utf-8'))
edit_bone.parent = armature_data.edit_bones[bone.parent_index]
edit_bone.head = (bone.location.x, bone.location.y, bone.location.z)
rotation = mathutils.Quaternion(*bone.rotation)
edit_bone.tail = edit_bone.head + (mathutils.Vector(0, 0, 1) @ rotation)
# MESH
mesh_data = bpy.data.meshes.new('mesh')
mesh_object = bpy.data.objects.new('new_mo', mesh_data)
# MATERIALS
for material in psk.materials:
bpy_material = bpy.data.materials.new(material.name.decode('utf-8'))
mesh_data.materials.append(bpy_material)
bm = bmesh.new()
# VERTICES
for point in psk.points:
bm.verts.new((point.x, point.y, point.z))
bm.verts.ensure_lookup_table()
for face in psk.faces:
point_indices = [bm.verts[psk.wedges[i].point_index] for i in reversed(face.wedge_indices)]
bm_face = bm.faces.new(point_indices)
bm_face.material_index = face.material_index
bm.to_mesh(mesh_data)
# TEXTURE COORDINATES
data_index = 0
uv_layer = mesh_data.uv_layers.new()
for face_index, face in enumerate(psk.faces):
face_wedges = [psk.wedges[i] for i in reversed(face.wedge_indices)]
for wedge in face_wedges:
uv_layer.data[data_index].uv = wedge.u, 1.0 - wedge.v
data_index += 1
bm.free()
# TODO: weights (vertex grorups etc.)
context.scene.collection.objects.link(mesh_object)

View File

@@ -1,8 +1,29 @@
from bpy.types import Operator
from bpy_extras.io_utils import ExportHelper
from bpy_extras.io_utils import ExportHelper, ImportHelper
from bpy.props import StringProperty, BoolProperty, FloatProperty
from .builder import PskBuilder
from .exporter import PskExporter
from .reader import PskReader
from .importer import PskImporter
class PskImportOperator(Operator, ImportHelper):
bl_idname = 'import.psk'
bl_label = 'Export'
__doc__ = 'PSK Importer (.psk)'
filename_ext = '.psk'
filter_glob: StringProperty(default='*.psk', options={'HIDDEN'})
filepath: StringProperty(
name='File Path',
description='File path used for exporting the PSK file',
maxlen=1024,
default='')
def execute(self, context):
reader = PskReader()
psk = reader.read(self.filepath)
PskImporter().import_psk(psk, context)
return {'FINISHED'}
class PskExportOperator(Operator, ExportHelper):

View File

@@ -0,0 +1,46 @@
from .data import *
import ctypes
class PskReader(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 read(self, path) -> Psk:
psk = Psk()
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'ACTRHEAD':
pass
elif section.name == b'PNTS0000':
PskReader.read_types(fp, Vector3, section, psk.points)
elif section.name == b'VTXW0000':
if section.data_size == ctypes.sizeof(Psk.Wedge16):
PskReader.read_types(fp, Psk.Wedge16, section, psk.wedges)
elif section.data_size == ctypes.sizeof(Psk.Wedge32):
PskReader.read_types(fp, Psk.Wedge32, section, psk.wedges)
else:
raise RuntimeError('Unrecognized wedge format')
elif section.name == b'FACE0000':
PskReader.read_types(fp, Psk.Face, section, psk.faces)
elif section.name == b'MATT0000':
PskReader.read_types(fp, Psk.Material, section, psk.materials)
elif section.name == b'REFSKELT':
PskReader.read_types(fp, Psk.Bone, section, psk.bones)
elif section.name == b'RAWWEIGHTS':
PskReader.read_types(fp, Psk.Weight, section, psk.weights)
else:
raise RuntimeError(f'Unrecognized section "{section.name}"')
return psk