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