Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83e65687ac | ||
|
|
63fb6f7d09 | ||
|
|
741357d0af | ||
|
|
fb2ab89766 | ||
|
|
d0d6deb63c | ||
|
|
e9b09dc651 | ||
|
|
ed89e78927 |
@@ -1,7 +1,7 @@
|
||||
bl_info = {
|
||||
"name": "PSK/PSA Importer/Exporter",
|
||||
"author": "Colin Basnett, Yurii Ti",
|
||||
"version": (5, 0, 1),
|
||||
"version": (5, 0, 4),
|
||||
"blender": (3, 4, 0),
|
||||
"description": "PSK/PSA Import/Export (.psk/.psa)",
|
||||
"warning": "",
|
||||
|
||||
@@ -8,10 +8,10 @@ from bpy.types import Context, Armature, Action, Object, AnimData, TimelineMarke
|
||||
from bpy_extras.io_utils import ExportHelper
|
||||
from bpy_types import Operator
|
||||
|
||||
from io_scene_psk_psa.helpers import populate_bone_group_list, get_nla_strips_in_timeframe
|
||||
from io_scene_psk_psa.psa.builder import build_psa, PsaBuildSequence, PsaBuildOptions
|
||||
from io_scene_psk_psa.psa.export.properties import PSA_PG_export, PSA_PG_export_action_list_item, filter_sequences
|
||||
from io_scene_psk_psa.psa.writer import write_psa
|
||||
from ..builder import build_psa, PsaBuildSequence, PsaBuildOptions
|
||||
from ..export.properties import PSA_PG_export, PSA_PG_export_action_list_item, filter_sequences
|
||||
from ..writer import write_psa
|
||||
from ...helpers import populate_bone_group_list, get_nla_strips_in_timeframe
|
||||
|
||||
|
||||
def is_action_for_armature(armature: Armature, action: Action):
|
||||
@@ -358,7 +358,7 @@ class PSA_OT_export(Operator, ExportHelper):
|
||||
# Ensure that we actually have items that we are going to be exporting.
|
||||
if pg.sequence_source == 'ACTIONS' and len(pg.action_list) == 0:
|
||||
raise RuntimeError('No actions were selected for export')
|
||||
elif pg.sequence_source == 'TIMELINE_MARKERS' and len(pg.marker_names) == 0:
|
||||
elif pg.sequence_source == 'TIMELINE_MARKERS' and len(pg.marker_list) == 0:
|
||||
raise RuntimeError('No timeline markers were selected for export')
|
||||
|
||||
# Populate the export sequence list.
|
||||
|
||||
@@ -16,8 +16,7 @@ class Psk(object):
|
||||
|
||||
class Wedge16(Structure):
|
||||
_fields_ = [
|
||||
('point_index', c_uint16),
|
||||
('padding1', c_int16),
|
||||
('point_index', c_uint32),
|
||||
('u', c_float),
|
||||
('v', c_float),
|
||||
('material_index', c_uint8),
|
||||
|
||||
@@ -150,17 +150,22 @@ def import_psk(psk: Psk, context, options: PskImportOptions) -> PskImportResult:
|
||||
|
||||
bm.verts.ensure_lookup_table()
|
||||
|
||||
degenerate_face_indices = set()
|
||||
invalid_face_indices = set()
|
||||
for face_index, face in enumerate(psk.faces):
|
||||
point_indices = [bm.verts[psk.wedges[i].point_index] for i in reversed(face.wedge_indices)]
|
||||
point_indices = map(lambda i: psk.wedges[i].point_index, reversed(face.wedge_indices))
|
||||
points = [bm.verts[i] for i in point_indices]
|
||||
try:
|
||||
bm_face = bm.faces.new(point_indices)
|
||||
bm_face = bm.faces.new(points)
|
||||
bm_face.material_index = face.material_index
|
||||
except ValueError:
|
||||
degenerate_face_indices.add(face_index)
|
||||
# This happens for two reasons:
|
||||
# 1. Two or more of the face's points are the same. (i.e, point indices of [0, 0, 1])
|
||||
# 2. The face is a duplicate of another face. (i.e., point indices of [0, 1, 2] and [0, 1, 2])
|
||||
invalid_face_indices.add(face_index)
|
||||
|
||||
if len(degenerate_face_indices) > 0:
|
||||
result.warnings.append(f'Discarded {len(degenerate_face_indices)} degenerate face(s).')
|
||||
# TODO: Handle invalid faces better.
|
||||
if len(invalid_face_indices) > 0:
|
||||
result.warnings.append(f'Discarded {len(invalid_face_indices)} invalid face(s).')
|
||||
|
||||
bm.to_mesh(mesh_data)
|
||||
|
||||
@@ -168,7 +173,7 @@ def import_psk(psk: Psk, context, options: PskImportOptions) -> PskImportResult:
|
||||
data_index = 0
|
||||
uv_layer = mesh_data.uv_layers.new(name='VTXW0000')
|
||||
for face_index, face in enumerate(psk.faces):
|
||||
if face_index in degenerate_face_indices:
|
||||
if face_index in invalid_face_indices:
|
||||
continue
|
||||
face_wedges = [psk.wedges[i] for i in reversed(face.wedge_indices)]
|
||||
for wedge in face_wedges:
|
||||
@@ -183,7 +188,7 @@ def import_psk(psk: Psk, context, options: PskImportOptions) -> PskImportResult:
|
||||
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:
|
||||
if face_index in invalid_face_indices:
|
||||
continue
|
||||
for wedge_index in reversed(face.wedge_indices):
|
||||
u, v = psk.extra_uvs[wedge_index_offset + wedge_index]
|
||||
|
||||
@@ -78,4 +78,16 @@ def read_psk(path: str) -> Psk:
|
||||
'''
|
||||
psk.material_references = _read_material_references(path)
|
||||
|
||||
'''
|
||||
Tools like UEViewer and CUE4Parse write the point index as a 32-bit integer, exploiting the fact that due to struct
|
||||
alignment, there were 16-bits of padding following the original 16-bit point index in the wedge struct.
|
||||
However, this breaks compatibility with PSK files that were created with older tools that treated the
|
||||
point index as a 16-bit integer and might have junk data written to the padding bits.
|
||||
To work around this, we check if each point is still addressable using a 16-bit index, and if it is, assume the
|
||||
point index is a 16-bit integer and truncate the high bits.
|
||||
'''
|
||||
if len(psk.points) <= 65536:
|
||||
for wedge in psk.wedges:
|
||||
wedge.point_index &= 0xFFFF
|
||||
|
||||
return psk
|
||||
|
||||
Reference in New Issue
Block a user