1
0
mirror of https://github.com/DarklightGames/io_scene_psk_psa.git synced 2025-02-07 22:41:26 +01:00

Initial commit for PSKX support

This commit is contained in:
Colin Basnett 2022-01-25 19:41:09 -08:00
parent 5a13faeb5e
commit 4099c95381
5 changed files with 122 additions and 7 deletions

View File

@ -58,7 +58,7 @@ def psk_export_menu_func(self, context):
def psk_import_menu_func(self, context):
self.layout.operator(psk_importer.PskImportOperator.bl_idname, text='Unreal PSK (.psk)')
self.layout.operator(psk_importer.PskImportOperator.bl_idname, text='Unreal PSK (.psk/.pskx)')
def psa_export_menu_func(self, context):

View File

@ -1,4 +1,43 @@
from ctypes import *
from typing import Tuple
class Color(Structure):
_fields_ = [
('r', c_ubyte),
('g', c_ubyte),
('b', c_ubyte),
('a', c_ubyte),
]
def __iter__(self):
yield self.r
yield self.g
yield self.b
yield self.a
def __eq__(self, other):
return all(map(lambda x: x[0] == x[1], zip(self, other)))
def __repr__(self):
return repr(tuple(self))
def normalized(self) -> Tuple:
return tuple(map(lambda x: x / 255.0, iter(self)))
class Vector2(Structure):
_fields_ = [
('x', c_float),
('y', c_float),
]
def __iter__(self):
yield self.x
yield self.y
def __repr__(self):
return repr(tuple(self))
class Vector3(Structure):

View File

@ -41,6 +41,15 @@ class Psk(object):
('smoothing_groups', c_int32)
]
class Face32(Structure):
_pack_ = 1
_fields_ = [
('wedge_indices', c_uint32 * 3),
('material_index', c_uint8),
('aux_material_index', c_uint8),
('smoothing_groups', c_int32)
]
class Material(Structure):
_fields_ = [
('name', c_char * 64),
@ -71,6 +80,18 @@ class Psk(object):
('bone_index', c_int32),
]
@property
def has_extra_uvs(self):
return len(self.extra_uvs) > 0
@property
def has_vertex_colors(self):
return len(self.vertex_colors)
@property
def has_vertex_normals(self):
return len(self.vertex_normals)
def __init__(self):
self.points: List[Vector3] = []
self.wedges: List[Psk.Wedge] = []
@ -78,3 +99,6 @@ class Psk(object):
self.materials: List[Psk.Material] = []
self.weights: List[Psk.Weight] = []
self.bones: List[Psk.Bone] = []
self.extra_uvs: List[Vector2] = []
self.vertex_colors: List[Color] = []
self.vertex_normals: List[Vector3] = []

View File

@ -120,7 +120,6 @@ class PskImporter(object):
bm_face.material_index = face.material_index
except ValueError:
degenerate_face_indices.add(face_index)
pass
if len(degenerate_face_indices) > 0:
print(f'WARNING: Discarded {len(degenerate_face_indices)} degenerate face(s).')
@ -129,7 +128,7 @@ class PskImporter(object):
# TEXTURE COORDINATES
data_index = 0
uv_layer = mesh_data.uv_layers.new()
uv_layer = mesh_data.uv_layers.new(name='VTXW0000')
for face_index, face in enumerate(psk.faces):
if face_index in degenerate_face_indices:
continue
@ -138,11 +137,56 @@ class PskImporter(object):
uv_layer.data[data_index].uv = wedge.u, 1.0 - wedge.v
data_index += 1
# EXTRA UVS
if psk.has_extra_uvs:
extra_uv_channel_count = int(len(psk.extra_uvs) / len(psk.wedges))
wedge_index_offset = 0
for extra_uv_index in range(extra_uv_channel_count):
data_index = 0
uv_layer = mesh_data.uv_layers.new(name=f'EXTRAUV{extra_uv_index}')
for face_index, face in enumerate(psk.faces):
if face_index in degenerate_face_indices:
continue
for wedge_index in reversed(face.wedge_indices):
u, v = psk.extra_uvs[wedge_index_offset + wedge_index]
uv_layer.data[data_index].uv = u, 1.0 - v
data_index += 1
wedge_index_offset += len(psk.wedges)
# VERTEX COLORS
if psk.has_vertex_colors:
vertex_color_data = mesh_data.vertex_colors.new(name='VERTEXCOLOR')
vertex_colors = [None] * len(psk.points)
ambiguous_vertex_color_point_indices = []
for wedge_index, wedge in enumerate(psk.wedges):
point_index = wedge.point_index
psk_vertex_color = psk.vertex_colors[wedge_index]
if vertex_colors[point_index] is not None and vertex_colors[point_index] != psk_vertex_color:
ambiguous_vertex_color_point_indices.append(point_index)
vertex_colors[point_index] = psk_vertex_color
for loop_index, loop in enumerate(mesh_data.loops):
vertex_color = vertex_colors[loop.vertex_index]
if vertex_color is not None:
vertex_color_data.data[loop_index].color = vertex_color.normalized()
else:
vertex_color_data.data[loop_index].color = 1.0, 1.0, 1.0, 1.0
if len(ambiguous_vertex_color_point_indices) > 0:
print(f'WARNING: {len(ambiguous_vertex_color_point_indices)} vertex(es) with ambiguous vertex colors.')
# # VERTEX NORMALS
if psk.has_vertex_normals:
mesh_data.polygons.foreach_set("use_smooth", [True] * len(mesh_data.polygons))
normals = []
for vertex_normal in psk.vertex_normals:
normals.append(tuple(vertex_normal))
mesh_data.normals_split_custom_set_from_vertices(normals)
mesh_data.use_auto_smooth = True
bm.normal_update()
bm.free()
# VERTEX WEIGHTS
# Get a list of all bones that have weights associated with them.
vertex_group_bone_indices = set(map(lambda weight: weight.bone_index, psk.weights))
for import_bone in map(lambda x: import_bones[x], sorted(list(vertex_group_bone_indices))):
@ -169,7 +213,7 @@ class PskImportOperator(Operator, ImportHelper):
bl_label = 'Export'
__doc__ = 'Load a PSK file'
filename_ext = '.psk'
filter_glob: StringProperty(default='*.psk', options={'HIDDEN'})
filter_glob: StringProperty(default='*.psk;*.pskx', options={'HIDDEN'})
filepath: StringProperty(
name='File Path',
description='File path used for exporting the PSK file',

View File

@ -41,6 +41,14 @@ class PskReader(object):
PskReader.read_types(fp, Psk.Bone, section, psk.bones)
elif section.name == b'RAWWEIGHTS':
PskReader.read_types(fp, Psk.Weight, section, psk.weights)
elif section.name == b'FACE3200':
PskReader.read_types(fp, Psk.Face32, section, psk.faces)
elif section.name == b'VERTEXCOLOR':
PskReader.read_types(fp, Color, section, psk.vertex_colors)
elif section.name.startswith(b'EXTRAUVS'):
PskReader.read_types(fp, Vector2, section, psk.extra_uvs)
elif section.name == b'VTXNORMS':
PskReader.read_types(fp, Vector3, section, psk.vertex_normals)
else:
raise RuntimeError(f'Unrecognized section "{section.name}"')
raise RuntimeError(f'Unrecognized section "{section.name} at position {15:fp.tell()}"')
return psk